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