LeechCraft  %{LEECHCRAFT_VERSION}
Modular cross-platform feature rich live environment.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
tagslineedit.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * LeechCraft - modular cross-platform feature rich internet client.
3  * Copyright (C) 2006-2013 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 "tagscompletionmodel.h"
38 #include "tagscompleter.h"
39 
40 using namespace LeechCraft::Util;
41 
42 TagsLineEdit::TagsLineEdit (QWidget *parent)
43 : QLineEdit (parent)
44 , Completer_ (0)
45 , Separator_ ("; ")
46 {
47 }
48 
50 {
51  CategorySelector_.reset (new CategorySelector (parentWidget ()));
52  CategorySelector_->SetSeparator (Separator_);
53  CategorySelector_->hide ();
54 
55  QAbstractItemModel *model = Completer_->model ();
56 
57  if (model->metaObject ()->indexOfSignal (QMetaObject::normalizedSignature ("tagsUpdated (QStringList)")) >= 0)
58  connect (model,
59  SIGNAL (tagsUpdated (QStringList)),
60  this,
61  SLOT (handleTagsUpdated (QStringList)));
62 
63  QStringList initialTags;
64  for (int i = 0; i < model->rowCount (); ++i)
65  initialTags << model->data (model->index (i, 0)).toString ();
66  handleTagsUpdated (initialTags);
67 
68  connect (CategorySelector_.get (),
69  SIGNAL (tagsSelectionChanged (const QStringList&)),
70  this,
71  SLOT (handleSelectionChanged (const QStringList&)));
72 
73  connect (this,
74  SIGNAL (textChanged (const QString&)),
75  CategorySelector_.get (),
76  SLOT (lineTextChanged (const QString&)));
77 }
78 
80 {
81  return Separator_;
82 }
83 
84 void TagsLineEdit::SetSeparator (const QString& sep)
85 {
86  Separator_ = sep;
87  if (CategorySelector_)
88  CategorySelector_->SetSeparator (sep);
89 }
90 
91 void TagsLineEdit::insertTag (const QString& completion)
92 {
93  if (Completer_->widget () != this)
94  return;
95 
96  QString wtext = text ();
97  if (completion.startsWith (wtext))
98  wtext.clear ();
99  int pos = wtext.lastIndexOf (Separator_);
100  if (pos >= 0)
101  wtext = wtext.left (pos).append (Separator_);
102  else
103  wtext.clear ();
104  wtext.append (completion);
105  wtext = wtext.simplified ();
106  setText (wtext);
107 
108  emit tagsChosen ();
109 }
110 
111 void TagsLineEdit::handleTagsUpdated (const QStringList& tags)
112 {
113  CategorySelector_->setPossibleSelections (tags);
114 }
115 
116 void TagsLineEdit::setTags (const QStringList& tags)
117 {
118  setText (tags.join (Separator_));
119  if (CategorySelector_.get ())
120  CategorySelector_->SetSelections (tags);
121 }
122 
123 void TagsLineEdit::handleSelectionChanged (const QStringList& tags)
124 {
125  setText (tags.join (Separator_));
126 
127  emit tagsChosen ();
128 }
129 
130 void TagsLineEdit::keyPressEvent (QKeyEvent *e)
131 {
132  if (Completer_ && Completer_->popup ()->isVisible ())
133  switch (e->key ())
134  {
135  case Qt::Key_Enter:
136  case Qt::Key_Return:
137  case Qt::Key_Escape:
138  case Qt::Key_Tab:
139  case Qt::Key_Backtab:
140  e->ignore ();
141  return;
142  default:
143  break;
144  }
145 
146  QLineEdit::keyPressEvent (e);
147 
148  bool cos = e->modifiers () & (Qt::ControlModifier |
149  Qt::ShiftModifier |
150  Qt::AltModifier |
151  Qt::MetaModifier);
152  bool isShortcut = e->modifiers () & (Qt::ControlModifier |
153  Qt::AltModifier |
154  Qt::ShiftModifier);
155  if (!Completer_ ||
156  (cos && e->text ().isEmpty ()) ||
157  isShortcut)
158  return;
159 
160  QString completionPrefix = textUnderCursor ();
161  Completer_->setCompletionPrefix (completionPrefix);
162  Completer_->popup ()->
163  setCurrentIndex (Completer_->completionModel ()->index (0, 0));
164  Completer_->complete ();
165 }
166 
167 void TagsLineEdit::focusInEvent (QFocusEvent *e)
168 {
169  if (Completer_)
170  Completer_->setWidget (this);
171  QLineEdit::focusInEvent (e);
172 }
173 
174 void TagsLineEdit::contextMenuEvent (QContextMenuEvent *e)
175 {
176  if (!CategorySelector_.get ())
177  {
178  QLineEdit::contextMenuEvent (e);
179  return;
180  }
181 
182  CategorySelector_->move (e->globalPos ());
183  CategorySelector_->show ();
184 }
185 
187 {
188  if (Completer_)
189  disconnect (Completer_,
190  0,
191  this,
192  0);
193 
194  Completer_ = c;
195 
196  if (!Completer_)
197  return;
198 
199  Completer_->setWidget (this);
200  Completer_->setCompletionMode (QCompleter::PopupCompletion);
201  connect (Completer_,
202  SIGNAL (activated (const QString&)),
203  this,
204  SLOT (insertTag (const QString&)));
205 }
206 
207 QString TagsLineEdit::textUnderCursor () const
208 {
209  auto rxStr = Separator_;
210  rxStr.replace (' ', "\\s*");
211 
212  QRegExp rx (rxStr);
213 
214  QString wtext = text ();
215  int pos = cursorPosition () - 1;
216  int last = wtext.indexOf (rx, pos);
217  int first = wtext.lastIndexOf (rx, pos);
218  if (first == -1)
219  first = 0;
220  if (last == -1)
221  last = wtext.size ();
222  return wtext.mid (first, last - first);
223 }
224 
UTIL_API void setTags(const QStringList &tags)
Sets the currently selected tags.
UTIL_API void AddSelector()
Adds the selector widget to the line edit.
virtual void focusInEvent(QFocusEvent *)
UTIL_API void insertTag(const QString &string)
Completes the string.
UTIL_API void handleTagsUpdated(const QStringList &allTags)
Sets thew new list of the available tags.
Completer suitable for tag completion.
Definition: tagscompleter.h:58
UTIL_API TagsLineEdit(QWidget *parent)
Constructs the line edit widget.
UTIL_API void SetSeparator(const QString &)
Sets the separator for the tags.
void SetCompleter(TagsCompleter *)
virtual void keyPressEvent(QKeyEvent *)
The CategorySelector widget provides a way to select amongst a group of items.
virtual void contextMenuEvent(QContextMenuEvent *)
UTIL_API QString GetSeparator() const
Returns the separator for the tags.