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