• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • 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 <qclipboard.h>
00029 #include <qpainter.h>
00030 #include <qtimer.h>
00031 
00032 #include <kconfig.h>
00033 #include <qtooltip.h>
00034 #include <kcursor.h>
00035 #include <klocale.h>
00036 #include <kstdaccel.h>
00037 #include <kpopupmenu.h>
00038 #include <kdebug.h>
00039 #include <kcompletionbox.h>
00040 #include <kurl.h>
00041 #include <kurldrag.h>
00042 #include <kiconloader.h>
00043 #include <kapplication.h>
00044 
00045 #include "klineedit.h"
00046 #include "klineedit.moc"
00047 
00048 
00049 class KLineEdit::KLineEditPrivate
00050 {
00051 public:
00052     KLineEditPrivate()
00053     {
00054         completionBox = 0L;
00055         handleURLDrops = true;
00056         grabReturnKeyEvents = false;
00057 
00058         userSelection = true;
00059         autoSuggest = false;
00060         disableRestoreSelection = false;
00061         enableSqueezedText = false;
00062 
00063         if ( !initialized )
00064         {
00065             KConfigGroup config( KGlobal::config(), "General" );
00066             backspacePerformsCompletion = config.readBoolEntry( "Backspace performs completion", false );
00067 
00068             initialized = true;
00069         }
00070 
00071     }
00072 
00073     ~KLineEditPrivate()
00074     {
00075 // causes a weird crash in KWord at least, so let Qt delete it for us.
00076 //        delete completionBox;
00077     }
00078 
00079     static bool initialized;
00080     static bool backspacePerformsCompletion; // Configuration option
00081 
00082     QColor previousHighlightColor;
00083     QColor previousHighlightedTextColor;
00084 
00085     bool userSelection: 1;
00086     bool autoSuggest : 1;
00087     bool disableRestoreSelection: 1;
00088     bool handleURLDrops:1;
00089     bool grabReturnKeyEvents:1;
00090     bool enableSqueezedText:1;
00091 
00092     int squeezedEnd;
00093     int squeezedStart;
00094     BackgroundMode bgMode;
00095     QString squeezedText;
00096     KCompletionBox *completionBox;
00097 
00098     QString clickMessage;
00099     bool drawClickMsg:1;
00100 };
00101 
00102 bool KLineEdit::KLineEditPrivate::backspacePerformsCompletion = false;
00103 bool KLineEdit::KLineEditPrivate::initialized = false;
00104 
00105 
00106 KLineEdit::KLineEdit( const QString &string, QWidget *parent, const char *name )
00107           :QLineEdit( string, parent, name )
00108 {
00109     init();
00110 }
00111 
00112 KLineEdit::KLineEdit( QWidget *parent, const char *name )
00113           :QLineEdit( parent, name )
00114 {
00115     init();
00116 }
00117 
00118 KLineEdit::~KLineEdit ()
00119 {
00120     delete d;
00121     d = 0;
00122 }
00123 
00124 void KLineEdit::init()
00125 {
00126     d = new KLineEditPrivate;
00127     possibleTripleClick = false;
00128     d->bgMode = backgroundMode ();
00129 
00130     // Enable the context menu by default.
00131     KLineEdit::setContextMenuEnabled( true );
00132     KCursor::setAutoHideCursor( this, true, true );
00133     installEventFilter( this );
00134 
00135     KGlobalSettings::Completion mode = completionMode();
00136     d->autoSuggest = (mode == KGlobalSettings::CompletionMan ||
00137                       mode == KGlobalSettings::CompletionPopupAuto ||
00138                       mode == KGlobalSettings::CompletionAuto);
00139     connect( this, SIGNAL(selectionChanged()), this, SLOT(slotRestoreSelectionColors()));
00140 
00141     QPalette p = palette();
00142     if ( !d->previousHighlightedTextColor.isValid() )
00143       d->previousHighlightedTextColor=p.color(QPalette::Normal,QColorGroup::HighlightedText);
00144     if ( !d->previousHighlightColor.isValid() )
00145       d->previousHighlightColor=p.color(QPalette::Normal,QColorGroup::Highlight);
00146 
00147     d->drawClickMsg = false;
00148 }
00149 
00150 void KLineEdit::setCompletionMode( KGlobalSettings::Completion mode )
00151 {
00152     KGlobalSettings::Completion oldMode = completionMode();
00153 
00154     if ( oldMode != mode && (oldMode == KGlobalSettings::CompletionPopup ||
00155          oldMode == KGlobalSettings::CompletionPopupAuto ) &&
00156          d->completionBox && d->completionBox->isVisible() )
00157       d->completionBox->hide();
00158 
00159     // If the widgets echo mode is not Normal, no completion
00160     // feature will be enabled even if one is requested.
00161     if ( echoMode() != QLineEdit::Normal )
00162         mode = KGlobalSettings::CompletionNone; // Override the request.
00163 
00164     if ( kapp && !kapp->authorize("lineedit_text_completion") )
00165         mode = KGlobalSettings::CompletionNone;
00166 
00167     if ( mode == KGlobalSettings::CompletionPopupAuto ||
00168          mode == KGlobalSettings::CompletionAuto ||
00169          mode == KGlobalSettings::CompletionMan )
00170         d->autoSuggest = true;
00171     else
00172         d->autoSuggest = false;
00173 
00174     KCompletionBase::setCompletionMode( mode );
00175 }
00176 
00177 void KLineEdit::setCompletedText( const QString& t, bool marked )
00178 {
00179     if ( !d->autoSuggest )
00180       return;
00181 
00182     QString txt = text();
00183 
00184     if ( t != txt )
00185     {
00186         int start = marked ? txt.length() : t.length();
00187         validateAndSet( t, cursorPosition(), start, t.length() );
00188         setUserSelection(false);
00189     }
00190     else
00191       setUserSelection(true);
00192 
00193 }
00194 
00195 void KLineEdit::setCompletedText( const QString& text )
00196 {
00197     KGlobalSettings::Completion mode = completionMode();
00198     bool marked = ( mode == KGlobalSettings::CompletionAuto ||
00199                     mode == KGlobalSettings::CompletionMan ||
00200                     mode == KGlobalSettings::CompletionPopup ||
00201                     mode == KGlobalSettings::CompletionPopupAuto );
00202     setCompletedText( text, marked );
00203 }
00204 
00205 void KLineEdit::rotateText( KCompletionBase::KeyBindingType type )
00206 {
00207     KCompletion* comp = compObj();
00208     if ( comp &&
00209        (type == KCompletionBase::PrevCompletionMatch ||
00210         type == KCompletionBase::NextCompletionMatch ) )
00211     {
00212        QString input;
00213 
00214        if (type == KCompletionBase::PrevCompletionMatch)
00215           comp->previousMatch();
00216        else
00217           comp->nextMatch();
00218 
00219        // Skip rotation if previous/next match is null or the same text
00220        if ( input.isNull() || input == displayText() )
00221             return;
00222        setCompletedText( input, hasSelectedText() );
00223     }
00224 }
00225 
00226 void KLineEdit::makeCompletion( const QString& text )
00227 {
00228     KCompletion *comp = compObj();
00229     KGlobalSettings::Completion mode = completionMode();
00230 
00231     if ( !comp || mode == KGlobalSettings::CompletionNone )
00232         return;  // No completion object...
00233 
00234     QString match = comp->makeCompletion( text );
00235 
00236     if ( mode == KGlobalSettings::CompletionPopup ||
00237          mode == KGlobalSettings::CompletionPopupAuto )
00238     {
00239         if ( match.isNull() )
00240         {
00241             if ( d->completionBox )
00242             {
00243                 d->completionBox->hide();
00244                 d->completionBox->clear();
00245             }
00246         }
00247         else
00248             setCompletedItems( comp->allMatches() );
00249     }
00250     else // Auto,  ShortAuto (Man) and Shell
00251     {
00252         // all other completion modes
00253         // If no match or the same match, simply return without completing.
00254         if ( match.isNull() || match == text )
00255             return;
00256 
00257         if ( mode != KGlobalSettings::CompletionShell )
00258             setUserSelection(false);
00259 
00260         if ( d->autoSuggest )
00261             setCompletedText( match );
00262     }
00263 }
00264 
00265 void KLineEdit::setReadOnly(bool readOnly)
00266 {
00267     // Do not do anything if nothing changed...
00268     if (readOnly == isReadOnly ())
00269       return;
00270 
00271     QLineEdit::setReadOnly (readOnly);
00272 
00273     if (readOnly)
00274     {
00275         d->bgMode = backgroundMode ();
00276         setBackgroundMode (Qt::PaletteBackground);
00277         if (d->enableSqueezedText && d->squeezedText.isEmpty())
00278         {
00279             d->squeezedText = text();
00280             setSqueezedText();
00281         }
00282     }
00283     else
00284     {
00285         if (!d->squeezedText.isEmpty())
00286         {
00287            setText(d->squeezedText);
00288            d->squeezedText = QString::null;
00289         }
00290         setBackgroundMode (d->bgMode);
00291     }
00292 }
00293 
00294 void KLineEdit::setSqueezedText( const QString &text)
00295 {
00296     setEnableSqueezedText(true);
00297     setText(text);
00298 }
00299 
00300 void KLineEdit::setEnableSqueezedText( bool enable )
00301 {
00302     d->enableSqueezedText = enable;
00303 }
00304 
00305 bool KLineEdit::isSqueezedTextEnabled() const
00306 {
00307     return d->enableSqueezedText;
00308 }
00309 
00310 void KLineEdit::setText( const QString& text )
00311 {
00312     d->drawClickMsg = text.isEmpty() && !d->clickMessage.isEmpty();
00313     update();
00314 
00315     if( d->enableSqueezedText && isReadOnly() )
00316     {
00317         d->squeezedText = text;
00318         setSqueezedText();
00319         return;
00320     }
00321 
00322     QLineEdit::setText( text );
00323 }
00324 
00325 void KLineEdit::setSqueezedText()
00326 {
00327     d->squeezedStart = 0;
00328     d->squeezedEnd = 0;
00329     QString fullText = d->squeezedText;
00330     QFontMetrics fm(fontMetrics());
00331     int labelWidth = size().width() - 2*frameWidth() - 2;
00332     int textWidth = fm.width(fullText);
00333 
00334     if (textWidth > labelWidth)
00335     {
00336           // start with the dots only
00337           QString squeezedText = "...";
00338           int squeezedWidth = fm.width(squeezedText);
00339 
00340           // estimate how many letters we can add to the dots on both sides
00341           int letters = fullText.length() * (labelWidth - squeezedWidth) / textWidth / 2;
00342           squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
00343           squeezedWidth = fm.width(squeezedText);
00344 
00345       if (squeezedWidth < labelWidth)
00346       {
00347              // we estimated too short
00348              // add letters while text < label
00349           do
00350           {
00351                 letters++;
00352                 squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
00353                 squeezedWidth = fm.width(squeezedText);
00354              } while (squeezedWidth < labelWidth);
00355              letters--;
00356              squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
00357       }
00358       else if (squeezedWidth > labelWidth)
00359       {
00360              // we estimated too long
00361              // remove letters while text > label
00362           do
00363           {
00364                letters--;
00365                 squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
00366                 squeezedWidth = fm.width(squeezedText);
00367              } while (squeezedWidth > labelWidth);
00368           }
00369 
00370       if (letters < 5)
00371       {
00372              // too few letters added -> we give up squeezing
00373           QLineEdit::setText(fullText);
00374       }
00375       else
00376       {
00377           QLineEdit::setText(squeezedText);
00378              d->squeezedStart = letters;
00379              d->squeezedEnd = fullText.length() - letters;
00380           }
00381 
00382           QToolTip::remove( this );
00383           QToolTip::add( this, fullText );
00384 
00385     }
00386     else
00387     {
00388       QLineEdit::setText(fullText);
00389 
00390           QToolTip::remove( this );
00391           QToolTip::hide();
00392        }
00393 
00394        setCursorPosition(0);
00395 }
00396 
00397 void KLineEdit::copy() const
00398 {
00399     if( !copySqueezedText(true))
00400         QLineEdit::copy();
00401 }
00402 
00403 bool KLineEdit::copySqueezedText(bool clipboard) const
00404 {
00405    if (!d->squeezedText.isEmpty() && d->squeezedStart)
00406    {
00407       int start, end;
00408       KLineEdit *that = const_cast<KLineEdit *>(this);
00409       if (!that->getSelection(&start, &end))
00410          return false;
00411       if (start >= d->squeezedStart+3)
00412          start = start - 3 - d->squeezedStart + d->squeezedEnd;
00413       else if (start > d->squeezedStart)
00414          start = d->squeezedStart;
00415       if (end >= d->squeezedStart+3)
00416          end = end - 3 - d->squeezedStart + d->squeezedEnd;
00417       else if (end > d->squeezedStart)
00418          end = d->squeezedEnd;
00419       if (start == end)
00420          return false;
00421       QString t = d->squeezedText;
00422       t = t.mid(start, end - start);
00423       disconnect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0);
00424       QApplication::clipboard()->setText( t, clipboard ? QClipboard::Clipboard : QClipboard::Selection );
00425       connect( QApplication::clipboard(), SIGNAL(selectionChanged()), this,
00426                SLOT(clipboardChanged()) );
00427       return true;
00428    }
00429    return false;
00430 }
00431 
00432 void KLineEdit::resizeEvent( QResizeEvent * ev )
00433 {
00434     if (!d->squeezedText.isEmpty())
00435         setSqueezedText();
00436 
00437     QLineEdit::resizeEvent(ev);
00438 }
00439 
00440 void KLineEdit::keyPressEvent( QKeyEvent *e )
00441 {
00442     KKey key( e );
00443 
00444     if ( KStdAccel::copy().contains( key ) )
00445     {
00446         copy();
00447         return;
00448     }
00449     else if ( KStdAccel::paste().contains( key ) )
00450     {
00451         paste();
00452         return;
00453     }
00454     else if ( KStdAccel::pasteSelection().contains( key ) )
00455     {
00456         QString text = QApplication::clipboard()->text( QClipboard::Selection);
00457         insert( text );
00458         deselect();
00459         return;
00460     }
00461 
00462     else if ( KStdAccel::cut().contains( key ) )
00463     {
00464         cut();
00465         return;
00466     }
00467     else if ( KStdAccel::undo().contains( key ) )
00468     {
00469         undo();
00470         return;
00471     }
00472     else if ( KStdAccel::redo().contains( key ) )
00473     {
00474         redo();
00475         return;
00476     }
00477     else if ( KStdAccel::deleteWordBack().contains( key ) )
00478     {
00479         cursorWordBackward(true);
00480         if ( hasSelectedText() )
00481             del();
00482 
00483         e->accept();
00484         return;
00485     }
00486     else if ( KStdAccel::deleteWordForward().contains( key ) )
00487     {
00488         // Workaround for QT bug where
00489         cursorWordForward(true);
00490         if ( hasSelectedText() )
00491             del();
00492 
00493         e->accept();
00494         return;
00495     }
00496     else if ( KStdAccel::backwardWord().contains( key ) )
00497     {
00498       cursorWordBackward(false);
00499       e->accept();
00500       return;
00501     }
00502     else if ( KStdAccel::forwardWord().contains( key ) )
00503     {
00504       cursorWordForward(false);
00505       e->accept();
00506       return;
00507     }
00508     else if ( KStdAccel::beginningOfLine().contains( key ) )
00509     {
00510       home(false);
00511       e->accept();
00512       return;
00513     }
00514     else if ( KStdAccel::endOfLine().contains( key ) )
00515     {
00516       end(false);
00517       e->accept();
00518       return;
00519     }
00520 
00521 
00522     // Filter key-events if EchoMode is normal and
00523     // completion mode is not set to CompletionNone
00524     if ( echoMode() == QLineEdit::Normal &&
00525          completionMode() != KGlobalSettings::CompletionNone )
00526     {
00527         KeyBindingMap keys = getKeyBindings();
00528         KGlobalSettings::Completion mode = completionMode();
00529         bool noModifier = (e->state() == NoButton ||
00530                            e->state() == ShiftButton ||
00531                            e->state() == Keypad);
00532 
00533         if ( (mode == KGlobalSettings::CompletionAuto ||
00534               mode == KGlobalSettings::CompletionPopupAuto ||
00535               mode == KGlobalSettings::CompletionMan) && noModifier )
00536         {
00537             if ( !d->userSelection && hasSelectedText() &&
00538                  ( e->key() == Key_Right || e->key() == Key_Left ) &&
00539                  e->state()==NoButton )
00540             {
00541                 QString old_txt = text();
00542                 d->disableRestoreSelection = true;
00543                 int start,end;
00544                 getSelection(&start, &end);
00545 
00546                 deselect();
00547                 QLineEdit::keyPressEvent ( e );
00548                 int cPosition=cursorPosition();
00549                 if (e->key() ==Key_Right && cPosition > start )
00550                     validateAndSet(old_txt, cPosition, cPosition, old_txt.length());
00551                 else
00552                     validateAndSet(old_txt, cPosition, start, old_txt.length());
00553 
00554                 d->disableRestoreSelection = false;
00555                 return;
00556             }
00557 
00558             if ( e->key() == Key_Escape )
00559             {
00560                 if (hasSelectedText() && !d->userSelection )
00561                 {
00562                     del();
00563                     setUserSelection(true);
00564                 }
00565 
00566                 // Don't swallow the Escape press event for the case
00567                 // of dialogs, which have Escape associated to Cancel
00568                 e->ignore();
00569                 return;
00570             }
00571 
00572         }
00573 
00574         if ( (mode == KGlobalSettings::CompletionAuto ||
00575               mode == KGlobalSettings::CompletionMan) && noModifier )
00576         {
00577             QString keycode = e->text();
00578             if ( !keycode.isEmpty() && (keycode.unicode()->isPrint() ||
00579                 e->key() == Key_Backspace || e->key() == Key_Delete ) )
00580             {
00581                 bool hasUserSelection=d->userSelection;
00582                 bool hadSelection=hasSelectedText();
00583 
00584                 bool cursorNotAtEnd=false;
00585 
00586                 int start,end;
00587                 getSelection(&start, &end);
00588                 int cPos = cursorPosition();
00589 
00590                 // When moving the cursor, we want to keep the autocompletion as an
00591                 // autocompletion, so we want to process events at the cursor position
00592                 // as if there was no selection. After processing the key event, we
00593                 // can set the new autocompletion again.
00594                 if ( hadSelection && !hasUserSelection && start>cPos )
00595                 {
00596                     del();
00597                     setCursorPosition(cPos);
00598                     cursorNotAtEnd=true;
00599                 }
00600 
00601                 d->disableRestoreSelection = true;
00602                 QLineEdit::keyPressEvent ( e );
00603                 d->disableRestoreSelection = false;
00604 
00605                 QString txt = text();
00606                 int len = txt.length();
00607                 if ( !hasSelectedText() && len /*&& cursorPosition() == len */)
00608                 {
00609                     if ( e->key() == Key_Backspace )
00610                     {
00611                         if ( hadSelection && !hasUserSelection && !cursorNotAtEnd )
00612                         {
00613                             backspace();
00614                             txt = text();
00615                             len = txt.length();
00616                         }
00617 
00618                         if ( !d->backspacePerformsCompletion || !len )
00619                             d->autoSuggest = false;
00620                     }
00621 
00622                     if (e->key() == Key_Delete )
00623                         d->autoSuggest=false;
00624 
00625                     if ( emitSignals() )
00626                         emit completion( txt );
00627 
00628                     if ( handleSignals() )
00629                         makeCompletion( txt );
00630 
00631                     if(  (e->key() == Key_Backspace || e->key() == Key_Delete) )
00632                         d->autoSuggest=true;
00633 
00634                     e->accept();
00635                 }
00636 
00637                 return;
00638             }
00639 
00640         }
00641 
00642         else if (( mode == KGlobalSettings::CompletionPopup ||
00643                    mode == KGlobalSettings::CompletionPopupAuto ) &&
00644                    noModifier && !e->text().isEmpty() )
00645         {
00646             QString old_txt = text();
00647             bool hasUserSelection=d->userSelection;
00648             bool hadSelection=hasSelectedText();
00649             bool cursorNotAtEnd=false;
00650 
00651             int start,end;
00652             getSelection(&start, &end);
00653             int cPos = cursorPosition();
00654             QString keycode = e->text();
00655 
00656             // When moving the cursor, we want to keep the autocompletion as an
00657             // autocompletion, so we want to process events at the cursor position
00658             // as if there was no selection. After processing the key event, we
00659             // can set the new autocompletion again.
00660             if (hadSelection && !hasUserSelection && start>cPos &&
00661                ( (!keycode.isEmpty() && keycode.unicode()->isPrint()) ||
00662                  e->key() == Key_Backspace || e->key() == Key_Delete ) )
00663             {
00664                 del();
00665                 setCursorPosition(cPos);
00666                 cursorNotAtEnd=true;
00667             }
00668 
00669             uint selectedLength=selectedText().length();
00670 
00671             d->disableRestoreSelection = true;
00672             QLineEdit::keyPressEvent ( e );
00673             d->disableRestoreSelection = false;
00674 
00675             if (( selectedLength != selectedText().length() ) && !hasUserSelection )
00676                 slotRestoreSelectionColors(); // and set userSelection to true
00677 
00678             QString txt = text();
00679             int len = txt.length();
00680 
00681             if ( txt != old_txt && len/* && ( cursorPosition() == len || force )*/ &&
00682                  ( (!keycode.isEmpty() && keycode.unicode()->isPrint()) ||
00683                    e->key() == Key_Backspace || e->key() == Key_Delete) )
00684             {
00685                 if ( e->key() == Key_Backspace )
00686                 {
00687                     if ( hadSelection && !hasUserSelection && !cursorNotAtEnd )
00688                     {
00689                         backspace();
00690                         txt = text();
00691                         len = txt.length();
00692                     }
00693 
00694                     if ( !d->backspacePerformsCompletion )
00695                         d->autoSuggest = false;
00696                 }
00697 
00698                 if (e->key() == Key_Delete )
00699                     d->autoSuggest=false;
00700 
00701                 if ( d->completionBox )
00702                   d->completionBox->setCancelledText( txt );
00703     
00704                 if ( emitSignals() )
00705                   emit completion( txt ); // emit when requested...
00706 
00707                 if ( handleSignals() ) {
00708                   makeCompletion( txt );  // handle when requested...
00709                 }
00710 
00711                 if ( (e->key() == Key_Backspace || e->key() == Key_Delete ) &&
00712                     mode == KGlobalSettings::CompletionPopupAuto )
00713                   d->autoSuggest=true;
00714 
00715                 e->accept();
00716             }
00717             else if (!len && d->completionBox && d->completionBox->isVisible())
00718                 d->completionBox->hide();
00719 
00720             return;
00721         }
00722 
00723         else if ( mode == KGlobalSettings::CompletionShell )
00724         {
00725             // Handles completion.
00726             KShortcut cut;
00727             if ( keys[TextCompletion].isNull() )
00728                 cut = KStdAccel::shortcut(KStdAccel::TextCompletion);
00729             else
00730                 cut = keys[TextCompletion];
00731 
00732             if ( cut.contains( key ) )
00733             {
00734                 // Emit completion if the completion mode is CompletionShell
00735                 // and the cursor is at the end of the string.
00736                 QString txt = text();
00737                 int len = txt.length();
00738                 if ( cursorPosition() == len && len != 0 )
00739                 {
00740                     if ( emitSignals() )
00741                         emit completion( txt );
00742                     if ( handleSignals() )
00743                         makeCompletion( txt );
00744                     return;
00745                 }
00746             }
00747             else if ( d->completionBox )
00748                 d->completionBox->hide();
00749         }
00750 
00751         // handle rotation
00752         if ( mode != KGlobalSettings::CompletionNone )
00753         {
00754             // Handles previous match
00755             KShortcut cut;
00756             if ( keys[PrevCompletionMatch].isNull() )
00757                 cut = KStdAccel::shortcut(KStdAccel::PrevCompletion);
00758             else
00759                 cut = keys[PrevCompletionMatch];
00760 
00761             if ( cut.contains( key ) )
00762             {
00763                 if ( emitSignals() )
00764                     emit textRotation( KCompletionBase::PrevCompletionMatch );
00765                 if ( handleSignals() )
00766                     rotateText( KCompletionBase::PrevCompletionMatch );
00767                 return;
00768             }
00769 
00770             // Handles next match
00771             if ( keys[NextCompletionMatch].isNull() )
00772                 cut = KStdAccel::shortcut(KStdAccel::NextCompletion);
00773             else
00774                 cut = keys[NextCompletionMatch];
00775 
00776             if ( cut.contains( key ) )
00777             {
00778                 if ( emitSignals() )
00779                     emit textRotation( KCompletionBase::NextCompletionMatch );
00780                 if ( handleSignals() )
00781                     rotateText( KCompletionBase::NextCompletionMatch );
00782                 return;
00783             }
00784         }
00785 
00786         // substring completion
00787         if ( compObj() )
00788         {
00789             KShortcut cut;
00790             if ( keys[SubstringCompletion].isNull() )
00791                 cut = KStdAccel::shortcut(KStdAccel::SubstringCompletion);
00792             else
00793                 cut = keys[SubstringCompletion];
00794 
00795             if ( cut.contains( key ) )
00796             {
00797                 if ( emitSignals() )
00798                     emit substringCompletion( text() );
00799                 if ( handleSignals() )
00800                 {
00801                     setCompletedItems( compObj()->substringCompletion(text()));
00802                     e->accept();
00803                 }
00804                 return;
00805             }
00806         }
00807     }
00808 
00809     uint selectedLength = selectedText().length();
00810 
00811     // Let QLineEdit handle any other keys events.
00812     QLineEdit::keyPressEvent ( e );
00813 
00814     if ( selectedLength != selectedText().length() )
00815         slotRestoreSelectionColors(); // and set userSelection to true
00816 }
00817 
00818 void KLineEdit::mouseDoubleClickEvent( QMouseEvent* e )
00819 {
00820     if ( e->button() == Qt::LeftButton  )
00821     {
00822         possibleTripleClick=true;
00823         QTimer::singleShot( QApplication::doubleClickInterval(),this,
00824                             SLOT(tripleClickTimeout()) );
00825     }
00826     QLineEdit::mouseDoubleClickEvent( e );
00827 }
00828 
00829 void KLineEdit::mousePressEvent( QMouseEvent* e )
00830 {
00831     if ( possibleTripleClick && e->button() == Qt::LeftButton )
00832     {
00833         selectAll();
00834         e->accept();
00835         return;
00836     }
00837     QLineEdit::mousePressEvent( e );
00838 }
00839 
00840 void KLineEdit::mouseReleaseEvent( QMouseEvent* e )
00841 {
00842     QLineEdit::mouseReleaseEvent( e );
00843     if (QApplication::clipboard()->supportsSelection() ) {
00844         if ( e->button() == LeftButton ) {
00845             // Fix copying of squeezed text if needed
00846             copySqueezedText( false );
00847         }
00848     }
00849 }
00850 
00851 void KLineEdit::tripleClickTimeout()
00852 {
00853     possibleTripleClick=false;
00854 }
00855 
00856 void KLineEdit::contextMenuEvent( QContextMenuEvent * e )
00857 {
00858     if ( m_bEnableMenu )
00859         QLineEdit::contextMenuEvent( e );
00860 }
00861 
00862 QPopupMenu *KLineEdit::createPopupMenu()
00863 {
00864     enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll };
00865 
00866     QPopupMenu *popup = QLineEdit::createPopupMenu();
00867 
00868       int id = popup->idAt(0);
00869       popup->changeItem( id - IdUndo, SmallIconSet("undo"), popup->text( id - IdUndo) );
00870       popup->changeItem( id - IdRedo, SmallIconSet("redo"), popup->text( id - IdRedo) );
00871       popup->changeItem( id - IdCut, SmallIconSet("editcut"), popup->text( id - IdCut) );
00872       popup->changeItem( id - IdCopy, SmallIconSet("editcopy"), popup->text( id - IdCopy) );
00873       popup->changeItem( id - IdPaste, SmallIconSet("editpaste"), popup->text( id - IdPaste) );
00874       popup->changeItem( id - IdClear, SmallIconSet("editclear"), popup->text( id - IdClear) );
00875 
00876     // If a completion object is present and the input
00877     // widget is not read-only, show the Text Completion
00878     // menu item.
00879     if ( compObj() && !isReadOnly() && kapp->authorize("lineedit_text_completion") )
00880     {
00881         QPopupMenu *subMenu = new QPopupMenu( popup );
00882         connect( subMenu, SIGNAL( activated( int ) ),
00883                  this, SLOT( completionMenuActivated( int ) ) );
00884 
00885         popup->insertSeparator();
00886         popup->insertItem( SmallIconSet("completion"), i18n("Text Completion"),
00887                            subMenu );
00888 
00889         subMenu->insertItem( i18n("None"), NoCompletion );
00890         subMenu->insertItem( i18n("Manual"), ShellCompletion );
00891         subMenu->insertItem( i18n("Automatic"), AutoCompletion );
00892         subMenu->insertItem( i18n("Dropdown List"), PopupCompletion );
00893         subMenu->insertItem( i18n("Short Automatic"), ShortAutoCompletion );
00894         subMenu->insertItem( i18n("Dropdown List && Automatic"), PopupAutoCompletion );
00895 
00896         subMenu->setAccel( KStdAccel::completion(), ShellCompletion );
00897 
00898         KGlobalSettings::Completion mode = completionMode();
00899         subMenu->setItemChecked( NoCompletion,
00900                                  mode == KGlobalSettings::CompletionNone );
00901         subMenu->setItemChecked( ShellCompletion,
00902                                  mode == KGlobalSettings::CompletionShell );
00903         subMenu->setItemChecked( PopupCompletion,
00904                                  mode == KGlobalSettings::CompletionPopup );
00905         subMenu->setItemChecked( AutoCompletion,
00906                                  mode == KGlobalSettings::CompletionAuto );
00907         subMenu->setItemChecked( ShortAutoCompletion,
00908                                  mode == KGlobalSettings::CompletionMan );
00909         subMenu->setItemChecked( PopupAutoCompletion,
00910                                  mode == KGlobalSettings::CompletionPopupAuto );
00911         if ( mode != KGlobalSettings::completionMode() )
00912         {
00913             subMenu->insertSeparator();
00914             subMenu->insertItem( i18n("Default"), Default );
00915         }
00916     }
00917 
00918     // ### do we really need this?  Yes, Please do not remove!  This
00919     // allows applications to extend the popup menu without having to
00920     // inherit from this class! (DA)
00921     emit aboutToShowContextMenu( popup );
00922 
00923     return popup;
00924 }
00925 
00926 void KLineEdit::completionMenuActivated( int id )
00927 {
00928     KGlobalSettings::Completion oldMode = completionMode();
00929 
00930     switch ( id )
00931     {
00932         case Default:
00933            setCompletionMode( KGlobalSettings::completionMode() );
00934            break;
00935         case NoCompletion:
00936            setCompletionMode( KGlobalSettings::CompletionNone );
00937            break;
00938         case AutoCompletion:
00939             setCompletionMode( KGlobalSettings::CompletionAuto );
00940             break;
00941         case ShortAutoCompletion:
00942             setCompletionMode( KGlobalSettings::CompletionMan );
00943             break;
00944         case ShellCompletion:
00945             setCompletionMode( KGlobalSettings::CompletionShell );
00946             break;
00947         case PopupCompletion:
00948             setCompletionMode( KGlobalSettings::CompletionPopup );
00949             break;
00950         case PopupAutoCompletion:
00951             setCompletionMode( KGlobalSettings::CompletionPopupAuto );
00952             break;
00953         default:
00954             return;
00955     }
00956 
00957     if ( oldMode != completionMode() )
00958     {
00959         if ( (oldMode == KGlobalSettings::CompletionPopup ||
00960               oldMode == KGlobalSettings::CompletionPopupAuto ) &&
00961               d->completionBox && d->completionBox->isVisible() )
00962             d->completionBox->hide();
00963         emit completionModeChanged( completionMode() );
00964     }
00965 }
00966 
00967 void KLineEdit::drawContents( QPainter *p )
00968 {
00969     QLineEdit::drawContents( p );
00970 
00971     if ( d->drawClickMsg && !hasFocus() ) {
00972         QPen tmp = p->pen();
00973         p->setPen( palette().color( QPalette::Disabled, QColorGroup::Text ) );
00974         QRect cr = contentsRect();
00975 
00976         // Add two pixel margin on the left side
00977         cr.rLeft() += 3;
00978         p->drawText( cr, AlignAuto | AlignVCenter, d->clickMessage );
00979         p->setPen( tmp );
00980     }
00981 }
00982 
00983 void KLineEdit::dropEvent(QDropEvent *e)
00984 {
00985     d->drawClickMsg = false;
00986     KURL::List urlList;
00987     if( d->handleURLDrops && KURLDrag::decode( e, urlList ) )
00988     {
00989         QString dropText = text();
00990         KURL::List::ConstIterator it;
00991         for( it = urlList.begin() ; it != urlList.end() ; ++it )
00992         {
00993             if(!dropText.isEmpty())
00994                 dropText+=' ';
00995 
00996             dropText += (*it).prettyURL();
00997         }
00998 
00999         validateAndSet( dropText, dropText.length(), 0, 0);
01000 
01001         e->accept();
01002     }
01003     else
01004         QLineEdit::dropEvent(e);
01005 }
01006 
01007 bool KLineEdit::eventFilter( QObject* o, QEvent* ev )
01008 {
01009     if( o == this )
01010     {
01011         KCursor::autoHideEventFilter( this, ev );
01012         if ( ev->type() == QEvent::AccelOverride )
01013         {
01014             QKeyEvent *e = static_cast<QKeyEvent *>( ev );
01015             if (overrideAccel (e))
01016             {
01017                 e->accept();
01018                 return true;
01019             }
01020         }
01021         else if( ev->type() == QEvent::KeyPress )
01022         {
01023             QKeyEvent *e = static_cast<QKeyEvent *>( ev );
01024 
01025             if( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter )
01026             {
01027                 bool trap = d->completionBox && d->completionBox->isVisible();
01028 
01029                 bool stopEvent = trap || (d->grabReturnKeyEvents &&
01030                                           (e->state() == NoButton ||
01031                                            e->state() == Keypad));
01032 
01033                 // Qt will emit returnPressed() itself if we return false
01034                 if ( stopEvent )
01035                 {
01036                   emit QLineEdit::returnPressed();
01037                   e->accept ();
01038                 }
01039 
01040                 emit returnPressed( displayText() );
01041 
01042                 if ( trap )
01043                 {
01044                     d->completionBox->hide();
01045                     deselect();
01046                     setCursorPosition(text().length());
01047                 }
01048 
01049                 // Eat the event if the user asked for it, or if a completionbox was visible
01050                 return stopEvent;
01051             }
01052         }
01053     }
01054     return QLineEdit::eventFilter( o, ev );
01055 }
01056 
01057 
01058 void KLineEdit::setURLDropsEnabled(bool enable)
01059 {
01060     d->handleURLDrops=enable;
01061 }
01062 
01063 bool KLineEdit::isURLDropsEnabled() const
01064 {
01065     return d->handleURLDrops;
01066 }
01067 
01068 void KLineEdit::setTrapReturnKey( bool grab )
01069 {
01070     d->grabReturnKeyEvents = grab;
01071 }
01072 
01073 bool KLineEdit::trapReturnKey() const
01074 {
01075     return d->grabReturnKeyEvents;
01076 }
01077 
01078 void KLineEdit::setURL( const KURL& url )
01079 {
01080     setText( url.prettyURL() );
01081 }
01082 
01083 void KLineEdit::setCompletionBox( KCompletionBox *box )
01084 {
01085     if ( d->completionBox )
01086         return;
01087 
01088     d->completionBox = box;
01089     if ( handleSignals() )
01090     {
01091         connect( d->completionBox, SIGNAL(highlighted( const QString& )),
01092                  SLOT(setTextWorkaround( const QString& )) );
01093         connect( d->completionBox, SIGNAL(userCancelled( const QString& )),
01094                  SLOT(userCancelled( const QString& )) );
01095 
01096         // TODO: we need our own slot, and to call setModified(true) if Qt4 has that.
01097         connect( d->completionBox, SIGNAL( activated( const QString& )),
01098                  SIGNAL(completionBoxActivated( const QString& )) );
01099     }
01100 }
01101 
01102 void KLineEdit::userCancelled(const QString & cancelText)
01103 {
01104     if ( completionMode() != KGlobalSettings::CompletionPopupAuto )
01105     {
01106       // TODO: this sets modified==false. But maybe it was true before...
01107       setText(cancelText);
01108     }
01109     else if (hasSelectedText() )
01110     {
01111       if (d->userSelection)
01112         deselect();
01113       else
01114       {
01115         d->autoSuggest=false;
01116         int start,end;
01117         getSelection(&start, &end);
01118         QString s=text().remove(start, end-start+1);
01119         validateAndSet(s,start,s.length(),s.length());
01120         d->autoSuggest=true;
01121       }
01122     }
01123 }
01124 
01125 bool KLineEdit::overrideAccel (const QKeyEvent* e)
01126 {
01127     KShortcut scKey;
01128 
01129     KKey key( e );
01130     KeyBindingMap keys = getKeyBindings();
01131 
01132     if (keys[TextCompletion].isNull())
01133         scKey = KStdAccel::shortcut(KStdAccel::TextCompletion);
01134     else
01135         scKey = keys[TextCompletion];
01136 
01137     if (scKey.contains( key ))
01138         return true;
01139 
01140     if (keys[NextCompletionMatch].isNull())
01141         scKey = KStdAccel::shortcut(KStdAccel::NextCompletion);
01142     else
01143         scKey = keys[NextCompletionMatch];
01144 
01145     if (scKey.contains( key ))
01146         return true;
01147 
01148     if (keys[PrevCompletionMatch].isNull())
01149         scKey = KStdAccel::shortcut(KStdAccel::PrevCompletion);
01150     else
01151         scKey = keys[PrevCompletionMatch];
01152 
01153     if (scKey.contains( key ))
01154         return true;
01155 
01156     // Override all the text manupilation accelerators...
01157     if ( KStdAccel::copy().contains( key ) )
01158         return true;
01159     else if ( KStdAccel::paste().contains( key ) )
01160         return true;
01161     else if ( KStdAccel::cut().contains( key ) )
01162         return true;
01163     else if ( KStdAccel::undo().contains( key ) )
01164         return true;
01165     else if ( KStdAccel::redo().contains( key ) )
01166         return true;
01167     else if (KStdAccel::deleteWordBack().contains( key ))
01168         return true;
01169     else if (KStdAccel::deleteWordForward().contains( key ))
01170         return true;
01171     else if (KStdAccel::forwardWord().contains( key ))
01172         return true;
01173     else if (KStdAccel::backwardWord().contains( key ))
01174         return true;
01175     else if (KStdAccel::beginningOfLine().contains( key ))
01176         return true;
01177     else if (KStdAccel::endOfLine().contains( key ))
01178         return true;
01179 
01180     if (d->completionBox && d->completionBox->isVisible ())
01181     {
01182         int key = e->key();
01183         ButtonState state = e->state();
01184         if ((key == Key_Backtab || key == Key_Tab) &&
01185             (state == NoButton || (state & ShiftButton)))
01186         {
01187             return true;
01188         }
01189     }
01190 
01191 
01192     return false;
01193 }
01194 
01195 void KLineEdit::setCompletedItems( const QStringList& items )
01196 {
01197     setCompletedItems( items, true );
01198 }
01199 
01200 void KLineEdit::setCompletedItems( const QStringList& items, bool autoSuggest )
01201 {
01202     QString txt;
01203     if ( d->completionBox && d->completionBox->isVisible() ) {
01204         // The popup is visible already - do the matching on the initial string,
01205         // not on the currently selected one.
01206         txt = completionBox()->cancelledText();
01207     } else {
01208         txt = text();
01209     }
01210 
01211     if ( !items.isEmpty() &&
01212          !(items.count() == 1 && txt == items.first()) )
01213     {
01214         // create completion box if non-existent
01215         completionBox();
01216 
01217         if ( d->completionBox->isVisible() )
01218         {
01219             bool wasSelected = d->completionBox->isSelected( d->completionBox->currentItem() );
01220             const QString currentSelection = d->completionBox->currentText();
01221             d->completionBox->setItems( items );
01222             QListBoxItem* item = d->completionBox->findItem( currentSelection, Qt::ExactMatch );
01223             // If no item is selected, that means the listbox hasn't been manipulated by the user yet,
01224             // because it's not possible otherwise to have no selected item. In such case make
01225             // always the first item current and unselected, so that the current item doesn't jump.
01226             if( !item || !wasSelected )
01227             {
01228                 wasSelected = false;
01229                 item = d->completionBox->item( 0 );
01230             }
01231             if ( item )
01232             {
01233                 d->completionBox->blockSignals( true );
01234                 d->completionBox->setCurrentItem( item );
01235                 d->completionBox->setSelected( item, wasSelected );
01236                 d->completionBox->blockSignals( false );
01237             }
01238         }
01239         else // completion box not visible yet -> show it
01240         {
01241             if ( !txt.isEmpty() )
01242                 d->completionBox->setCancelledText( txt );
01243             d->completionBox->setItems( items );
01244             d->completionBox->popup();
01245         }
01246 
01247         if ( d->autoSuggest && autoSuggest )
01248         {
01249             int index = items.first().find( txt );
01250             QString newText = items.first().mid( index );
01251             setUserSelection(false);
01252             setCompletedText(newText,true);
01253         }
01254     }
01255     else
01256     {
01257         if ( d->completionBox && d->completionBox->isVisible() )
01258             d->completionBox->hide();
01259     }
01260 }
01261 
01262 KCompletionBox * KLineEdit::completionBox( bool create )
01263 {
01264     if ( create && !d->completionBox ) {
01265         setCompletionBox( new KCompletionBox( this, "completion box" ) );
01266         d->completionBox->setFont(font());
01267     }
01268 
01269     return d->completionBox;
01270 }
01271 
01272 void KLineEdit::setCompletionObject( KCompletion* comp, bool hsig )
01273 {
01274     KCompletion *oldComp = compObj();
01275     if ( oldComp && handleSignals() )
01276         disconnect( oldComp, SIGNAL( matches( const QStringList& )),
01277                     this, SLOT( setCompletedItems( const QStringList& )));
01278 
01279     if ( comp && hsig )
01280       connect( comp, SIGNAL( matches( const QStringList& )),
01281                this, SLOT( setCompletedItems( const QStringList& )));
01282 
01283     KCompletionBase::setCompletionObject( comp, hsig );
01284 }
01285 
01286 // QWidget::create() turns off mouse-Tracking which would break auto-hiding
01287 void KLineEdit::create( WId id, bool initializeWindow, bool destroyOldWindow )
01288 {
01289     QLineEdit::create( id, initializeWindow, destroyOldWindow );
01290     KCursor::setAutoHideCursor( this, true, true );
01291 }
01292 
01293 void KLineEdit::setUserSelection(bool userSelection)
01294 {
01295     QPalette p = palette();
01296 
01297     if (userSelection)
01298     {
01299         p.setColor(QColorGroup::Highlight, d->previousHighlightColor);
01300         p.setColor(QColorGroup::HighlightedText, d->previousHighlightedTextColor);
01301     }
01302     else
01303     {
01304         QColor color=p.color(QPalette::Disabled, QColorGroup::Text);
01305         p.setColor(QColorGroup::HighlightedText, color);
01306         color=p.color(QPalette::Active, QColorGroup::Base);
01307         p.setColor(QColorGroup::Highlight, color);
01308     }
01309 
01310     d->userSelection=userSelection;
01311     setPalette(p);
01312 }
01313 
01314 void KLineEdit::slotRestoreSelectionColors()
01315 {
01316     if (d->disableRestoreSelection)
01317       return;
01318 
01319     setUserSelection(true);
01320 }
01321 
01322 void KLineEdit::clear()
01323 {
01324     setText( QString::null );
01325 }
01326 
01327 void KLineEdit::setTextWorkaround( const QString& text )
01328 {
01329     setText( text );
01330     end( false ); // force cursor at end
01331 }
01332 
01333 QString KLineEdit::originalText() const
01334 {
01335     if ( d->enableSqueezedText && isReadOnly() )
01336         return d->squeezedText;
01337 
01338     return text();
01339 }
01340 
01341 void KLineEdit::focusInEvent( QFocusEvent* ev)
01342 {
01343     if ( d->drawClickMsg ) {
01344         d->drawClickMsg = false;
01345         update();
01346     }
01347 
01348     // Don't selectAll() in QLineEdit::focusInEvent if selection exists
01349     if ( ev->reason() == QFocusEvent::Tab && inputMask().isNull() && hasSelectedText() )
01350         return;
01351     
01352     QLineEdit::focusInEvent(ev);
01353 }
01354 
01355 void KLineEdit::focusOutEvent( QFocusEvent* ev)
01356 {
01357     if ( text().isEmpty() && !d->clickMessage.isEmpty() ) {
01358         d->drawClickMsg = true;
01359         update();
01360     }
01361     QLineEdit::focusOutEvent( ev );
01362 }
01363 
01364 bool KLineEdit::autoSuggest() const
01365 {
01366     return d->autoSuggest;
01367 }
01368 
01369 void KLineEdit::setClickMessage( const QString &msg )
01370 {
01371     d->clickMessage = msg;
01372     update();
01373 }
01374 
01375 QString KLineEdit::clickMessage() const
01376 {
01377     return d->clickMessage;
01378 }
01379 
01380 
01381 void KLineEdit::virtual_hook( int id, void* data )
01382 { KCompletionBase::virtual_hook( id, data ); }

kdeui

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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