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 QPopupMenu *KLineEdit::createPopupMenu()
00840 {
00841     enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll };
00842 
00843     // Return if popup menu is not enabled !!
00844     if ( !m_bEnableMenu )
00845         return 0;
00846 
00847     QPopupMenu *popup = QLineEdit::createPopupMenu();
00848 
00849     if ( isReadOnly() )
00850       popup->changeItem( popup->idAt(0), SmallIconSet("editcopy"), popup->text( popup->idAt(0) ) );
00851     else {
00852       int id = popup->idAt(0);
00853       popup->changeItem( id - IdUndo, SmallIconSet("undo"), popup->text( id - IdUndo) );
00854       popup->changeItem( id - IdRedo, SmallIconSet("redo"), popup->text( id - IdRedo) );
00855       popup->changeItem( id - IdCut, SmallIconSet("editcut"), popup->text( id - IdCut) );
00856       popup->changeItem( id - IdCopy, SmallIconSet("editcopy"), popup->text( id - IdCopy) );
00857       popup->changeItem( id - IdPaste, SmallIconSet("editpaste"), popup->text( id - IdPaste) );
00858       popup->changeItem( id - IdClear, SmallIconSet("editclear"), popup->text( id - IdClear) );
00859     }
00860       
00861     // If a completion object is present and the input
00862     // widget is not read-only, show the Text Completion
00863     // menu item.
00864     if ( compObj() && !isReadOnly() && kapp->authorize("lineedit_text_completion") )
00865     {
00866         QPopupMenu *subMenu = new QPopupMenu( popup );
00867         connect( subMenu, SIGNAL( activated( int ) ),
00868                  this, SLOT( completionMenuActivated( int ) ) );
00869 
00870         popup->insertSeparator();
00871         popup->insertItem( SmallIconSet("completion"), i18n("Text Completion"),
00872                            subMenu );
00873 
00874         subMenu->insertItem( i18n("None"), NoCompletion );
00875         subMenu->insertItem( i18n("Manual"), ShellCompletion );
00876         subMenu->insertItem( i18n("Automatic"), AutoCompletion );
00877         subMenu->insertItem( i18n("Dropdown List"), PopupCompletion );
00878         subMenu->insertItem( i18n("Short Automatic"), ShortAutoCompletion );
00879         subMenu->insertItem( i18n("Dropdown List && Automatic"), PopupAutoCompletion );
00880 
00881         subMenu->setAccel( KStdAccel::completion(), ShellCompletion );
00882 
00883         KGlobalSettings::Completion mode = completionMode();
00884         subMenu->setItemChecked( NoCompletion,
00885                                  mode == KGlobalSettings::CompletionNone );
00886         subMenu->setItemChecked( ShellCompletion,
00887                                  mode == KGlobalSettings::CompletionShell );
00888         subMenu->setItemChecked( PopupCompletion,
00889                                  mode == KGlobalSettings::CompletionPopup );
00890         subMenu->setItemChecked( AutoCompletion,
00891                                  mode == KGlobalSettings::CompletionAuto );
00892         subMenu->setItemChecked( ShortAutoCompletion,
00893                                  mode == KGlobalSettings::CompletionMan );
00894         subMenu->setItemChecked( PopupAutoCompletion,
00895                                  mode == KGlobalSettings::CompletionPopupAuto );
00896         if ( mode != KGlobalSettings::completionMode() )
00897         {
00898             subMenu->insertSeparator();
00899             subMenu->insertItem( i18n("Default"), Default );
00900         }
00901     }
00902 
00903     // ### do we really need this?  Yes, Please do not remove!  This
00904     // allows applications to extend the popup menu without having to
00905     // inherit from this class! (DA)
00906     emit aboutToShowContextMenu( popup );
00907 
00908     return popup;
00909 }
00910 
00911 void KLineEdit::completionMenuActivated( int id )
00912 {
00913     KGlobalSettings::Completion oldMode = completionMode();
00914 
00915     switch ( id )
00916     {
00917         case Default:
00918            setCompletionMode( KGlobalSettings::completionMode() );
00919            break;
00920         case NoCompletion:
00921            setCompletionMode( KGlobalSettings::CompletionNone );
00922            break;
00923         case AutoCompletion:
00924             setCompletionMode( KGlobalSettings::CompletionAuto );
00925             break;
00926         case ShortAutoCompletion:
00927             setCompletionMode( KGlobalSettings::CompletionMan );
00928             break;
00929         case ShellCompletion:
00930             setCompletionMode( KGlobalSettings::CompletionShell );
00931             break;
00932         case PopupCompletion:
00933             setCompletionMode( KGlobalSettings::CompletionPopup );
00934             break;
00935         case PopupAutoCompletion:
00936             setCompletionMode( KGlobalSettings::CompletionPopupAuto );
00937             break;
00938         default:
00939             return;
00940     }
00941 
00942     if ( oldMode != completionMode() )
00943     {
00944         if ( (oldMode == KGlobalSettings::CompletionPopup ||
00945               oldMode == KGlobalSettings::CompletionPopupAuto ) &&
00946               d->completionBox && d->completionBox->isVisible() )
00947             d->completionBox->hide();
00948         emit completionModeChanged( completionMode() );
00949     }
00950 }
00951 
00952 void KLineEdit::dropEvent(QDropEvent *e)
00953 {
00954     KURL::List urlList;
00955     if( d->handleURLDrops && KURLDrag::decode( e, urlList ) )
00956     {
00957         QString dropText = text();
00958         KURL::List::ConstIterator it;
00959         for( it = urlList.begin() ; it != urlList.end() ; ++it )
00960         {
00961             if(!dropText.isEmpty())
00962                 dropText+=' ';
00963 
00964             dropText += (*it).prettyURL();
00965         }
00966 
00967         validateAndSet( dropText, dropText.length(), 0, 0);
00968 
00969         e->accept();
00970     }
00971     else
00972         QLineEdit::dropEvent(e);
00973 }
00974 
00975 bool KLineEdit::eventFilter( QObject* o, QEvent* ev )
00976 {
00977     if( o == this )
00978     {
00979         KCursor::autoHideEventFilter( this, ev );
00980         if ( ev->type() == QEvent::AccelOverride )
00981         {
00982             QKeyEvent *e = static_cast<QKeyEvent *>( ev );
00983             if (overrideAccel (e))
00984             {
00985                 e->accept();
00986                 return true;
00987             }
00988         }
00989         else if( ev->type() == QEvent::KeyPress )
00990         {
00991             QKeyEvent *e = static_cast<QKeyEvent *>( ev );
00992 
00993             if( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter )
00994             {
00995                 bool trap = d->completionBox && d->completionBox->isVisible();
00996 
00997                 bool stopEvent = trap || (d->grabReturnKeyEvents &&
00998                                           (e->state() == NoButton ||
00999                                            e->state() == Keypad));
01000 
01001                 // Qt will emit returnPressed() itself if we return false
01002                 if ( stopEvent )
01003                 {
01004                   emit QLineEdit::returnPressed();
01005                   e->accept ();
01006                 }
01007 
01008                 emit returnPressed( displayText() );
01009 
01010                 if ( trap )
01011                 {
01012                     d->completionBox->hide();
01013                     deselect();
01014                     setCursorPosition(text().length());
01015                 }
01016 
01017                 // Eat the event if the user asked for it, or if a completionbox was visible
01018                 return stopEvent;
01019             }
01020         }
01021     }
01022     return QLineEdit::eventFilter( o, ev );
01023 }
01024 
01025 
01026 void KLineEdit::setURLDropsEnabled(bool enable)
01027 {
01028     d->handleURLDrops=enable;
01029 }
01030 
01031 bool KLineEdit::isURLDropsEnabled() const
01032 {
01033     return d->handleURLDrops;
01034 }
01035 
01036 void KLineEdit::setTrapReturnKey( bool grab )
01037 {
01038     d->grabReturnKeyEvents = grab;
01039 }
01040 
01041 bool KLineEdit::trapReturnKey() const
01042 {
01043     return d->grabReturnKeyEvents;
01044 }
01045 
01046 void KLineEdit::setURL( const KURL& url )
01047 {
01048     setText( url.prettyURL() );
01049 }
01050 
01051 void KLineEdit::makeCompletionBox()
01052 {
01053     if ( d->completionBox )
01054         return;
01055 
01056     d->completionBox = new KCompletionBox( this, "completion box" );
01057     if ( handleSignals() )
01058     {
01059         connect( d->completionBox, SIGNAL(highlighted( const QString& )),
01060                  SLOT(setTextWorkaround( const QString& )) );
01061         connect( d->completionBox, SIGNAL(userCancelled( const QString& )),
01062                  SLOT(userCancelled( const QString& )) );
01063 
01064         connect( d->completionBox, SIGNAL( activated( const QString& )),
01065                  SIGNAL(completionBoxActivated( const QString& )) );
01066     }
01067 }
01068 
01069 void KLineEdit::userCancelled(const QString & cancelText)
01070 {
01071     if ( completionMode() != KGlobalSettings::CompletionPopupAuto )
01072     {
01073       setText(cancelText);
01074     }
01075     else if (hasSelectedText() )
01076     {
01077       if (d->userSelection)
01078         deselect();
01079       else
01080       {
01081         d->autoSuggest=false;
01082         int start,end;
01083         getSelection(&start, &end);
01084         QString s=text().remove(start, end-start+1);
01085         validateAndSet(s,start,s.length(),s.length());
01086         d->autoSuggest=true;
01087       }
01088     }
01089 }
01090 
01091 bool KLineEdit::overrideAccel (const QKeyEvent* e)
01092 {
01093     KShortcut scKey;
01094 
01095     KKey key( e );
01096     KeyBindingMap keys = getKeyBindings();
01097 
01098     if (keys[TextCompletion].isNull())
01099         scKey = KStdAccel::shortcut(KStdAccel::TextCompletion);
01100     else
01101         scKey = keys[TextCompletion];
01102 
01103     if (scKey.contains( key ))
01104         return true;
01105 
01106     if (keys[NextCompletionMatch].isNull())
01107         scKey = KStdAccel::shortcut(KStdAccel::NextCompletion);
01108     else
01109         scKey = keys[NextCompletionMatch];
01110 
01111     if (scKey.contains( key ))
01112         return true;
01113 
01114     if (keys[PrevCompletionMatch].isNull())
01115         scKey = KStdAccel::shortcut(KStdAccel::PrevCompletion);
01116     else
01117         scKey = keys[PrevCompletionMatch];
01118 
01119     if (scKey.contains( key ))
01120         return true;
01121 
01122     // Override all the text manupilation accelerators...
01123     if ( KStdAccel::copy().contains( key ) )
01124         return true;
01125     else if ( KStdAccel::paste().contains( key ) )
01126         return true;
01127     else if ( KStdAccel::cut().contains( key ) )
01128         return true;
01129     else if ( KStdAccel::undo().contains( key ) )
01130         return true;
01131     else if ( KStdAccel::redo().contains( key ) )
01132         return true;
01133     else if (KStdAccel::deleteWordBack().contains( key ))
01134         return true;
01135     else if (KStdAccel::deleteWordForward().contains( key ))
01136         return true;
01137     else if (KStdAccel::forwardWord().contains( key ))
01138         return true;
01139     else if (KStdAccel::backwardWord().contains( key ))
01140         return true;
01141     else if (KStdAccel::beginningOfLine().contains( key ))
01142         return true;
01143     else if (KStdAccel::endOfLine().contains( key ))
01144         return true;
01145 
01146     if (d->completionBox && d->completionBox->isVisible ())
01147     {
01148         int key = e->key();
01149         ButtonState state = e->state();
01150         if ((key == Key_Backtab || key == Key_Tab) &&
01151             (state == NoButton || (state & ShiftButton)))
01152         {
01153             return true;
01154         }
01155     }
01156 
01157 
01158     return false;
01159 }
01160 
01161 void KLineEdit::setCompletedItems( const QStringList& items )
01162 {
01163     setCompletedItems( items, true );
01164 }
01165 
01166 void KLineEdit::setCompletedItems( const QStringList& items, bool autoSuggest )
01167 {
01168     QString txt = text();
01169 
01170     if ( !items.isEmpty() &&
01171          !(items.count() == 1 && txt == items.first()) )
01172     {
01173         if ( !d->completionBox )
01174             makeCompletionBox();
01175 
01176         if ( !txt.isEmpty() )
01177             d->completionBox->setCancelledText( txt );
01178 
01179         d->completionBox->setItems( items );
01180         d->completionBox->popup();
01181 
01182         if ( d->autoSuggest && autoSuggest )
01183         {
01184             int index = items.first().find( txt );
01185             QString newText = items.first().mid( index );
01186             setUserSelection(false);
01187             setCompletedText(newText,true);
01188         }
01189     }
01190     else
01191     {
01192         if ( d->completionBox && d->completionBox->isVisible() )
01193             d->completionBox->hide();
01194     }
01195 }
01196 
01197 KCompletionBox * KLineEdit::completionBox( bool create )
01198 {
01199     if ( create )
01200         makeCompletionBox();
01201 
01202     return d->completionBox;
01203 }
01204 
01205 void KLineEdit::setCompletionObject( KCompletion* comp, bool hsig )
01206 {
01207     KCompletion *oldComp = compObj();
01208     if ( oldComp && handleSignals() )
01209         disconnect( oldComp, SIGNAL( matches( const QStringList& )),
01210                     this, SLOT( setCompletedItems( const QStringList& )));
01211 
01212     if ( comp && hsig )
01213       connect( comp, SIGNAL( matches( const QStringList& )),
01214                this, SLOT( setCompletedItems( const QStringList& )));
01215 
01216     KCompletionBase::setCompletionObject( comp, hsig );
01217 }
01218 
01219 // QWidget::create() turns off mouse-Tracking which would break auto-hiding
01220 void KLineEdit::create( WId id, bool initializeWindow, bool destroyOldWindow )
01221 {
01222     QLineEdit::create( id, initializeWindow, destroyOldWindow );
01223     KCursor::setAutoHideCursor( this, true, true );
01224 }
01225 
01226 void KLineEdit::setUserSelection(bool userSelection)
01227 {
01228     QPalette p = palette();
01229 
01230     if (userSelection)
01231     {
01232         p.setColor(QColorGroup::Highlight, d->previousHighlightColor);
01233         p.setColor(QColorGroup::HighlightedText, d->previousHighlightedTextColor);
01234     }
01235     else
01236     {
01237         QColor color=p.color(QPalette::Disabled, QColorGroup::Text);
01238         p.setColor(QColorGroup::HighlightedText, color);
01239         color=p.color(QPalette::Active, QColorGroup::Base);
01240         p.setColor(QColorGroup::Highlight, color);
01241     }
01242 
01243     d->userSelection=userSelection;
01244     setPalette(p);
01245 }
01246 
01247 void KLineEdit::slotRestoreSelectionColors()
01248 {
01249     if (d->disableRestoreSelection)
01250       return;
01251 
01252     setUserSelection(true);
01253 }
01254 
01255 void KLineEdit::clear()
01256 {
01257     setText( QString::null );
01258 }
01259 
01260 void KLineEdit::setTextWorkaround( const QString& text )
01261 {
01262     setText( text );
01263     end( false ); // force cursor at end
01264 }
01265 
01266 QString KLineEdit::originalText() const
01267 {
01268     if ( d->enableSqueezedText && isReadOnly() )
01269         return d->squeezedText;
01270 
01271     return text();
01272 }
01273 
01274 void KLineEdit::virtual_hook( int id, void* data )
01275 { KCompletionBase::virtual_hook( id, data ); }
KDE Logo
This file is part of the documentation for kdeui Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Nov 27 13:43:07 2004 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003