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