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

KDEUI

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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