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 
00441     // support for pasting Selection with Shift-Ctrl-Insert
00442     else if ( e->key() == Key_Insert &&
00443               (e->state() == (ShiftButton | ControlButton)) )
00444     {
00445 #if QT_VERSION >= 0x030100
00446         QString text = QApplication::clipboard()->text( QClipboard::Selection);
00447 #else
00448         QClipboard *clip = QApplication::clipboard();
00449         bool oldMode = clip->selectionModeEnabled();
00450         clip->setSelectionMode( true );
00451         QString text = QApplication::clipboard()->text();
00452         clip->setSelectionMode( oldMode );
00453 #endif
00454 
00455         insert( text );
00456         deselect();
00457         return;
00458     }
00459 
00460     else if ( KStdAccel::cut().contains( key ) )
00461     {
00462         cut();
00463         return;
00464     }
00465     else if ( KStdAccel::undo().contains( key ) )
00466     {
00467         undo();
00468         return;
00469     }
00470     else if ( KStdAccel::redo().contains( key ) )
00471     {
00472         redo();
00473         return;
00474     }
00475     else if ( KStdAccel::deleteWordBack().contains( key ) )
00476     {
00477         cursorWordBackward(true);
00478         if ( hasSelectedText() )
00479             del();
00480 
00481         e->accept();
00482         return;
00483     }
00484     else if ( KStdAccel::deleteWordForward().contains( key ) )
00485     {
00486         // Workaround for QT bug where
00487         cursorWordForward(true);
00488         if ( hasSelectedText() )
00489             del();
00490 
00491         e->accept();
00492         return;
00493     }
00494     else if ( KStdAccel::backwardWord().contains( key ) )
00495     {
00496       cursorWordBackward(false);
00497       e->accept();
00498       return;
00499     }
00500     else if ( KStdAccel::forwardWord().contains( key ) )
00501     {
00502       cursorWordForward(false);
00503       e->accept();
00504       return;
00505     }
00506     else if ( KStdAccel::beginningOfLine().contains( key ) )
00507     {
00508       home(false);
00509       e->accept();
00510       return;
00511     }
00512     else if ( KStdAccel::endOfLine().contains( key ) )
00513     {
00514       end(false);
00515       e->accept();
00516       return;
00517     }
00518 
00519 
00520     // Filter key-events if EchoMode is normal and
00521     // completion mode is not set to CompletionNone
00522     if ( echoMode() == QLineEdit::Normal &&
00523          completionMode() != KGlobalSettings::CompletionNone )
00524     {
00525         KeyBindingMap keys = getKeyBindings();
00526         KGlobalSettings::Completion mode = completionMode();
00527         bool noModifier = (e->state() == NoButton ||
00528                            e->state() == ShiftButton ||
00529                            e->state() == Keypad);
00530 
00531         if ( (mode == KGlobalSettings::CompletionAuto ||
00532               mode == KGlobalSettings::CompletionPopupAuto ||
00533               mode == KGlobalSettings::CompletionMan) && noModifier )
00534         {
00535             if ( !d->userSelection && hasSelectedText() &&
00536                  ( e->key() == Key_Right || e->key() == Key_Left ) &&
00537                  e->state()==NoButton )
00538             {
00539                 QString old_txt = text();
00540                 d->disableRestoreSelection = true;
00541                 int start,end;
00542                 getSelection(&start, &end);
00543 
00544                 deselect();
00545                 QLineEdit::keyPressEvent ( e );
00546                 int cPosition=cursorPosition();
00547                 if (e->key() ==Key_Right && cPosition > start )
00548                     validateAndSet(old_txt, cPosition, cPosition, old_txt.length());
00549                 else
00550                     validateAndSet(old_txt, cPosition, start, old_txt.length());
00551 
00552                 d->disableRestoreSelection = false;
00553                 return;
00554             }
00555 
00556             if ( e->key() == Key_Escape )
00557             {
00558                 if (hasSelectedText() && !d->userSelection )
00559                 {
00560                     del();
00561                     setUserSelection(true);
00562                 }
00563 
00564                 // Don't swallow the Escape press event for the case
00565                 // of dialogs, which have Escape associated to Cancel
00566                 e->ignore();
00567                 return;
00568             }
00569 
00570         }
00571 
00572         if ( (mode == KGlobalSettings::CompletionAuto ||
00573               mode == KGlobalSettings::CompletionMan) && noModifier )
00574         {
00575             QString keycode = e->text();
00576             if ( !keycode.isEmpty() && (keycode.unicode()->isPrint() ||
00577                 e->key() == Key_Backspace || e->key() == Key_Delete ) )
00578             {
00579                 bool hasUserSelection=d->userSelection;
00580                 bool hadSelection=hasSelectedText();
00581 
00582                 bool cursorNotAtEnd=false;
00583 
00584                 int start,end;
00585                 getSelection(&start, &end);
00586                 int cPos = cursorPosition();
00587 
00588                 // When moving the cursor, we want to keep the autocompletion as an
00589                 // autocompletion, so we want to process events at the cursor position
00590                 // as if there was no selection. After processing the key event, we
00591                 // can set the new autocompletion again.
00592                 if ( hadSelection && !hasUserSelection && start>cPos )
00593                 {
00594                     del();
00595                     setCursorPosition(cPos);
00596                     cursorNotAtEnd=true;
00597                 }
00598 
00599                 d->disableRestoreSelection = true;
00600                 QLineEdit::keyPressEvent ( e );
00601                 d->disableRestoreSelection = false;
00602 
00603                 QString txt = text();
00604                 int len = txt.length();
00605                 if ( !hasSelectedText() && len /*&& cursorPosition() == len */)
00606                 {
00607                     if ( e->key() == Key_Backspace )
00608                     {
00609                         if ( hadSelection && !hasUserSelection && !cursorNotAtEnd )
00610                         {
00611                             backspace();
00612                             txt = text();
00613                             len = txt.length();
00614                         }
00615 
00616                         if ( !d->backspacePerformsCompletion || !len )
00617                             d->autoSuggest = false;
00618                     }
00619 
00620                     if (e->key() == Key_Delete )
00621                         d->autoSuggest=false;
00622 
00623                     if ( emitSignals() )
00624                         emit completion( txt );
00625 
00626                     if ( handleSignals() )
00627                         makeCompletion( txt );
00628 
00629                     if(  (e->key() == Key_Backspace || e->key() == Key_Delete) )
00630                         d->autoSuggest=true;
00631 
00632                     e->accept();
00633                 }
00634 
00635                 return;
00636             }
00637 
00638         }
00639 
00640         else if (( mode == KGlobalSettings::CompletionPopup ||
00641                    mode == KGlobalSettings::CompletionPopupAuto ) &&
00642                    noModifier && !e->text().isEmpty() )
00643         {
00644             QString old_txt = text();
00645             bool hasUserSelection=d->userSelection;
00646             bool hadSelection=hasSelectedText();
00647             bool cursorNotAtEnd=false;
00648 
00649             int start,end;
00650             getSelection(&start, &end);
00651             int cPos = cursorPosition();
00652             QString keycode = e->text();
00653 
00654             // When moving the cursor, we want to keep the autocompletion as an
00655             // autocompletion, so we want to process events at the cursor position
00656             // as if there was no selection. After processing the key event, we
00657             // can set the new autocompletion again.
00658             if (hadSelection && !hasUserSelection && start>cPos &&
00659                ( (!keycode.isEmpty() && keycode.unicode()->isPrint()) ||
00660                  e->key() == Key_Backspace || e->key() == Key_Delete ) )
00661             {
00662                 del();
00663                 setCursorPosition(cPos);
00664                 cursorNotAtEnd=true;
00665             }
00666 
00667             uint selectedLength=selectedText().length();
00668 
00669             d->disableRestoreSelection = true;
00670             QLineEdit::keyPressEvent ( e );
00671             d->disableRestoreSelection = false;
00672 
00673             if (( selectedLength != selectedText().length() ) && !hasUserSelection )
00674                 slotRestoreSelectionColors(); // and set userSelection to true
00675 
00676             QString txt = text();
00677             int len = txt.length();
00678 
00679             if ( txt != old_txt && len/* && ( cursorPosition() == len || force )*/ &&
00680                  ( (!keycode.isEmpty() && keycode.unicode()->isPrint()) ||
00681                    e->key() == Key_Backspace || e->key() == Key_Delete) )
00682             {
00683                 if ( e->key() == Key_Backspace )
00684                 {
00685                     if ( hadSelection && !hasUserSelection && !cursorNotAtEnd )
00686                     {
00687                         backspace();
00688                         txt = text();
00689                         len = txt.length();
00690                     }
00691 
00692                     if ( !d->backspacePerformsCompletion )
00693                         d->autoSuggest = false;
00694                 }
00695 
00696                 if (e->key() == Key_Delete )
00697                     d->autoSuggest=false;
00698 
00699                 if ( emitSignals() )
00700                   emit completion( txt ); // emit when requested...
00701 
00702                 if ( handleSignals() )
00703                   makeCompletion( txt );  // handle when requested...
00704 
00705                 if ( (e->key() == Key_Backspace || e->key() == Key_Delete ) &&
00706                     mode == KGlobalSettings::CompletionPopupAuto )
00707                   d->autoSuggest=true;
00708 
00709                 e->accept();
00710             }
00711             else if (!len && d->completionBox && d->completionBox->isVisible())
00712                 d->completionBox->hide();
00713 
00714             return;
00715         }
00716 
00717         else if ( mode == KGlobalSettings::CompletionShell )
00718         {
00719             // Handles completion.
00720             KShortcut cut;
00721             if ( keys[TextCompletion].isNull() )
00722                 cut = KStdAccel::shortcut(KStdAccel::TextCompletion);
00723             else
00724                 cut = keys[TextCompletion];
00725 
00726             if ( cut.contains( key ) )
00727             {
00728                 // Emit completion if the completion mode is CompletionShell
00729                 // and the cursor is at the end of the string.
00730                 QString txt = text();
00731                 int len = txt.length();
00732                 if ( cursorPosition() == len && len != 0 )
00733                 {
00734                     if ( emitSignals() )
00735                         emit completion( txt );
00736                     if ( handleSignals() )
00737                         makeCompletion( txt );
00738                     return;
00739                 }
00740             }
00741             else if ( d->completionBox )
00742                 d->completionBox->hide();
00743         }
00744 
00745         // handle rotation
00746         if ( mode != KGlobalSettings::CompletionNone )
00747         {
00748             // Handles previous match
00749             KShortcut cut;
00750             if ( keys[PrevCompletionMatch].isNull() )
00751                 cut = KStdAccel::shortcut(KStdAccel::PrevCompletion);
00752             else
00753                 cut = keys[PrevCompletionMatch];
00754 
00755             if ( cut.contains( key ) )
00756             {
00757                 if ( emitSignals() )
00758                     emit textRotation( KCompletionBase::PrevCompletionMatch );
00759                 if ( handleSignals() )
00760                     rotateText( KCompletionBase::PrevCompletionMatch );
00761                 return;
00762             }
00763 
00764             // Handles next match
00765             if ( keys[NextCompletionMatch].isNull() )
00766                 cut = KStdAccel::shortcut(KStdAccel::NextCompletion);
00767             else
00768                 cut = keys[NextCompletionMatch];
00769 
00770             if ( cut.contains( key ) )
00771             {
00772                 if ( emitSignals() )
00773                     emit textRotation( KCompletionBase::NextCompletionMatch );
00774                 if ( handleSignals() )
00775                     rotateText( KCompletionBase::NextCompletionMatch );
00776                 return;
00777             }
00778         }
00779 
00780         // substring completion
00781         if ( compObj() )
00782         {
00783             KShortcut cut;
00784             if ( keys[SubstringCompletion].isNull() )
00785                 cut = KStdAccel::shortcut(KStdAccel::SubstringCompletion);
00786             else
00787                 cut = keys[SubstringCompletion];
00788 
00789             if ( cut.contains( key ) )
00790             {
00791                 if ( emitSignals() )
00792                     emit substringCompletion( text() );
00793                 if ( handleSignals() )
00794                 {
00795                     setCompletedItems( compObj()->substringCompletion(text()));
00796                     e->accept();
00797                 }
00798                 return;
00799             }
00800         }
00801     }
00802 
00803     uint selectedLength = selectedText().length();
00804 
00805     // Let QLineEdit handle any other keys events.
00806     QLineEdit::keyPressEvent ( e );
00807 
00808     if ( selectedLength != selectedText().length() )
00809         slotRestoreSelectionColors(); // and set userSelection to true
00810 }
00811 
00812 void KLineEdit::mouseDoubleClickEvent( QMouseEvent* e )
00813 {
00814     if ( e->button() == Qt::LeftButton  )
00815     {
00816         possibleTripleClick=true;
00817         QTimer::singleShot( QApplication::doubleClickInterval(),this,
00818                             SLOT(tripleClickTimeout()) );
00819     }
00820     QLineEdit::mouseDoubleClickEvent( e );
00821 }
00822 
00823 void KLineEdit::mousePressEvent( QMouseEvent* e )
00824 {
00825     if ( possibleTripleClick && e->button() == Qt::LeftButton )
00826     {
00827         selectAll();
00828         e->accept();
00829         return;
00830     }
00831     QLineEdit::mousePressEvent( e );
00832 }
00833 
00834 void KLineEdit::tripleClickTimeout()
00835 {
00836     possibleTripleClick=false;
00837 }
00838 
00839 void KLineEdit::contextMenuEvent( QContextMenuEvent * e )
00840 {
00841     if ( m_bEnableMenu )
00842         QLineEdit::contextMenuEvent( e );
00843 }
00844 
00845 QPopupMenu *KLineEdit::createPopupMenu()
00846 {
00847     enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll };
00848 
00849     QPopupMenu *popup = QLineEdit::createPopupMenu();
00850 
00851     if ( isReadOnly() )
00852       popup->changeItem( popup->idAt(0), SmallIconSet("editcopy"), popup->text( popup->idAt(0) ) );
00853     else {
00854       int id = popup->idAt(0);
00855       popup->changeItem( id - IdUndo, SmallIconSet("undo"), popup->text( id - IdUndo) );
00856       popup->changeItem( id - IdRedo, SmallIconSet("redo"), popup->text( id - IdRedo) );
00857       popup->changeItem( id - IdCut, SmallIconSet("editcut"), popup->text( id - IdCut) );
00858       popup->changeItem( id - IdCopy, SmallIconSet("editcopy"), popup->text( id - IdCopy) );
00859       popup->changeItem( id - IdPaste, SmallIconSet("editpaste"), popup->text( id - IdPaste) );
00860       popup->changeItem( id - IdClear, SmallIconSet("editclear"), popup->text( id - IdClear) );
00861     }
00862       
00863     // If a completion object is present and the input
00864     // widget is not read-only, show the Text Completion
00865     // menu item.
00866     if ( compObj() && !isReadOnly() && kapp->authorize("lineedit_text_completion") )
00867     {
00868         QPopupMenu *subMenu = new QPopupMenu( popup );
00869         connect( subMenu, SIGNAL( activated( int ) ),
00870                  this, SLOT( completionMenuActivated( int ) ) );
00871 
00872         popup->insertSeparator();
00873         popup->insertItem( SmallIconSet("completion"), i18n("Text Completion"),
00874                            subMenu );
00875 
00876         subMenu->insertItem( i18n("None"), NoCompletion );
00877         subMenu->insertItem( i18n("Manual"), ShellCompletion );
00878         subMenu->insertItem( i18n("Automatic"), AutoCompletion );
00879         subMenu->insertItem( i18n("Dropdown List"), PopupCompletion );
00880         subMenu->insertItem( i18n("Short Automatic"), ShortAutoCompletion );
00881         subMenu->insertItem( i18n("Dropdown List && Automatic"), PopupAutoCompletion );
00882 
00883         subMenu->setAccel( KStdAccel::completion(), ShellCompletion );
00884 
00885         KGlobalSettings::Completion mode = completionMode();
00886         subMenu->setItemChecked( NoCompletion,
00887                                  mode == KGlobalSettings::CompletionNone );
00888         subMenu->setItemChecked( ShellCompletion,
00889                                  mode == KGlobalSettings::CompletionShell );
00890         subMenu->setItemChecked( PopupCompletion,
00891                                  mode == KGlobalSettings::CompletionPopup );
00892         subMenu->setItemChecked( AutoCompletion,
00893                                  mode == KGlobalSettings::CompletionAuto );
00894         subMenu->setItemChecked( ShortAutoCompletion,
00895                                  mode == KGlobalSettings::CompletionMan );
00896         subMenu->setItemChecked( PopupAutoCompletion,
00897                                  mode == KGlobalSettings::CompletionPopupAuto );
00898         if ( mode != KGlobalSettings::completionMode() )
00899         {
00900             subMenu->insertSeparator();
00901             subMenu->insertItem( i18n("Default"), Default );
00902         }
00903     }
00904 
00905     // ### do we really need this?  Yes, Please do not remove!  This
00906     // allows applications to extend the popup menu without having to
00907     // inherit from this class! (DA)
00908     emit aboutToShowContextMenu( popup );
00909 
00910     return popup;
00911 }
00912 
00913 void KLineEdit::completionMenuActivated( int id )
00914 {
00915     KGlobalSettings::Completion oldMode = completionMode();
00916 
00917     switch ( id )
00918     {
00919         case Default:
00920            setCompletionMode( KGlobalSettings::completionMode() );
00921            break;
00922         case NoCompletion:
00923            setCompletionMode( KGlobalSettings::CompletionNone );
00924            break;
00925         case AutoCompletion:
00926             setCompletionMode( KGlobalSettings::CompletionAuto );
00927             break;
00928         case ShortAutoCompletion:
00929             setCompletionMode( KGlobalSettings::CompletionMan );
00930             break;
00931         case ShellCompletion:
00932             setCompletionMode( KGlobalSettings::CompletionShell );
00933             break;
00934         case PopupCompletion:
00935             setCompletionMode( KGlobalSettings::CompletionPopup );
00936             break;
00937         case PopupAutoCompletion:
00938             setCompletionMode( KGlobalSettings::CompletionPopupAuto );
00939             break;
00940         default:
00941             return;
00942     }
00943 
00944     if ( oldMode != completionMode() )
00945     {
00946         if ( (oldMode == KGlobalSettings::CompletionPopup ||
00947               oldMode == KGlobalSettings::CompletionPopupAuto ) &&
00948               d->completionBox && d->completionBox->isVisible() )
00949             d->completionBox->hide();
00950         emit completionModeChanged( completionMode() );
00951     }
00952 }
00953 
00954 void KLineEdit::dropEvent(QDropEvent *e)
00955 {
00956     KURL::List urlList;
00957     if( d->handleURLDrops && KURLDrag::decode( e, urlList ) )
00958     {
00959         QString dropText = text();
00960         KURL::List::ConstIterator it;
00961         for( it = urlList.begin() ; it != urlList.end() ; ++it )
00962         {
00963             if(!dropText.isEmpty())
00964                 dropText+=' ';
00965 
00966             dropText += (*it).prettyURL();
00967         }
00968 
00969         validateAndSet( dropText, dropText.length(), 0, 0);
00970 
00971         e->accept();
00972     }
00973     else
00974         QLineEdit::dropEvent(e);
00975 }
00976 
00977 bool KLineEdit::eventFilter( QObject* o, QEvent* ev )
00978 {
00979     if( o == this )
00980     {
00981         KCursor::autoHideEventFilter( this, ev );
00982         if ( ev->type() == QEvent::AccelOverride )
00983         {
00984             QKeyEvent *e = static_cast<QKeyEvent *>( ev );
00985             if (overrideAccel (e))
00986             {
00987                 e->accept();
00988                 return true;
00989             }
00990         }
00991         else if( ev->type() == QEvent::KeyPress )
00992         {
00993             QKeyEvent *e = static_cast<QKeyEvent *>( ev );
00994 
00995             if( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter )
00996             {
00997                 bool trap = d->completionBox && d->completionBox->isVisible();
00998 
00999                 bool stopEvent = trap || (d->grabReturnKeyEvents &&
01000                                           (e->state() == NoButton ||
01001                                            e->state() == Keypad));
01002 
01003                 // Qt will emit returnPressed() itself if we return false
01004                 if ( stopEvent )
01005                 {
01006                   emit QLineEdit::returnPressed();
01007                   e->accept ();
01008                 }
01009 
01010                 emit returnPressed( displayText() );
01011 
01012                 if ( trap )
01013                 {
01014                     d->completionBox->hide();
01015                     deselect();
01016                     setCursorPosition(text().length());
01017                 }
01018 
01019                 // Eat the event if the user asked for it, or if a completionbox was visible
01020                 return stopEvent;
01021             }
01022         }
01023     }
01024     return QLineEdit::eventFilter( o, ev );
01025 }
01026 
01027 
01028 void KLineEdit::setURLDropsEnabled(bool enable)
01029 {
01030     d->handleURLDrops=enable;
01031 }
01032 
01033 bool KLineEdit::isURLDropsEnabled() const
01034 {
01035     return d->handleURLDrops;
01036 }
01037 
01038 void KLineEdit::setTrapReturnKey( bool grab )
01039 {
01040     d->grabReturnKeyEvents = grab;
01041 }
01042 
01043 bool KLineEdit::trapReturnKey() const
01044 {
01045     return d->grabReturnKeyEvents;
01046 }
01047 
01048 void KLineEdit::setURL( const KURL& url )
01049 {
01050     setText( url.prettyURL() );
01051 }
01052 
01053 void KLineEdit::makeCompletionBox()
01054 {
01055     if ( d->completionBox )
01056         return;
01057 
01058     d->completionBox = new KCompletionBox( this, "completion box" );
01059     if ( handleSignals() )
01060     {
01061         connect( d->completionBox, SIGNAL(highlighted( const QString& )),
01062                  SLOT(setTextWorkaround( const QString& )) );
01063         connect( d->completionBox, SIGNAL(userCancelled( const QString& )),
01064                  SLOT(userCancelled( const QString& )) );
01065 
01066         connect( d->completionBox, SIGNAL( activated( const QString& )),
01067                  SIGNAL(completionBoxActivated( const QString& )) );
01068     }
01069 }
01070 
01071 void KLineEdit::userCancelled(const QString & cancelText)
01072 {
01073     if ( completionMode() != KGlobalSettings::CompletionPopupAuto )
01074     {
01075       setText(cancelText);
01076     }
01077     else if (hasSelectedText() )
01078     {
01079       if (d->userSelection)
01080         deselect();
01081       else
01082       {
01083         d->autoSuggest=false;
01084         int start,end;
01085         getSelection(&start, &end);
01086         QString s=text().remove(start, end-start+1);
01087         validateAndSet(s,start,s.length(),s.length());
01088         d->autoSuggest=true;
01089       }
01090     }
01091 }
01092 
01093 bool KLineEdit::overrideAccel (const QKeyEvent* e)
01094 {
01095     KShortcut scKey;
01096 
01097     KKey key( e );
01098     KeyBindingMap keys = getKeyBindings();
01099 
01100     if (keys[TextCompletion].isNull())
01101         scKey = KStdAccel::shortcut(KStdAccel::TextCompletion);
01102     else
01103         scKey = keys[TextCompletion];
01104 
01105     if (scKey.contains( key ))
01106         return true;
01107 
01108     if (keys[NextCompletionMatch].isNull())
01109         scKey = KStdAccel::shortcut(KStdAccel::NextCompletion);
01110     else
01111         scKey = keys[NextCompletionMatch];
01112 
01113     if (scKey.contains( key ))
01114         return true;
01115 
01116     if (keys[PrevCompletionMatch].isNull())
01117         scKey = KStdAccel::shortcut(KStdAccel::PrevCompletion);
01118     else
01119         scKey = keys[PrevCompletionMatch];
01120 
01121     if (scKey.contains( key ))
01122         return true;
01123 
01124     // Override all the text manupilation accelerators...
01125     if ( KStdAccel::copy().contains( key ) )
01126         return true;
01127     else if ( KStdAccel::paste().contains( key ) )
01128         return true;
01129     else if ( KStdAccel::cut().contains( key ) )
01130         return true;
01131     else if ( KStdAccel::undo().contains( key ) )
01132         return true;
01133     else if ( KStdAccel::redo().contains( key ) )
01134         return true;
01135     else if (KStdAccel::deleteWordBack().contains( key ))
01136         return true;
01137     else if (KStdAccel::deleteWordForward().contains( key ))
01138         return true;
01139     else if (KStdAccel::forwardWord().contains( key ))
01140         return true;
01141     else if (KStdAccel::backwardWord().contains( key ))
01142         return true;
01143     else if (KStdAccel::beginningOfLine().contains( key ))
01144         return true;
01145     else if (KStdAccel::endOfLine().contains( key ))
01146         return true;
01147 
01148     if (d->completionBox && d->completionBox->isVisible ())
01149     {
01150         int key = e->key();
01151         ButtonState state = e->state();
01152         if ((key == Key_Backtab || key == Key_Tab) &&
01153             (state == NoButton || (state & ShiftButton)))
01154         {
01155             return true;
01156         }
01157     }
01158 
01159 
01160     return false;
01161 }
01162 
01163 void KLineEdit::setCompletedItems( const QStringList& items )
01164 {
01165     setCompletedItems( items, true );
01166 }
01167 
01168 void KLineEdit::setCompletedItems( const QStringList& items, bool autoSuggest )
01169 {
01170     QString txt = text();
01171 
01172     if ( !items.isEmpty() &&
01173          !(items.count() == 1 && txt == items.first()) )
01174     {
01175         if ( !d->completionBox )
01176             makeCompletionBox();
01177 
01178         if ( !txt.isEmpty() )
01179             d->completionBox->setCancelledText( txt );
01180 
01181         d->completionBox->setItems( items );
01182         d->completionBox->popup();
01183 
01184         if ( d->autoSuggest && autoSuggest )
01185         {
01186             int index = items.first().find( txt );
01187             QString newText = items.first().mid( index );
01188             setUserSelection(false);
01189             setCompletedText(newText,true);
01190         }
01191     }
01192     else
01193     {
01194         if ( d->completionBox && d->completionBox->isVisible() )
01195             d->completionBox->hide();
01196     }
01197 }
01198 
01199 KCompletionBox * KLineEdit::completionBox( bool create )
01200 {
01201     if ( create )
01202         makeCompletionBox();
01203 
01204     return d->completionBox;
01205 }
01206 
01207 void KLineEdit::setCompletionObject( KCompletion* comp, bool hsig )
01208 {
01209     KCompletion *oldComp = compObj();
01210     if ( oldComp && handleSignals() )
01211         disconnect( oldComp, SIGNAL( matches( const QStringList& )),
01212                     this, SLOT( setCompletedItems( const QStringList& )));
01213 
01214     if ( comp && hsig )
01215       connect( comp, SIGNAL( matches( const QStringList& )),
01216                this, SLOT( setCompletedItems( const QStringList& )));
01217 
01218     KCompletionBase::setCompletionObject( comp, hsig );
01219 }
01220 
01221 // QWidget::create() turns off mouse-Tracking which would break auto-hiding
01222 void KLineEdit::create( WId id, bool initializeWindow, bool destroyOldWindow )
01223 {
01224     QLineEdit::create( id, initializeWindow, destroyOldWindow );
01225     KCursor::setAutoHideCursor( this, true, true );
01226 }
01227 
01228 void KLineEdit::setUserSelection(bool userSelection)
01229 {
01230     QPalette p = palette();
01231 
01232     if (userSelection)
01233     {
01234         p.setColor(QColorGroup::Highlight, d->previousHighlightColor);
01235         p.setColor(QColorGroup::HighlightedText, d->previousHighlightedTextColor);
01236     }
01237     else
01238     {
01239         QColor color=p.color(QPalette::Disabled, QColorGroup::Text);
01240         p.setColor(QColorGroup::HighlightedText, color);
01241         color=p.color(QPalette::Active, QColorGroup::Base);
01242         p.setColor(QColorGroup::Highlight, color);
01243     }
01244 
01245     d->userSelection=userSelection;
01246     setPalette(p);
01247 }
01248 
01249 void KLineEdit::slotRestoreSelectionColors()
01250 {
01251     if (d->disableRestoreSelection)
01252       return;
01253 
01254     setUserSelection(true);
01255 }
01256 
01257 void KLineEdit::clear()
01258 {
01259     setText( QString::null );
01260 }
01261 
01262 void KLineEdit::setTextWorkaround( const QString& text )
01263 {
01264     setText( text );
01265     end( false ); // force cursor at end
01266 }
01267 
01268 QString KLineEdit::originalText() const
01269 {
01270     if ( d->enableSqueezedText && isReadOnly() )
01271         return d->squeezedText;
01272 
01273     return text();
01274 }
01275 
01276 void KLineEdit::virtual_hook( int id, void* data )
01277 { KCompletionBase::virtual_hook( id, data ); }
KDE Logo
This file is part of the documentation for kdeui Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jan 22 16:45:12 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003