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

KDEUI

klineedit.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002 
00003    Copyright (C) 1997 Sven Radej (sven.radej@iname.com)
00004    Copyright (c) 1999 Patrick Ward <PAT_WARD@HP-USA-om5.om.hp.com>
00005    Copyright (c) 1999 Preston Brown <pbrown@kde.org>
00006 
00007    Re-designed for KDE 2.x by
00008    Copyright (c) 2000, 2001 Dawit Alemayehu <adawit@kde.org>
00009    Copyright (c) 2000, 2001 Carsten Pfeiffer <pfeiffer@kde.org>
00010 
00011    This library is free software; you can redistribute it and/or
00012    modify it under the terms of the GNU Lesser General Public
00013    License (LGPL) as published by the Free Software Foundation;
00014    either version 2 of the License, or (at your option) any later
00015    version.
00016 
00017    This library is distributed in the hope that it will be useful,
00018    but WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020    Lesser General Public License for more details.
00021 
00022    You should have received a copy of the GNU Lesser General Public License
00023    along with this library; see the file COPYING.LIB.  If not, write to
00024    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00025    Boston, MA 02110-1301, USA.
00026 */
00027 
00028 #include "klineedit.h"
00029 #include "klineedit_p.h"
00030 
00031 #include <kaction.h>
00032 #include <kapplication.h>
00033 #include <kauthorized.h>
00034 #include <kconfig.h>
00035 #include <kconfiggroup.h>
00036 #include <kcursor.h>
00037 #include <kdebug.h>
00038 #include <kcompletionbox.h>
00039 #include <kicontheme.h>
00040 #include <kicon.h>
00041 #include <klocale.h>
00042 #include <kmenu.h>
00043 #include <kstandardaction.h>
00044 #include <kstandardshortcut.h>
00045 
00046 #include <QtCore/QTimer>
00047 #include <QtGui/QClipboard>
00048 #include <QtGui/QStyleOption>
00049 #include <QtGui/QToolTip>
00050 
00051 class KLineEditStyle;
00052 
00053 class KLineEditPrivate
00054 {
00055 public:
00056     KLineEditPrivate(KLineEdit* qq)
00057         : q(qq)
00058     {
00059         completionBox = 0L;
00060         handleURLDrops = true;
00061         grabReturnKeyEvents = false;
00062 
00063         userSelection = true;
00064         autoSuggest = false;
00065         disableRestoreSelection = false;
00066         enableSqueezedText = false;
00067 
00068         drawClickMsg = false;
00069         enableClickMsg = false;
00070         threeStars = false;
00071         completionRunning = false;
00072         if (!s_initialized) {
00073             KConfigGroup config( KGlobal::config(), "General" );
00074             s_backspacePerformsCompletion = config.readEntry("Backspace performs completion", false);
00075             s_initialized = true;
00076         }
00077 
00078         clearButton = 0;
00079         clickInClear = false;
00080         wideEnoughForClear = true;
00081 
00082         // i18n: Placeholder text in line edit widgets is the text appearing
00083         // before any user input, briefly explaining to the user what to type
00084         // (e.g. "Enter search pattern").
00085         // By default the text is set in italic, which may not be appropriate
00086         // for some languages and scripts (e.g. for CJK ideographs).
00087         QString metaMsg = i18nc("Italic placeholder text in line edits: 0 no, 1 yes", "1");
00088         italicizePlaceholder = (metaMsg.trimmed() != QString('0'));
00089     }
00090 
00091     ~KLineEditPrivate()
00092     {
00093 // causes a weird crash in KWord at least, so let Qt delete it for us.
00094 //        delete completionBox;
00095         delete style.data();
00096     }
00097 
00098     void _k_slotSettingsChanged(int category)
00099     {
00100         Q_UNUSED(category);
00101 
00102         if (clearButton) {
00103             clearButton->setAnimationsEnabled(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects);
00104         }
00105     }
00106 
00107     void _k_textChanged(const QString &txt)
00108     {
00109         // COMPAT (as documented): emit userTextChanged whenever textChanged is emitted
00110         // KDE5: remove userTextChanged signal, textEdited does the same...
00111         if (!completionRunning && (txt != userText)) {
00112             userText = txt;
00113 #ifndef KDE_NO_DEPRECATED
00114             emit q->userTextChanged(txt);
00115 #endif
00116         }
00117     }
00118 
00119     // Call this when a completion operation changes the lineedit text
00120     // "as if it had been edited by the user".
00121     void _k_updateUserText(const QString &txt)
00122     {
00123         if (!completionRunning && (txt != userText)) {
00124             userText = txt;
00125             q->setModified(true);
00126 #ifndef KDE_NO_DEPRECATED
00127             emit q->userTextChanged(txt);
00128 #endif
00129             emit q->textEdited(txt);
00130             emit q->textChanged(txt);
00131         }
00132     }
00133 
00134     // This is called when the lineedit is readonly.
00135     // Either from setReadOnly() itself, or when we realize that
00136     // we became readonly and setReadOnly() wasn't called (because it's not virtual)
00137     // Typical case: comboBox->lineEdit()->setReadOnly(true)
00138     void adjustForReadOnly()
00139     {
00140         if (style && style.data()->m_overlap) {
00141             style.data()->m_overlap = 0;
00142         }
00143     }
00144 
00145 
00151     bool overrideShortcut(const QKeyEvent* e);
00152 
00153     static bool s_initialized;
00154     static bool s_backspacePerformsCompletion; // Configuration option
00155 
00156     QColor previousHighlightColor;
00157     QColor previousHighlightedTextColor;
00158 
00159     bool userSelection: 1;
00160     bool autoSuggest : 1;
00161     bool disableRestoreSelection: 1;
00162     bool handleURLDrops:1;
00163     bool grabReturnKeyEvents:1;
00164     bool enableSqueezedText:1;
00165     bool completionRunning:1;
00166 
00167     int squeezedEnd;
00168     int squeezedStart;
00169     QPalette::ColorRole bgRole;
00170     QString squeezedText;
00171     QString userText;
00172 
00173     QString clickMessage;
00174     bool enableClickMsg:1;
00175     bool drawClickMsg:1;
00176     bool threeStars:1;
00177 
00178     bool possibleTripleClick :1;  // set in mousePressEvent, deleted in tripleClickTimeout
00179 
00180     bool clickInClear:1;
00181     bool wideEnoughForClear:1;
00182     KLineEditButton *clearButton;
00183     QWeakPointer<KLineEditStyle> style;
00184     QString lastStyleClass;
00185 
00186     KCompletionBox *completionBox;
00187 
00188     bool italicizePlaceholder:1;
00189 
00190     QAction *noCompletionAction, *shellCompletionAction, *autoCompletionAction, *popupCompletionAction, *shortAutoCompletionAction, *popupAutoCompletionAction, *defaultAction;
00191 
00192     QMap<KGlobalSettings::Completion, bool> disableCompletionMap;
00193     KLineEdit* q;
00194 };
00195 
00196 QStyle *KLineEditStyle::style() const
00197 {
00198     if (m_subStyle) {
00199         return m_subStyle.data();
00200     }
00201 
00202     return KdeUiProxyStyle::style();
00203 }
00204 
00205 QRect KLineEditStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
00206 {
00207   if (element == SE_LineEditContents) {
00208       KLineEditStyle *unconstThis = const_cast<KLineEditStyle *>(this);
00209 
00210     if (m_sentinel) {
00211         // we are recursing: we're wrapping a style that wraps us!
00212         unconstThis->m_subStyle.clear();
00213     }
00214 
00215     unconstThis->m_sentinel = true;
00216     QStyle *s = m_subStyle ? m_subStyle.data() : style();
00217     QRect rect = s->subElementRect(SE_LineEditContents, option, widget);
00218     unconstThis->m_sentinel = false;
00219 
00220     if (option->direction == Qt::LeftToRight) {
00221         return rect.adjusted(0, 0, -m_overlap, 0);
00222     } else {
00223         return rect.adjusted(m_overlap, 0, 0, 0);
00224     }
00225   }
00226 
00227   return KdeUiProxyStyle::subElementRect(element, option, widget);
00228 }
00229 
00230 bool KLineEditPrivate::s_backspacePerformsCompletion = false;
00231 bool KLineEditPrivate::s_initialized = false;
00232 
00233 
00234 KLineEdit::KLineEdit( const QString &string, QWidget *parent )
00235     : QLineEdit( string, parent ), d(new KLineEditPrivate(this))
00236 {
00237     init();
00238 }
00239 
00240 KLineEdit::KLineEdit( QWidget *parent )
00241     : QLineEdit( parent ), d(new KLineEditPrivate(this))
00242 {
00243     init();
00244 }
00245 
00246 
00247 KLineEdit::~KLineEdit ()
00248 {
00249     delete d;
00250 }
00251 
00252 void KLineEdit::init()
00253 {
00254     d->possibleTripleClick = false;
00255     d->bgRole = backgroundRole();
00256 
00257     // Enable the context menu by default.
00258     QLineEdit::setContextMenuPolicy( Qt::DefaultContextMenu );
00259     KCursor::setAutoHideCursor( this, true, true );
00260 
00261     KGlobalSettings::Completion mode = completionMode();
00262     d->autoSuggest = (mode == KGlobalSettings::CompletionMan ||
00263                       mode == KGlobalSettings::CompletionPopupAuto ||
00264                       mode == KGlobalSettings::CompletionAuto);
00265     connect( this, SIGNAL(selectionChanged()), this, SLOT(slotRestoreSelectionColors()));
00266 
00267     connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), this, SLOT(_k_slotSettingsChanged(int)));
00268 
00269     const QPalette p = palette();
00270     if ( !d->previousHighlightedTextColor.isValid() )
00271       d->previousHighlightedTextColor=p.color(QPalette::Normal,QPalette::HighlightedText);
00272     if ( !d->previousHighlightColor.isValid() )
00273       d->previousHighlightColor=p.color(QPalette::Normal,QPalette::Highlight);
00274 
00275     d->style = new KLineEditStyle(this);
00276     setStyle(d->style.data());
00277 
00278     connect(this, SIGNAL(textChanged(QString)), this, SLOT(_k_textChanged(QString)));
00279 }
00280 
00281 QString KLineEdit::clickMessage() const
00282 {
00283     return d->clickMessage;
00284 }
00285 
00286 void KLineEdit::setClearButtonShown(bool show)
00287 {
00288     if (show) {
00289         if (d->clearButton) {
00290             return;
00291         }
00292 
00293         d->clearButton = new KLineEditButton(this);
00294         d->clearButton->setObjectName("KLineEditButton");
00295         d->clearButton->setCursor( Qt::ArrowCursor );
00296         d->clearButton->setToolTip( i18nc( "@action:button Clear current text in the line edit", "Clear text" ) );
00297 
00298         updateClearButtonIcon(text());
00299         updateClearButton();
00300         connect(this, SIGNAL(textChanged(QString)), this, SLOT(updateClearButtonIcon(QString)));
00301     } else {
00302         disconnect(this, SIGNAL(textChanged(QString)), this, SLOT(updateClearButtonIcon(QString)));
00303         delete d->clearButton;
00304         d->clearButton = 0;
00305         d->clickInClear = false;
00306         if (d->style) {
00307             d->style.data()->m_overlap = 0;
00308         }
00309     }
00310 }
00311 
00312 bool KLineEdit::isClearButtonShown() const
00313 {
00314     return d->clearButton != 0;
00315 }
00316 
00317 QSize KLineEdit::clearButtonUsedSize() const
00318 {
00319     QSize s;
00320     if (d->clearButton) {
00321         const int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this);
00322         s = d->clearButton->sizeHint();
00323         s.rwidth() += frameWidth;
00324     }
00325     return s;
00326 }
00327 
00328 // Decides whether to show or hide the icon; called when the text changes
00329 void KLineEdit::updateClearButtonIcon(const QString& text)
00330 {
00331     if (!d->clearButton) {
00332         return;
00333     }
00334     if (isReadOnly()) {
00335         d->adjustForReadOnly();
00336         return;
00337     }
00338 
00339     int clearButtonState = KIconLoader::DefaultState;
00340 
00341     if (d->wideEnoughForClear && text.length() > 0) {
00342         d->clearButton->animateVisible(true);
00343     } else {
00344         d->clearButton->animateVisible(false);
00345     }
00346 
00347     if (!d->clearButton->pixmap().isNull()) {
00348         return;
00349     }
00350 
00351     if (layoutDirection() == Qt::LeftToRight) {
00352         d->clearButton->setPixmap(SmallIcon("edit-clear-locationbar-rtl", 0, clearButtonState));
00353     } else {
00354         d->clearButton->setPixmap(SmallIcon("edit-clear-locationbar-ltr", 0, clearButtonState));
00355     }
00356 
00357     d->clearButton->setVisible(text.length() > 0);
00358 }
00359 
00360 // Determine geometry of clear button. Called initially, and on resizeEvent.
00361 void KLineEdit::updateClearButton()
00362 {
00363     if (!d->clearButton) {
00364         return;
00365     }
00366     if (isReadOnly()) {
00367         d->adjustForReadOnly();
00368         return;
00369     }
00370 
00371     const QSize geom = size();
00372     const int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth,0,this);
00373     const int buttonWidth = d->clearButton->sizeHint().width();
00374     const QSize newButtonSize(buttonWidth, geom.height());
00375     const QFontMetrics fm(font());
00376     const int em = fm.width("m");
00377 
00378     // make sure we have enough room for the clear button
00379     // no point in showing it if we can't also see a few characters as well
00380     const bool wideEnough = geom.width() > 4 * em + buttonWidth + frameWidth;
00381 
00382     if (newButtonSize != d->clearButton->size()) {
00383         d->clearButton->resize(newButtonSize);
00384     }
00385 
00386     if (d->style) {
00387         d->style.data()->m_overlap = wideEnough ? buttonWidth + frameWidth : 0;
00388     }
00389 
00390     if (layoutDirection() == Qt::LeftToRight ) {
00391         d->clearButton->move(geom.width() - frameWidth - buttonWidth - 1, 0);
00392     } else {
00393         d->clearButton->move(frameWidth + 1, 0);
00394     }
00395 
00396     if (wideEnough != d->wideEnoughForClear) {
00397         // we may (or may not) have been showing the button, but now our
00398         // positiong on that matter has shifted, so let's ensure that it
00399         // is properly visible (or not)
00400         d->wideEnoughForClear = wideEnough;
00401         updateClearButtonIcon(text());
00402     }
00403 }
00404 
00405 void KLineEdit::setCompletionMode( KGlobalSettings::Completion mode )
00406 {
00407     KGlobalSettings::Completion oldMode = completionMode();
00408 
00409     if ( oldMode != mode && (oldMode == KGlobalSettings::CompletionPopup ||
00410          oldMode == KGlobalSettings::CompletionPopupAuto ) &&
00411          d->completionBox && d->completionBox->isVisible() )
00412       d->completionBox->hide();
00413 
00414     // If the widgets echo mode is not Normal, no completion
00415     // feature will be enabled even if one is requested.
00416     if ( echoMode() != QLineEdit::Normal )
00417         mode = KGlobalSettings::CompletionNone; // Override the request.
00418 
00419     if ( kapp && !KAuthorized::authorize("lineedit_text_completion") )
00420         mode = KGlobalSettings::CompletionNone;
00421 
00422     if ( mode == KGlobalSettings::CompletionPopupAuto ||
00423          mode == KGlobalSettings::CompletionAuto ||
00424          mode == KGlobalSettings::CompletionMan )
00425         d->autoSuggest = true;
00426     else
00427         d->autoSuggest = false;
00428 
00429     KCompletionBase::setCompletionMode( mode );
00430 }
00431 
00432 void KLineEdit::setCompletionModeDisabled( KGlobalSettings::Completion mode, bool disable )
00433 {
00434   d->disableCompletionMap[ mode ] = disable;
00435 }
00436 
00437 void KLineEdit::setCompletedText( const QString& t, bool marked )
00438 {
00439     if ( !d->autoSuggest )
00440       return;
00441 
00442     const QString txt = text();
00443 
00444     if ( t != txt )
00445     {
00446         setText(t);
00447         if ( marked )
00448             setSelection(t.length(), txt.length()-t.length());
00449         setUserSelection(false);
00450     }
00451     else
00452       setUserSelection(true);
00453 
00454 }
00455 
00456 void KLineEdit::setCompletedText( const QString& text )
00457 {
00458     KGlobalSettings::Completion mode = completionMode();
00459     const bool marked = ( mode == KGlobalSettings::CompletionAuto ||
00460                     mode == KGlobalSettings::CompletionMan ||
00461                     mode == KGlobalSettings::CompletionPopup ||
00462                     mode == KGlobalSettings::CompletionPopupAuto );
00463     setCompletedText( text, marked );
00464 }
00465 
00466 void KLineEdit::rotateText( KCompletionBase::KeyBindingType type )
00467 {
00468     KCompletion* comp = compObj();
00469     if ( comp &&
00470        (type == KCompletionBase::PrevCompletionMatch ||
00471         type == KCompletionBase::NextCompletionMatch ) )
00472     {
00473        QString input;
00474 
00475        if (type == KCompletionBase::PrevCompletionMatch)
00476           input = comp->previousMatch();
00477        else
00478           input = comp->nextMatch();
00479 
00480        // Skip rotation if previous/next match is null or the same text
00481        if ( input.isEmpty() || input == displayText() )
00482             return;
00483        setCompletedText( input, hasSelectedText() );
00484     }
00485 }
00486 
00487 void KLineEdit::makeCompletion( const QString& text )
00488 {
00489     KCompletion *comp = compObj();
00490     KGlobalSettings::Completion mode = completionMode();
00491 
00492     if ( !comp || mode == KGlobalSettings::CompletionNone )
00493         return;  // No completion object...
00494 
00495     const QString match = comp->makeCompletion( text );
00496 
00497     if ( mode == KGlobalSettings::CompletionPopup ||
00498          mode == KGlobalSettings::CompletionPopupAuto )
00499     {
00500         if ( match.isEmpty() )
00501         {
00502             if ( d->completionBox )
00503             {
00504                 d->completionBox->hide();
00505                 d->completionBox->clear();
00506             }
00507         }
00508         else
00509             setCompletedItems( comp->allMatches() );
00510     }
00511     else // Auto,  ShortAuto (Man) and Shell
00512     {
00513         // all other completion modes
00514         // If no match or the same match, simply return without completing.
00515         if ( match.isEmpty() || match == text )
00516             return;
00517 
00518         if ( mode != KGlobalSettings::CompletionShell )
00519             setUserSelection(false);
00520 
00521         if ( d->autoSuggest )
00522             setCompletedText( match );
00523     }
00524 }
00525 
00526 void KLineEdit::setReadOnly(bool readOnly)
00527 {
00528     // Do not do anything if nothing changed...
00529     if (readOnly == isReadOnly ()) {
00530       return;
00531     }
00532 
00533     QLineEdit::setReadOnly(readOnly);
00534 
00535     if (readOnly) {
00536         d->bgRole = backgroundRole();
00537         setBackgroundRole(QPalette::Window);
00538         if (d->enableSqueezedText && d->squeezedText.isEmpty()) {
00539             d->squeezedText = text();
00540             setSqueezedText();
00541         }
00542 
00543         if (d->clearButton) {
00544             d->clearButton->animateVisible(false);
00545             d->adjustForReadOnly();
00546         }
00547     } else {
00548         if (!d->squeezedText.isEmpty()) {
00549            setText(d->squeezedText);
00550            d->squeezedText.clear();
00551         }
00552 
00553         setBackgroundRole(d->bgRole);
00554         updateClearButton();
00555     }
00556 }
00557 
00558 void KLineEdit::setSqueezedText( const QString &text)
00559 {
00560     setSqueezedTextEnabled(true);
00561     setText(text);
00562 }
00563 
00564 void KLineEdit::setSqueezedTextEnabled( bool enable )
00565 {
00566     d->enableSqueezedText = enable;
00567 }
00568 
00569 bool KLineEdit::isSqueezedTextEnabled() const
00570 {
00571     return d->enableSqueezedText;
00572 }
00573 
00574 void KLineEdit::setText( const QString& text )
00575 {
00576     if( d->enableClickMsg )
00577     {
00578           d->drawClickMsg = text.isEmpty();
00579           update();
00580     }
00581     if( d->enableSqueezedText && isReadOnly() )
00582     {
00583         d->squeezedText = text;
00584         setSqueezedText();
00585         return;
00586     }
00587 
00588     QLineEdit::setText( text );
00589 }
00590 
00591 void KLineEdit::setSqueezedText()
00592 {
00593     d->squeezedStart = 0;
00594     d->squeezedEnd = 0;
00595     const QString fullText = d->squeezedText;
00596     const QFontMetrics fm(fontMetrics());
00597     const int labelWidth = size().width() - 2*style()->pixelMetric(QStyle::PM_DefaultFrameWidth) - 2;
00598     const int textWidth = fm.width(fullText);
00599 
00600     if (textWidth > labelWidth)
00601     {
00602           // start with the dots only
00603           QString squeezedText = "...";
00604           int squeezedWidth = fm.width(squeezedText);
00605 
00606           // estimate how many letters we can add to the dots on both sides
00607           int letters = fullText.length() * (labelWidth - squeezedWidth) / textWidth / 2;
00608           squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
00609           squeezedWidth = fm.width(squeezedText);
00610 
00611       if (squeezedWidth < labelWidth)
00612       {
00613              // we estimated too short
00614              // add letters while text < label
00615           do
00616           {
00617                 letters++;
00618                 squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
00619                 squeezedWidth = fm.width(squeezedText);
00620              } while (squeezedWidth < labelWidth);
00621              letters--;
00622              squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
00623       }
00624       else if (squeezedWidth > labelWidth)
00625       {
00626              // we estimated too long
00627              // remove letters while text > label
00628           do
00629           {
00630                letters--;
00631                 squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
00632                 squeezedWidth = fm.width(squeezedText);
00633              } while (squeezedWidth > labelWidth);
00634           }
00635 
00636       if (letters < 5)
00637       {
00638              // too few letters added -> we give up squeezing
00639           QLineEdit::setText(fullText);
00640       }
00641       else
00642       {
00643           QLineEdit::setText(squeezedText);
00644              d->squeezedStart = letters;
00645              d->squeezedEnd = fullText.length() - letters;
00646           }
00647 
00648           setToolTip( fullText );
00649 
00650     }
00651     else
00652     {
00653       QLineEdit::setText(fullText);
00654 
00655       this->setToolTip( "" );
00656       QToolTip::showText(pos(), QString()); // hide
00657     }
00658 
00659     setCursorPosition(0);
00660 }
00661 
00662 void KLineEdit::copy() const
00663 {
00664     if( !copySqueezedText(true))
00665         QLineEdit::copy();
00666 }
00667 
00668 bool KLineEdit::copySqueezedText(bool clipboard) const
00669 {
00670    if (!d->squeezedText.isEmpty() && d->squeezedStart)
00671    {
00672       KLineEdit *that = const_cast<KLineEdit *>(this);
00673       if (!that->hasSelectedText())
00674          return false;
00675       int start = selectionStart(), end = start + selectedText().length();
00676       if (start >= d->squeezedStart+3)
00677          start = start - 3 - d->squeezedStart + d->squeezedEnd;
00678       else if (start > d->squeezedStart)
00679          start = d->squeezedStart;
00680       if (end >= d->squeezedStart+3)
00681          end = end - 3 - d->squeezedStart + d->squeezedEnd;
00682       else if (end > d->squeezedStart)
00683          end = d->squeezedEnd;
00684       if (start == end)
00685          return false;
00686       QString t = d->squeezedText;
00687       t = t.mid(start, end - start);
00688       disconnect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0);
00689       QApplication::clipboard()->setText( t, clipboard ? QClipboard::Clipboard : QClipboard::Selection );
00690       connect( QApplication::clipboard(), SIGNAL(selectionChanged()), this,
00691                SLOT(_q_clipboardChanged()) );
00692       return true;
00693    }
00694    return false;
00695 }
00696 
00697 void KLineEdit::resizeEvent( QResizeEvent * ev )
00698 {
00699     if (!d->squeezedText.isEmpty())
00700         setSqueezedText();
00701 
00702     updateClearButton();
00703     QLineEdit::resizeEvent(ev);
00704 }
00705 
00706 
00707 void KLineEdit::keyPressEvent( QKeyEvent *e )
00708 {
00709     const int key = e->key() | e->modifiers();
00710 
00711     if ( KStandardShortcut::copy().contains( key ) )
00712     {
00713         copy();
00714         return;
00715     }
00716     else if ( KStandardShortcut::paste().contains( key ) )
00717     {
00718       // TODO:
00719       // we should restore the original text (not autocompleted), otherwise the paste
00720       // will get into troubles Bug: 134691
00721         if( !isReadOnly() )
00722           paste();
00723         return;
00724     }
00725     else if ( KStandardShortcut::pasteSelection().contains( key ) )
00726     {
00727         QString text = QApplication::clipboard()->text( QClipboard::Selection);
00728         insert( text );
00729         deselect();
00730         return;
00731     }
00732 
00733     else if ( KStandardShortcut::cut().contains( key ) )
00734     {
00735         if( !isReadOnly() )
00736            cut();
00737         return;
00738     }
00739     else if ( KStandardShortcut::undo().contains( key ) )
00740     {
00741         if( !isReadOnly() )
00742           undo();
00743         return;
00744     }
00745     else if ( KStandardShortcut::redo().contains( key ) )
00746     {
00747         if( !isReadOnly() )
00748            redo();
00749         return;
00750     }
00751     else if ( KStandardShortcut::deleteWordBack().contains( key ) )
00752     {
00753         cursorWordBackward(true);
00754         if ( hasSelectedText() )
00755             del();
00756 
00757         e->accept();
00758         return;
00759     }
00760     else if ( KStandardShortcut::deleteWordForward().contains( key ) )
00761     {
00762         // Workaround for QT bug where
00763         cursorWordForward(true);
00764         if ( hasSelectedText() )
00765             del();
00766 
00767         e->accept();
00768         return;
00769     }
00770     else if ( KStandardShortcut::backwardWord().contains( key ) )
00771     {
00772       cursorWordBackward(false);
00773       e->accept();
00774       return;
00775     }
00776     else if ( KStandardShortcut::forwardWord().contains( key ) )
00777     {
00778       cursorWordForward(false);
00779       e->accept();
00780       return;
00781     }
00782     else if ( KStandardShortcut::beginningOfLine().contains( key ) )
00783     {
00784       home(false);
00785       e->accept();
00786       return;
00787     }
00788     else if ( KStandardShortcut::endOfLine().contains( key ) )
00789     {
00790       end(false);
00791       e->accept();
00792       return;
00793     }
00794 
00795 
00796     // Filter key-events if EchoMode is normal and
00797     // completion mode is not set to CompletionNone
00798     if ( echoMode() == QLineEdit::Normal &&
00799          completionMode() != KGlobalSettings::CompletionNone )
00800     {
00801         if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
00802             const bool trap = (d->completionBox && d->completionBox->isVisible());
00803             const bool stopEvent = (trap || (d->grabReturnKeyEvents &&
00804                                     (e->modifiers() == Qt::NoButton ||
00805                                      e->modifiers() == Qt::KeypadModifier)));
00806 
00807             if (stopEvent) {
00808                 emit QLineEdit::returnPressed();
00809                 e->accept();
00810             }
00811 
00812             emit returnPressed( displayText() );
00813 
00814             if (trap) {
00815                 d->completionBox->hide();
00816                 deselect();
00817                 setCursorPosition(text().length());
00818             }
00819 
00820             // Eat the event if the user asked for it, or if a completionbox was visible
00821             if (stopEvent) {
00822                 return;
00823             }
00824         }
00825 
00826         const KeyBindingMap keys = getKeyBindings();
00827         const KGlobalSettings::Completion mode = completionMode();
00828         const bool noModifier = (e->modifiers() == Qt::NoButton ||
00829                            e->modifiers() == Qt::ShiftModifier ||
00830                            e->modifiers() == Qt::KeypadModifier);
00831 
00832         if ( (mode == KGlobalSettings::CompletionAuto ||
00833               mode == KGlobalSettings::CompletionPopupAuto ||
00834               mode == KGlobalSettings::CompletionMan) && noModifier )
00835         {
00836             if ( !d->userSelection && hasSelectedText() &&
00837                  ( e->key() == Qt::Key_Right || e->key() == Qt::Key_Left ) &&
00838                  e->modifiers()==Qt::NoButton )
00839             {
00840                 const QString old_txt = text();
00841                 d->disableRestoreSelection = true;
00842                 const int start = selectionStart();
00843 
00844                 deselect();
00845                 QLineEdit::keyPressEvent ( e );
00846                 const int cPosition=cursorPosition();
00847                 setText(old_txt);
00848 
00849                 // keep cursor at cPosition
00850                 setSelection(old_txt.length(), cPosition - old_txt.length());
00851                 if (e->key() == Qt::Key_Right && cPosition > start )
00852                 {
00853                     //the user explicitly accepted the autocompletion
00854                     d->_k_updateUserText(text());
00855                 }
00856 
00857                 d->disableRestoreSelection = false;
00858                 return;
00859             }
00860 
00861             if ( e->key() == Qt::Key_Escape )
00862             {
00863                 if (hasSelectedText() && !d->userSelection )
00864                 {
00865                     del();
00866                     setUserSelection(true);
00867                 }
00868 
00869                 // Don't swallow the Escape press event for the case
00870                 // of dialogs, which have Escape associated to Cancel
00871                 e->ignore();
00872                 return;
00873             }
00874 
00875         }
00876 
00877         if ( (mode == KGlobalSettings::CompletionAuto ||
00878               mode == KGlobalSettings::CompletionMan) && noModifier )
00879         {
00880             const QString keycode = e->text();
00881             if ( !keycode.isEmpty() && (keycode.unicode()->isPrint() ||
00882                 e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) )
00883             {
00884                 const bool hasUserSelection=d->userSelection;
00885                 const bool hadSelection=hasSelectedText();
00886 
00887                 bool cursorNotAtEnd=false;
00888 
00889                 const int start = selectionStart();
00890                 const int cPos = cursorPosition();
00891 
00892                 // When moving the cursor, we want to keep the autocompletion as an
00893                 // autocompletion, so we want to process events at the cursor position
00894                 // as if there was no selection. After processing the key event, we
00895                 // can set the new autocompletion again.
00896                 if ( hadSelection && !hasUserSelection && start>cPos )
00897                 {
00898                     del();
00899                     setCursorPosition(cPos);
00900                     cursorNotAtEnd=true;
00901                 }
00902 
00903                 d->disableRestoreSelection = true;
00904                 QLineEdit::keyPressEvent ( e );
00905                 d->disableRestoreSelection = false;
00906 
00907                 QString txt = text();
00908                 int len = txt.length();
00909                 if ( !hasSelectedText() && len /*&& cursorPosition() == len */)
00910                 {
00911                     if ( e->key() == Qt::Key_Backspace )
00912                     {
00913                         if ( hadSelection && !hasUserSelection && !cursorNotAtEnd )
00914                         {
00915                             backspace();
00916                             txt = text();
00917                             len = txt.length();
00918                         }
00919 
00920                         if (!d->s_backspacePerformsCompletion || !len) {
00921                             d->autoSuggest = false;
00922                         }
00923                     }
00924 
00925                     if (e->key() == Qt::Key_Delete )
00926                         d->autoSuggest=false;
00927 
00928                     doCompletion(txt);
00929 
00930                     if(  (e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete) )
00931                         d->autoSuggest=true;
00932 
00933                     e->accept();
00934                 }
00935 
00936                 return;
00937             }
00938 
00939         }
00940 
00941         else if (( mode == KGlobalSettings::CompletionPopup ||
00942                    mode == KGlobalSettings::CompletionPopupAuto ) &&
00943                    noModifier && !e->text().isEmpty() )
00944         {
00945             const QString old_txt = text();
00946             const bool hasUserSelection=d->userSelection;
00947             const bool hadSelection=hasSelectedText();
00948             bool cursorNotAtEnd=false;
00949 
00950             const int start = selectionStart();
00951             const int cPos = cursorPosition();
00952             const QString keycode = e->text();
00953 
00954             // When moving the cursor, we want to keep the autocompletion as an
00955             // autocompletion, so we want to process events at the cursor position
00956             // as if there was no selection. After processing the key event, we
00957             // can set the new autocompletion again.
00958             if (hadSelection && !hasUserSelection && start>cPos &&
00959                ( (!keycode.isEmpty() && keycode.unicode()->isPrint()) ||
00960                  e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) )
00961             {
00962                 del();
00963                 setCursorPosition(cPos);
00964                 cursorNotAtEnd=true;
00965             }
00966 
00967             const int selectedLength=selectedText().length();
00968 
00969             d->disableRestoreSelection = true;
00970             QLineEdit::keyPressEvent ( e );
00971             d->disableRestoreSelection = false;
00972 
00973             if (( selectedLength != selectedText().length() ) && !hasUserSelection )
00974                 slotRestoreSelectionColors(); // and set userSelection to true
00975 
00976             QString txt = text();
00977             int len = txt.length();
00978             if ( ( txt != old_txt || txt != e->text() ) && len/* && ( cursorPosition() == len || force )*/ &&
00979                  ( (!keycode.isEmpty() && keycode.unicode()->isPrint()) ||
00980                    e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete) )
00981             {
00982                 if ( e->key() == Qt::Key_Backspace )
00983                 {
00984                     if ( hadSelection && !hasUserSelection && !cursorNotAtEnd )
00985                     {
00986                         backspace();
00987                         txt = text();
00988                         len = txt.length();
00989                     }
00990 
00991                     if (!d->s_backspacePerformsCompletion) {
00992                         d->autoSuggest = false;
00993                     }
00994                 }
00995 
00996                 if (e->key() == Qt::Key_Delete )
00997                     d->autoSuggest=false;
00998 
00999                 if ( d->completionBox )
01000                   d->completionBox->setCancelledText( txt );
01001 
01002                 doCompletion(txt);
01003 
01004                 if ( (e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) &&
01005                     mode == KGlobalSettings::CompletionPopupAuto )
01006                   d->autoSuggest=true;
01007 
01008                 e->accept();
01009             }
01010             else if (!len && d->completionBox && d->completionBox->isVisible())
01011                 d->completionBox->hide();
01012 
01013             return;
01014         }
01015 
01016         else if ( mode == KGlobalSettings::CompletionShell )
01017         {
01018             // Handles completion.
01019             KShortcut cut;
01020             if ( keys[TextCompletion].isEmpty() )
01021                 cut = KStandardShortcut::shortcut(KStandardShortcut::TextCompletion);
01022             else
01023                 cut = keys[TextCompletion];
01024 
01025             if ( cut.contains( key ) )
01026             {
01027                 // Emit completion if the completion mode is CompletionShell
01028                 // and the cursor is at the end of the string.
01029                 const QString txt = text();
01030                 const int len = txt.length();
01031                 if ( cursorPosition() == len && len != 0 )
01032                 {
01033                     doCompletion(txt);
01034                     return;
01035                 }
01036             }
01037             else if ( d->completionBox )
01038                 d->completionBox->hide();
01039         }
01040 
01041         // handle rotation
01042         if ( mode != KGlobalSettings::CompletionNone )
01043         {
01044             // Handles previous match
01045             KShortcut cut;
01046             if ( keys[PrevCompletionMatch].isEmpty() )
01047                 cut = KStandardShortcut::shortcut(KStandardShortcut::PrevCompletion);
01048             else
01049                 cut = keys[PrevCompletionMatch];
01050 
01051             if ( cut.contains( key ) )
01052             {
01053                 if ( emitSignals() )
01054                     emit textRotation( KCompletionBase::PrevCompletionMatch );
01055                 if ( handleSignals() )
01056                     rotateText( KCompletionBase::PrevCompletionMatch );
01057                 return;
01058             }
01059 
01060             // Handles next match
01061             if ( keys[NextCompletionMatch].isEmpty() )
01062                 cut = KStandardShortcut::shortcut(KStandardShortcut::NextCompletion);
01063             else
01064                 cut = keys[NextCompletionMatch];
01065 
01066             if ( cut.contains( key ) )
01067             {
01068                 if ( emitSignals() )
01069                     emit textRotation( KCompletionBase::NextCompletionMatch );
01070                 if ( handleSignals() )
01071                     rotateText( KCompletionBase::NextCompletionMatch );
01072                 return;
01073             }
01074         }
01075 
01076         // substring completion
01077         if ( compObj() )
01078         {
01079             KShortcut cut;
01080             if ( keys[SubstringCompletion].isEmpty() )
01081                 cut = KStandardShortcut::shortcut(KStandardShortcut::SubstringCompletion);
01082             else
01083                 cut = keys[SubstringCompletion];
01084 
01085             if ( cut.contains( key ) )
01086             {
01087                 if ( emitSignals() )
01088                     emit substringCompletion( text() );
01089                 if ( handleSignals() )
01090                 {
01091                     setCompletedItems( compObj()->substringCompletion(text()));
01092                     e->accept();
01093                 }
01094                 return;
01095             }
01096         }
01097     }
01098     const int selectedLength = selectedText().length();
01099 
01100     // Let QLineEdit handle any other keys events.
01101     QLineEdit::keyPressEvent ( e );
01102 
01103     if ( selectedLength != selectedText().length() )
01104         slotRestoreSelectionColors(); // and set userSelection to true
01105 }
01106 
01107 void KLineEdit::mouseDoubleClickEvent( QMouseEvent* e )
01108 {
01109     if ( e->button() == Qt::LeftButton  )
01110     {
01111         d->possibleTripleClick=true;
01112         QTimer::singleShot( QApplication::doubleClickInterval(),this,
01113                             SLOT(tripleClickTimeout()) );
01114     }
01115     QLineEdit::mouseDoubleClickEvent( e );
01116 }
01117 
01118 void KLineEdit::mousePressEvent( QMouseEvent* e )
01119 {
01120     if  ( (e->button() == Qt::LeftButton ||
01121            e->button() == Qt::MidButton ) &&
01122           d->clearButton ) {
01123         d->clickInClear = ( d->clearButton == childAt(e->pos()) || d->clearButton->underMouse() );
01124 
01125         if ( d->clickInClear ) {
01126             d->possibleTripleClick = false;
01127         }
01128     }
01129 
01130     if ( e->button() == Qt::LeftButton && d->possibleTripleClick ) {
01131         selectAll();
01132         e->accept();
01133         return;
01134     }
01135 
01136     // if middle clicking and if text is present in the clipboard then clear the selection
01137     // to prepare paste operation
01138     if ( e->button() == Qt::MidButton ) {
01139         if ( hasSelectedText() ) {
01140             if ( QApplication::clipboard()->text( QClipboard::Selection ).length() >0 ) {
01141                 backspace();
01142             }
01143         }
01144     }
01145 
01146     QLineEdit::mousePressEvent( e );
01147 }
01148 
01149 void KLineEdit::mouseReleaseEvent( QMouseEvent* e )
01150 {
01151     if ( d->clickInClear ) {
01152         if ( d->clearButton == childAt(e->pos()) || d->clearButton->underMouse() ) {
01153             QString newText;
01154             if ( e->button() == Qt::MidButton ) {
01155                 newText = QApplication::clipboard()->text( QClipboard::Selection );
01156                 setText( newText );
01157             } else {
01158                 setSelection(0, text().size());
01159                 del();
01160                 emit clearButtonClicked();
01161             }
01162             emit textChanged( newText );
01163         }
01164 
01165         d->clickInClear = false;
01166         e->accept();
01167         return;
01168     }
01169 
01170     QLineEdit::mouseReleaseEvent( e );
01171 
01172     if (QApplication::clipboard()->supportsSelection() ) {
01173         if ( e->button() == Qt::LeftButton ) {
01174             // Fix copying of squeezed text if needed
01175             copySqueezedText( false );
01176         }
01177     }
01178 }
01179 
01180 void KLineEdit::tripleClickTimeout()
01181 {
01182     d->possibleTripleClick=false;
01183 }
01184 
01185 QMenu* KLineEdit::createStandardContextMenu()
01186 {
01187     QMenu *popup = QLineEdit::createStandardContextMenu();
01188 
01189     if( !isReadOnly() )
01190     {
01191         // FIXME: This code depends on Qt's action ordering.
01192         const QList<QAction *> actionList = popup->actions();
01193         enum { UndoAct, RedoAct, Separator1, CutAct, CopyAct, PasteAct, DeleteAct, ClearAct,
01194                Separator2, SelectAllAct, NCountActs };
01195         QAction *separatorAction = 0L;
01196         // separator we want is right after Delete right now.
01197         const int idx = actionList.indexOf( actionList[DeleteAct] ) + 1;
01198         if ( idx < actionList.count() )
01199             separatorAction = actionList.at( idx );
01200         if ( separatorAction )
01201         {
01202             KAction *clearAllAction = KStandardAction::clear( this, SLOT( clear() ), this) ;
01203             if ( text().isEmpty() )
01204                 clearAllAction->setEnabled( false );
01205             popup->insertAction( separatorAction, clearAllAction );
01206         }
01207     }
01208 
01209     KIconTheme::assignIconsToContextMenu( KIconTheme::TextEditor, popup->actions () );
01210 
01211     // If a completion object is present and the input
01212     // widget is not read-only, show the Text Completion
01213     // menu item.
01214     if ( compObj() && !isReadOnly() && KAuthorized::authorize("lineedit_text_completion") )
01215     {
01216         QMenu *subMenu = popup->addMenu( KIcon("text-completion"), i18nc("@title:menu", "Text Completion") );
01217         connect( subMenu, SIGNAL( triggered ( QAction* ) ),
01218                  this, SLOT( completionMenuActivated( QAction* ) ) );
01219 
01220         popup->addSeparator();
01221 
01222         QActionGroup* ag = new QActionGroup( this );
01223         d->noCompletionAction = ag->addAction( i18nc("@item:inmenu Text Completion", "None"));
01224         d->shellCompletionAction = ag->addAction( i18nc("@item:inmenu Text Completion", "Manual") );
01225         d->autoCompletionAction = ag->addAction( i18nc("@item:inmenu Text Completion", "Automatic") );
01226         d->popupCompletionAction = ag->addAction( i18nc("@item:inmenu Text Completion", "Dropdown List") );
01227         d->shortAutoCompletionAction = ag->addAction( i18nc("@item:inmenu Text Completion", "Short Automatic") );
01228         d->popupAutoCompletionAction = ag->addAction( i18nc("@item:inmenu Text Completion", "Dropdown List && Automatic"));
01229         subMenu->addActions( ag->actions() );
01230 
01231         //subMenu->setAccel( KStandardShortcut::completion(), ShellCompletion );
01232 
01233         d->shellCompletionAction->setCheckable( true );
01234         d->noCompletionAction->setCheckable( true );
01235         d->popupCompletionAction->setCheckable( true );
01236         d->autoCompletionAction->setCheckable( true );
01237         d->shortAutoCompletionAction->setCheckable( true );
01238         d->popupAutoCompletionAction->setCheckable( true );
01239 
01240         d->shellCompletionAction->setEnabled( !d->disableCompletionMap[ KGlobalSettings::CompletionShell ] );
01241         d->noCompletionAction->setEnabled( !d->disableCompletionMap[ KGlobalSettings::CompletionNone ] );
01242         d->popupCompletionAction->setEnabled( !d->disableCompletionMap[ KGlobalSettings::CompletionPopup ] );
01243         d->autoCompletionAction->setEnabled( !d->disableCompletionMap[ KGlobalSettings::CompletionAuto ] );
01244         d->shortAutoCompletionAction->setEnabled( !d->disableCompletionMap[ KGlobalSettings::CompletionMan ] );
01245         d->popupAutoCompletionAction->setEnabled( !d->disableCompletionMap[ KGlobalSettings::CompletionPopupAuto ] );
01246 
01247         const KGlobalSettings::Completion mode = completionMode();
01248         d->noCompletionAction->setChecked( mode == KGlobalSettings::CompletionNone );
01249         d->shellCompletionAction->setChecked( mode == KGlobalSettings::CompletionShell );
01250         d->popupCompletionAction->setChecked( mode == KGlobalSettings::CompletionPopup );
01251         d->autoCompletionAction->setChecked(  mode == KGlobalSettings::CompletionAuto );
01252         d->shortAutoCompletionAction->setChecked( mode == KGlobalSettings::CompletionMan );
01253         d->popupAutoCompletionAction->setChecked( mode == KGlobalSettings::CompletionPopupAuto );
01254 
01255         const KGlobalSettings::Completion defaultMode = KGlobalSettings::completionMode();
01256         if ( mode != defaultMode && !d->disableCompletionMap[ defaultMode ] )
01257         {
01258             subMenu->addSeparator();
01259             d->defaultAction = subMenu->addAction( i18nc("@item:inmenu Text Completion", "Default") );
01260         }
01261     }
01262 
01263     return popup;
01264 }
01265 
01266 void KLineEdit::contextMenuEvent( QContextMenuEvent *e )
01267 {
01268     if ( QLineEdit::contextMenuPolicy() != Qt::DefaultContextMenu )
01269       return;
01270     QMenu *popup = createStandardContextMenu();
01271 
01272     // ### do we really need this?  Yes, Please do not remove!  This
01273     // allows applications to extend the popup menu without having to
01274     // inherit from this class! (DA)
01275     emit aboutToShowContextMenu( popup );
01276 
01277     popup->exec(e->globalPos());
01278     delete popup;
01279 }
01280 
01281 void KLineEdit::completionMenuActivated( QAction  *act)
01282 {
01283     KGlobalSettings::Completion oldMode = completionMode();
01284 
01285     if( act == d->noCompletionAction )
01286     {
01287         setCompletionMode( KGlobalSettings::CompletionNone );
01288     }
01289     else if( act ==  d->shellCompletionAction)
01290     {
01291         setCompletionMode( KGlobalSettings::CompletionShell );
01292     }
01293     else if( act == d->autoCompletionAction)
01294     {
01295         setCompletionMode( KGlobalSettings::CompletionAuto );
01296     }
01297     else if( act == d->popupCompletionAction)
01298     {
01299         setCompletionMode( KGlobalSettings::CompletionPopup );
01300     }
01301     else if( act == d->shortAutoCompletionAction)
01302     {
01303         setCompletionMode( KGlobalSettings::CompletionMan );
01304     }
01305     else if( act == d->popupAutoCompletionAction)
01306     {
01307         setCompletionMode( KGlobalSettings::CompletionPopupAuto );
01308     }
01309     else if( act == d->defaultAction )
01310     {
01311         setCompletionMode( KGlobalSettings::completionMode() );
01312     }
01313     else
01314         return;
01315 
01316     if ( oldMode != completionMode() )
01317     {
01318         if ( (oldMode == KGlobalSettings::CompletionPopup ||
01319               oldMode == KGlobalSettings::CompletionPopupAuto ) &&
01320              d->completionBox && d->completionBox->isVisible() )
01321             d->completionBox->hide();
01322         emit completionModeChanged( completionMode() );
01323     }
01324 }
01325 
01326 void KLineEdit::dropEvent(QDropEvent *e)
01327 {
01328     if( d->handleURLDrops )
01329     {
01330         const KUrl::List urlList = KUrl::List::fromMimeData( e->mimeData() );
01331         if ( !urlList.isEmpty() )
01332         {
01333             // Let's replace the current text with the dropped URL(s), rather than appending.
01334             // Makes more sense in general (#188129), e.g. konq location bar and kurlrequester
01335             // can only hold one url anyway. OK this code supports multiple urls being dropped,
01336             // but that's not the common case [and it breaks if they contain spaces... this is why
01337             // kfiledialog uses double quotes around filenames in multiple-selection mode]...
01338             //
01339             // Anyway, if some apps prefer "append" then we should have a
01340             // setUrlDropsSupport( {NoUrlDrops, SingleUrlDrops, MultipleUrlDrops} )
01341             // where Single replaces and Multiple appends.
01342             QString dropText;
01343             //QString dropText = text();
01344             KUrl::List::ConstIterator it;
01345             for( it = urlList.begin() ; it != urlList.end() ; ++it )
01346             {
01347                 if(!dropText.isEmpty())
01348                     dropText+=' ';
01349 
01350                 dropText += (*it).prettyUrl();
01351             }
01352 
01353             setText(dropText);
01354             setCursorPosition(dropText.length());
01355 
01356             e->accept();
01357             return;
01358         }
01359     }
01360     QLineEdit::dropEvent(e);
01361 }
01362 
01363 bool KLineEdit::event( QEvent* ev )
01364 {
01365     KCursor::autoHideEventFilter( this, ev );
01366     if ( ev->type() == QEvent::ShortcutOverride )
01367     {
01368         QKeyEvent *e = static_cast<QKeyEvent *>( ev );
01369         if (d->overrideShortcut(e)) {
01370             ev->accept();
01371         }
01372     } else if (ev->type() == QEvent::ApplicationPaletteChange
01373                || ev->type() == QEvent::PaletteChange) {
01374         // Assume the widget uses the application's palette
01375         QPalette p = QApplication::palette();
01376         d->previousHighlightedTextColor=p.color(QPalette::Normal,QPalette::HighlightedText);
01377         d->previousHighlightColor=p.color(QPalette::Normal,QPalette::Highlight);
01378         setUserSelection(d->userSelection);
01379     } else if (ev->type() == QEvent::StyleChange) {
01380         // since we have our own style and it relies on this style to Get Things Right,
01381         // if a style is set specifically on the widget (which would replace our own style!)
01382         // hang on to this special style and re-instate our own style.
01383         //FIXME: Qt currently has a grave bug where already deleted QStyleSheetStyle objects
01384         // will get passed back in if we set a new style on it here. remove the qstrmcp test
01385         // when this is fixed in Qt (or a better approach is found)
01386         if (!qobject_cast<KLineEditStyle *>(style()) &&
01387             qstrcmp(style()->metaObject()->className(), "QStyleSheetStyle") != 0 &&
01388             QLatin1String(style()->metaObject()->className()) != d->lastStyleClass) {
01389             KLineEditStyle *kleStyle = d->style.data();
01390             if (!kleStyle) {
01391                 d->style = kleStyle = new KLineEditStyle(this);
01392             }
01393 
01394             kleStyle->m_subStyle = style();
01395             // this guards against "wrap around" where another style, e.g. QStyleSheetStyle,
01396             // is setting the style on QEvent::StyleChange
01397             d->lastStyleClass = QLatin1String(style()->metaObject()->className());
01398             setStyle(kleStyle);
01399             d->lastStyleClass.clear();
01400         }
01401     }
01402 
01403     return QLineEdit::event( ev );
01404 }
01405 
01406 
01407 void KLineEdit::setUrlDropsEnabled(bool enable)
01408 {
01409     d->handleURLDrops=enable;
01410 }
01411 
01412 bool KLineEdit::urlDropsEnabled() const
01413 {
01414     return d->handleURLDrops;
01415 }
01416 
01417 void KLineEdit::setTrapReturnKey( bool grab )
01418 {
01419     d->grabReturnKeyEvents = grab;
01420 }
01421 
01422 bool KLineEdit::trapReturnKey() const
01423 {
01424     return d->grabReturnKeyEvents;
01425 }
01426 
01427 void KLineEdit::setUrl( const KUrl& url )
01428 {
01429     setText( url.prettyUrl() );
01430 }
01431 
01432 void KLineEdit::setCompletionBox( KCompletionBox *box )
01433 {
01434     if ( d->completionBox )
01435         return;
01436 
01437     d->completionBox = box;
01438     if ( handleSignals() )
01439     {
01440         connect( d->completionBox, SIGNAL(currentTextChanged( const QString& )),
01441                  SLOT(_k_slotCompletionBoxTextChanged( const QString& )) );
01442         connect( d->completionBox, SIGNAL(userCancelled( const QString& )),
01443                  SLOT(userCancelled( const QString& )) );
01444         connect( d->completionBox, SIGNAL(activated(QString)),
01445                  SIGNAL(completionBoxActivated(QString)) );
01446         connect( d->completionBox, SIGNAL(activated(QString)),
01447                  SIGNAL(textEdited(QString)) );
01448     }
01449 }
01450 
01451 /*
01452  * Set the line edit text without changing the modified flag. By default
01453  * calling setText resets the modified flag to false.
01454  */
01455 static void setEditText(KLineEdit* edit, const QString& text)
01456 {
01457     if (!edit) {
01458         return;
01459     }
01460 
01461     const bool wasModified = edit->isModified();
01462     edit->setText(text);
01463     edit->setModified(wasModified);
01464 }
01465 
01466 void KLineEdit::userCancelled(const QString & cancelText)
01467 {
01468     if ( completionMode() != KGlobalSettings::CompletionPopupAuto )
01469     {
01470       setEditText(this, cancelText);
01471     }
01472     else if (hasSelectedText() )
01473     {
01474       if (d->userSelection)
01475         deselect();
01476       else
01477       {
01478         d->autoSuggest=false;
01479         const int start = selectionStart() ;
01480         const QString s = text().remove(selectionStart(), selectedText().length());
01481         setEditText(this, s);
01482         setCursorPosition(start);
01483         d->autoSuggest=true;
01484       }
01485     }
01486 }
01487 
01488 bool KLineEditPrivate::overrideShortcut(const QKeyEvent* e)
01489 {
01490     KShortcut scKey;
01491 
01492     const int key = e->key() | e->modifiers();
01493     const KLineEdit::KeyBindingMap keys = q->getKeyBindings();
01494 
01495     if (keys[KLineEdit::TextCompletion].isEmpty())
01496         scKey = KStandardShortcut::shortcut(KStandardShortcut::TextCompletion);
01497     else
01498         scKey = keys[KLineEdit::TextCompletion];
01499 
01500     if (scKey.contains( key ))
01501         return true;
01502 
01503     if (keys[KLineEdit::NextCompletionMatch].isEmpty())
01504         scKey = KStandardShortcut::shortcut(KStandardShortcut::NextCompletion);
01505     else
01506         scKey = keys[KLineEdit::NextCompletionMatch];
01507 
01508     if (scKey.contains( key ))
01509         return true;
01510 
01511     if (keys[KLineEdit::PrevCompletionMatch].isEmpty())
01512         scKey = KStandardShortcut::shortcut(KStandardShortcut::PrevCompletion);
01513     else
01514         scKey = keys[KLineEdit::PrevCompletionMatch];
01515 
01516     if (scKey.contains( key ))
01517         return true;
01518 
01519     // Override all the text manupilation accelerators...
01520     if ( KStandardShortcut::copy().contains( key ) )
01521         return true;
01522     else if ( KStandardShortcut::paste().contains( key ) )
01523         return true;
01524     else if ( KStandardShortcut::cut().contains( key ) )
01525         return true;
01526     else if ( KStandardShortcut::undo().contains( key ) )
01527         return true;
01528     else if ( KStandardShortcut::redo().contains( key ) )
01529         return true;
01530     else if (KStandardShortcut::deleteWordBack().contains( key ))
01531         return true;
01532     else if (KStandardShortcut::deleteWordForward().contains( key ))
01533         return true;
01534     else if (KStandardShortcut::forwardWord().contains( key ))
01535         return true;
01536     else if (KStandardShortcut::backwardWord().contains( key ))
01537         return true;
01538     else if (KStandardShortcut::beginningOfLine().contains( key ))
01539         return true;
01540     else if (KStandardShortcut::endOfLine().contains( key ))
01541         return true;
01542 
01543     // Shortcut overrides for shortcuts that QLineEdit handles
01544     // but doesn't dare force as "stronger than kaction shortcuts"...
01545     else if (e->matches(QKeySequence::SelectAll)) {
01546         return true;
01547     }
01548 #ifdef Q_WS_X11
01549     else if (key == Qt::CTRL + Qt::Key_E || key == Qt::CTRL + Qt::Key_U)
01550         return true;
01551 #endif
01552 
01553     if (completionBox && completionBox->isVisible ())
01554     {
01555         const int key = e->key();
01556         const Qt::KeyboardModifiers modifiers = e->modifiers();
01557         if ((key == Qt::Key_Backtab || key == Qt::Key_Tab) &&
01558             (modifiers == Qt::NoModifier || (modifiers & Qt::ShiftModifier)))
01559         {
01560             return true;
01561         }
01562     }
01563 
01564 
01565     return false;
01566 }
01567 
01568 void KLineEdit::setCompletedItems( const QStringList& items, bool autoSuggest )
01569 {
01570     QString txt;
01571     if ( d->completionBox && d->completionBox->isVisible() ) {
01572         // The popup is visible already - do the matching on the initial string,
01573         // not on the currently selected one.
01574         txt = completionBox()->cancelledText();
01575     } else {
01576         txt = text();
01577     }
01578 
01579     if ( !items.isEmpty() &&
01580          !(items.count() == 1 && txt == items.first()) )
01581     {
01582         // create completion box if non-existent
01583         completionBox();
01584 
01585         if ( d->completionBox->isVisible() )
01586         {
01587             QListWidgetItem* currentItem = d->completionBox->currentItem();
01588 
01589             QString currentSelection;
01590             if ( currentItem != 0 ) {
01591                 currentSelection = currentItem->text();
01592             }
01593 
01594             d->completionBox->setItems( items );
01595 
01596             const QList<QListWidgetItem*> matchedItems = d->completionBox->findItems(currentSelection, Qt::MatchExactly);
01597             QListWidgetItem* matchedItem = matchedItems.isEmpty() ? 0 : matchedItems.first();
01598 
01599             if (matchedItem) {
01600                 const bool blocked = d->completionBox->blockSignals( true );
01601                 d->completionBox->setCurrentItem( matchedItem );
01602                 d->completionBox->blockSignals( blocked );
01603             } else {
01604                 d->completionBox->setCurrentRow(-1);
01605             }
01606         }
01607         else // completion box not visible yet -> show it
01608         {
01609             if ( !txt.isEmpty() )
01610                 d->completionBox->setCancelledText( txt );
01611             d->completionBox->setItems( items );
01612             d->completionBox->popup();
01613         }
01614 
01615         if ( d->autoSuggest && autoSuggest )
01616         {
01617             const int index = items.first().indexOf( txt );
01618             const QString newText = items.first().mid( index );
01619             setUserSelection(false); // can be removed? setCompletedText sets it anyway
01620             setCompletedText(newText,true);
01621         }
01622     }
01623     else
01624     {
01625         if ( d->completionBox && d->completionBox->isVisible() )
01626             d->completionBox->hide();
01627     }
01628 }
01629 
01630 KCompletionBox * KLineEdit::completionBox( bool create )
01631 {
01632     if ( create && !d->completionBox ) {
01633         setCompletionBox( new KCompletionBox( this ) );
01634         d->completionBox->setObjectName("completion box");
01635         d->completionBox->setFont(font());
01636     }
01637 
01638     return d->completionBox;
01639 }
01640 
01641 void KLineEdit::setCompletionObject( KCompletion* comp, bool hsig )
01642 {
01643     KCompletion *oldComp = compObj();
01644     if ( oldComp && handleSignals() )
01645         disconnect( oldComp, SIGNAL( matches( const QStringList& )),
01646                     this, SLOT( setCompletedItems( const QStringList& )));
01647 
01648     if ( comp && hsig )
01649       connect( comp, SIGNAL( matches( const QStringList& )),
01650                this, SLOT( setCompletedItems( const QStringList& )));
01651 
01652     KCompletionBase::setCompletionObject( comp, hsig );
01653 }
01654 
01655 // QWidget::create() turns off mouse-Tracking which would break auto-hiding
01656 void KLineEdit::create( WId id, bool initializeWindow, bool destroyOldWindow )
01657 {
01658     QLineEdit::create( id, initializeWindow, destroyOldWindow );
01659     KCursor::setAutoHideCursor( this, true, true );
01660 }
01661 
01662 void KLineEdit::setUserSelection(bool userSelection)
01663 {
01664     //if !d->userSelection && userSelection we are accepting a completion,
01665     //so trigger an update
01666 
01667     if (!d->userSelection && userSelection)
01668     {
01669     d->_k_updateUserText(text());
01670     }
01671 
01672     QPalette p = palette();
01673 
01674     if (userSelection)
01675     {
01676         p.setColor(QPalette::Highlight, d->previousHighlightColor);
01677         p.setColor(QPalette::HighlightedText, d->previousHighlightedTextColor);
01678     }
01679     else
01680     {
01681         QColor color=p.color(QPalette::Disabled, QPalette::Text);
01682         p.setColor(QPalette::HighlightedText, color);
01683         color=p.color(QPalette::Active, QPalette::Base);
01684         p.setColor(QPalette::Highlight, color);
01685     }
01686 
01687     d->userSelection=userSelection;
01688     setPalette(p);
01689 }
01690 
01691 void KLineEdit::slotRestoreSelectionColors()
01692 {
01693     if (d->disableRestoreSelection)
01694       return;
01695 
01696     setUserSelection(true);
01697 }
01698 
01699 void KLineEdit::clear()
01700 {
01701     setText( QString() );
01702 }
01703 
01704 void KLineEdit::_k_slotCompletionBoxTextChanged( const QString& text )
01705 {
01706     if (!text.isEmpty())
01707     {
01708         setText( text );
01709         setModified(true);
01710         end( false ); // force cursor at end
01711     }
01712 }
01713 
01714 QString KLineEdit::originalText() const
01715 {
01716     if ( d->enableSqueezedText && isReadOnly() )
01717         return d->squeezedText;
01718 
01719     return text();
01720 }
01721 
01722 QString KLineEdit::userText() const
01723 {
01724     return d->userText;
01725 }
01726 
01727 bool KLineEdit::autoSuggest() const
01728 {
01729     return d->autoSuggest;
01730 }
01731 
01732 void KLineEdit::paintEvent( QPaintEvent *ev )
01733 {
01734     if (echoMode() == Password && d->threeStars) {
01735         // ### hack alert!
01736         // QLineEdit has currently no hooks to modify the displayed string.
01737         // When we call setText(), an update() is triggered and we get
01738         // into an infinite recursion.
01739         // Qt offers the setUpdatesEnabled() method, but when we re-enable
01740         // them, update() is triggered, and we get into the same recursion.
01741         // To work around this problem, we set/clear the internal Qt flag which
01742         // marks the updatesDisabled state manually.
01743         setAttribute(Qt::WA_UpdatesDisabled, true);
01744         blockSignals(true);
01745         const QString oldText = text();
01746         const bool isModifiedState = isModified(); // save modified state because setText resets it
01747         setText(oldText + oldText + oldText);
01748         QLineEdit::paintEvent(ev);
01749         setText(oldText);
01750         setModified(isModifiedState);
01751         blockSignals(false);
01752         setAttribute(Qt::WA_UpdatesDisabled, false);
01753     } else {
01754         QLineEdit::paintEvent( ev );
01755     }
01756 
01757     if (d->enableClickMsg && d->drawClickMsg && !hasFocus() && text().isEmpty()) {
01758         QPainter p(this);
01759         QFont f = font();
01760         f.setItalic(d->italicizePlaceholder);
01761         p.setFont(f);
01762 
01763         QColor color(palette().color(foregroundRole()));
01764         color.setAlphaF(0.5);
01765         p.setPen(color);
01766 
01767         QStyleOptionFrame opt;
01768         initStyleOption(&opt);
01769         QRect cr = style()->subElementRect(QStyle::SE_LineEditContents, &opt, this);
01770 
01771         // this is copied/adapted from QLineEdit::paintEvent
01772         const int verticalMargin(1);
01773         const int horizontalMargin(2);
01774 
01775         int left, top, right, bottom;
01776         getTextMargins( &left, &top, &right, &bottom );
01777         cr.adjust( left, top, -right, -bottom );
01778 
01779         p.setClipRect(cr);
01780 
01781         QFontMetrics fm = fontMetrics();
01782         Qt::Alignment va = alignment() & Qt::AlignVertical_Mask;
01783         int vscroll;
01784         switch (va & Qt::AlignVertical_Mask)
01785         {
01786             case Qt::AlignBottom:
01787             vscroll = cr.y() + cr.height() - fm.height() - verticalMargin;
01788             break;
01789 
01790             case Qt::AlignTop:
01791             vscroll = cr.y() + verticalMargin;
01792             break;
01793 
01794             default:
01795             vscroll = cr.y() + (cr.height() - fm.height() + 1) / 2;
01796             break;
01797 
01798         }
01799 
01800         QRect lineRect(cr.x() + horizontalMargin, vscroll, cr.width() - 2*horizontalMargin, fm.height());
01801         p.drawText(lineRect, Qt::AlignLeft|Qt::AlignVCenter, d->clickMessage);
01802 
01803     }
01804 }
01805 
01806 void KLineEdit::focusInEvent( QFocusEvent *ev )
01807 {
01808     if ( d->enableClickMsg && d->drawClickMsg )
01809     {
01810         d->drawClickMsg = false;
01811         update();
01812     }
01813     QLineEdit::focusInEvent( ev );
01814 }
01815 
01816 void KLineEdit::focusOutEvent( QFocusEvent *ev )
01817 {
01818     if ( d->enableClickMsg && text().isEmpty() )
01819     {
01820         d->drawClickMsg = true;
01821         update();
01822     }
01823     QLineEdit::focusOutEvent( ev );
01824 }
01825 
01826 void KLineEdit::setClickMessage( const QString &msg )
01827 {
01828     d->enableClickMsg = !msg.isEmpty();
01829     d->clickMessage = msg;
01830     d->drawClickMsg = text().isEmpty();
01831     update();
01832 }
01833 
01834 #ifndef KDE_NO_DEPRECATED
01835 void KLineEdit::setContextMenuEnabled( bool showMenu )
01836 {
01837     QLineEdit::setContextMenuPolicy( showMenu ? Qt::DefaultContextMenu : Qt::NoContextMenu );
01838 }
01839 #endif
01840 
01841 #ifndef KDE_NO_DEPRECATED
01842 bool KLineEdit::isContextMenuEnabled() const
01843 {
01844     return  ( contextMenuPolicy() == Qt::DefaultContextMenu );
01845 }
01846 #endif
01847 
01848 void KLineEdit::setPasswordMode(bool b)
01849 {
01850     if(b)
01851     {
01852         KConfigGroup cg(KGlobal::config(), "Passwords");
01853         const QString val = cg.readEntry("EchoMode", "OneStar");
01854         if (val == "NoEcho")
01855             setEchoMode(NoEcho);
01856         else {
01857             d->threeStars = (val == "ThreeStars");
01858             setEchoMode(Password);
01859         }
01860     }
01861     else
01862     {
01863         setEchoMode( Normal );
01864     }
01865 }
01866 
01867 bool KLineEdit::passwordMode() const
01868 {
01869     return echoMode() == NoEcho || echoMode() == Password;
01870 }
01871 
01872 void KLineEdit::doCompletion(const QString& txt)
01873 {
01874     if (emitSignals()) {
01875         emit completion(txt); // emit when requested...
01876     }
01877     d->completionRunning = true;
01878     if (handleSignals()) {
01879         makeCompletion(txt);  // handle when requested...
01880     }
01881     d->completionRunning = false;
01882 }
01883 
01884 #include "klineedit.moc"
01885 #include "klineedit_p.moc"

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

Skip menu "kdelibs"
  • 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
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal