kdeui Library API Documentation

klineedit.cpp

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