kdeui Library API Documentation

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         d->completionBox->setFont(font());
01223     }
01224 
01225     return d->completionBox;
01226 }
01227 
01228 void KLineEdit::setCompletionObject( KCompletion* comp, bool hsig )
01229 {
01230     KCompletion *oldComp = compObj();
01231     if ( oldComp && handleSignals() )
01232         disconnect( oldComp, SIGNAL( matches( const QStringList& )),
01233                     this, SLOT( setCompletedItems( const QStringList& )));
01234 
01235     if ( comp && hsig )
01236       connect( comp, SIGNAL( matches( const QStringList& )),
01237                this, SLOT( setCompletedItems( const QStringList& )));
01238 
01239     KCompletionBase::setCompletionObject( comp, hsig );
01240 }
01241 
01242 // QWidget::create() turns off mouse-Tracking which would break auto-hiding
01243 void KLineEdit::create( WId id, bool initializeWindow, bool destroyOldWindow )
01244 {
01245     QLineEdit::create( id, initializeWindow, destroyOldWindow );
01246     KCursor::setAutoHideCursor( this, true, true );
01247 }
01248 
01249 void KLineEdit::setUserSelection(bool userSelection)
01250 {
01251     QPalette p = palette();
01252 
01253     if (userSelection)
01254     {
01255         p.setColor(QColorGroup::Highlight, d->previousHighlightColor);
01256         p.setColor(QColorGroup::HighlightedText, d->previousHighlightedTextColor);
01257     }
01258     else
01259     {
01260         QColor color=p.color(QPalette::Disabled, QColorGroup::Text);
01261         p.setColor(QColorGroup::HighlightedText, color);
01262         color=p.color(QPalette::Active, QColorGroup::Base);
01263         p.setColor(QColorGroup::Highlight, color);
01264     }
01265 
01266     d->userSelection=userSelection;
01267     setPalette(p);
01268 }
01269 
01270 void KLineEdit::slotRestoreSelectionColors()
01271 {
01272     if (d->disableRestoreSelection)
01273       return;
01274 
01275     setUserSelection(true);
01276 }
01277 
01278 void KLineEdit::clear()
01279 {
01280     setText( QString::null );
01281 }
01282 
01283 void KLineEdit::setTextWorkaround( const QString& text )
01284 {
01285     setText( text );
01286     end( false ); // force cursor at end
01287 }
01288 
01289 QString KLineEdit::originalText() const
01290 {
01291     if ( d->enableSqueezedText && isReadOnly() )
01292         return d->squeezedText;
01293 
01294     return text();
01295 }
01296 
01297 void KLineEdit::focusInEvent( QFocusEvent* ev)
01298 {
01299     // Don't selectAll() in QLineEdit::focusInEvent if selection exists
01300     if ( ev->reason() == QFocusEvent::Tab && inputMask().isNull() && hasSelectedText() )
01301         return;
01302     
01303     QLineEdit::focusInEvent(ev);
01304 }
01305 
01306 bool KLineEdit::autoSuggest() const
01307 {
01308     return d->autoSuggest;
01309 }
01310 
01311 void KLineEdit::virtual_hook( int id, void* data )
01312 { KCompletionBase::virtual_hook( id, data ); }
KDE Logo
This file is part of the documentation for kdeui Library Version 3.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Sep 16 06:49:57 2005 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003