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

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