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

Skip menu "kdelibs-4.10.0 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