# kdeui Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# klineedit.cpp

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

This file is part of the documentation for kdeui Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:20:18 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003