• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KDEUI

  • sources
  • kde-4.12
  • kdelibs
  • kdeui
  • widgets
khistorycombobox.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2 
3  Copyright (c) 2000,2001 Dawit Alemayehu <adawit@kde.org>
4  Copyright (c) 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
5  Copyright (c) 2000 Stefan Schimanski <1Stein@gmx.de>
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License (LGPL) as published by the Free Software Foundation; either
10  version 2 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public License
18  along with this library; see the file COPYING.LIB. If not, write to
19  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  Boston, MA 02110-1301, USA.
21 */
22 
23 #include "khistorycombobox.h"
24 
25 #include <QtGui/QAbstractItemView>
26 #include <QtGui/QApplication>
27 #include <QtGui/QKeyEvent>
28 #include <QtGui/QMenu>
29 #include <QtGui/QWheelEvent>
30 
31 #include <klocale.h>
32 #include <knotification.h>
33 #include <kpixmapprovider.h>
34 #include <kstandardshortcut.h>
35 #include <kicontheme.h>
36 #include <kicon.h>
37 
38 #include <kdebug.h>
39 
40 class KHistoryComboBox::Private
41 {
42 public:
43  Private(KHistoryComboBox *q): q(q), myPixProvider(0) {}
44 
45  KHistoryComboBox *q;
46 
50  int myIterateIndex;
51 
55  QString myText;
56 
61  bool myRotated;
62  KPixmapProvider *myPixProvider;
63 };
64 
65 // we are always read-write
66 KHistoryComboBox::KHistoryComboBox( QWidget *parent )
67  : KComboBox( true, parent ), d(new Private(this))
68 {
69  init( true ); // using completion
70 }
71 
72 // we are always read-write
73 KHistoryComboBox::KHistoryComboBox( bool useCompletion,
74  QWidget *parent )
75  : KComboBox( true, parent ), d(new Private(this))
76 {
77  init( useCompletion );
78 }
79 
80 void KHistoryComboBox::init( bool useCompletion )
81 {
82  // Set a default history size to something reasonable, Qt sets it to INT_MAX by default
83  setMaxCount( 50 );
84 
85  if ( useCompletion )
86  completionObject()->setOrder( KCompletion::Weighted );
87 
88  setInsertPolicy( NoInsert );
89  d->myIterateIndex = -1;
90  d->myRotated = false;
91  d->myPixProvider = 0L;
92 
93  // obey HISTCONTROL setting
94  QByteArray histControl = qgetenv("HISTCONTROL");
95  if ( histControl == "ignoredups" || histControl == "ignoreboth" )
96  setDuplicatesEnabled( false );
97 
98  connect(this, SIGNAL(aboutToShowContextMenu(QMenu*)), SLOT(addContextMenuItems(QMenu*)));
99  connect(this, SIGNAL(activated(int)), SLOT(slotReset()));
100  connect(this, SIGNAL(returnPressed(QString)), SLOT(slotReset()));
101  // We want slotSimulateActivated to be called _after_ QComboBoxPrivate::_q_returnPressed
102  // otherwise there's a risk of emitting activated twice (slotSimulateActivated will find
103  // the item, after some app's slotActivated inserted the item into the combo).
104  connect(this, SIGNAL(returnPressed(QString)), SLOT(slotSimulateActivated(QString)), Qt::QueuedConnection);
105 }
106 
107 KHistoryComboBox::~KHistoryComboBox()
108 {
109  delete d->myPixProvider;
110  delete d;
111 }
112 
113 void KHistoryComboBox::setHistoryItems( const QStringList &items )
114 {
115  setHistoryItems(items, false);
116 }
117 
118 void KHistoryComboBox::setHistoryItems( const QStringList &items,
119  bool setCompletionList )
120 {
121  QStringList insertingItems = items;
122  KComboBox::clear();
123 
124  // limit to maxCount()
125  const int itemCount = insertingItems.count();
126  const int toRemove = itemCount - maxCount();
127 
128  if (toRemove >= itemCount) {
129  insertingItems.clear();
130  } else {
131  for (int i = 0; i < toRemove; ++i)
132  insertingItems.pop_front();
133  }
134 
135  insertItems( insertingItems );
136 
137  if ( setCompletionList && useCompletion() ) {
138  // we don't have any weighting information here ;(
139  KCompletion *comp = completionObject();
140  comp->setOrder( KCompletion::Insertion );
141  comp->setItems( insertingItems );
142  comp->setOrder( KCompletion::Weighted );
143  }
144 
145  clearEditText();
146 }
147 
148 QStringList KHistoryComboBox::historyItems() const
149 {
150  QStringList list;
151  const int itemCount = count();
152  for ( int i = 0; i < itemCount; ++i )
153  list.append( itemText( i ) );
154 
155  return list;
156 }
157 
158 bool KHistoryComboBox::useCompletion() const
159 {
160  return compObj();
161 }
162 
163 void KHistoryComboBox::clearHistory()
164 {
165  const QString temp = currentText();
166  KComboBox::clear();
167  if ( useCompletion() )
168  completionObject()->clear();
169  setEditText( temp );
170 }
171 
172 void KHistoryComboBox::addContextMenuItems( QMenu* menu )
173 {
174  if ( menu )
175  {
176  menu->addSeparator();
177  QAction* clearHistory = menu->addAction( KIcon("edit-clear-history"), i18n("Clear &History"), this, SLOT(slotClear()));
178  if (!count())
179  clearHistory->setEnabled(false);
180  }
181 }
182 
183 void KHistoryComboBox::addToHistory( const QString& item )
184 {
185  if ( item.isEmpty() || (count() > 0 && item == itemText(0) )) {
186  return;
187  }
188 
189  bool wasCurrent = false;
190  // remove all existing items before adding
191  if ( !duplicatesEnabled() ) {
192  int i = 0;
193  int itemCount = count();
194  while ( i < itemCount ) {
195  if ( itemText( i ) == item ) {
196  if ( !wasCurrent )
197  wasCurrent = ( i == currentIndex() );
198  removeItem( i );
199  --itemCount;
200  } else {
201  ++i;
202  }
203  }
204  }
205 
206  // now add the item
207  if ( d->myPixProvider )
208  insertItem( 0, d->myPixProvider->pixmapFor(item, iconSize().height()), item);
209  else
210  insertItem( 0, item );
211 
212  if ( wasCurrent )
213  setCurrentIndex( 0 );
214 
215  const bool useComp = useCompletion();
216 
217  const int last = count() - 1; // last valid index
218  const int mc = maxCount();
219  const int stopAt = qMax(mc, 0);
220 
221  for (int rmIndex = last; rmIndex >= stopAt; --rmIndex) {
222  // remove the last item, as long as we are longer than maxCount()
223  // remove the removed item from the completionObject if it isn't
224  // anymore available at all in the combobox.
225  const QString rmItem = itemText( rmIndex );
226  removeItem( rmIndex );
227  if ( useComp && !contains( rmItem ) )
228  completionObject()->removeItem( rmItem );
229  }
230 
231  if ( useComp )
232  completionObject()->addItem( item );
233 }
234 
235 bool KHistoryComboBox::removeFromHistory( const QString& item )
236 {
237  if ( item.isEmpty() )
238  return false;
239 
240  bool removed = false;
241  const QString temp = currentText();
242  int i = 0;
243  int itemCount = count();
244  while ( i < itemCount ) {
245  if ( item == itemText( i ) ) {
246  removed = true;
247  removeItem( i );
248  --itemCount;
249  } else {
250  ++i;
251  }
252  }
253 
254  if ( removed && useCompletion() )
255  completionObject()->removeItem( item );
256 
257  setEditText( temp );
258  return removed;
259 }
260 
261 // going up in the history, rotating when reaching QListBox::count()
262 //
263 // Note: this differs from QComboBox because "up" means ++index here,
264 // to simulate the way shell history works (up goes to the most
265 // recent item). In QComboBox "down" means ++index, to match the popup...
266 //
267 void KHistoryComboBox::rotateUp()
268 {
269  // save the current text in the lineedit
270  // (This is also where this differs from standard up/down in QComboBox,
271  // where a single keypress can make you lose your typed text)
272  if ( d->myIterateIndex == -1 )
273  d->myText = currentText();
274 
275  ++d->myIterateIndex;
276 
277  // skip duplicates/empty items
278  const int last = count() - 1; // last valid index
279  const QString currText = currentText();
280 
281  while ( d->myIterateIndex < last &&
282  (currText == itemText( d->myIterateIndex ) ||
283  itemText( d->myIterateIndex ).isEmpty()) )
284  ++d->myIterateIndex;
285 
286  if ( d->myIterateIndex >= count() ) {
287  d->myRotated = true;
288  d->myIterateIndex = -1;
289 
290  // if the typed text is the same as the first item, skip the first
291  if ( count() > 0 && d->myText == itemText(0) )
292  d->myIterateIndex = 0;
293 
294  setEditText( d->myText );
295  } else {
296  setCurrentIndex(d->myIterateIndex);
297  }
298 }
299 
300 // going down in the history, no rotation possible. Last item will be
301 // the text that was in the lineedit before Up was called.
302 void KHistoryComboBox::rotateDown()
303 {
304  // save the current text in the lineedit
305  if ( d->myIterateIndex == -1 )
306  d->myText = currentText();
307 
308  --d->myIterateIndex;
309 
310  const QString currText = currentText();
311  // skip duplicates/empty items
312  while ( d->myIterateIndex >= 0 &&
313  (currText == itemText( d->myIterateIndex ) ||
314  itemText( d->myIterateIndex ).isEmpty()) )
315  --d->myIterateIndex;
316 
317 
318  if ( d->myIterateIndex < 0 ) {
319  if ( d->myRotated && d->myIterateIndex == -2 ) {
320  d->myRotated = false;
321  d->myIterateIndex = count() - 1;
322  setEditText( itemText(d->myIterateIndex) );
323  }
324  else { // bottom of history
325  if ( d->myIterateIndex == -2 ) {
326  KNotification::event( "Textcompletion: No Match" ,
327  i18n("No further items in the history."),
328  QPixmap() , this, KNotification::DefaultEvent);
329  }
330 
331  d->myIterateIndex = -1;
332  if ( currentText() != d->myText )
333  setEditText( d->myText );
334  }
335  } else {
336  setCurrentIndex(d->myIterateIndex);
337  }
338 }
339 
340 void KHistoryComboBox::keyPressEvent( QKeyEvent *e )
341 {
342  int event_key = e->key() | e->modifiers();
343 
344  if ( KStandardShortcut::rotateUp().contains(event_key) )
345  rotateUp();
346  else if ( KStandardShortcut::rotateDown().contains(event_key) )
347  rotateDown();
348  else
349  KComboBox::keyPressEvent( e );
350 }
351 
352 void KHistoryComboBox::wheelEvent( QWheelEvent *ev )
353 {
354  // Pass to poppable listbox if it's up
355  QAbstractItemView* const iv = view();
356  if ( iv && iv->isVisible() )
357  {
358  QApplication::sendEvent( iv, ev );
359  return;
360  }
361  // Otherwise make it change the text without emitting activated
362  if ( ev->delta() > 0 ) {
363  rotateUp();
364  } else {
365  rotateDown();
366  }
367  ev->accept();
368 }
369 
370 void KHistoryComboBox::slotReset()
371 {
372  d->myIterateIndex = -1;
373  d->myRotated = false;
374 }
375 
376 
377 void KHistoryComboBox::setPixmapProvider( KPixmapProvider *prov )
378 {
379  if ( d->myPixProvider == prov )
380  return;
381 
382  delete d->myPixProvider;
383  d->myPixProvider = prov;
384 
385  // re-insert all the items with/without pixmap
386  // I would prefer to use changeItem(), but that doesn't honor the pixmap
387  // when using an editable combobox (what we do)
388  if ( count() > 0 ) {
389  QStringList items( historyItems() );
390  clear();
391  insertItems( items );
392  }
393 }
394 
395 void KHistoryComboBox::insertItems( const QStringList& items )
396 {
397  QStringList::ConstIterator it = items.constBegin();
398  const QStringList::ConstIterator itEnd = items.constEnd();
399 
400  while ( it != itEnd ) {
401  const QString item = *it;
402  if ( !item.isEmpty() ) { // only insert non-empty items
403  if ( d->myPixProvider )
404  addItem( d->myPixProvider->pixmapFor(item, iconSize().height()),
405  item );
406  else
407  addItem( item );
408  }
409  ++it;
410  }
411 }
412 
413 void KHistoryComboBox::slotClear()
414 {
415  clearHistory();
416  emit cleared();
417 }
418 
419 void KHistoryComboBox::slotSimulateActivated( const QString& text )
420 {
421  /* With the insertion policy NoInsert, which we use by default,
422  Qt doesn't emit activated on typed text if the item is not already there,
423  which is perhaps reasonable. Generate the signal ourselves if that's the case.
424  */
425  if ((insertPolicy() == NoInsert && findText(text, Qt::MatchFixedString|Qt::MatchCaseSensitive) == -1)) {
426  emit activated(text);
427  }
428 
429  /*
430  Qt also doesn't emit it if the box is full, and policy is not
431  InsertAtCurrent
432  */
433  else if (insertPolicy() != InsertAtCurrent && count() >= maxCount()) {
434  emit activated(text);
435  }
436 }
437 
438 KPixmapProvider *KHistoryComboBox::pixmapProvider() const
439 {
440  return d->myPixProvider;
441 }
442 
443 void KHistoryComboBox::reset()
444 {
445  slotReset();
446 }
447 
448 #include "khistorycombobox.moc"
KHistoryComboBox::insertItems
void insertItems(const QStringList &items)
Inserts items into the combo, honoring pixmapProvider() Does not update the completionObject.
Definition: khistorycombobox.cpp:395
i18n
QString i18n(const char *text)
KNotification::DefaultEvent
Definition: knotification.h:247
KCompletion::clear
virtual void clear()
Removes all inserted items.
Definition: kcompletion.cpp:218
setEditText
static void setEditText(KLineEdit *edit, const QString &text)
Definition: klineedit.cpp:1454
kdebug.h
KCompletion::Weighted
Use weighted order.
Definition: kcompletion.h:145
KHistoryComboBox::pixmapProvider
KPixmapProvider * pixmapProvider() const
Definition: khistorycombobox.cpp:438
QWidget
KHistoryComboBox::clearHistory
void clearHistory()
Clears the history and the completion list.
Definition: khistorycombobox.cpp:163
KHistoryComboBox::wheelEvent
virtual void wheelEvent(QWheelEvent *ev)
Handling wheel-events, to rotate the items.
Definition: khistorycombobox.cpp:352
KCompletionBase::compObj
KCompletion * compObj() const
Returns a pointer to the completion object.
Definition: kcompletionbase.cpp:220
KComboBox::contains
bool contains(const QString &text) const
Convenience method which iterates over all items and checks if any of them is equal to text...
Definition: kcombobox.cpp:88
QString
KHistoryComboBox::removeFromHistory
bool removeFromHistory(const QString &item)
Removes all items named item.
Definition: khistorycombobox.cpp:235
klocale.h
KHistoryComboBox::addToHistory
void addToHistory(const QString &item)
Adds an item to the end of the history list and to the completion list.
Definition: khistorycombobox.cpp:183
KComboBox::aboutToShowContextMenu
void aboutToShowContextMenu(QMenu *p)
Emitted before the context menu is displayed.
KHistoryComboBox
A combobox for offering a history and completion.
Definition: khistorycombobox.h:48
knotification.h
KCompletion::Insertion
Use order of insertion.
Definition: kcompletion.h:144
kpixmapprovider.h
KHistoryComboBox::KHistoryComboBox
KHistoryComboBox(QWidget *parent=0)
Constructs a "read-write" combobox.
Definition: khistorycombobox.cpp:66
QStringList
KHistoryComboBox::keyPressEvent
virtual void keyPressEvent(QKeyEvent *)
Handling key-events, the shortcuts to rotate the items.
Definition: khistorycombobox.cpp:340
KCompletion
A generic class for completing QStrings.
Definition: kcompletion.h:130
KIcon
A wrapper around QIcon that provides KDE icon features.
Definition: kicon.h:40
KStandardAction::clear
KAction * clear(const QObject *recvr, const char *slot, QObject *parent)
Clear the content of the focus widget.
Definition: kstandardaction.cpp:314
KHistoryComboBox::reset
void reset()
Resets the current position of the up/down history.
Definition: khistorycombobox.cpp:443
khistorycombobox.h
KComboBox::returnPressed
void returnPressed()
Emitted when the user presses the Enter key.
KCompletion::setItems
virtual void setItems(const QStringList &list)
Sets the list of items available for completion.
Definition: kcompletion.cpp:99
KHistoryComboBox::~KHistoryComboBox
~KHistoryComboBox()
Destructs the combo, the completion-object and the pixmap-provider.
Definition: khistorycombobox.cpp:107
kstandardshortcut.h
KCompletionBase::completionObject
KCompletion * completionObject(bool hsig=true)
Returns a pointer to the current completion object.
Definition: kcompletionbase.cpp:96
kicontheme.h
QMenu
KNotification::event
static KNotification * event(const QString &eventId, const QString &title, const QString &text, const QPixmap &pixmap=QPixmap(), QWidget *widget=0L, const NotificationFlags &flags=CloseOnTimeout, const KComponentData &componentData=KComponentData())
emit an event
Definition: knotification.cpp:291
KHistoryComboBox::useCompletion
bool useCompletion() const
Definition: khistorycombobox.cpp:158
KComboBox
An enhanced combo box.
Definition: kcombobox.h:148
KCompletion::removeItem
void removeItem(const QString &item)
Removes an item from the list of available completions.
Definition: kcompletion.cpp:208
KCompletion::addItem
void addItem(const QString &item)
Adds an item to the list of available completions.
Definition: kcompletion.cpp:146
KStandardShortcut::rotateDown
const KShortcut & rotateDown()
Help users iterate through a list of entries.
Definition: kstandardshortcut.cpp:367
KHistoryComboBox::setPixmapProvider
void setPixmapProvider(KPixmapProvider *prov)
Sets a pixmap provider, so that items in the combobox can have a pixmap.
Definition: khistorycombobox.cpp:377
kicon.h
KHistoryComboBox::Private
friend class Private
Definition: khistorycombobox.h:273
KStandardShortcut::rotateUp
const KShortcut & rotateUp()
Help users iterate through a list of entries.
Definition: kstandardshortcut.cpp:366
KPixmapProvider
A tiny abstract class with just one method: pixmapFor()
Definition: kpixmapprovider.h:38
KHistoryComboBox::setHistoryItems
void setHistoryItems(const QStringList &items)
Inserts items into the combobox.
Definition: khistorycombobox.cpp:113
KCompletion::setOrder
virtual void setOrder(CompOrder order)
KCompletion offers three different ways in which it offers its items:
Definition: kcompletion.cpp:78
QAction
KHistoryComboBox::historyItems
QStringList historyItems() const
Returns the list of history items.
KHistoryComboBox::cleared
void cleared()
Emitted when the history was cleared by the entry in the popup menu.
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:49:14 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal