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

KDEUI

  • kdeui
  • widgets
klineedit.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2 
3  Copyright (C) 1997 Sven Radej (sven.radej@iname.com)
4  Copyright (c) 1999 Patrick Ward <PAT_WARD@HP-USA-om5.om.hp.com>
5  Copyright (c) 1999 Preston Brown <pbrown@kde.org>
6 
7  Re-designed for KDE 2.x by
8  Copyright (c) 2000, 2001 Dawit Alemayehu <adawit@kde.org>
9  Copyright (c) 2000, 2001 Carsten Pfeiffer <pfeiffer@kde.org>
10 
11  This library is free software; you can redistribute it and/or
12  modify it under the terms of the GNU Lesser General Public
13  License (LGPL) as published by the Free Software Foundation;
14  either version 2 of the License, or (at your option) any later
15  version.
16 
17  This library is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  Lesser General Public License for more details.
21 
22  You should have received a copy of the GNU Lesser General Public License
23  along with this library; see the file COPYING.LIB. If not, write to
24  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  Boston, MA 02110-1301, USA.
26 */
27 
28 #include "klineedit.h"
29 #include "klineedit_p.h"
30 
31 #include <kaction.h>
32 #include <kapplication.h>
33 #include <kauthorized.h>
34 #include <kconfig.h>
35 #include <kconfiggroup.h>
36 #include <kcursor.h>
37 #include <kdebug.h>
38 #include <kcompletionbox.h>
39 #include <kicontheme.h>
40 #include <kicon.h>
41 #include <klocale.h>
42 #include <kmenu.h>
43 #include <kstandardaction.h>
44 #include <kstandardshortcut.h>
45 
46 #include <QtCore/QTimer>
47 #include <QtGui/QClipboard>
48 #include <QtGui/QStyleOption>
49 #include <QtGui/QToolTip>
50 
51 class KLineEditStyle;
52 
53 class KLineEditPrivate
54 {
55 public:
56  KLineEditPrivate(KLineEdit* qq)
57  : q(qq)
58  {
59  completionBox = 0L;
60  handleURLDrops = true;
61  grabReturnKeyEvents = false;
62 
63  userSelection = true;
64  autoSuggest = false;
65  disableRestoreSelection = false;
66  enableSqueezedText = false;
67 
68  enableClickMsg = false;
69  threeStars = false;
70  completionRunning = false;
71  if (!s_initialized) {
72  KConfigGroup config( KGlobal::config(), "General" );
73  s_backspacePerformsCompletion = config.readEntry("Backspace performs completion", false);
74  s_initialized = true;
75  }
76 
77  clearButton = 0;
78  clickInClear = false;
79  wideEnoughForClear = true;
80 
81  // i18n: Placeholder text in line edit widgets is the text appearing
82  // before any user input, briefly explaining to the user what to type
83  // (e.g. "Enter search pattern").
84  // By default the text is set in italic, which may not be appropriate
85  // for some languages and scripts (e.g. for CJK ideographs).
86  QString metaMsg = i18nc("Italic placeholder text in line edits: 0 no, 1 yes", "1");
87  italicizePlaceholder = (metaMsg.trimmed() != QString('0'));
88  }
89 
90  ~KLineEditPrivate()
91  {
92 // causes a weird crash in KWord at least, so let Qt delete it for us.
93 // delete completionBox;
94  delete style.data();
95  }
96 
97  void _k_slotSettingsChanged(int category)
98  {
99  Q_UNUSED(category);
100 
101  if (clearButton) {
102  clearButton->setAnimationsEnabled(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects);
103  }
104  }
105 
106  void _k_textChanged(const QString &txt)
107  {
108  // COMPAT (as documented): emit userTextChanged whenever textChanged is emitted
109  // KDE5: remove userTextChanged signal, textEdited does the same...
110  if (!completionRunning && (txt != userText)) {
111  userText = txt;
112 #ifndef KDE_NO_DEPRECATED
113  emit q->userTextChanged(txt);
114 #endif
115  }
116  }
117 
118  // Call this when a completion operation changes the lineedit text
119  // "as if it had been edited by the user".
120  void _k_updateUserText(const QString &txt)
121  {
122  if (!completionRunning && (txt != userText)) {
123  userText = txt;
124  q->setModified(true);
125 #ifndef KDE_NO_DEPRECATED
126  emit q->userTextChanged(txt);
127 #endif
128  emit q->textEdited(txt);
129  emit q->textChanged(txt);
130  }
131  }
132 
133  // This is called when the lineedit is readonly.
134  // Either from setReadOnly() itself, or when we realize that
135  // we became readonly and setReadOnly() wasn't called (because it's not virtual)
136  // Typical case: comboBox->lineEdit()->setReadOnly(true)
137  void adjustForReadOnly()
138  {
139  if (style && style.data()->m_overlap) {
140  style.data()->m_overlap = 0;
141  }
142  }
143 
144 
150  bool overrideShortcut(const QKeyEvent* e);
151 
152  static bool s_initialized;
153  static bool s_backspacePerformsCompletion; // Configuration option
154 
155  QColor previousHighlightColor;
156  QColor previousHighlightedTextColor;
157 
158  bool userSelection: 1;
159  bool autoSuggest : 1;
160  bool disableRestoreSelection: 1;
161  bool handleURLDrops:1;
162  bool grabReturnKeyEvents:1;
163  bool enableSqueezedText:1;
164  bool completionRunning:1;
165 
166  int squeezedEnd;
167  int squeezedStart;
168  QPalette::ColorRole bgRole;
169  QString squeezedText;
170  QString userText;
171 
172  QString clickMessage;
173  bool enableClickMsg:1;
174  bool threeStars:1;
175 
176  bool possibleTripleClick :1; // set in mousePressEvent, deleted in tripleClickTimeout
177 
178  bool clickInClear:1;
179  bool wideEnoughForClear:1;
180  KLineEditButton *clearButton;
181  QWeakPointer<KLineEditStyle> style;
182  QString lastStyleClass;
183 
184  KCompletionBox *completionBox;
185 
186  bool italicizePlaceholder:1;
187 
188  QAction *noCompletionAction, *shellCompletionAction, *autoCompletionAction, *popupCompletionAction, *shortAutoCompletionAction, *popupAutoCompletionAction, *defaultAction;
189 
190  QMap<KGlobalSettings::Completion, bool> disableCompletionMap;
191  KLineEdit* q;
192 };
193 
194 QStyle *KLineEditStyle::style() const
195 {
196  if (m_subStyle) {
197  return m_subStyle.data();
198  }
199 
200  return KdeUiProxyStyle::style();
201 }
202 
203 QRect KLineEditStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
204 {
205  if (element == SE_LineEditContents) {
206  KLineEditStyle *unconstThis = const_cast<KLineEditStyle *>(this);
207 
208  if (m_sentinel) {
209  // we are recursing: we're wrapping a style that wraps us!
210  unconstThis->m_subStyle.clear();
211  }
212 
213  unconstThis->m_sentinel = true;
214  QStyle *s = m_subStyle ? m_subStyle.data() : style();
215  QRect rect = s->subElementRect(SE_LineEditContents, option, widget);
216  unconstThis->m_sentinel = false;
217 
218  if (option->direction == Qt::LeftToRight) {
219  return rect.adjusted(0, 0, -m_overlap, 0);
220  } else {
221  return rect.adjusted(m_overlap, 0, 0, 0);
222  }
223  }
224 
225  return KdeUiProxyStyle::subElementRect(element, option, widget);
226 }
227 
228 bool KLineEditPrivate::s_backspacePerformsCompletion = false;
229 bool KLineEditPrivate::s_initialized = false;
230 
231 
232 KLineEdit::KLineEdit( const QString &string, QWidget *parent )
233  : QLineEdit( string, parent ), d(new KLineEditPrivate(this))
234 {
235  init();
236 }
237 
238 KLineEdit::KLineEdit( QWidget *parent )
239  : QLineEdit( parent ), d(new KLineEditPrivate(this))
240 {
241  init();
242 }
243 
244 
245 KLineEdit::~KLineEdit ()
246 {
247  delete d;
248 }
249 
250 void KLineEdit::init()
251 {
252  d->possibleTripleClick = false;
253  d->bgRole = backgroundRole();
254 
255  // Enable the context menu by default.
256  QLineEdit::setContextMenuPolicy( Qt::DefaultContextMenu );
257  KCursor::setAutoHideCursor( this, true, true );
258 
259  KGlobalSettings::Completion mode = completionMode();
260  d->autoSuggest = (mode == KGlobalSettings::CompletionMan ||
261  mode == KGlobalSettings::CompletionPopupAuto ||
262  mode == KGlobalSettings::CompletionAuto);
263  connect( this, SIGNAL(selectionChanged()), this, SLOT(slotRestoreSelectionColors()));
264 
265  connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), this, SLOT(_k_slotSettingsChanged(int)));
266 
267  const QPalette p = palette();
268  if ( !d->previousHighlightedTextColor.isValid() )
269  d->previousHighlightedTextColor=p.color(QPalette::Normal,QPalette::HighlightedText);
270  if ( !d->previousHighlightColor.isValid() )
271  d->previousHighlightColor=p.color(QPalette::Normal,QPalette::Highlight);
272 
273  d->style = new KLineEditStyle(this);
274  setStyle(d->style.data());
275 
276  connect(this, SIGNAL(textChanged(QString)), this, SLOT(_k_textChanged(QString)));
277 }
278 
279 QString KLineEdit::clickMessage() const
280 {
281  return d->clickMessage;
282 }
283 
284 void KLineEdit::setClearButtonShown(bool show)
285 {
286  if (show) {
287  if (d->clearButton) {
288  return;
289  }
290 
291  d->clearButton = new KLineEditButton(this);
292  d->clearButton->setObjectName("KLineEditButton");
293  d->clearButton->setCursor( Qt::ArrowCursor );
294  d->clearButton->setToolTip( i18nc( "@action:button Clear current text in the line edit", "Clear text" ) );
295 
296  updateClearButtonIcon(text());
297  updateClearButton();
298  connect(this, SIGNAL(textChanged(QString)), this, SLOT(updateClearButtonIcon(QString)));
299  } else {
300  disconnect(this, SIGNAL(textChanged(QString)), this, SLOT(updateClearButtonIcon(QString)));
301  delete d->clearButton;
302  d->clearButton = 0;
303  d->clickInClear = false;
304  if (d->style) {
305  d->style.data()->m_overlap = 0;
306  }
307  }
308 }
309 
310 bool KLineEdit::isClearButtonShown() const
311 {
312  return d->clearButton != 0;
313 }
314 
315 QSize KLineEdit::clearButtonUsedSize() const
316 {
317  QSize s;
318  if (d->clearButton) {
319  const int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this);
320  s = d->clearButton->sizeHint();
321  s.rwidth() += frameWidth;
322  }
323  return s;
324 }
325 
326 // Decides whether to show or hide the icon; called when the text changes
327 void KLineEdit::updateClearButtonIcon(const QString& text)
328 {
329  if (!d->clearButton) {
330  return;
331  }
332  if (isReadOnly()) {
333  d->adjustForReadOnly();
334  return;
335  }
336 
337  // set proper icon if necessary
338  if (d->clearButton->pixmap().isNull()) {
339  const int clearButtonState = KIconLoader::DefaultState;
340  if (layoutDirection() == Qt::LeftToRight) {
341  d->clearButton->setPixmap(SmallIcon("edit-clear-locationbar-rtl", 0, clearButtonState));
342  } else {
343  d->clearButton->setPixmap(SmallIcon("edit-clear-locationbar-ltr", 0, clearButtonState));
344  }
345  }
346 
347  // trigger animation
348  if (d->wideEnoughForClear && text.length() > 0) {
349  d->clearButton->animateVisible(true);
350  } else {
351  d->clearButton->animateVisible(false);
352  }
353 }
354 
355 // Determine geometry of clear button. Called initially, and on resizeEvent.
356 void KLineEdit::updateClearButton()
357 {
358  if (!d->clearButton) {
359  return;
360  }
361  if (isReadOnly()) {
362  d->adjustForReadOnly();
363  return;
364  }
365 
366  const QSize geom = size();
367  const int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth,0,this);
368  const int buttonWidth = d->clearButton->sizeHint().width();
369  const QSize newButtonSize(buttonWidth, geom.height());
370  const QFontMetrics fm(font());
371  const int em = fm.width("m");
372 
373  // make sure we have enough room for the clear button
374  // no point in showing it if we can't also see a few characters as well
375  const bool wideEnough = geom.width() > 4 * em + buttonWidth + frameWidth;
376 
377  if (newButtonSize != d->clearButton->size()) {
378  d->clearButton->resize(newButtonSize);
379  }
380 
381  if (d->style) {
382  d->style.data()->m_overlap = wideEnough ? buttonWidth + frameWidth : 0;
383  }
384 
385  if (layoutDirection() == Qt::LeftToRight ) {
386  d->clearButton->move(geom.width() - frameWidth - buttonWidth - 1, 0);
387  } else {
388  d->clearButton->move(frameWidth + 1, 0);
389  }
390 
391  if (wideEnough != d->wideEnoughForClear) {
392  // we may (or may not) have been showing the button, but now our
393  // positiong on that matter has shifted, so let's ensure that it
394  // is properly visible (or not)
395  d->wideEnoughForClear = wideEnough;
396  updateClearButtonIcon(text());
397  }
398 }
399 
400 void KLineEdit::setCompletionMode( KGlobalSettings::Completion mode )
401 {
402  KGlobalSettings::Completion oldMode = completionMode();
403 
404  if ( oldMode != mode && (oldMode == KGlobalSettings::CompletionPopup ||
405  oldMode == KGlobalSettings::CompletionPopupAuto ) &&
406  d->completionBox && d->completionBox->isVisible() )
407  d->completionBox->hide();
408 
409  // If the widgets echo mode is not Normal, no completion
410  // feature will be enabled even if one is requested.
411  if ( echoMode() != QLineEdit::Normal )
412  mode = KGlobalSettings::CompletionNone; // Override the request.
413 
414  if ( kapp && !KAuthorized::authorize("lineedit_text_completion") )
415  mode = KGlobalSettings::CompletionNone;
416 
417  if ( mode == KGlobalSettings::CompletionPopupAuto ||
418  mode == KGlobalSettings::CompletionAuto ||
419  mode == KGlobalSettings::CompletionMan )
420  d->autoSuggest = true;
421  else
422  d->autoSuggest = false;
423 
424  KCompletionBase::setCompletionMode( mode );
425 }
426 
427 void KLineEdit::setCompletionModeDisabled( KGlobalSettings::Completion mode, bool disable )
428 {
429  d->disableCompletionMap[ mode ] = disable;
430 }
431 
432 void KLineEdit::setCompletedText( const QString& t, bool marked )
433 {
434  if ( !d->autoSuggest )
435  return;
436 
437  const QString txt = text();
438 
439  if ( t != txt )
440  {
441  setText(t);
442  if ( marked )
443  setSelection(t.length(), txt.length()-t.length());
444  setUserSelection(false);
445  }
446  else
447  setUserSelection(true);
448 
449 }
450 
451 void KLineEdit::setCompletedText( const QString& text )
452 {
453  KGlobalSettings::Completion mode = completionMode();
454  const bool marked = ( mode == KGlobalSettings::CompletionAuto ||
455  mode == KGlobalSettings::CompletionMan ||
456  mode == KGlobalSettings::CompletionPopup ||
457  mode == KGlobalSettings::CompletionPopupAuto );
458  setCompletedText( text, marked );
459 }
460 
461 void KLineEdit::rotateText( KCompletionBase::KeyBindingType type )
462 {
463  KCompletion* comp = compObj();
464  if ( comp &&
465  (type == KCompletionBase::PrevCompletionMatch ||
466  type == KCompletionBase::NextCompletionMatch ) )
467  {
468  QString input;
469 
470  if (type == KCompletionBase::PrevCompletionMatch)
471  input = comp->previousMatch();
472  else
473  input = comp->nextMatch();
474 
475  // Skip rotation if previous/next match is null or the same text
476  if ( input.isEmpty() || input == displayText() )
477  return;
478  setCompletedText( input, hasSelectedText() );
479  }
480 }
481 
482 void KLineEdit::makeCompletion( const QString& text )
483 {
484  KCompletion *comp = compObj();
485  KGlobalSettings::Completion mode = completionMode();
486 
487  if ( !comp || mode == KGlobalSettings::CompletionNone )
488  return; // No completion object...
489 
490  const QString match = comp->makeCompletion( text );
491 
492  if ( mode == KGlobalSettings::CompletionPopup ||
493  mode == KGlobalSettings::CompletionPopupAuto )
494  {
495  if ( match.isEmpty() )
496  {
497  if ( d->completionBox )
498  {
499  d->completionBox->hide();
500  d->completionBox->clear();
501  }
502  }
503  else
504  setCompletedItems( comp->allMatches() );
505  }
506  else // Auto, ShortAuto (Man) and Shell
507  {
508  // all other completion modes
509  // If no match or the same match, simply return without completing.
510  if ( match.isEmpty() || match == text )
511  return;
512 
513  if ( mode != KGlobalSettings::CompletionShell )
514  setUserSelection(false);
515 
516  if ( d->autoSuggest )
517  setCompletedText( match );
518  }
519 }
520 
521 void KLineEdit::setReadOnly(bool readOnly)
522 {
523  // Do not do anything if nothing changed...
524  if (readOnly == isReadOnly ()) {
525  return;
526  }
527 
528  QLineEdit::setReadOnly(readOnly);
529 
530  if (readOnly) {
531  d->bgRole = backgroundRole();
532  setBackgroundRole(QPalette::Window);
533  if (d->enableSqueezedText && d->squeezedText.isEmpty()) {
534  d->squeezedText = text();
535  setSqueezedText();
536  }
537 
538  if (d->clearButton) {
539  d->clearButton->animateVisible(false);
540  d->adjustForReadOnly();
541  }
542  } else {
543  if (!d->squeezedText.isEmpty()) {
544  setText(d->squeezedText);
545  d->squeezedText.clear();
546  }
547 
548  setBackgroundRole(d->bgRole);
549  updateClearButton();
550  }
551 }
552 
553 void KLineEdit::setSqueezedText( const QString &text)
554 {
555  setSqueezedTextEnabled(true);
556  setText(text);
557 }
558 
559 void KLineEdit::setSqueezedTextEnabled( bool enable )
560 {
561  d->enableSqueezedText = enable;
562 }
563 
564 bool KLineEdit::isSqueezedTextEnabled() const
565 {
566  return d->enableSqueezedText;
567 }
568 
569 void KLineEdit::setText( const QString& text )
570 {
571  if( d->enableClickMsg )
572  {
573  update();
574  }
575  if( d->enableSqueezedText && isReadOnly() )
576  {
577  d->squeezedText = text;
578  setSqueezedText();
579  return;
580  }
581 
582  QLineEdit::setText( text );
583 }
584 
585 void KLineEdit::setSqueezedText()
586 {
587  d->squeezedStart = 0;
588  d->squeezedEnd = 0;
589  const QString fullText = d->squeezedText;
590  const QFontMetrics fm(fontMetrics());
591  const int labelWidth = size().width() - 2*style()->pixelMetric(QStyle::PM_DefaultFrameWidth) - 2;
592  const int textWidth = fm.width(fullText);
593 
594  if (textWidth > labelWidth)
595  {
596  // start with the dots only
597  QString squeezedText = "...";
598  int squeezedWidth = fm.width(squeezedText);
599 
600  // estimate how many letters we can add to the dots on both sides
601  int letters = fullText.length() * (labelWidth - squeezedWidth) / textWidth / 2;
602  squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
603  squeezedWidth = fm.width(squeezedText);
604 
605  if (squeezedWidth < labelWidth)
606  {
607  // we estimated too short
608  // add letters while text < label
609  do
610  {
611  letters++;
612  squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
613  squeezedWidth = fm.width(squeezedText);
614  } while (squeezedWidth < labelWidth);
615  letters--;
616  squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
617  }
618  else if (squeezedWidth > labelWidth)
619  {
620  // we estimated too long
621  // remove letters while text > label
622  do
623  {
624  letters--;
625  squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
626  squeezedWidth = fm.width(squeezedText);
627  } while (squeezedWidth > labelWidth);
628  }
629 
630  if (letters < 5)
631  {
632  // too few letters added -> we give up squeezing
633  QLineEdit::setText(fullText);
634  }
635  else
636  {
637  QLineEdit::setText(squeezedText);
638  d->squeezedStart = letters;
639  d->squeezedEnd = fullText.length() - letters;
640  }
641 
642  setToolTip( fullText );
643 
644  }
645  else
646  {
647  QLineEdit::setText(fullText);
648 
649  this->setToolTip( "" );
650  QToolTip::showText(pos(), QString()); // hide
651  }
652 
653  setCursorPosition(0);
654 }
655 
656 void KLineEdit::copy() const
657 {
658  if( !copySqueezedText(true))
659  QLineEdit::copy();
660 }
661 
662 bool KLineEdit::copySqueezedText(bool clipboard) const
663 {
664  if (!d->squeezedText.isEmpty() && d->squeezedStart)
665  {
666  KLineEdit *that = const_cast<KLineEdit *>(this);
667  if (!that->hasSelectedText())
668  return false;
669  int start = selectionStart(), end = start + selectedText().length();
670  if (start >= d->squeezedStart+3)
671  start = start - 3 - d->squeezedStart + d->squeezedEnd;
672  else if (start > d->squeezedStart)
673  start = d->squeezedStart;
674  if (end >= d->squeezedStart+3)
675  end = end - 3 - d->squeezedStart + d->squeezedEnd;
676  else if (end > d->squeezedStart)
677  end = d->squeezedEnd;
678  if (start == end)
679  return false;
680  QString t = d->squeezedText;
681  t = t.mid(start, end - start);
682  disconnect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0);
683  QApplication::clipboard()->setText( t, clipboard ? QClipboard::Clipboard : QClipboard::Selection );
684  connect( QApplication::clipboard(), SIGNAL(selectionChanged()), this,
685  SLOT(_q_clipboardChanged()) );
686  return true;
687  }
688  return false;
689 }
690 
691 void KLineEdit::resizeEvent( QResizeEvent * ev )
692 {
693  if (!d->squeezedText.isEmpty())
694  setSqueezedText();
695 
696  updateClearButton();
697  QLineEdit::resizeEvent(ev);
698 }
699 
700 
701 void KLineEdit::keyPressEvent( QKeyEvent *e )
702 {
703  const int key = e->key() | e->modifiers();
704 
705  if ( KStandardShortcut::copy().contains( key ) )
706  {
707  copy();
708  return;
709  }
710  else if ( KStandardShortcut::paste().contains( key ) )
711  {
712  // TODO:
713  // we should restore the original text (not autocompleted), otherwise the paste
714  // will get into troubles Bug: 134691
715  if( !isReadOnly() )
716  paste();
717  return;
718  }
719  else if ( KStandardShortcut::pasteSelection().contains( key ) )
720  {
721  QString text = QApplication::clipboard()->text( QClipboard::Selection);
722  insert( text );
723  deselect();
724  return;
725  }
726 
727  else if ( KStandardShortcut::cut().contains( key ) )
728  {
729  if( !isReadOnly() )
730  cut();
731  return;
732  }
733  else if ( KStandardShortcut::undo().contains( key ) )
734  {
735  if( !isReadOnly() )
736  undo();
737  return;
738  }
739  else if ( KStandardShortcut::redo().contains( key ) )
740  {
741  if( !isReadOnly() )
742  redo();
743  return;
744  }
745  else if ( KStandardShortcut::deleteWordBack().contains( key ) )
746  {
747  cursorWordBackward(true);
748  if ( hasSelectedText() )
749  del();
750 
751  e->accept();
752  return;
753  }
754  else if ( KStandardShortcut::deleteWordForward().contains( key ) )
755  {
756  // Workaround for QT bug where
757  cursorWordForward(true);
758  if ( hasSelectedText() )
759  del();
760 
761  e->accept();
762  return;
763  }
764  else if ( KStandardShortcut::backwardWord().contains( key ) )
765  {
766  cursorWordBackward(false);
767  e->accept();
768  return;
769  }
770  else if ( KStandardShortcut::forwardWord().contains( key ) )
771  {
772  cursorWordForward(false);
773  e->accept();
774  return;
775  }
776  else if ( KStandardShortcut::beginningOfLine().contains( key ) )
777  {
778  home(false);
779  e->accept();
780  return;
781  }
782  else if ( KStandardShortcut::endOfLine().contains( key ) )
783  {
784  end(false);
785  e->accept();
786  return;
787  }
788 
789 
790  // Filter key-events if EchoMode is normal and
791  // completion mode is not set to CompletionNone
792  if ( echoMode() == QLineEdit::Normal &&
793  completionMode() != KGlobalSettings::CompletionNone )
794  {
795  if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
796  const bool trap = (d->completionBox && d->completionBox->isVisible());
797  const bool stopEvent = (trap || (d->grabReturnKeyEvents &&
798  (e->modifiers() == Qt::NoButton ||
799  e->modifiers() == Qt::KeypadModifier)));
800 
801  if (stopEvent) {
802  emit QLineEdit::returnPressed();
803  e->accept();
804  }
805 
806  emit returnPressed( displayText() );
807 
808  if (trap) {
809  d->completionBox->hide();
810  deselect();
811  setCursorPosition(text().length());
812  }
813 
814  // Eat the event if the user asked for it, or if a completionbox was visible
815  if (stopEvent) {
816  return;
817  }
818  }
819 
820  const KeyBindingMap keys = getKeyBindings();
821  const KGlobalSettings::Completion mode = completionMode();
822  const bool noModifier = (e->modifiers() == Qt::NoButton ||
823  e->modifiers() == Qt::ShiftModifier ||
824  e->modifiers() == Qt::KeypadModifier);
825 
826  if ( (mode == KGlobalSettings::CompletionAuto ||
827  mode == KGlobalSettings::CompletionPopupAuto ||
828  mode == KGlobalSettings::CompletionMan) && noModifier )
829  {
830  if ( !d->userSelection && hasSelectedText() &&
831  ( e->key() == Qt::Key_Right || e->key() == Qt::Key_Left ) &&
832  e->modifiers()==Qt::NoButton )
833  {
834  const QString old_txt = text();
835  d->disableRestoreSelection = true;
836  const int start = selectionStart();
837 
838  deselect();
839  QLineEdit::keyPressEvent ( e );
840  const int cPosition=cursorPosition();
841  setText(old_txt);
842 
843  // keep cursor at cPosition
844  setSelection(old_txt.length(), cPosition - old_txt.length());
845  if (e->key() == Qt::Key_Right && cPosition > start )
846  {
847  //the user explicitly accepted the autocompletion
848  d->_k_updateUserText(text());
849  }
850 
851  d->disableRestoreSelection = false;
852  return;
853  }
854 
855  if ( e->key() == Qt::Key_Escape )
856  {
857  if (hasSelectedText() && !d->userSelection )
858  {
859  del();
860  setUserSelection(true);
861  }
862 
863  // Don't swallow the Escape press event for the case
864  // of dialogs, which have Escape associated to Cancel
865  e->ignore();
866  return;
867  }
868 
869  }
870 
871  if ( (mode == KGlobalSettings::CompletionAuto ||
872  mode == KGlobalSettings::CompletionMan) && noModifier )
873  {
874  const QString keycode = e->text();
875  if ( !keycode.isEmpty() && (keycode.unicode()->isPrint() ||
876  e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) )
877  {
878  const bool hasUserSelection=d->userSelection;
879  const bool hadSelection=hasSelectedText();
880 
881  bool cursorNotAtEnd=false;
882 
883  const int start = selectionStart();
884  const int cPos = cursorPosition();
885 
886  // When moving the cursor, we want to keep the autocompletion as an
887  // autocompletion, so we want to process events at the cursor position
888  // as if there was no selection. After processing the key event, we
889  // can set the new autocompletion again.
890  if ( hadSelection && !hasUserSelection && start>cPos )
891  {
892  del();
893  setCursorPosition(cPos);
894  cursorNotAtEnd=true;
895  }
896 
897  d->disableRestoreSelection = true;
898  QLineEdit::keyPressEvent ( e );
899  d->disableRestoreSelection = false;
900 
901  QString txt = text();
902  int len = txt.length();
903  if ( !hasSelectedText() && len /*&& cursorPosition() == len */)
904  {
905  if ( e->key() == Qt::Key_Backspace )
906  {
907  if ( hadSelection && !hasUserSelection && !cursorNotAtEnd )
908  {
909  backspace();
910  txt = text();
911  len = txt.length();
912  }
913 
914  if (!d->s_backspacePerformsCompletion || !len) {
915  d->autoSuggest = false;
916  }
917  }
918 
919  if (e->key() == Qt::Key_Delete )
920  d->autoSuggest=false;
921 
922  doCompletion(txt);
923 
924  if( (e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete) )
925  d->autoSuggest=true;
926 
927  e->accept();
928  }
929 
930  return;
931  }
932 
933  }
934 
935  else if (( mode == KGlobalSettings::CompletionPopup ||
936  mode == KGlobalSettings::CompletionPopupAuto ) &&
937  noModifier && !e->text().isEmpty() )
938  {
939  const QString old_txt = text();
940  const bool hasUserSelection=d->userSelection;
941  const bool hadSelection=hasSelectedText();
942  bool cursorNotAtEnd=false;
943 
944  const int start = selectionStart();
945  const int cPos = cursorPosition();
946  const QString keycode = e->text();
947 
948  // When moving the cursor, we want to keep the autocompletion as an
949  // autocompletion, so we want to process events at the cursor position
950  // as if there was no selection. After processing the key event, we
951  // can set the new autocompletion again.
952  if (hadSelection && !hasUserSelection && start>cPos &&
953  ( (!keycode.isEmpty() && keycode.unicode()->isPrint()) ||
954  e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) )
955  {
956  del();
957  setCursorPosition(cPos);
958  cursorNotAtEnd=true;
959  }
960 
961  const int selectedLength=selectedText().length();
962 
963  d->disableRestoreSelection = true;
964  QLineEdit::keyPressEvent ( e );
965  d->disableRestoreSelection = false;
966 
967  if (( selectedLength != selectedText().length() ) && !hasUserSelection )
968  slotRestoreSelectionColors(); // and set userSelection to true
969 
970  QString txt = text();
971  int len = txt.length();
972  if ( ( txt != old_txt || txt != e->text() ) && len/* && ( cursorPosition() == len || force )*/ &&
973  ( (!keycode.isEmpty() && keycode.unicode()->isPrint()) ||
974  e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete) )
975  {
976  if ( e->key() == Qt::Key_Backspace )
977  {
978  if ( hadSelection && !hasUserSelection && !cursorNotAtEnd )
979  {
980  backspace();
981  txt = text();
982  len = txt.length();
983  }
984 
985  if (!d->s_backspacePerformsCompletion) {
986  d->autoSuggest = false;
987  }
988  }
989 
990  if (e->key() == Qt::Key_Delete )
991  d->autoSuggest=false;
992 
993  if ( d->completionBox )
994  d->completionBox->setCancelledText( txt );
995 
996  doCompletion(txt);
997 
998  if ( (e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) &&
999  mode == KGlobalSettings::CompletionPopupAuto )
1000  d->autoSuggest=true;
1001 
1002  e->accept();
1003  }
1004  else if (!len && d->completionBox && d->completionBox->isVisible())
1005  d->completionBox->hide();
1006 
1007  return;
1008  }
1009 
1010  else if ( mode == KGlobalSettings::CompletionShell )
1011  {
1012  // Handles completion.
1013  KShortcut cut;
1014  if ( keys[TextCompletion].isEmpty() )
1015  cut = KStandardShortcut::shortcut(KStandardShortcut::TextCompletion);
1016  else
1017  cut = keys[TextCompletion];
1018 
1019  if ( cut.contains( key ) )
1020  {
1021  // Emit completion if the completion mode is CompletionShell
1022  // and the cursor is at the end of the string.
1023  const QString txt = text();
1024  const int len = txt.length();
1025  if ( cursorPosition() == len && len != 0 )
1026  {
1027  doCompletion(txt);
1028  return;
1029  }
1030  }
1031  else if ( d->completionBox )
1032  d->completionBox->hide();
1033  }
1034 
1035  // handle rotation
1036  if ( mode != KGlobalSettings::CompletionNone )
1037  {
1038  // Handles previous match
1039  KShortcut cut;
1040  if ( keys[PrevCompletionMatch].isEmpty() )
1041  cut = KStandardShortcut::shortcut(KStandardShortcut::PrevCompletion);
1042  else
1043  cut = keys[PrevCompletionMatch];
1044 
1045  if ( cut.contains( key ) )
1046  {
1047  if ( emitSignals() )
1048  emit textRotation( KCompletionBase::PrevCompletionMatch );
1049  if ( handleSignals() )
1050  rotateText( KCompletionBase::PrevCompletionMatch );
1051  return;
1052  }
1053 
1054  // Handles next match
1055  if ( keys[NextCompletionMatch].isEmpty() )
1056  cut = KStandardShortcut::shortcut(KStandardShortcut::NextCompletion);
1057  else
1058  cut = keys[NextCompletionMatch];
1059 
1060  if ( cut.contains( key ) )
1061  {
1062  if ( emitSignals() )
1063  emit textRotation( KCompletionBase::NextCompletionMatch );
1064  if ( handleSignals() )
1065  rotateText( KCompletionBase::NextCompletionMatch );
1066  return;
1067  }
1068  }
1069 
1070  // substring completion
1071  if ( compObj() )
1072  {
1073  KShortcut cut;
1074  if ( keys[SubstringCompletion].isEmpty() )
1075  cut = KStandardShortcut::shortcut(KStandardShortcut::SubstringCompletion);
1076  else
1077  cut = keys[SubstringCompletion];
1078 
1079  if ( cut.contains( key ) )
1080  {
1081  if ( emitSignals() )
1082  emit substringCompletion( text() );
1083  if ( handleSignals() )
1084  {
1085  setCompletedItems( compObj()->substringCompletion(text()));
1086  e->accept();
1087  }
1088  return;
1089  }
1090  }
1091  }
1092  const int selectedLength = selectedText().length();
1093 
1094  // Let QLineEdit handle any other keys events.
1095  QLineEdit::keyPressEvent ( e );
1096 
1097  if ( selectedLength != selectedText().length() )
1098  slotRestoreSelectionColors(); // and set userSelection to true
1099 }
1100 
1101 void KLineEdit::mouseDoubleClickEvent( QMouseEvent* e )
1102 {
1103  if ( e->button() == Qt::LeftButton )
1104  {
1105  d->possibleTripleClick=true;
1106  QTimer::singleShot( QApplication::doubleClickInterval(),this,
1107  SLOT(tripleClickTimeout()) );
1108  }
1109  QLineEdit::mouseDoubleClickEvent( e );
1110 }
1111 
1112 void KLineEdit::mousePressEvent( QMouseEvent* e )
1113 {
1114  if ( (e->button() == Qt::LeftButton ||
1115  e->button() == Qt::MidButton ) &&
1116  d->clearButton ) {
1117  d->clickInClear = ( d->clearButton == childAt(e->pos()) || d->clearButton->underMouse() );
1118 
1119  if ( d->clickInClear ) {
1120  d->possibleTripleClick = false;
1121  }
1122  }
1123 
1124  if ( e->button() == Qt::LeftButton && d->possibleTripleClick ) {
1125  selectAll();
1126  e->accept();
1127  return;
1128  }
1129 
1130  // if middle clicking and if text is present in the clipboard then clear the selection
1131  // to prepare paste operation
1132  if ( e->button() == Qt::MidButton ) {
1133  if ( hasSelectedText() ) {
1134  if ( QApplication::clipboard()->text( QClipboard::Selection ).length() >0 ) {
1135  backspace();
1136  }
1137  }
1138  }
1139 
1140  QLineEdit::mousePressEvent( e );
1141 }
1142 
1143 void KLineEdit::mouseReleaseEvent( QMouseEvent* e )
1144 {
1145  if ( d->clickInClear ) {
1146  if ( d->clearButton == childAt(e->pos()) || d->clearButton->underMouse() ) {
1147  QString newText;
1148  if ( e->button() == Qt::MidButton ) {
1149  newText = QApplication::clipboard()->text( QClipboard::Selection );
1150  setText( newText );
1151  } else {
1152  setSelection(0, text().size());
1153  del();
1154  emit clearButtonClicked();
1155  }
1156  emit textChanged( newText );
1157  }
1158 
1159  d->clickInClear = false;
1160  e->accept();
1161  return;
1162  }
1163 
1164  QLineEdit::mouseReleaseEvent( e );
1165 
1166  if (QApplication::clipboard()->supportsSelection() ) {
1167  if ( e->button() == Qt::LeftButton ) {
1168  // Fix copying of squeezed text if needed
1169  copySqueezedText( false );
1170  }
1171  }
1172 }
1173 
1174 void KLineEdit::tripleClickTimeout()
1175 {
1176  d->possibleTripleClick=false;
1177 }
1178 
1179 QMenu* KLineEdit::createStandardContextMenu()
1180 {
1181  QMenu *popup = QLineEdit::createStandardContextMenu();
1182 
1183  if( !isReadOnly() )
1184  {
1185  // FIXME: This code depends on Qt's action ordering.
1186  const QList<QAction *> actionList = popup->actions();
1187  enum { UndoAct, RedoAct, Separator1, CutAct, CopyAct, PasteAct, DeleteAct, ClearAct,
1188  Separator2, SelectAllAct, NCountActs };
1189  QAction *separatorAction = 0L;
1190  // separator we want is right after Delete right now.
1191  const int idx = actionList.indexOf( actionList[DeleteAct] ) + 1;
1192  if ( idx < actionList.count() )
1193  separatorAction = actionList.at( idx );
1194  if ( separatorAction )
1195  {
1196  KAction *clearAllAction = KStandardAction::clear( this, SLOT(clear()), popup) ;
1197  if ( text().isEmpty() )
1198  clearAllAction->setEnabled( false );
1199  popup->insertAction( separatorAction, clearAllAction );
1200  }
1201  }
1202 
1203  KIconTheme::assignIconsToContextMenu( KIconTheme::TextEditor, popup->actions () );
1204 
1205  // If a completion object is present and the input
1206  // widget is not read-only, show the Text Completion
1207  // menu item.
1208  if ( compObj() && !isReadOnly() && KAuthorized::authorize("lineedit_text_completion") )
1209  {
1210  QMenu *subMenu = popup->addMenu( KIcon("text-completion"), i18nc("@title:menu", "Text Completion") );
1211  connect( subMenu, SIGNAL(triggered(QAction*)),
1212  this, SLOT(completionMenuActivated(QAction*)) );
1213 
1214  popup->addSeparator();
1215 
1216  QActionGroup* ag = new QActionGroup( this );
1217  d->noCompletionAction = ag->addAction( i18nc("@item:inmenu Text Completion", "None"));
1218  d->shellCompletionAction = ag->addAction( i18nc("@item:inmenu Text Completion", "Manual") );
1219  d->autoCompletionAction = ag->addAction( i18nc("@item:inmenu Text Completion", "Automatic") );
1220  d->popupCompletionAction = ag->addAction( i18nc("@item:inmenu Text Completion", "Dropdown List") );
1221  d->shortAutoCompletionAction = ag->addAction( i18nc("@item:inmenu Text Completion", "Short Automatic") );
1222  d->popupAutoCompletionAction = ag->addAction( i18nc("@item:inmenu Text Completion", "Dropdown List && Automatic"));
1223  subMenu->addActions( ag->actions() );
1224 
1225  //subMenu->setAccel( KStandardShortcut::completion(), ShellCompletion );
1226 
1227  d->shellCompletionAction->setCheckable( true );
1228  d->noCompletionAction->setCheckable( true );
1229  d->popupCompletionAction->setCheckable( true );
1230  d->autoCompletionAction->setCheckable( true );
1231  d->shortAutoCompletionAction->setCheckable( true );
1232  d->popupAutoCompletionAction->setCheckable( true );
1233 
1234  d->shellCompletionAction->setEnabled( !d->disableCompletionMap[ KGlobalSettings::CompletionShell ] );
1235  d->noCompletionAction->setEnabled( !d->disableCompletionMap[ KGlobalSettings::CompletionNone ] );
1236  d->popupCompletionAction->setEnabled( !d->disableCompletionMap[ KGlobalSettings::CompletionPopup ] );
1237  d->autoCompletionAction->setEnabled( !d->disableCompletionMap[ KGlobalSettings::CompletionAuto ] );
1238  d->shortAutoCompletionAction->setEnabled( !d->disableCompletionMap[ KGlobalSettings::CompletionMan ] );
1239  d->popupAutoCompletionAction->setEnabled( !d->disableCompletionMap[ KGlobalSettings::CompletionPopupAuto ] );
1240 
1241  const KGlobalSettings::Completion mode = completionMode();
1242  d->noCompletionAction->setChecked( mode == KGlobalSettings::CompletionNone );
1243  d->shellCompletionAction->setChecked( mode == KGlobalSettings::CompletionShell );
1244  d->popupCompletionAction->setChecked( mode == KGlobalSettings::CompletionPopup );
1245  d->autoCompletionAction->setChecked( mode == KGlobalSettings::CompletionAuto );
1246  d->shortAutoCompletionAction->setChecked( mode == KGlobalSettings::CompletionMan );
1247  d->popupAutoCompletionAction->setChecked( mode == KGlobalSettings::CompletionPopupAuto );
1248 
1249  const KGlobalSettings::Completion defaultMode = KGlobalSettings::completionMode();
1250  if ( mode != defaultMode && !d->disableCompletionMap[ defaultMode ] )
1251  {
1252  subMenu->addSeparator();
1253  d->defaultAction = subMenu->addAction( i18nc("@item:inmenu Text Completion", "Default") );
1254  }
1255  }
1256 
1257  return popup;
1258 }
1259 
1260 void KLineEdit::contextMenuEvent( QContextMenuEvent *e )
1261 {
1262  if ( QLineEdit::contextMenuPolicy() != Qt::DefaultContextMenu )
1263  return;
1264  QMenu *popup = createStandardContextMenu();
1265 
1266  // ### do we really need this? Yes, Please do not remove! This
1267  // allows applications to extend the popup menu without having to
1268  // inherit from this class! (DA)
1269  emit aboutToShowContextMenu( popup );
1270 
1271  popup->exec(e->globalPos());
1272  delete popup;
1273 }
1274 
1275 void KLineEdit::completionMenuActivated( QAction *act)
1276 {
1277  KGlobalSettings::Completion oldMode = completionMode();
1278 
1279  if( act == d->noCompletionAction )
1280  {
1281  setCompletionMode( KGlobalSettings::CompletionNone );
1282  }
1283  else if( act == d->shellCompletionAction)
1284  {
1285  setCompletionMode( KGlobalSettings::CompletionShell );
1286  }
1287  else if( act == d->autoCompletionAction)
1288  {
1289  setCompletionMode( KGlobalSettings::CompletionAuto );
1290  }
1291  else if( act == d->popupCompletionAction)
1292  {
1293  setCompletionMode( KGlobalSettings::CompletionPopup );
1294  }
1295  else if( act == d->shortAutoCompletionAction)
1296  {
1297  setCompletionMode( KGlobalSettings::CompletionMan );
1298  }
1299  else if( act == d->popupAutoCompletionAction)
1300  {
1301  setCompletionMode( KGlobalSettings::CompletionPopupAuto );
1302  }
1303  else if( act == d->defaultAction )
1304  {
1305  setCompletionMode( KGlobalSettings::completionMode() );
1306  }
1307  else
1308  return;
1309 
1310  if ( oldMode != completionMode() )
1311  {
1312  if ( (oldMode == KGlobalSettings::CompletionPopup ||
1313  oldMode == KGlobalSettings::CompletionPopupAuto ) &&
1314  d->completionBox && d->completionBox->isVisible() )
1315  d->completionBox->hide();
1316  emit completionModeChanged( completionMode() );
1317  }
1318 }
1319 
1320 void KLineEdit::dropEvent(QDropEvent *e)
1321 {
1322  if( d->handleURLDrops )
1323  {
1324  const KUrl::List urlList = KUrl::List::fromMimeData( e->mimeData() );
1325  if ( !urlList.isEmpty() )
1326  {
1327  // Let's replace the current text with the dropped URL(s), rather than appending.
1328  // Makes more sense in general (#188129), e.g. konq location bar and kurlrequester
1329  // can only hold one url anyway. OK this code supports multiple urls being dropped,
1330  // but that's not the common case [and it breaks if they contain spaces... this is why
1331  // kfiledialog uses double quotes around filenames in multiple-selection mode]...
1332  //
1333  // Anyway, if some apps prefer "append" then we should have a
1334  // setUrlDropsSupport( {NoUrlDrops, SingleUrlDrops, MultipleUrlDrops} )
1335  // where Single replaces and Multiple appends.
1336  QString dropText;
1337  //QString dropText = text();
1338  KUrl::List::ConstIterator it;
1339  for( it = urlList.begin() ; it != urlList.end() ; ++it )
1340  {
1341  if(!dropText.isEmpty())
1342  dropText+=' ';
1343 
1344  dropText += (*it).prettyUrl();
1345  }
1346 
1347  setText(dropText);
1348  setCursorPosition(dropText.length());
1349 
1350  e->accept();
1351  return;
1352  }
1353  }
1354  QLineEdit::dropEvent(e);
1355 }
1356 
1357 bool KLineEdit::event( QEvent* ev )
1358 {
1359  KCursor::autoHideEventFilter( this, ev );
1360  if ( ev->type() == QEvent::ShortcutOverride )
1361  {
1362  QKeyEvent *e = static_cast<QKeyEvent *>( ev );
1363  if (d->overrideShortcut(e)) {
1364  ev->accept();
1365  }
1366  } else if (ev->type() == QEvent::ApplicationPaletteChange
1367  || ev->type() == QEvent::PaletteChange) {
1368  // Assume the widget uses the application's palette
1369  QPalette p = QApplication::palette();
1370  d->previousHighlightedTextColor=p.color(QPalette::Normal,QPalette::HighlightedText);
1371  d->previousHighlightColor=p.color(QPalette::Normal,QPalette::Highlight);
1372  setUserSelection(d->userSelection);
1373  } else if (ev->type() == QEvent::StyleChange) {
1374  // since we have our own style and it relies on this style to Get Things Right,
1375  // if a style is set specifically on the widget (which would replace our own style!)
1376  // hang on to this special style and re-instate our own style.
1377  //FIXME: Qt currently has a grave bug where already deleted QStyleSheetStyle objects
1378  // will get passed back in if we set a new style on it here. remove the qstrmcp test
1379  // when this is fixed in Qt (or a better approach is found)
1380  if (!qobject_cast<KLineEditStyle *>(style()) &&
1381  qstrcmp(style()->metaObject()->className(), "QStyleSheetStyle") != 0 &&
1382  QLatin1String(style()->metaObject()->className()) != d->lastStyleClass) {
1383  KLineEditStyle *kleStyle = d->style.data();
1384  if (!kleStyle) {
1385  d->style = kleStyle = new KLineEditStyle(this);
1386  }
1387 
1388  kleStyle->m_subStyle = style();
1389  // this guards against "wrap around" where another style, e.g. QStyleSheetStyle,
1390  // is setting the style on QEvent::StyleChange
1391  d->lastStyleClass = QLatin1String(style()->metaObject()->className());
1392  setStyle(kleStyle);
1393  d->lastStyleClass.clear();
1394  }
1395  }
1396 
1397  return QLineEdit::event( ev );
1398 }
1399 
1400 
1401 void KLineEdit::setUrlDropsEnabled(bool enable)
1402 {
1403  d->handleURLDrops=enable;
1404 }
1405 
1406 bool KLineEdit::urlDropsEnabled() const
1407 {
1408  return d->handleURLDrops;
1409 }
1410 
1411 void KLineEdit::setTrapReturnKey( bool grab )
1412 {
1413  d->grabReturnKeyEvents = grab;
1414 }
1415 
1416 bool KLineEdit::trapReturnKey() const
1417 {
1418  return d->grabReturnKeyEvents;
1419 }
1420 
1421 void KLineEdit::setUrl( const KUrl& url )
1422 {
1423  setText( url.prettyUrl() );
1424 }
1425 
1426 void KLineEdit::setCompletionBox( KCompletionBox *box )
1427 {
1428  if ( d->completionBox )
1429  return;
1430 
1431  d->completionBox = box;
1432  if ( handleSignals() )
1433  {
1434  connect( d->completionBox, SIGNAL(currentTextChanged(QString)),
1435  SLOT(_k_slotCompletionBoxTextChanged(QString)) );
1436  connect( d->completionBox, SIGNAL(userCancelled(QString)),
1437  SLOT(userCancelled(QString)) );
1438  connect( d->completionBox, SIGNAL(activated(QString)),
1439  SIGNAL(completionBoxActivated(QString)) );
1440  connect( d->completionBox, SIGNAL(activated(QString)),
1441  SIGNAL(textEdited(QString)) );
1442  }
1443 }
1444 
1445 /*
1446  * Set the line edit text without changing the modified flag. By default
1447  * calling setText resets the modified flag to false.
1448  */
1449 static void setEditText(KLineEdit* edit, const QString& text)
1450 {
1451  if (!edit) {
1452  return;
1453  }
1454 
1455  const bool wasModified = edit->isModified();
1456  edit->setText(text);
1457  edit->setModified(wasModified);
1458 }
1459 
1460 void KLineEdit::userCancelled(const QString & cancelText)
1461 {
1462  if ( completionMode() != KGlobalSettings::CompletionPopupAuto )
1463  {
1464  setEditText(this, cancelText);
1465  }
1466  else if (hasSelectedText() )
1467  {
1468  if (d->userSelection)
1469  deselect();
1470  else
1471  {
1472  d->autoSuggest=false;
1473  const int start = selectionStart() ;
1474  const QString s = text().remove(selectionStart(), selectedText().length());
1475  setEditText(this, s);
1476  setCursorPosition(start);
1477  d->autoSuggest=true;
1478  }
1479  }
1480 }
1481 
1482 bool KLineEditPrivate::overrideShortcut(const QKeyEvent* e)
1483 {
1484  KShortcut scKey;
1485 
1486  const int key = e->key() | e->modifiers();
1487  const KLineEdit::KeyBindingMap keys = q->getKeyBindings();
1488 
1489  if (keys[KLineEdit::TextCompletion].isEmpty())
1490  scKey = KStandardShortcut::shortcut(KStandardShortcut::TextCompletion);
1491  else
1492  scKey = keys[KLineEdit::TextCompletion];
1493 
1494  if (scKey.contains( key ))
1495  return true;
1496 
1497  if (keys[KLineEdit::NextCompletionMatch].isEmpty())
1498  scKey = KStandardShortcut::shortcut(KStandardShortcut::NextCompletion);
1499  else
1500  scKey = keys[KLineEdit::NextCompletionMatch];
1501 
1502  if (scKey.contains( key ))
1503  return true;
1504 
1505  if (keys[KLineEdit::PrevCompletionMatch].isEmpty())
1506  scKey = KStandardShortcut::shortcut(KStandardShortcut::PrevCompletion);
1507  else
1508  scKey = keys[KLineEdit::PrevCompletionMatch];
1509 
1510  if (scKey.contains( key ))
1511  return true;
1512 
1513  // Override all the text manupilation accelerators...
1514  if ( KStandardShortcut::copy().contains( key ) )
1515  return true;
1516  else if ( KStandardShortcut::paste().contains( key ) )
1517  return true;
1518  else if ( KStandardShortcut::cut().contains( key ) )
1519  return true;
1520  else if ( KStandardShortcut::undo().contains( key ) )
1521  return true;
1522  else if ( KStandardShortcut::redo().contains( key ) )
1523  return true;
1524  else if (KStandardShortcut::deleteWordBack().contains( key ))
1525  return true;
1526  else if (KStandardShortcut::deleteWordForward().contains( key ))
1527  return true;
1528  else if (KStandardShortcut::forwardWord().contains( key ))
1529  return true;
1530  else if (KStandardShortcut::backwardWord().contains( key ))
1531  return true;
1532  else if (KStandardShortcut::beginningOfLine().contains( key ))
1533  return true;
1534  else if (KStandardShortcut::endOfLine().contains( key ))
1535  return true;
1536 
1537  // Shortcut overrides for shortcuts that QLineEdit handles
1538  // but doesn't dare force as "stronger than kaction shortcuts"...
1539  else if (e->matches(QKeySequence::SelectAll)) {
1540  return true;
1541  }
1542 #ifdef Q_WS_X11
1543  else if (key == Qt::CTRL + Qt::Key_E || key == Qt::CTRL + Qt::Key_U)
1544  return true;
1545 #endif
1546 
1547  if (completionBox && completionBox->isVisible ())
1548  {
1549  const int key = e->key();
1550  const Qt::KeyboardModifiers modifiers = e->modifiers();
1551  if ((key == Qt::Key_Backtab || key == Qt::Key_Tab) &&
1552  (modifiers == Qt::NoModifier || (modifiers & Qt::ShiftModifier)))
1553  {
1554  return true;
1555  }
1556  }
1557 
1558 
1559  return false;
1560 }
1561 
1562 void KLineEdit::setCompletedItems( const QStringList& items, bool autoSuggest )
1563 {
1564  QString txt;
1565  if ( d->completionBox && d->completionBox->isVisible() ) {
1566  // The popup is visible already - do the matching on the initial string,
1567  // not on the currently selected one.
1568  txt = completionBox()->cancelledText();
1569  } else {
1570  txt = text();
1571  }
1572 
1573  if ( !items.isEmpty() &&
1574  !(items.count() == 1 && txt == items.first()) )
1575  {
1576  // create completion box if non-existent
1577  completionBox();
1578 
1579  if ( d->completionBox->isVisible() )
1580  {
1581  QListWidgetItem* currentItem = d->completionBox->currentItem();
1582 
1583  QString currentSelection;
1584  if ( currentItem != 0 ) {
1585  currentSelection = currentItem->text();
1586  }
1587 
1588  d->completionBox->setItems( items );
1589 
1590  const QList<QListWidgetItem*> matchedItems = d->completionBox->findItems(currentSelection, Qt::MatchExactly);
1591  QListWidgetItem* matchedItem = matchedItems.isEmpty() ? 0 : matchedItems.first();
1592 
1593  if (matchedItem) {
1594  const bool blocked = d->completionBox->blockSignals( true );
1595  d->completionBox->setCurrentItem( matchedItem );
1596  d->completionBox->blockSignals( blocked );
1597  } else {
1598  d->completionBox->setCurrentRow(-1);
1599  }
1600  }
1601  else // completion box not visible yet -> show it
1602  {
1603  if ( !txt.isEmpty() )
1604  d->completionBox->setCancelledText( txt );
1605  d->completionBox->setItems( items );
1606  d->completionBox->popup();
1607  }
1608 
1609  if ( d->autoSuggest && autoSuggest )
1610  {
1611  const int index = items.first().indexOf( txt );
1612  const QString newText = items.first().mid( index );
1613  setUserSelection(false); // can be removed? setCompletedText sets it anyway
1614  setCompletedText(newText,true);
1615  }
1616  }
1617  else
1618  {
1619  if ( d->completionBox && d->completionBox->isVisible() )
1620  d->completionBox->hide();
1621  }
1622 }
1623 
1624 KCompletionBox * KLineEdit::completionBox( bool create )
1625 {
1626  if ( create && !d->completionBox ) {
1627  setCompletionBox( new KCompletionBox( this ) );
1628  d->completionBox->setObjectName("completion box");
1629  d->completionBox->setFont(font());
1630  }
1631 
1632  return d->completionBox;
1633 }
1634 
1635 void KLineEdit::setCompletionObject( KCompletion* comp, bool hsig )
1636 {
1637  KCompletion *oldComp = compObj();
1638  if ( oldComp && handleSignals() )
1639  disconnect( oldComp, SIGNAL(matches(QStringList)),
1640  this, SLOT(setCompletedItems(QStringList)));
1641 
1642  if ( comp && hsig )
1643  connect( comp, SIGNAL(matches(QStringList)),
1644  this, SLOT(setCompletedItems(QStringList)));
1645 
1646  KCompletionBase::setCompletionObject( comp, hsig );
1647 }
1648 
1649 // QWidget::create() turns off mouse-Tracking which would break auto-hiding
1650 void KLineEdit::create( WId id, bool initializeWindow, bool destroyOldWindow )
1651 {
1652  QLineEdit::create( id, initializeWindow, destroyOldWindow );
1653  KCursor::setAutoHideCursor( this, true, true );
1654 }
1655 
1656 void KLineEdit::setUserSelection(bool userSelection)
1657 {
1658  //if !d->userSelection && userSelection we are accepting a completion,
1659  //so trigger an update
1660 
1661  if (!d->userSelection && userSelection)
1662  {
1663  d->_k_updateUserText(text());
1664  }
1665 
1666  QPalette p = palette();
1667 
1668  if (userSelection)
1669  {
1670  p.setColor(QPalette::Highlight, d->previousHighlightColor);
1671  p.setColor(QPalette::HighlightedText, d->previousHighlightedTextColor);
1672  }
1673  else
1674  {
1675  QColor color=p.color(QPalette::Disabled, QPalette::Text);
1676  p.setColor(QPalette::HighlightedText, color);
1677  color=p.color(QPalette::Active, QPalette::Base);
1678  p.setColor(QPalette::Highlight, color);
1679  }
1680 
1681  d->userSelection=userSelection;
1682  setPalette(p);
1683 }
1684 
1685 void KLineEdit::slotRestoreSelectionColors()
1686 {
1687  if (d->disableRestoreSelection)
1688  return;
1689 
1690  setUserSelection(true);
1691 }
1692 
1693 void KLineEdit::clear()
1694 {
1695  setText( QString() );
1696 }
1697 
1698 void KLineEdit::_k_slotCompletionBoxTextChanged( const QString& text )
1699 {
1700  if (!text.isEmpty())
1701  {
1702  setText( text );
1703  setModified(true);
1704  end( false ); // force cursor at end
1705  }
1706 }
1707 
1708 QString KLineEdit::originalText() const
1709 {
1710  if ( d->enableSqueezedText && isReadOnly() )
1711  return d->squeezedText;
1712 
1713  return text();
1714 }
1715 
1716 QString KLineEdit::userText() const
1717 {
1718  return d->userText;
1719 }
1720 
1721 bool KLineEdit::autoSuggest() const
1722 {
1723  return d->autoSuggest;
1724 }
1725 
1726 void KLineEdit::paintEvent( QPaintEvent *ev )
1727 {
1728  if (echoMode() == Password && d->threeStars) {
1729  // ### hack alert!
1730  // QLineEdit has currently no hooks to modify the displayed string.
1731  // When we call setText(), an update() is triggered and we get
1732  // into an infinite recursion.
1733  // Qt offers the setUpdatesEnabled() method, but when we re-enable
1734  // them, update() is triggered, and we get into the same recursion.
1735  // To work around this problem, we set/clear the internal Qt flag which
1736  // marks the updatesDisabled state manually.
1737  setAttribute(Qt::WA_UpdatesDisabled, true);
1738  blockSignals(true);
1739  const QString oldText = text();
1740  const bool isModifiedState = isModified(); // save modified state because setText resets it
1741  setText(oldText + oldText + oldText);
1742  QLineEdit::paintEvent(ev);
1743  setText(oldText);
1744  setModified(isModifiedState);
1745  blockSignals(false);
1746  setAttribute(Qt::WA_UpdatesDisabled, false);
1747  } else {
1748  QLineEdit::paintEvent( ev );
1749  }
1750 
1751  if (d->enableClickMsg && text().isEmpty()) {
1752  QPainter p(this);
1753  QFont f = font();
1754  f.setItalic(d->italicizePlaceholder);
1755  p.setFont(f);
1756 
1757  QColor color(palette().color(foregroundRole()));
1758  color.setAlphaF(0.5);
1759  p.setPen(color);
1760 
1761  QStyleOptionFrame opt;
1762  initStyleOption(&opt);
1763  QRect cr = style()->subElementRect(QStyle::SE_LineEditContents, &opt, this);
1764 
1765  // this is copied/adapted from QLineEdit::paintEvent
1766  const int verticalMargin(1);
1767  const int horizontalMargin(2);
1768 
1769  int left, top, right, bottom;
1770  getTextMargins( &left, &top, &right, &bottom );
1771  cr.adjust( left, top, -right, -bottom );
1772 
1773  p.setClipRect(cr);
1774 
1775  QFontMetrics fm = fontMetrics();
1776  Qt::Alignment va = alignment() & Qt::AlignVertical_Mask;
1777  int vscroll;
1778  switch (va & Qt::AlignVertical_Mask)
1779  {
1780  case Qt::AlignBottom:
1781  vscroll = cr.y() + cr.height() - fm.height() - verticalMargin;
1782  break;
1783 
1784  case Qt::AlignTop:
1785  vscroll = cr.y() + verticalMargin;
1786  break;
1787 
1788  default:
1789  vscroll = cr.y() + (cr.height() - fm.height() + 1) / 2;
1790  break;
1791 
1792  }
1793 
1794  QRect lineRect(cr.x() + horizontalMargin, vscroll, cr.width() - 2*horizontalMargin, fm.height());
1795  p.drawText(lineRect, Qt::AlignLeft|Qt::AlignVCenter, d->clickMessage);
1796 
1797  }
1798 }
1799 
1800 void KLineEdit::focusInEvent( QFocusEvent *ev )
1801 {
1802  QLineEdit::focusInEvent( ev );
1803 }
1804 
1805 void KLineEdit::focusOutEvent( QFocusEvent *ev )
1806 {
1807  QLineEdit::focusOutEvent( ev );
1808 }
1809 
1810 void KLineEdit::setClickMessage( const QString &msg )
1811 {
1812  d->enableClickMsg = !msg.isEmpty();
1813  d->clickMessage = msg;
1814  update();
1815 }
1816 
1817 #ifndef KDE_NO_DEPRECATED
1818 void KLineEdit::setContextMenuEnabled( bool showMenu )
1819 {
1820  QLineEdit::setContextMenuPolicy( showMenu ? Qt::DefaultContextMenu : Qt::NoContextMenu );
1821 }
1822 #endif
1823 
1824 #ifndef KDE_NO_DEPRECATED
1825 bool KLineEdit::isContextMenuEnabled() const
1826 {
1827  return ( contextMenuPolicy() == Qt::DefaultContextMenu );
1828 }
1829 #endif
1830 
1831 void KLineEdit::setPasswordMode(bool b)
1832 {
1833  if(b)
1834  {
1835  KConfigGroup cg(KGlobal::config(), "Passwords");
1836  const QString val = cg.readEntry("EchoMode", "OneStar");
1837  if (val == "NoEcho")
1838  setEchoMode(NoEcho);
1839  else {
1840  d->threeStars = (val == "ThreeStars");
1841  setEchoMode(Password);
1842  }
1843  }
1844  else
1845  {
1846  setEchoMode( Normal );
1847  }
1848 }
1849 
1850 bool KLineEdit::passwordMode() const
1851 {
1852  return echoMode() == NoEcho || echoMode() == Password;
1853 }
1854 
1855 void KLineEdit::doCompletion(const QString& txt)
1856 {
1857  if (emitSignals()) {
1858  emit completion(txt); // emit when requested...
1859  }
1860  d->completionRunning = true;
1861  if (handleSignals()) {
1862  makeCompletion(txt); // handle when requested...
1863  }
1864  d->completionRunning = false;
1865 }
1866 
1867 #include "klineedit.moc"
1868 #include "klineedit_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Tue Apr 16 2013 21:01:37 by doxygen 1.8.3.1 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-4.10.2 API Reference

Skip menu "kdelibs-4.10.2 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
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
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