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

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
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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