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

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
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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