kdeui Library API Documentation

klineedit.cpp

00001 /* This file is part of the KDE libraries 00002 00003 Copyright (C) 1997 Sven Radej (sven.radej@iname.com) 00004 Copyright (c) 1999 Patrick Ward <PAT_WARD@HP-USA-om5.om.hp.com> 00005 Copyright (c) 1999 Preston Brown <pbrown@kde.org> 00006 00007 Re-designed for KDE 2.x by 00008 Copyright (c) 2000, 2001 Dawit Alemayehu <adawit@kde.org> 00009 Copyright (c) 2000, 2001 Carsten Pfeiffer <pfeiffer@kde.org> 00010 00011 This library is free software; you can redistribute it and/or 00012 modify it under the terms of the GNU Lesser General Public 00013 License (LGPL) as published by the Free Software Foundation; 00014 either version 2 of the License, or (at your option) any later 00015 version. 00016 00017 This library is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00020 Lesser General Public License for more details. 00021 00022 You should have received a copy of the GNU Lesser General Public License 00023 along with this library; see the file COPYING.LIB. If not, write to 00024 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00025 Boston, MA 02111-1307, USA. 00026 */ 00027 00028 #include <qclipboard.h> 00029 #include <qtimer.h> 00030 00031 #include <kconfig.h> 00032 #include <qtooltip.h> 00033 #include <kcursor.h> 00034 #include <klocale.h> 00035 #include <kstdaccel.h> 00036 #include <kpopupmenu.h> 00037 #include <kdebug.h> 00038 #include <kcompletionbox.h> 00039 #include <kurl.h> 00040 #include <kurldrag.h> 00041 #include <kiconloader.h> 00042 #include <kapplication.h> 00043 00044 #include "klineedit.h" 00045 #include "klineedit.moc" 00046 00047 00048 class KLineEdit::KLineEditPrivate 00049 { 00050 public: 00051 KLineEditPrivate() 00052 { 00053 completionBox = 0L; 00054 handleURLDrops = true; 00055 grabReturnKeyEvents = false; 00056 00057 userSelection = true; 00058 autoSuggest = false; 00059 disableRestoreSelection = false; 00060 enableSqueezedText = false; 00061 00062 if ( !initialized ) 00063 { 00064 KConfigGroup config( KGlobal::config(), "General" ); 00065 backspacePerformsCompletion = config.readBoolEntry( "Backspace performs completion", false ); 00066 00067 initialized = true; 00068 } 00069 00070 } 00071 00072 ~KLineEditPrivate() 00073 { 00074 // causes a weird crash in KWord at least, so let Qt delete it for us. 00075 // delete completionBox; 00076 } 00077 00078 static bool initialized; 00079 static bool backspacePerformsCompletion; // Configuration option 00080 00081 QColor previousHighlightColor; 00082 QColor previousHighlightedTextColor; 00083 00084 bool userSelection: 1; 00085 bool autoSuggest : 1; 00086 bool disableRestoreSelection: 1; 00087 bool handleURLDrops:1; 00088 bool grabReturnKeyEvents:1; 00089 bool enableSqueezedText:1; 00090 00091 int squeezedEnd; 00092 int squeezedStart; 00093 BackgroundMode bgMode; 00094 QString squeezedText; 00095 KCompletionBox *completionBox; 00096 }; 00097 00098 bool KLineEdit::KLineEditPrivate::backspacePerformsCompletion = false; 00099 bool KLineEdit::KLineEditPrivate::initialized = false; 00100 00101 00102 KLineEdit::KLineEdit( const QString &string, QWidget *parent, const char *name ) 00103 :QLineEdit( string, parent, name ) 00104 { 00105 init(); 00106 } 00107 00108 KLineEdit::KLineEdit( QWidget *parent, const char *name ) 00109 :QLineEdit( parent, name ) 00110 { 00111 init(); 00112 } 00113 00114 KLineEdit::~KLineEdit () 00115 { 00116 delete d; 00117 d = 0; 00118 } 00119 00120 void KLineEdit::init() 00121 { 00122 d = new KLineEditPrivate; 00123 possibleTripleClick = false; 00124 d->bgMode = backgroundMode (); 00125 00126 // Enable the context menu by default. 00127 KLineEdit::setContextMenuEnabled( true ); 00128 KCursor::setAutoHideCursor( this, true, true ); 00129 installEventFilter( this ); 00130 00131 KGlobalSettings::Completion mode = completionMode(); 00132 d->autoSuggest = (mode == KGlobalSettings::CompletionMan || 00133 mode == KGlobalSettings::CompletionPopupAuto || 00134 mode == KGlobalSettings::CompletionAuto); 00135 connect( this, SIGNAL(selectionChanged()), this, SLOT(slotRestoreSelectionColors())); 00136 00137 QPalette p = palette(); 00138 if ( !d->previousHighlightedTextColor.isValid() ) 00139 d->previousHighlightedTextColor=p.color(QPalette::Normal,QColorGroup::HighlightedText); 00140 if ( !d->previousHighlightColor.isValid() ) 00141 d->previousHighlightColor=p.color(QPalette::Normal,QColorGroup::Highlight); 00142 } 00143 00144 void KLineEdit::setCompletionMode( KGlobalSettings::Completion mode ) 00145 { 00146 KGlobalSettings::Completion oldMode = completionMode(); 00147 00148 if ( oldMode != mode && (oldMode == KGlobalSettings::CompletionPopup || 00149 oldMode == KGlobalSettings::CompletionPopupAuto ) && 00150 d->completionBox && d->completionBox->isVisible() ) 00151 d->completionBox->hide(); 00152 00153 // If the widgets echo mode is not Normal, no completion 00154 // feature will be enabled even if one is requested. 00155 if ( echoMode() != QLineEdit::Normal ) 00156 mode = KGlobalSettings::CompletionNone; // Override the request. 00157 00158 if ( kapp && !kapp->authorize("lineedit_text_completion") ) 00159 mode = KGlobalSettings::CompletionNone; 00160 00161 if ( mode == KGlobalSettings::CompletionPopupAuto || 00162 mode == KGlobalSettings::CompletionAuto || 00163 mode == KGlobalSettings::CompletionMan ) 00164 d->autoSuggest = true; 00165 else 00166 d->autoSuggest = false; 00167 00168 KCompletionBase::setCompletionMode( mode ); 00169 } 00170 00171 void KLineEdit::setCompletedText( const QString& t, bool marked ) 00172 { 00173 if ( !d->autoSuggest ) 00174 return; 00175 00176 QString txt = text(); 00177 00178 if ( t != txt ) 00179 { 00180 int start = marked ? txt.length() : t.length(); 00181 validateAndSet( t, cursorPosition(), start, t.length() ); 00182 setUserSelection(false); 00183 } 00184 else 00185 setUserSelection(true); 00186 00187 } 00188 00189 void KLineEdit::setCompletedText( const QString& text ) 00190 { 00191 KGlobalSettings::Completion mode = completionMode(); 00192 bool marked = ( mode == KGlobalSettings::CompletionAuto || 00193 mode == KGlobalSettings::CompletionMan || 00194 mode == KGlobalSettings::CompletionPopup || 00195 mode == KGlobalSettings::CompletionPopupAuto ); 00196 setCompletedText( text, marked ); 00197 } 00198 00199 void KLineEdit::rotateText( KCompletionBase::KeyBindingType type ) 00200 { 00201 KCompletion* comp = compObj(); 00202 if ( comp && 00203 (type == KCompletionBase::PrevCompletionMatch || 00204 type == KCompletionBase::NextCompletionMatch ) ) 00205 { 00206 QString input; 00207 00208 if (type == KCompletionBase::PrevCompletionMatch) 00209 comp->previousMatch(); 00210 else 00211 comp->nextMatch(); 00212 00213 // Skip rotation if previous/next match is null or the same text 00214 if ( input.isNull() || input == displayText() ) 00215 return; 00216 setCompletedText( input, hasSelectedText() ); 00217 } 00218 } 00219 00220 void KLineEdit::makeCompletion( const QString& text ) 00221 { 00222 KCompletion *comp = compObj(); 00223 KGlobalSettings::Completion mode = completionMode(); 00224 00225 if ( !comp || mode == KGlobalSettings::CompletionNone ) 00226 return; // No completion object... 00227 00228 QString match = comp->makeCompletion( text ); 00229 00230 if ( mode == KGlobalSettings::CompletionPopup || 00231 mode == KGlobalSettings::CompletionPopupAuto ) 00232 { 00233 if ( match.isNull() ) 00234 { 00235 if ( d->completionBox ) 00236 { 00237 d->completionBox->hide(); 00238 d->completionBox->clear(); 00239 } 00240 } 00241 else 00242 setCompletedItems( comp->allMatches() ); 00243 } 00244 else // Auto, ShortAuto (Man) and Shell 00245 { 00246 // all other completion modes 00247 // If no match or the same match, simply return without completing. 00248 if ( match.isNull() || match == text ) 00249 return; 00250 00251 if ( mode != KGlobalSettings::CompletionShell ) 00252 setUserSelection(false); 00253 00254 if ( d->autoSuggest ) 00255 setCompletedText( match ); 00256 } 00257 } 00258 00259 void KLineEdit::setReadOnly(bool readOnly) 00260 { 00261 // Do not do anything if nothing changed... 00262 if (readOnly == isReadOnly ()) 00263 return; 00264 00265 QLineEdit::setReadOnly (readOnly); 00266 00267 if (readOnly) 00268 { 00269 d->bgMode = backgroundMode (); 00270 setBackgroundMode (Qt::PaletteBackground); 00271 if (d->enableSqueezedText && d->squeezedText.isEmpty()) 00272 { 00273 d->squeezedText = text(); 00274 setSqueezedText(); 00275 } 00276 } 00277 else 00278 { 00279 if (!d->squeezedText.isEmpty()) 00280 { 00281 setText(d->squeezedText); 00282 d->squeezedText = QString::null; 00283 } 00284 setBackgroundMode (d->bgMode); 00285 } 00286 } 00287 00288 void KLineEdit::setSqueezedText( const QString &text) 00289 { 00290 setEnableSqueezedText(true); 00291 setText(text); 00292 } 00293 00294 void KLineEdit::setEnableSqueezedText( bool enable ) 00295 { 00296 d->enableSqueezedText = enable; 00297 } 00298 00299 bool KLineEdit::isSqueezedTextEnabled() const 00300 { 00301 return d->enableSqueezedText; 00302 } 00303 00304 void KLineEdit::setText( const QString& text ) 00305 { 00306 if( d->enableSqueezedText && isReadOnly() ) 00307 { 00308 d->squeezedText = text; 00309 setSqueezedText(); 00310 return; 00311 } 00312 00313 QLineEdit::setText( text ); 00314 } 00315 00316 void KLineEdit::setSqueezedText() 00317 { 00318 d->squeezedStart = 0; 00319 d->squeezedEnd = 0; 00320 QString fullText = d->squeezedText; 00321 QFontMetrics fm(fontMetrics()); 00322 int labelWidth = size().width() - 2*frameWidth() - 2; 00323 int textWidth = fm.width(fullText); 00324 00325 if (textWidth > labelWidth) 00326 { 00327 // start with the dots only 00328 QString squeezedText = "..."; 00329 int squeezedWidth = fm.width(squeezedText); 00330 00331 // estimate how many letters we can add to the dots on both sides 00332 int letters = fullText.length() * (labelWidth - squeezedWidth) / textWidth / 2; 00333 squeezedText = fullText.left(letters) + "..." + fullText.right(letters); 00334 squeezedWidth = fm.width(squeezedText); 00335 00336 if (squeezedWidth < labelWidth) 00337 { 00338 // we estimated too short 00339 // add letters while text < label 00340 do 00341 { 00342 letters++; 00343 squeezedText = fullText.left(letters) + "..." + fullText.right(letters); 00344 squeezedWidth = fm.width(squeezedText); 00345 } while (squeezedWidth < labelWidth); 00346 letters--; 00347 squeezedText = fullText.left(letters) + "..." + fullText.right(letters); 00348 } 00349 else if (squeezedWidth > labelWidth) 00350 { 00351 // we estimated too long 00352 // remove letters while text > label 00353 do 00354 { 00355 letters--; 00356 squeezedText = fullText.left(letters) + "..." + fullText.right(letters); 00357 squeezedWidth = fm.width(squeezedText); 00358 } while (squeezedWidth > labelWidth); 00359 } 00360 00361 if (letters < 5) 00362 { 00363 // too few letters added -> we give up squeezing 00364 QLineEdit::setText(fullText); 00365 } 00366 else 00367 { 00368 QLineEdit::setText(squeezedText); 00369 d->squeezedStart = letters; 00370 d->squeezedEnd = fullText.length() - letters; 00371 } 00372 00373 QToolTip::remove( this ); 00374 QToolTip::add( this, fullText ); 00375 00376 } 00377 else 00378 { 00379 QLineEdit::setText(fullText); 00380 00381 QToolTip::remove( this ); 00382 QToolTip::hide(); 00383 } 00384 00385 setCursorPosition(0); 00386 } 00387 00388 void KLineEdit::copy() const 00389 { 00390 if (!d->squeezedText.isEmpty() && d->squeezedStart) 00391 { 00392 int start, end; 00393 KLineEdit *that = const_cast<KLineEdit *>(this); 00394 if (!that->getSelection(&start, &end)) 00395 return; 00396 if (start >= d->squeezedStart+3) 00397 start = start - 3 - d->squeezedStart + d->squeezedEnd; 00398 else if (start > d->squeezedStart) 00399 start = d->squeezedStart; 00400 if (end >= d->squeezedStart+3) 00401 end = end - 3 - d->squeezedStart + d->squeezedEnd; 00402 else if (end > d->squeezedStart) 00403 end = d->squeezedEnd; 00404 if (start == end) 00405 return; 00406 QString t = d->squeezedText; 00407 t = t.mid(start, end - start); 00408 disconnect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0); 00409 QApplication::clipboard()->setText( t ); 00410 connect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, 00411 SLOT(clipboardChanged()) ); 00412 return; 00413 } 00414 00415 QLineEdit::copy(); 00416 } 00417 00418 void KLineEdit::resizeEvent( QResizeEvent * ev ) 00419 { 00420 if (!d->squeezedText.isEmpty()) 00421 setSqueezedText(); 00422 00423 QLineEdit::resizeEvent(ev); 00424 } 00425 00426 void KLineEdit::keyPressEvent( QKeyEvent *e ) 00427 { 00428 KKey key( e ); 00429 00430 if ( KStdAccel::copy().contains( key ) ) 00431 { 00432 copy(); 00433 return; 00434 } 00435 else if ( KStdAccel::paste().contains( key ) ) 00436 { 00437 paste(); 00438 return; 00439 } 00440 else if ( KStdAccel::pasteSelection().contains( key ) ) 00441 { 00442 QString text = QApplication::clipboard()->text( QClipboard::Selection); 00443 insert( text ); 00444 deselect(); 00445 return; 00446 } 00447 00448 else if ( KStdAccel::cut().contains( key ) ) 00449 { 00450 cut(); 00451 return; 00452 } 00453 else if ( KStdAccel::undo().contains( key ) ) 00454 { 00455 undo(); 00456 return; 00457 } 00458 else if ( KStdAccel::redo().contains( key ) ) 00459 { 00460 redo(); 00461 return; 00462 } 00463 else if ( KStdAccel::deleteWordBack().contains( key ) ) 00464 { 00465 cursorWordBackward(true); 00466 if ( hasSelectedText() ) 00467 del(); 00468 00469 e->accept(); 00470 return; 00471 } 00472 else if ( KStdAccel::deleteWordForward().contains( key ) ) 00473 { 00474 // Workaround for QT bug where 00475 cursorWordForward(true); 00476 if ( hasSelectedText() ) 00477 del(); 00478 00479 e->accept(); 00480 return; 00481 } 00482 else if ( KStdAccel::backwardWord().contains( key ) ) 00483 { 00484 cursorWordBackward(false); 00485 e->accept(); 00486 return; 00487 } 00488 else if ( KStdAccel::forwardWord().contains( key ) ) 00489 { 00490 cursorWordForward(false); 00491 e->accept(); 00492 return; 00493 } 00494 else if ( KStdAccel::beginningOfLine().contains( key ) ) 00495 { 00496 home(false); 00497 e->accept(); 00498 return; 00499 } 00500 else if ( KStdAccel::endOfLine().contains( key ) ) 00501 { 00502 end(false); 00503 e->accept(); 00504 return; 00505 } 00506 00507 00508 // Filter key-events if EchoMode is normal and 00509 // completion mode is not set to CompletionNone 00510 if ( echoMode() == QLineEdit::Normal && 00511 completionMode() != KGlobalSettings::CompletionNone ) 00512 { 00513 KeyBindingMap keys = getKeyBindings(); 00514 KGlobalSettings::Completion mode = completionMode(); 00515 bool noModifier = (e->state() == NoButton || 00516 e->state() == ShiftButton || 00517 e->state() == Keypad); 00518 00519 if ( (mode == KGlobalSettings::CompletionAuto || 00520 mode == KGlobalSettings::CompletionPopupAuto || 00521 mode == KGlobalSettings::CompletionMan) && noModifier ) 00522 { 00523 if ( !d->userSelection && hasSelectedText() && 00524 ( e->key() == Key_Right || e->key() == Key_Left ) && 00525 e->state()==NoButton ) 00526 { 00527 QString old_txt = text(); 00528 d->disableRestoreSelection = true; 00529 int start,end; 00530 getSelection(&start, &end); 00531 00532 deselect(); 00533 QLineEdit::keyPressEvent ( e ); 00534 int cPosition=cursorPosition(); 00535 if (e->key() ==Key_Right && cPosition > start ) 00536 validateAndSet(old_txt, cPosition, cPosition, old_txt.length()); 00537 else 00538 validateAndSet(old_txt, cPosition, start, old_txt.length()); 00539 00540 d->disableRestoreSelection = false; 00541 return; 00542 } 00543 00544 if ( e->key() == Key_Escape ) 00545 { 00546 if (hasSelectedText() && !d->userSelection ) 00547 { 00548 del(); 00549 setUserSelection(true); 00550 } 00551 00552 // Don't swallow the Escape press event for the case 00553 // of dialogs, which have Escape associated to Cancel 00554 e->ignore(); 00555 return; 00556 } 00557 00558 } 00559 00560 if ( (mode == KGlobalSettings::CompletionAuto || 00561 mode == KGlobalSettings::CompletionMan) && noModifier ) 00562 { 00563 QString keycode = e->text(); 00564 if ( !keycode.isEmpty() && (keycode.unicode()->isPrint() || 00565 e->key() == Key_Backspace || e->key() == Key_Delete ) ) 00566 { 00567 bool hasUserSelection=d->userSelection; 00568 bool hadSelection=hasSelectedText(); 00569 00570 bool cursorNotAtEnd=false; 00571 00572 int start,end; 00573 getSelection(&start, &end); 00574 int cPos = cursorPosition(); 00575 00576 // When moving the cursor, we want to keep the autocompletion as an 00577 // autocompletion, so we want to process events at the cursor position 00578 // as if there was no selection. After processing the key event, we 00579 // can set the new autocompletion again. 00580 if ( hadSelection && !hasUserSelection && start>cPos ) 00581 { 00582 del(); 00583 setCursorPosition(cPos); 00584 cursorNotAtEnd=true; 00585 } 00586 00587 d->disableRestoreSelection = true; 00588 QLineEdit::keyPressEvent ( e ); 00589 d->disableRestoreSelection = false; 00590 00591 QString txt = text(); 00592 int len = txt.length(); 00593 if ( !hasSelectedText() && len /*&& cursorPosition() == len */) 00594 { 00595 if ( e->key() == Key_Backspace ) 00596 { 00597 if ( hadSelection && !hasUserSelection && !cursorNotAtEnd ) 00598 { 00599 backspace(); 00600 txt = text(); 00601 len = txt.length(); 00602 } 00603 00604 if ( !d->backspacePerformsCompletion || !len ) 00605 d->autoSuggest = false; 00606 } 00607 00608 if (e->key() == Key_Delete ) 00609 d->autoSuggest=false; 00610 00611 if ( emitSignals() ) 00612 emit completion( txt ); 00613 00614 if ( handleSignals() ) 00615 makeCompletion( txt ); 00616 00617 if( (e->key() == Key_Backspace || e->key() == Key_Delete) ) 00618 d->autoSuggest=true; 00619 00620 e->accept(); 00621 } 00622 00623 return; 00624 } 00625 00626 } 00627 00628 else if (( mode == KGlobalSettings::CompletionPopup || 00629 mode == KGlobalSettings::CompletionPopupAuto ) && 00630 noModifier && !e->text().isEmpty() ) 00631 { 00632 QString old_txt = text(); 00633 bool hasUserSelection=d->userSelection; 00634 bool hadSelection=hasSelectedText(); 00635 bool cursorNotAtEnd=false; 00636 00637 int start,end; 00638 getSelection(&start, &end); 00639 int cPos = cursorPosition(); 00640 QString keycode = e->text(); 00641 00642 // When moving the cursor, we want to keep the autocompletion as an 00643 // autocompletion, so we want to process events at the cursor position 00644 // as if there was no selection. After processing the key event, we 00645 // can set the new autocompletion again. 00646 if (hadSelection && !hasUserSelection && start>cPos && 00647 ( (!keycode.isEmpty() && keycode.unicode()->isPrint()) || 00648 e->key() == Key_Backspace || e->key() == Key_Delete ) ) 00649 { 00650 del(); 00651 setCursorPosition(cPos); 00652 cursorNotAtEnd=true; 00653 } 00654 00655 uint selectedLength=selectedText().length(); 00656 00657 d->disableRestoreSelection = true; 00658 QLineEdit::keyPressEvent ( e ); 00659 d->disableRestoreSelection = false; 00660 00661 if (( selectedLength != selectedText().length() ) && !hasUserSelection ) 00662 slotRestoreSelectionColors(); // and set userSelection to true 00663 00664 QString txt = text(); 00665 int len = txt.length(); 00666 00667 if ( txt != old_txt && len/* && ( cursorPosition() == len || force )*/ && 00668 ( (!keycode.isEmpty() && keycode.unicode()->isPrint()) || 00669 e->key() == Key_Backspace || e->key() == Key_Delete) ) 00670 { 00671 if ( e->key() == Key_Backspace ) 00672 { 00673 if ( hadSelection && !hasUserSelection && !cursorNotAtEnd ) 00674 { 00675 backspace(); 00676 txt = text(); 00677 len = txt.length(); 00678 } 00679 00680 if ( !d->backspacePerformsCompletion ) 00681 d->autoSuggest = false; 00682 } 00683 00684 if (e->key() == Key_Delete ) 00685 d->autoSuggest=false; 00686 00687 if ( d->completionBox ) 00688 d->completionBox->setCancelledText( txt ); 00689 00690 if ( emitSignals() ) 00691 emit completion( txt ); // emit when requested... 00692 00693 if ( handleSignals() ) { 00694 makeCompletion( txt ); // handle when requested... 00695 } 00696 00697 if ( (e->key() == Key_Backspace || e->key() == Key_Delete ) && 00698 mode == KGlobalSettings::CompletionPopupAuto ) 00699 d->autoSuggest=true; 00700 00701 e->accept(); 00702 } 00703 else if (!len && d->completionBox && d->completionBox->isVisible()) 00704 d->completionBox->hide(); 00705 00706 return; 00707 } 00708 00709 else if ( mode == KGlobalSettings::CompletionShell ) 00710 { 00711 // Handles completion. 00712 KShortcut cut; 00713 if ( keys[TextCompletion].isNull() ) 00714 cut = KStdAccel::shortcut(KStdAccel::TextCompletion); 00715 else 00716 cut = keys[TextCompletion]; 00717 00718 if ( cut.contains( key ) ) 00719 { 00720 // Emit completion if the completion mode is CompletionShell 00721 // and the cursor is at the end of the string. 00722 QString txt = text(); 00723 int len = txt.length(); 00724 if ( cursorPosition() == len && len != 0 ) 00725 { 00726 if ( emitSignals() ) 00727 emit completion( txt ); 00728 if ( handleSignals() ) 00729 makeCompletion( txt ); 00730 return; 00731 } 00732 } 00733 else if ( d->completionBox ) 00734 d->completionBox->hide(); 00735 } 00736 00737 // handle rotation 00738 if ( mode != KGlobalSettings::CompletionNone ) 00739 { 00740 // Handles previous match 00741 KShortcut cut; 00742 if ( keys[PrevCompletionMatch].isNull() ) 00743 cut = KStdAccel::shortcut(KStdAccel::PrevCompletion); 00744 else 00745 cut = keys[PrevCompletionMatch]; 00746 00747 if ( cut.contains( key ) ) 00748 { 00749 if ( emitSignals() ) 00750 emit textRotation( KCompletionBase::PrevCompletionMatch ); 00751 if ( handleSignals() ) 00752 rotateText( KCompletionBase::PrevCompletionMatch ); 00753 return; 00754 } 00755 00756 // Handles next match 00757 if ( keys[NextCompletionMatch].isNull() ) 00758 cut = KStdAccel::shortcut(KStdAccel::NextCompletion); 00759 else 00760 cut = keys[NextCompletionMatch]; 00761 00762 if ( cut.contains( key ) ) 00763 { 00764 if ( emitSignals() ) 00765 emit textRotation( KCompletionBase::NextCompletionMatch ); 00766 if ( handleSignals() ) 00767 rotateText( KCompletionBase::NextCompletionMatch ); 00768 return; 00769 } 00770 } 00771 00772 // substring completion 00773 if ( compObj() ) 00774 { 00775 KShortcut cut; 00776 if ( keys[SubstringCompletion].isNull() ) 00777 cut = KStdAccel::shortcut(KStdAccel::SubstringCompletion); 00778 else 00779 cut = keys[SubstringCompletion]; 00780 00781 if ( cut.contains( key ) ) 00782 { 00783 if ( emitSignals() ) 00784 emit substringCompletion( text() ); 00785 if ( handleSignals() ) 00786 { 00787 setCompletedItems( compObj()->substringCompletion(text())); 00788 e->accept(); 00789 } 00790 return; 00791 } 00792 } 00793 } 00794 00795 uint selectedLength = selectedText().length(); 00796 00797 // Let QLineEdit handle any other keys events. 00798 QLineEdit::keyPressEvent ( e ); 00799 00800 if ( selectedLength != selectedText().length() ) 00801 slotRestoreSelectionColors(); // and set userSelection to true 00802 } 00803 00804 void KLineEdit::mouseDoubleClickEvent( QMouseEvent* e ) 00805 { 00806 if ( e->button() == Qt::LeftButton ) 00807 { 00808 possibleTripleClick=true; 00809 QTimer::singleShot( QApplication::doubleClickInterval(),this, 00810 SLOT(tripleClickTimeout()) ); 00811 } 00812 QLineEdit::mouseDoubleClickEvent( e ); 00813 } 00814 00815 void KLineEdit::mousePressEvent( QMouseEvent* e ) 00816 { 00817 if ( possibleTripleClick && e->button() == Qt::LeftButton ) 00818 { 00819 selectAll(); 00820 e->accept(); 00821 return; 00822 } 00823 QLineEdit::mousePressEvent( e ); 00824 } 00825 00826 void KLineEdit::tripleClickTimeout() 00827 { 00828 possibleTripleClick=false; 00829 } 00830 00831 void KLineEdit::contextMenuEvent( QContextMenuEvent * e ) 00832 { 00833 if ( m_bEnableMenu ) 00834 QLineEdit::contextMenuEvent( e ); 00835 } 00836 00837 QPopupMenu *KLineEdit::createPopupMenu() 00838 { 00839 enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll }; 00840 00841 QPopupMenu *popup = QLineEdit::createPopupMenu(); 00842 00843 int id = popup->idAt(0); 00844 popup->changeItem( id - IdUndo, SmallIconSet("undo"), popup->text( id - IdUndo) ); 00845 popup->changeItem( id - IdRedo, SmallIconSet("redo"), popup->text( id - IdRedo) ); 00846 popup->changeItem( id - IdCut, SmallIconSet("editcut"), popup->text( id - IdCut) ); 00847 popup->changeItem( id - IdCopy, SmallIconSet("editcopy"), popup->text( id - IdCopy) ); 00848 popup->changeItem( id - IdPaste, SmallIconSet("editpaste"), popup->text( id - IdPaste) ); 00849 popup->changeItem( id - IdClear, SmallIconSet("editclear"), popup->text( id - IdClear) ); 00850 00851 // If a completion object is present and the input 00852 // widget is not read-only, show the Text Completion 00853 // menu item. 00854 if ( compObj() && !isReadOnly() && kapp->authorize("lineedit_text_completion") ) 00855 { 00856 QPopupMenu *subMenu = new QPopupMenu( popup ); 00857 connect( subMenu, SIGNAL( activated( int ) ), 00858 this, SLOT( completionMenuActivated( int ) ) ); 00859 00860 popup->insertSeparator(); 00861 popup->insertItem( SmallIconSet("completion"), i18n("Text Completion"), 00862 subMenu ); 00863 00864 subMenu->insertItem( i18n("None"), NoCompletion ); 00865 subMenu->insertItem( i18n("Manual"), ShellCompletion ); 00866 subMenu->insertItem( i18n("Automatic"), AutoCompletion ); 00867 subMenu->insertItem( i18n("Dropdown List"), PopupCompletion ); 00868 subMenu->insertItem( i18n("Short Automatic"), ShortAutoCompletion ); 00869 subMenu->insertItem( i18n("Dropdown List && Automatic"), PopupAutoCompletion ); 00870 00871 subMenu->setAccel( KStdAccel::completion(), ShellCompletion ); 00872 00873 KGlobalSettings::Completion mode = completionMode(); 00874 subMenu->setItemChecked( NoCompletion, 00875 mode == KGlobalSettings::CompletionNone ); 00876 subMenu->setItemChecked( ShellCompletion, 00877 mode == KGlobalSettings::CompletionShell ); 00878 subMenu->setItemChecked( PopupCompletion, 00879 mode == KGlobalSettings::CompletionPopup ); 00880 subMenu->setItemChecked( AutoCompletion, 00881 mode == KGlobalSettings::CompletionAuto ); 00882 subMenu->setItemChecked( ShortAutoCompletion, 00883 mode == KGlobalSettings::CompletionMan ); 00884 subMenu->setItemChecked( PopupAutoCompletion, 00885 mode == KGlobalSettings::CompletionPopupAuto ); 00886 if ( mode != KGlobalSettings::completionMode() ) 00887 { 00888 subMenu->insertSeparator(); 00889 subMenu->insertItem( i18n("Default"), Default ); 00890 } 00891 } 00892 00893 // ### do we really need this? Yes, Please do not remove! This 00894 // allows applications to extend the popup menu without having to 00895 // inherit from this class! (DA) 00896 emit aboutToShowContextMenu( popup ); 00897 00898 return popup; 00899 } 00900 00901 void KLineEdit::completionMenuActivated( int id ) 00902 { 00903 KGlobalSettings::Completion oldMode = completionMode(); 00904 00905 switch ( id ) 00906 { 00907 case Default: 00908 setCompletionMode( KGlobalSettings::completionMode() ); 00909 break; 00910 case NoCompletion: 00911 setCompletionMode( KGlobalSettings::CompletionNone ); 00912 break; 00913 case AutoCompletion: 00914 setCompletionMode( KGlobalSettings::CompletionAuto ); 00915 break; 00916 case ShortAutoCompletion: 00917 setCompletionMode( KGlobalSettings::CompletionMan ); 00918 break; 00919 case ShellCompletion: 00920 setCompletionMode( KGlobalSettings::CompletionShell ); 00921 break; 00922 case PopupCompletion: 00923 setCompletionMode( KGlobalSettings::CompletionPopup ); 00924 break; 00925 case PopupAutoCompletion: 00926 setCompletionMode( KGlobalSettings::CompletionPopupAuto ); 00927 break; 00928 default: 00929 return; 00930 } 00931 00932 if ( oldMode != completionMode() ) 00933 { 00934 if ( (oldMode == KGlobalSettings::CompletionPopup || 00935 oldMode == KGlobalSettings::CompletionPopupAuto ) && 00936 d->completionBox && d->completionBox->isVisible() ) 00937 d->completionBox->hide(); 00938 emit completionModeChanged( completionMode() ); 00939 } 00940 } 00941 00942 void KLineEdit::dropEvent(QDropEvent *e) 00943 { 00944 KURL::List urlList; 00945 if( d->handleURLDrops && KURLDrag::decode( e, urlList ) ) 00946 { 00947 QString dropText = text(); 00948 KURL::List::ConstIterator it; 00949 for( it = urlList.begin() ; it != urlList.end() ; ++it ) 00950 { 00951 if(!dropText.isEmpty()) 00952 dropText+=' '; 00953 00954 dropText += (*it).prettyURL(); 00955 } 00956 00957 validateAndSet( dropText, dropText.length(), 0, 0); 00958 00959 e->accept(); 00960 } 00961 else 00962 QLineEdit::dropEvent(e); 00963 } 00964 00965 bool KLineEdit::eventFilter( QObject* o, QEvent* ev ) 00966 { 00967 if( o == this ) 00968 { 00969 KCursor::autoHideEventFilter( this, ev ); 00970 if ( ev->type() == QEvent::AccelOverride ) 00971 { 00972 QKeyEvent *e = static_cast<QKeyEvent *>( ev ); 00973 if (overrideAccel (e)) 00974 { 00975 e->accept(); 00976 return true; 00977 } 00978 } 00979 else if( ev->type() == QEvent::KeyPress ) 00980 { 00981 QKeyEvent *e = static_cast<QKeyEvent *>( ev ); 00982 00983 if( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter ) 00984 { 00985 bool trap = d->completionBox && d->completionBox->isVisible(); 00986 00987 bool stopEvent = trap || (d->grabReturnKeyEvents && 00988 (e->state() == NoButton || 00989 e->state() == Keypad)); 00990 00991 // Qt will emit returnPressed() itself if we return false 00992 if ( stopEvent ) 00993 { 00994 emit QLineEdit::returnPressed(); 00995 e->accept (); 00996 } 00997 00998 emit returnPressed( displayText() ); 00999 01000 if ( trap ) 01001 { 01002 d->completionBox->hide(); 01003 deselect(); 01004 setCursorPosition(text().length()); 01005 } 01006 01007 // Eat the event if the user asked for it, or if a completionbox was visible 01008 return stopEvent; 01009 } 01010 } 01011 } 01012 return QLineEdit::eventFilter( o, ev ); 01013 } 01014 01015 01016 void KLineEdit::setURLDropsEnabled(bool enable) 01017 { 01018 d->handleURLDrops=enable; 01019 } 01020 01021 bool KLineEdit::isURLDropsEnabled() const 01022 { 01023 return d->handleURLDrops; 01024 } 01025 01026 void KLineEdit::setTrapReturnKey( bool grab ) 01027 { 01028 d->grabReturnKeyEvents = grab; 01029 } 01030 01031 bool KLineEdit::trapReturnKey() const 01032 { 01033 return d->grabReturnKeyEvents; 01034 } 01035 01036 void KLineEdit::setURL( const KURL& url ) 01037 { 01038 setText( url.prettyURL() ); 01039 } 01040 01041 void KLineEdit::setCompletionBox( KCompletionBox *box ) 01042 { 01043 if ( d->completionBox ) 01044 return; 01045 01046 d->completionBox = box; 01047 if ( handleSignals() ) 01048 { 01049 connect( d->completionBox, SIGNAL(highlighted( const QString& )), 01050 SLOT(setTextWorkaround( const QString& )) ); 01051 connect( d->completionBox, SIGNAL(userCancelled( const QString& )), 01052 SLOT(userCancelled( const QString& )) ); 01053 01054 connect( d->completionBox, SIGNAL( activated( const QString& )), 01055 SIGNAL(completionBoxActivated( const QString& )) ); 01056 } 01057 } 01058 01059 void KLineEdit::userCancelled(const QString & cancelText) 01060 { 01061 if ( completionMode() != KGlobalSettings::CompletionPopupAuto ) 01062 { 01063 setText(cancelText); 01064 } 01065 else if (hasSelectedText() ) 01066 { 01067 if (d->userSelection) 01068 deselect(); 01069 else 01070 { 01071 d->autoSuggest=false; 01072 int start,end; 01073 getSelection(&start, &end); 01074 QString s=text().remove(start, end-start+1); 01075 validateAndSet(s,start,s.length(),s.length()); 01076 d->autoSuggest=true; 01077 } 01078 } 01079 } 01080 01081 bool KLineEdit::overrideAccel (const QKeyEvent* e) 01082 { 01083 KShortcut scKey; 01084 01085 KKey key( e ); 01086 KeyBindingMap keys = getKeyBindings(); 01087 01088 if (keys[TextCompletion].isNull()) 01089 scKey = KStdAccel::shortcut(KStdAccel::TextCompletion); 01090 else 01091 scKey = keys[TextCompletion]; 01092 01093 if (scKey.contains( key )) 01094 return true; 01095 01096 if (keys[NextCompletionMatch].isNull()) 01097 scKey = KStdAccel::shortcut(KStdAccel::NextCompletion); 01098 else 01099 scKey = keys[NextCompletionMatch]; 01100 01101 if (scKey.contains( key )) 01102 return true; 01103 01104 if (keys[PrevCompletionMatch].isNull()) 01105 scKey = KStdAccel::shortcut(KStdAccel::PrevCompletion); 01106 else 01107 scKey = keys[PrevCompletionMatch]; 01108 01109 if (scKey.contains( key )) 01110 return true; 01111 01112 // Override all the text manupilation accelerators... 01113 if ( KStdAccel::copy().contains( key ) ) 01114 return true; 01115 else if ( KStdAccel::paste().contains( key ) ) 01116 return true; 01117 else if ( KStdAccel::cut().contains( key ) ) 01118 return true; 01119 else if ( KStdAccel::undo().contains( key ) ) 01120 return true; 01121 else if ( KStdAccel::redo().contains( key ) ) 01122 return true; 01123 else if (KStdAccel::deleteWordBack().contains( key )) 01124 return true; 01125 else if (KStdAccel::deleteWordForward().contains( key )) 01126 return true; 01127 else if (KStdAccel::forwardWord().contains( key )) 01128 return true; 01129 else if (KStdAccel::backwardWord().contains( key )) 01130 return true; 01131 else if (KStdAccel::beginningOfLine().contains( key )) 01132 return true; 01133 else if (KStdAccel::endOfLine().contains( key )) 01134 return true; 01135 01136 if (d->completionBox && d->completionBox->isVisible ()) 01137 { 01138 int key = e->key(); 01139 ButtonState state = e->state(); 01140 if ((key == Key_Backtab || key == Key_Tab) && 01141 (state == NoButton || (state & ShiftButton))) 01142 { 01143 return true; 01144 } 01145 } 01146 01147 01148 return false; 01149 } 01150 01151 void KLineEdit::setCompletedItems( const QStringList& items ) 01152 { 01153 setCompletedItems( items, true ); 01154 } 01155 01156 void KLineEdit::setCompletedItems( const QStringList& items, bool autoSuggest ) 01157 { 01158 QString txt; 01159 if ( d->completionBox && d->completionBox->isVisible() ) { 01160 // The popup is visible already - do the matching on the initial string, 01161 // not on the currently selected one. 01162 txt = completionBox()->cancelledText(); 01163 } else { 01164 txt = text(); 01165 } 01166 01167 if ( !items.isEmpty() && 01168 !(items.count() == 1 && txt == items.first()) ) 01169 { 01170 // create completion box if non-existent 01171 completionBox(); 01172 01173 if ( d->completionBox->isVisible() ) 01174 { 01175 bool wasSelected = d->completionBox->isSelected( d->completionBox->currentItem() ); 01176 const QString currentSelection = d->completionBox->currentText(); 01177 d->completionBox->setItems( items ); 01178 QListBoxItem* item = d->completionBox->findItem( currentSelection, Qt::ExactMatch ); 01179 // If no item is selected, that means the listbox hasn't been manipulated by the user yet, 01180 // because it's not possible otherwise to have no selected item. In such case make 01181 // always the first item current and unselected, so that the current item doesn't jump. 01182 if( !item || !wasSelected ) 01183 { 01184 wasSelected = false; 01185 item = d->completionBox->item( 0 ); 01186 } 01187 if ( item ) 01188 { 01189 d->completionBox->blockSignals( true ); 01190 d->completionBox->setCurrentItem( item ); 01191 d->completionBox->setSelected( item, wasSelected ); 01192 d->completionBox->blockSignals( false ); 01193 } 01194 } 01195 else // completion box not visible yet -> show it 01196 { 01197 if ( !txt.isEmpty() ) 01198 d->completionBox->setCancelledText( txt ); 01199 d->completionBox->setItems( items ); 01200 d->completionBox->popup(); 01201 } 01202 01203 if ( d->autoSuggest && autoSuggest ) 01204 { 01205 int index = items.first().find( txt ); 01206 QString newText = items.first().mid( index ); 01207 setUserSelection(false); 01208 setCompletedText(newText,true); 01209 } 01210 } 01211 else 01212 { 01213 if ( d->completionBox && d->completionBox->isVisible() ) 01214 d->completionBox->hide(); 01215 } 01216 } 01217 01218 KCompletionBox * KLineEdit::completionBox( bool create ) 01219 { 01220 if ( create && !d->completionBox ) 01221 setCompletionBox( new KCompletionBox( this, "completion box" ) ); 01222 01223 return d->completionBox; 01224 } 01225 01226 void KLineEdit::setCompletionObject( KCompletion* comp, bool hsig ) 01227 { 01228 KCompletion *oldComp = compObj(); 01229 if ( oldComp && handleSignals() ) 01230 disconnect( oldComp, SIGNAL( matches( const QStringList& )), 01231 this, SLOT( setCompletedItems( const QStringList& ))); 01232 01233 if ( comp && hsig ) 01234 connect( comp, SIGNAL( matches( const QStringList& )), 01235 this, SLOT( setCompletedItems( const QStringList& ))); 01236 01237 KCompletionBase::setCompletionObject( comp, hsig ); 01238 } 01239 01240 // QWidget::create() turns off mouse-Tracking which would break auto-hiding 01241 void KLineEdit::create( WId id, bool initializeWindow, bool destroyOldWindow ) 01242 { 01243 QLineEdit::create( id, initializeWindow, destroyOldWindow ); 01244 KCursor::setAutoHideCursor( this, true, true ); 01245 } 01246 01247 void KLineEdit::setUserSelection(bool userSelection) 01248 { 01249 QPalette p = palette(); 01250 01251 if (userSelection) 01252 { 01253 p.setColor(QColorGroup::Highlight, d->previousHighlightColor); 01254 p.setColor(QColorGroup::HighlightedText, d->previousHighlightedTextColor); 01255 } 01256 else 01257 { 01258 QColor color=p.color(QPalette::Disabled, QColorGroup::Text); 01259 p.setColor(QColorGroup::HighlightedText, color); 01260 color=p.color(QPalette::Active, QColorGroup::Base); 01261 p.setColor(QColorGroup::Highlight, color); 01262 } 01263 01264 d->userSelection=userSelection; 01265 setPalette(p); 01266 } 01267 01268 void KLineEdit::slotRestoreSelectionColors() 01269 { 01270 if (d->disableRestoreSelection) 01271 return; 01272 01273 setUserSelection(true); 01274 } 01275 01276 void KLineEdit::clear() 01277 { 01278 setText( QString::null ); 01279 } 01280 01281 void KLineEdit::setTextWorkaround( const QString& text ) 01282 { 01283 setText( text ); 01284 end( false ); // force cursor at end 01285 } 01286 01287 QString KLineEdit::originalText() const 01288 { 01289 if ( d->enableSqueezedText && isReadOnly() ) 01290 return d->squeezedText; 01291 01292 return text(); 01293 } 01294 01295 void KLineEdit::focusInEvent( QFocusEvent* ev) 01296 { 01297 // Don't selectAll() in QLineEdit::focusInEvent if selection exists 01298 if ( ev->reason() == QFocusEvent::Tab && inputMask().isNull() && hasSelectedText() ) 01299 return; 01300 01301 QLineEdit::focusInEvent(ev); 01302 } 01303 01304 bool KLineEdit::autoSuggest() const 01305 { 01306 return d->autoSuggest; 01307 } 01308 01309 void KLineEdit::virtual_hook( int id, void* data ) 01310 { KCompletionBase::virtual_hook( id, data ); }
KDE Logo
This file is part of the documentation for kdeui Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:10:13 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003