LeechCraft  0.6.70-16373-g319c272718
Modular cross-platform feature rich live environment.
tagslineedit.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * LeechCraft - modular cross-platform feature rich internet client.
3  * Copyright (C) 2006-2014 Georg Rudoy
4  *
5  * Distributed under the Boost Software License, Version 1.0.
6  * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7  **********************************************************************/
8 
9 #include "tagslineedit.h"
10 #include <QtDebug>
11 #include <QTimer>
12 #include <QCompleter>
13 #include <QContextMenuEvent>
14 #include <QHBoxLayout>
15 #include <QPushButton>
16 #include <QToolButton>
17 #include <QAbstractItemView>
18 #include <util/sll/qtutil.h>
20 #include "tagscompletionmodel.h"
21 #include "tagscompleter.h"
22 #include "util.h"
23 
24 namespace LC::Util
25 {
26  TagsLineEdit::TagsLineEdit (QWidget *parent)
27  : QLineEdit (parent)
28  , Separator_ (GetDefaultTagsSeparator ())
29  {
30  }
31 
33  {
34  auto selector = new CategorySelector (this);
35  selector->hide ();
36 
37  AddSelector (selector);
38 
39  if (!mgr)
40  mgr = new LineEditButtonManager { this };
41 
42  auto button = new QToolButton { this };
43  button->setIconSize ({ 16, 16 });
44  button->setIcon (QIcon::fromTheme (QStringLiteral ("mail-tagged")));
45  button->setCursor (Qt::ArrowCursor);
46  button->setStyleSheet (QStringLiteral ("QToolButton { border: none; padding: 0px; }"));
47 
48  mgr->Add (button);
49 
50  connect (button,
51  &QToolButton::clicked,
52  this,
53  [selector]
54  {
55  selector->move (QCursor::pos ());
56  selector->show ();
57  });
58  }
59 
61  {
62  CategorySelector_ = selector;
63  CategorySelector_->SetSeparator (Separator_);
64 
65  QAbstractItemModel *model = Completer_->model ();
66 
67  QStringList initialTags;
68  for (int i = 0; i < model->rowCount (); ++i)
69  initialTags << model->data (model->index (i, 0)).toString ();
70  CategorySelector_->SetPossibleSelections (initialTags);
71 
72  connect (CategorySelector_,
74  this,
75  [this] (const QStringList& tags)
76  {
77  setText (tags.join (Separator_));
78  emit tagsChosen ();
79  });
80 
81  connect (this,
82  &QLineEdit::textChanged,
83  CategorySelector_,
85  }
86 
87  QString TagsLineEdit::GetSeparator () const
88  {
89  return Separator_;
90  }
91 
92  void TagsLineEdit::SetSeparator (const QString& sep)
93  {
94  Separator_ = sep;
95  if (CategorySelector_)
96  CategorySelector_->SetSeparator (sep);
97  }
98 
99  void TagsLineEdit::InsertTag (const QString& completion)
100  {
101  if (Completer_->widget () != this)
102  return;
103 
104  QString wtext = text ();
105  if (completion.startsWith (wtext))
106  wtext.clear ();
107  int pos = wtext.lastIndexOf (Separator_);
108  if (pos >= 0)
109  wtext = wtext.left (pos).append (Separator_);
110  else
111  wtext.clear ();
112  wtext.append (completion);
113  wtext = wtext.simplified ();
114  setText (wtext);
115 
116  emit tagsChosen ();
117  }
118 
119  void TagsLineEdit::setTags (const QStringList& tags)
120  {
121  setText (tags.join (Separator_));
122  if (CategorySelector_)
123  CategorySelector_->SetSelections (tags);
124  }
125 
126  void TagsLineEdit::keyPressEvent (QKeyEvent *e)
127  {
128  if (Completer_ && Completer_->popup ()->isVisible ())
129  switch (e->key ())
130  {
131  case Qt::Key_Enter:
132  case Qt::Key_Return:
133  case Qt::Key_Escape:
134  case Qt::Key_Tab:
135  case Qt::Key_Backtab:
136  e->ignore ();
137  return;
138  default:
139  break;
140  }
141 
142  QLineEdit::keyPressEvent (e);
143 
144  bool cos = e->modifiers () & (Qt::ControlModifier |
145  Qt::ShiftModifier |
146  Qt::AltModifier |
147  Qt::MetaModifier);
148  bool isShortcut = e->modifiers () & (Qt::ControlModifier |
149  Qt::AltModifier |
150  Qt::ShiftModifier);
151  if (!Completer_ ||
152  (cos && e->text ().isEmpty ()) ||
153  isShortcut)
154  return;
155 
156  QString completionPrefix = textUnderCursor ();
157  Completer_->setCompletionPrefix (completionPrefix);
158  Completer_->popup ()->
159  setCurrentIndex (Completer_->completionModel ()->index (0, 0));
160  Completer_->complete ();
161  }
162 
163  void TagsLineEdit::focusInEvent (QFocusEvent *e)
164  {
165  if (Completer_)
166  Completer_->setWidget (this);
167  QLineEdit::focusInEvent (e);
168  }
169 
170  void TagsLineEdit::contextMenuEvent (QContextMenuEvent *e)
171  {
172  if (!CategorySelector_ || CategorySelector_->parentWidget () != this)
173  {
174  QLineEdit::contextMenuEvent (e);
175  return;
176  }
177 
178  CategorySelector_->move (e->globalPos ());
179  CategorySelector_->show ();
180  }
181 
183  {
184  if (Completer_)
185  disconnect (Completer_,
186  nullptr,
187  this,
188  nullptr);
189 
190  Completer_ = c;
191 
192  if (!Completer_)
193  return;
194 
195  Completer_->setWidget (this);
196  Completer_->setCompletionMode (QCompleter::PopupCompletion);
197  connect (Completer_,
198  qOverload<const QString&> (&QCompleter::activated),
199  this,
200  &TagsLineEdit::InsertTag);
201  }
202 
203  QString TagsLineEdit::textUnderCursor () const
204  {
205  auto rxStr = Separator_;
206  rxStr.replace (' ', R"(\s*)"_ql);
207 
208  QRegExp rx (rxStr);
209 
210  QString wtext = text ();
211  int pos = cursorPosition () - 1;
212  int last = wtext.indexOf (rx, pos);
213  int first = wtext.lastIndexOf (rx, pos);
214  if (first == -1)
215  first = 0;
216  if (last == -1)
217  last = wtext.size ();
218  return wtext.mid (first, last - first);
219  }
220 }
QString GetSeparator() const
Returns the separator for the tags.
void AddSelector(LineEditButtonManager *manager=nullptr)
Adds the selector widget to the line edit.
auto && sep
Definition: ctstringutils.h:40
QString GetDefaultTagsSeparator()
Definition: util.cpp:14
void tagsSelectionChanged(const QStringList &newSelections)
Indicates that selections have changed.
TagsLineEdit(QWidget *parent)
Constructs the line edit widget.
void Add(QToolButton *button)
Adds a button to the line edit.
void focusInEvent(QFocusEvent *) override
void contextMenuEvent(QContextMenuEvent *) override
void SetSelectionsFromString(const QString &newText)
Notifies CategorySelector about logical selection changes.
Completer suitable for tag completion.
Definition: tagscompleter.h:38
void SetSeparator(const QString &)
Sets the separator for the tags.
void SetSelections(const QStringList &subset)
Selects some of the items.
void SetSeparator(const QString &)
Sets the separator for the tags.
void setTags(const QStringList &tags)
Sets the currently selected tags.
Manages additional overlay buttons in a QLineEdit.
char * toString(const PKey< T, Args... > &pkey)
Definition: common.h:46
The CategorySelector widget provides a way to select amongst a group of items.
virtual void SetPossibleSelections(QStringList selections, bool sort=true)
Sets possible selections.
void SetCompleter(TagsCompleter *)
void keyPressEvent(QKeyEvent *) override