LeechCraft  %{LEECHCRAFT_VERSION}
Modular cross-platform feature rich live environment.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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  * Boost Software License - Version 1.0 - August 17th, 2003
6  *
7  * Permission is hereby granted, free of charge, to any person or organization
8  * obtaining a copy of the software and accompanying documentation covered by
9  * this license (the "Software") to use, reproduce, display, distribute,
10  * execute, and transmit the Software, and to prepare derivative works of the
11  * Software, and to permit third-parties to whom the Software is furnished to
12  * do so, all subject to the following:
13  *
14  * The copyright notices in the Software and this entire statement, including
15  * the above license grant, this restriction and the following disclaimer,
16  * must be included in all copies of the Software, in whole or in part, and
17  * all derivative works of the Software, unless such copies or derivative
18  * works are solely in the form of machine-executable object code generated by
19  * a source language processor.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  **********************************************************************/
29 
30 #include "tagslineedit.h"
31 #include <QtDebug>
32 #include <QTimer>
33 #include <QCompleter>
34 #include <QContextMenuEvent>
35 #include <QHBoxLayout>
36 #include <QPushButton>
37 #include <QToolButton>
39 #include "tagscompletionmodel.h"
40 #include "tagscompleter.h"
41 
42 namespace LeechCraft
43 {
44 namespace Util
45 {
46  TagsLineEdit::TagsLineEdit (QWidget *parent)
47  : QLineEdit (parent)
48  , Completer_ (0)
49  , Separator_ ("; ")
50  {
51  }
52 
54  {
55  CategorySelector_.reset (new CategorySelector (parentWidget ()));
56  CategorySelector_->SetSeparator (Separator_);
57  CategorySelector_->hide ();
58 
59  QAbstractItemModel *model = Completer_->model ();
60 
61  if (model->metaObject ()->indexOfSignal (QMetaObject::normalizedSignature ("tagsUpdated (QStringList)")) >= 0)
62  connect (model,
63  SIGNAL (tagsUpdated (QStringList)),
64  this,
65  SLOT (handleTagsUpdated (QStringList)));
66 
67  QStringList initialTags;
68  for (int i = 0; i < model->rowCount (); ++i)
69  initialTags << model->data (model->index (i, 0)).toString ();
70  handleTagsUpdated (initialTags);
71 
72  connect (CategorySelector_.get (),
73  SIGNAL (tagsSelectionChanged (const QStringList&)),
74  this,
75  SLOT (handleSelectionChanged (const QStringList&)));
76 
77  connect (this,
78  SIGNAL (textChanged (const QString&)),
79  CategorySelector_.get (),
80  SLOT (lineTextChanged (const QString&)));
81 
82  if (!mgr)
83  mgr = new LineEditButtonManager { this };
84 
85  auto button = new QToolButton { this };
86  button->setIconSize ({ 16, 16 });
87  button->setIcon (QIcon::fromTheme ("mail-tagged"));
88  button->setCursor (Qt::ArrowCursor);
89  button->setStyleSheet ("QToolButton { border: none; padding: 0px; }");
90 
91  mgr->Add (button);
92 
93  connect (button,
94  SIGNAL (clicked ()),
95  this,
96  SLOT (showSelector ()));
97  }
98 
99  QString TagsLineEdit::GetSeparator () const
100  {
101  return Separator_;
102  }
103 
104  void TagsLineEdit::SetSeparator (const QString& sep)
105  {
106  Separator_ = sep;
107  if (CategorySelector_)
108  CategorySelector_->SetSeparator (sep);
109  }
110 
111  void TagsLineEdit::insertTag (const QString& completion)
112  {
113  if (Completer_->widget () != this)
114  return;
115 
116  QString wtext = text ();
117  if (completion.startsWith (wtext))
118  wtext.clear ();
119  int pos = wtext.lastIndexOf (Separator_);
120  if (pos >= 0)
121  wtext = wtext.left (pos).append (Separator_);
122  else
123  wtext.clear ();
124  wtext.append (completion);
125  wtext = wtext.simplified ();
126  setText (wtext);
127 
128  emit tagsChosen ();
129  }
130 
131  void TagsLineEdit::handleTagsUpdated (const QStringList& tags)
132  {
133  CategorySelector_->setPossibleSelections (tags);
134  }
135 
136  void TagsLineEdit::setTags (const QStringList& tags)
137  {
138  setText (tags.join (Separator_));
139  if (CategorySelector_.get ())
140  CategorySelector_->SetSelections (tags);
141  }
142 
143  void TagsLineEdit::handleSelectionChanged (const QStringList& tags)
144  {
145  setText (tags.join (Separator_));
146 
147  emit tagsChosen ();
148  }
149 
150  void TagsLineEdit::showSelector ()
151  {
152  CategorySelector_->move (QCursor::pos ());
153  CategorySelector_->show ();
154  }
155 
156  void TagsLineEdit::keyPressEvent (QKeyEvent *e)
157  {
158  if (Completer_ && Completer_->popup ()->isVisible ())
159  switch (e->key ())
160  {
161  case Qt::Key_Enter:
162  case Qt::Key_Return:
163  case Qt::Key_Escape:
164  case Qt::Key_Tab:
165  case Qt::Key_Backtab:
166  e->ignore ();
167  return;
168  default:
169  break;
170  }
171 
172  QLineEdit::keyPressEvent (e);
173 
174  bool cos = e->modifiers () & (Qt::ControlModifier |
175  Qt::ShiftModifier |
176  Qt::AltModifier |
177  Qt::MetaModifier);
178  bool isShortcut = e->modifiers () & (Qt::ControlModifier |
179  Qt::AltModifier |
180  Qt::ShiftModifier);
181  if (!Completer_ ||
182  (cos && e->text ().isEmpty ()) ||
183  isShortcut)
184  return;
185 
186  QString completionPrefix = textUnderCursor ();
187  Completer_->setCompletionPrefix (completionPrefix);
188  Completer_->popup ()->
189  setCurrentIndex (Completer_->completionModel ()->index (0, 0));
190  Completer_->complete ();
191  }
192 
193  void TagsLineEdit::focusInEvent (QFocusEvent *e)
194  {
195  if (Completer_)
196  Completer_->setWidget (this);
197  QLineEdit::focusInEvent (e);
198  }
199 
200  void TagsLineEdit::contextMenuEvent (QContextMenuEvent *e)
201  {
202  if (!CategorySelector_.get ())
203  {
204  QLineEdit::contextMenuEvent (e);
205  return;
206  }
207 
208  CategorySelector_->move (e->globalPos ());
209  CategorySelector_->show ();
210  }
211 
213  {
214  if (Completer_)
215  disconnect (Completer_,
216  0,
217  this,
218  0);
219 
220  Completer_ = c;
221 
222  if (!Completer_)
223  return;
224 
225  Completer_->setWidget (this);
226  Completer_->setCompletionMode (QCompleter::PopupCompletion);
227  connect (Completer_,
228  SIGNAL (activated (const QString&)),
229  this,
230  SLOT (insertTag (const QString&)));
231  }
232 
233  QString TagsLineEdit::textUnderCursor () const
234  {
235  auto rxStr = Separator_;
236  rxStr.replace (' ', "\\s*");
237 
238  QRegExp rx (rxStr);
239 
240  QString wtext = text ();
241  int pos = cursorPosition () - 1;
242  int last = wtext.indexOf (rx, pos);
243  int first = wtext.lastIndexOf (rx, pos);
244  if (first == -1)
245  first = 0;
246  if (last == -1)
247  last = wtext.size ();
248  return wtext.mid (first, last - first);
249  }
250 }
251 }
virtual void keyPressEvent(QKeyEvent *)
void handleTagsUpdated(const QStringList &allTags)
Sets thew new list of the available tags.
Manages additional overlay buttons in a QLineEdit.
void insertTag(const QString &string)
Completes the string.
TagsLineEdit(QWidget *parent)
Constructs the line edit widget.
void Add(QToolButton *button)
Adds a button to the line edit.
Completer suitable for tag completion.
Definition: tagscompleter.h:58
QString GetSeparator() const
Returns the separator for the tags.
void SetSeparator(const QString &)
Sets the separator for the tags.
void SetCompleter(TagsCompleter *)
virtual void focusInEvent(QFocusEvent *)
virtual void contextMenuEvent(QContextMenuEvent *)
The CategorySelector widget provides a way to select amongst a group of items.
void setTags(const QStringList &tags)
Sets the currently selected tags.
void AddSelector(LineEditButtonManager *manager=nullptr)
Adds the selector widget to the line edit.