klineedit.cpp
/* This file is part of the KDE libraries
Copyright (C) 1997 Sven Radej (sven.radej@iname.com)
Copyright (c) 1999 Patrick Ward <PAT_WARD@HP-USA-om5.om.hp.com>
Copyright (c) 1999 Preston Brown <pbrown@kde.org>
Re-designed for KDE 2.x by
Copyright (c) 2000, 2001 Dawit Alemayehu <adawit@kde.org>
Copyright (c) 2000, 2001 Carsten Pfeiffer <pfeiffer@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License (LGPL) as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later
version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <qclipboard.h>
#include <qpainter.h>
#include <qtimer.h>
#include <kconfig.h>
#include <qtooltip.h>
#include <kcursor.h>
#include <klocale.h>
#include <kstdaccel.h>
#include <kpopupmenu.h>
#include <kdebug.h>
#include <kcompletionbox.h>
#include <kurl.h>
#include <kurldrag.h>
#include <kiconloader.h>
#include <kapplication.h>
#include "klineedit.h"
#include "klineedit.moc"
class KLineEdit::KLineEditPrivate
{
public:
KLineEditPrivate()
{
completionBox = 0L;
handleURLDrops = true;
grabReturnKeyEvents = false;
userSelection = true;
autoSuggest = false;
disableRestoreSelection = false;
enableSqueezedText = false;
if ( !initialized )
{
KConfigGroup config( KGlobal::config(), "General" );
backspacePerformsCompletion = config.readBoolEntry( "Backspace performs completion", false );
initialized = true;
}
}
~KLineEditPrivate()
{
// causes a weird crash in KWord at least, so let Qt delete it for us.
// delete completionBox;
}
static bool initialized;
static bool backspacePerformsCompletion; // Configuration option
QColor previousHighlightColor;
QColor previousHighlightedTextColor;
bool userSelection: 1;
bool autoSuggest : 1;
bool disableRestoreSelection: 1;
bool handleURLDrops:1;
bool grabReturnKeyEvents:1;
bool enableSqueezedText:1;
int squeezedEnd;
int squeezedStart;
BackgroundMode bgMode;
QString squeezedText;
KCompletionBox *completionBox;
QString clickMessage;
bool drawClickMsg:1;
};
bool KLineEdit::KLineEditPrivate::backspacePerformsCompletion = false;
bool KLineEdit::KLineEditPrivate::initialized = false;
KLineEdit::KLineEdit( const QString &string, QWidget *parent, const char *name )
:QLineEdit( string, parent, name )
{
init();
}
KLineEdit::KLineEdit( QWidget *parent, const char *name )
:QLineEdit( parent, name )
{
init();
}
KLineEdit::~KLineEdit ()
{
delete d;
d = 0;
}
void KLineEdit::init()
{
d = new KLineEditPrivate;
possibleTripleClick = false;
d->bgMode = backgroundMode ();
// Enable the context menu by default.
KLineEdit::setContextMenuEnabled( true );
KCursor::setAutoHideCursor( this, true, true );
installEventFilter( this );
KGlobalSettings::Completion mode = completionMode();
d->autoSuggest = (mode == KGlobalSettings::CompletionMan ||
mode == KGlobalSettings::CompletionPopupAuto ||
mode == KGlobalSettings::CompletionAuto);
connect( this, SIGNAL(selectionChanged()), this, SLOT(slotRestoreSelectionColors()));
QPalette p = palette();
if ( !d->previousHighlightedTextColor.isValid() )
d->previousHighlightedTextColor=p.color(QPalette::Normal,QColorGroup::HighlightedText);
if ( !d->previousHighlightColor.isValid() )
d->previousHighlightColor=p.color(QPalette::Normal,QColorGroup::Highlight);
d->drawClickMsg = false;
}
void KLineEdit::setCompletionMode( KGlobalSettings::Completion mode )
{
KGlobalSettings::Completion oldMode = completionMode();
if ( oldMode != mode && (oldMode == KGlobalSettings::CompletionPopup ||
oldMode == KGlobalSettings::CompletionPopupAuto ) &&
d->completionBox && d->completionBox->isVisible() )
d->completionBox->hide();
// If the widgets echo mode is not Normal, no completion
// feature will be enabled even if one is requested.
if ( echoMode() != QLineEdit::Normal )
mode = KGlobalSettings::CompletionNone; // Override the request.
if ( kapp && !kapp->authorize("lineedit_text_completion") )
mode = KGlobalSettings::CompletionNone;
if ( mode == KGlobalSettings::CompletionPopupAuto ||
mode == KGlobalSettings::CompletionAuto ||
mode == KGlobalSettings::CompletionMan )
d->autoSuggest = true;
else
d->autoSuggest = false;
KCompletionBase::setCompletionMode( mode );
}
void KLineEdit::setCompletedText( const QString& t, bool marked )
{
if ( !d->autoSuggest )
return;
QString txt = text();
if ( t != txt )
{
int start = marked ? txt.length() : t.length();
validateAndSet( t, cursorPosition(), start, t.length() );
setUserSelection(false);
}
else
setUserSelection(true);
}
void KLineEdit::setCompletedText( const QString& text )
{
KGlobalSettings::Completion mode = completionMode();
bool marked = ( mode == KGlobalSettings::CompletionAuto ||
mode == KGlobalSettings::CompletionMan ||
mode == KGlobalSettings::CompletionPopup ||
mode == KGlobalSettings::CompletionPopupAuto );
setCompletedText( text, marked );
}
void KLineEdit::rotateText( KCompletionBase::KeyBindingType type )
{
KCompletion* comp = compObj();
if ( comp &&
(type == KCompletionBase::PrevCompletionMatch ||
type == KCompletionBase::NextCompletionMatch ) )
{
QString input;
if (type == KCompletionBase::PrevCompletionMatch)
comp->previousMatch();
else
comp->nextMatch();
// Skip rotation if previous/next match is null or the same text
if ( input.isNull() || input == displayText() )
return;
setCompletedText( input, hasSelectedText() );
}
}
void KLineEdit::makeCompletion( const QString& text )
{
KCompletion *comp = compObj();
KGlobalSettings::Completion mode = completionMode();
if ( !comp || mode == KGlobalSettings::CompletionNone )
return; // No completion object...
QString match = comp->makeCompletion( text );
if ( mode == KGlobalSettings::CompletionPopup ||
mode == KGlobalSettings::CompletionPopupAuto )
{
if ( match.isNull() )
{
if ( d->completionBox )
{
d->completionBox->hide();
d->completionBox->clear();
}
}
else
setCompletedItems( comp->allMatches() );
}
else // Auto, ShortAuto (Man) and Shell
{
// all other completion modes
// If no match or the same match, simply return without completing.
if ( match.isNull() || match == text )
return;
if ( mode != KGlobalSettings::CompletionShell )
setUserSelection(false);
if ( d->autoSuggest )
setCompletedText( match );
}
}
void KLineEdit::setReadOnly(bool readOnly)
{
// Do not do anything if nothing changed...
if (readOnly == isReadOnly ())
return;
QLineEdit::setReadOnly (readOnly);
if (readOnly)
{
d->bgMode = backgroundMode ();
setBackgroundMode (Qt::PaletteBackground);
if (d->enableSqueezedText && d->squeezedText.isEmpty())
{
d->squeezedText = text();
setSqueezedText();
}
}
else
{
if (!d->squeezedText.isEmpty())
{
setText(d->squeezedText);
d->squeezedText = QString::null;
}
setBackgroundMode (d->bgMode);
}
}
void KLineEdit::setSqueezedText( const QString &text)
{
setEnableSqueezedText(true);
setText(text);
}
void KLineEdit::setEnableSqueezedText( bool enable )
{
d->enableSqueezedText = enable;
}
bool KLineEdit::isSqueezedTextEnabled() const
{
return d->enableSqueezedText;
}
void KLineEdit::setText( const QString& text )
{
d->drawClickMsg = text.isEmpty() && !d->clickMessage.isEmpty();
update();
if( d->enableSqueezedText && isReadOnly() )
{
d->squeezedText = text;
setSqueezedText();
return;
}
QLineEdit::setText( text );
}
void KLineEdit::setSqueezedText()
{
d->squeezedStart = 0;
d->squeezedEnd = 0;
QString fullText = d->squeezedText;
QFontMetrics fm(fontMetrics());
int labelWidth = size().width() - 2*frameWidth() - 2;
int textWidth = fm.width(fullText);
if (textWidth > labelWidth)
{
// start with the dots only
QString squeezedText = "...";
int squeezedWidth = fm.width(squeezedText);
// estimate how many letters we can add to the dots on both sides
int letters = fullText.length() * (labelWidth - squeezedWidth) / textWidth / 2;
squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
squeezedWidth = fm.width(squeezedText);
if (squeezedWidth < labelWidth)
{
// we estimated too short
// add letters while text < label
do
{
letters++;
squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
squeezedWidth = fm.width(squeezedText);
} while (squeezedWidth < labelWidth);
letters--;
squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
}
else if (squeezedWidth > labelWidth)
{
// we estimated too long
// remove letters while text > label
do
{
letters--;
squeezedText = fullText.left(letters) + "..." + fullText.right(letters);
squeezedWidth = fm.width(squeezedText);
} while (squeezedWidth > labelWidth);
}
if (letters < 5)
{
// too few letters added -> we give up squeezing
QLineEdit::setText(fullText);
}
else
{
QLineEdit::setText(squeezedText);
d->squeezedStart = letters;
d->squeezedEnd = fullText.length() - letters;
}
QToolTip::remove( this );
QToolTip::add( this, fullText );
}
else
{
QLineEdit::setText(fullText);
QToolTip::remove( this );
QToolTip::hide();
}
setCursorPosition(0);
}
void KLineEdit::copy() const
{
if( !copySqueezedText(true))
QLineEdit::copy();
}
bool KLineEdit::copySqueezedText(bool clipboard) const
{
if (!d->squeezedText.isEmpty() && d->squeezedStart)
{
int start, end;
KLineEdit *that = const_cast<KLineEdit *>(this);
if (!that->getSelection(&start, &end))
return false;
if (start >= d->squeezedStart+3)
start = start - 3 - d->squeezedStart + d->squeezedEnd;
else if (start > d->squeezedStart)
start = d->squeezedStart;
if (end >= d->squeezedStart+3)
end = end - 3 - d->squeezedStart + d->squeezedEnd;
else if (end > d->squeezedStart)
end = d->squeezedEnd;
if (start == end)
return false;
QString t = d->squeezedText;
t = t.mid(start, end - start);
disconnect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0);
QApplication::clipboard()->setText( t, clipboard ? QClipboard::Clipboard : QClipboard::Selection );
connect( QApplication::clipboard(), SIGNAL(selectionChanged()), this,
SLOT(clipboardChanged()) );
return true;
}
return false;
}
void KLineEdit::resizeEvent( QResizeEvent * ev )
{
if (!d->squeezedText.isEmpty())
setSqueezedText();
QLineEdit::resizeEvent(ev);
}
void KLineEdit::keyPressEvent( QKeyEvent *e )
{
KKey key( e );
if ( KStdAccel::copy().contains( key ) )
{
copy();
return;
}
else if ( KStdAccel::paste().contains( key ) )
{
paste();
return;
}
else if ( KStdAccel::pasteSelection().contains( key ) )
{
QString text = QApplication::clipboard()->text( QClipboard::Selection);
insert( text );
deselect();
return;
}
else if ( KStdAccel::cut().contains( key ) )
{
cut();
return;
}
else if ( KStdAccel::undo().contains( key ) )
{
undo();
return;
}
else if ( KStdAccel::redo().contains( key ) )
{
redo();
return;
}
else if ( KStdAccel::deleteWordBack().contains( key ) )
{
cursorWordBackward(true);
if ( hasSelectedText() )
del();
e->accept();
return;
}
else if ( KStdAccel::deleteWordForward().contains( key ) )
{
// Workaround for QT bug where
cursorWordForward(true);
if ( hasSelectedText() )
del();
e->accept();
return;
}
else if ( KStdAccel::backwardWord().contains( key ) )
{
cursorWordBackward(false);
e->accept();
return;
}
else if ( KStdAccel::forwardWord().contains( key ) )
{
cursorWordForward(false);
e->accept();
return;
}
else if ( KStdAccel::beginningOfLine().contains( key ) )
{
home(false);
e->accept();
return;
}
else if ( KStdAccel::endOfLine().contains( key ) )
{
end(false);
e->accept();
return;
}
// Filter key-events if EchoMode is normal and
// completion mode is not set to CompletionNone
if ( echoMode() == QLineEdit::Normal &&
completionMode() != KGlobalSettings::CompletionNone )
{
KeyBindingMap keys = getKeyBindings();
KGlobalSettings::Completion mode = completionMode();
bool noModifier = (e->state() == NoButton ||
e->state() == ShiftButton ||
e->state() == Keypad);
if ( (mode == KGlobalSettings::CompletionAuto ||
mode == KGlobalSettings::CompletionPopupAuto ||
mode == KGlobalSettings::CompletionMan) && noModifier )
{
if ( !d->userSelection && hasSelectedText() &&
( e->key() == Key_Right || e->key() == Key_Left ) &&
e->state()==NoButton )
{
QString old_txt = text();
d->disableRestoreSelection = true;
int start,end;
getSelection(&start, &end);
deselect();
QLineEdit::keyPressEvent ( e );
int cPosition=cursorPosition();
if (e->key() ==Key_Right && cPosition > start )
validateAndSet(old_txt, cPosition, cPosition, old_txt.length());
else
validateAndSet(old_txt, cPosition, start, old_txt.length());
d->disableRestoreSelection = false;
return;
}
if ( e->key() == Key_Escape )
{
if (hasSelectedText() && !d->userSelection )
{
del();
setUserSelection(true);
}
// Don't swallow the Escape press event for the case
// of dialogs, which have Escape associated to Cancel
e->ignore();
return;
}
}
if ( (mode == KGlobalSettings::CompletionAuto ||
mode == KGlobalSettings::CompletionMan) && noModifier )
{
QString keycode = e->text();
if ( !keycode.isEmpty() && (keycode.unicode()->isPrint() ||
e->key() == Key_Backspace || e->key() == Key_Delete ) )
{
bool hasUserSelection=d->userSelection;
bool hadSelection=hasSelectedText();
bool cursorNotAtEnd=false;
int start,end;
getSelection(&start, &end);
int cPos = cursorPosition();
// When moving the cursor, we want to keep the autocompletion as an
// autocompletion, so we want to process events at the cursor position
// as if there was no selection. After processing the key event, we
// can set the new autocompletion again.
if ( hadSelection && !hasUserSelection && start>cPos )
{
del();
setCursorPosition(cPos);
cursorNotAtEnd=true;
}
d->disableRestoreSelection = true;
QLineEdit::keyPressEvent ( e );
d->disableRestoreSelection = false;
QString txt = text();
int len = txt.length();
if ( !hasSelectedText() && len /*&& cursorPosition() == len */)
{
if ( e->key() == Key_Backspace )
{
if ( hadSelection && !hasUserSelection && !cursorNotAtEnd )
{
backspace();
txt = text();
len = txt.length();
}
if ( !d->backspacePerformsCompletion || !len )
d->autoSuggest = false;
}
if (e->key() == Key_Delete )
d->autoSuggest=false;
if ( emitSignals() )
emit completion( txt );
if ( handleSignals() )
makeCompletion( txt );
if( (e->key() == Key_Backspace || e->key() == Key_Delete) )
d->autoSuggest=true;
e->accept();
}
return;
}
}
else if (( mode == KGlobalSettings::CompletionPopup ||
mode == KGlobalSettings::CompletionPopupAuto ) &&
noModifier && !e->text().isEmpty() )
{
QString old_txt = text();
bool hasUserSelection=d->userSelection;
bool hadSelection=hasSelectedText();
bool cursorNotAtEnd=false;
int start,end;
getSelection(&start, &end);
int cPos = cursorPosition();
QString keycode = e->text();
// When moving the cursor, we want to keep the autocompletion as an
// autocompletion, so we want to process events at the cursor position
// as if there was no selection. After processing the key event, we
// can set the new autocompletion again.
if (hadSelection && !hasUserSelection && start>cPos &&
( (!keycode.isEmpty() && keycode.unicode()->isPrint()) ||
e->key() == Key_Backspace || e->key() == Key_Delete ) )
{
del();
setCursorPosition(cPos);
cursorNotAtEnd=true;
}
uint selectedLength=selectedText().length();
d->disableRestoreSelection = true;
QLineEdit::keyPressEvent ( e );
d->disableRestoreSelection = false;
if (( selectedLength != selectedText().length() ) && !hasUserSelection )
slotRestoreSelectionColors(); // and set userSelection to true
QString txt = text();
int len = txt.length();
if ( txt != old_txt && len/* && ( cursorPosition() == len || force )*/ &&
( (!keycode.isEmpty() && keycode.unicode()->isPrint()) ||
e->key() == Key_Backspace || e->key() == Key_Delete) )
{
if ( e->key() == Key_Backspace )
{
if ( hadSelection && !hasUserSelection && !cursorNotAtEnd )
{
backspace();
txt = text();
len = txt.length();
}
if ( !d->backspacePerformsCompletion )
d->autoSuggest = false;
}
if (e->key() == Key_Delete )
d->autoSuggest=false;
if ( d->completionBox )
d->completionBox->setCancelledText( txt );
if ( emitSignals() )
emit completion( txt ); // emit when requested...
if ( handleSignals() ) {
makeCompletion( txt ); // handle when requested...
}
if ( (e->key() == Key_Backspace || e->key() == Key_Delete ) &&
mode == KGlobalSettings::CompletionPopupAuto )
d->autoSuggest=true;
e->accept();
}
else if (!len && d->completionBox && d->completionBox->isVisible())
d->completionBox->hide();
return;
}
else if ( mode == KGlobalSettings::CompletionShell )
{
// Handles completion.
KShortcut cut;
if ( keys[TextCompletion].isNull() )
cut = KStdAccel::shortcut(KStdAccel::TextCompletion);
else
cut = keys[TextCompletion];
if ( cut.contains( key ) )
{
// Emit completion if the completion mode is CompletionShell
// and the cursor is at the end of the string.
QString txt = text();
int len = txt.length();
if ( cursorPosition() == len && len != 0 )
{
if ( emitSignals() )
emit completion( txt );
if ( handleSignals() )
makeCompletion( txt );
return;
}
}
else if ( d->completionBox )
d->completionBox->hide();
}
// handle rotation
if ( mode != KGlobalSettings::CompletionNone )
{
// Handles previous match
KShortcut cut;
if ( keys[PrevCompletionMatch].isNull() )
cut = KStdAccel::shortcut(KStdAccel::PrevCompletion);
else
cut = keys[PrevCompletionMatch];
if ( cut.contains( key ) )
{
if ( emitSignals() )
emit textRotation( KCompletionBase::PrevCompletionMatch );
if ( handleSignals() )
rotateText( KCompletionBase::PrevCompletionMatch );
return;
}
// Handles next match
if ( keys[NextCompletionMatch].isNull() )
cut = KStdAccel::shortcut(KStdAccel::NextCompletion);
else
cut = keys[NextCompletionMatch];
if ( cut.contains( key ) )
{
if ( emitSignals() )
emit textRotation( KCompletionBase::NextCompletionMatch );
if ( handleSignals() )
rotateText( KCompletionBase::NextCompletionMatch );
return;
}
}
// substring completion
if ( compObj() )
{
KShortcut cut;
if ( keys[SubstringCompletion].isNull() )
cut = KStdAccel::shortcut(KStdAccel::SubstringCompletion);
else
cut = keys[SubstringCompletion];
if ( cut.contains( key ) )
{
if ( emitSignals() )
emit substringCompletion( text() );
if ( handleSignals() )
{
setCompletedItems( compObj()->substringCompletion(text()));
e->accept();
}
return;
}
}
}
uint selectedLength = selectedText().length();
// Let QLineEdit handle any other keys events.
QLineEdit::keyPressEvent ( e );
if ( selectedLength != selectedText().length() )
slotRestoreSelectionColors(); // and set userSelection to true
}
void KLineEdit::mouseDoubleClickEvent( QMouseEvent* e )
{
if ( e->button() == Qt::LeftButton )
{
possibleTripleClick=true;
QTimer::singleShot( QApplication::doubleClickInterval(),this,
SLOT(tripleClickTimeout()) );
}
QLineEdit::mouseDoubleClickEvent( e );
}
void KLineEdit::mousePressEvent( QMouseEvent* e )
{
if ( possibleTripleClick && e->button() == Qt::LeftButton )
{
selectAll();
e->accept();
return;
}
QLineEdit::mousePressEvent( e );
}
void KLineEdit::mouseReleaseEvent( QMouseEvent* e )
{
QLineEdit::mouseReleaseEvent( e );
if (QApplication::clipboard()->supportsSelection() ) {
if ( e->button() == LeftButton ) {
// Fix copying of squeezed text if needed
copySqueezedText( false );
}
}
}
void KLineEdit::tripleClickTimeout()
{
possibleTripleClick=false;
}
void KLineEdit::contextMenuEvent( QContextMenuEvent * e )
{
if ( m_bEnableMenu )
QLineEdit::contextMenuEvent( e );
}
QPopupMenu *KLineEdit::createPopupMenu()
{
enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll };
QPopupMenu *popup = QLineEdit::createPopupMenu();
int id = popup->idAt(0);
popup->changeItem( id - IdUndo, SmallIconSet("undo"), popup->text( id - IdUndo) );
popup->changeItem( id - IdRedo, SmallIconSet("redo"), popup->text( id - IdRedo) );
popup->changeItem( id - IdCut, SmallIconSet("editcut"), popup->text( id - IdCut) );
popup->changeItem( id - IdCopy, SmallIconSet("editcopy"), popup->text( id - IdCopy) );
popup->changeItem( id - IdPaste, SmallIconSet("editpaste"), popup->text( id - IdPaste) );
popup->changeItem( id - IdClear, SmallIconSet("editclear"), popup->text( id - IdClear) );
// If a completion object is present and the input
// widget is not read-only, show the Text Completion
// menu item.
if ( compObj() && !isReadOnly() && kapp->authorize("lineedit_text_completion") )
{
QPopupMenu *subMenu = new QPopupMenu( popup );
connect( subMenu, SIGNAL( activated( int ) ),
this, SLOT( completionMenuActivated( int ) ) );
popup->insertSeparator();
popup->insertItem( SmallIconSet("completion"), i18n("Text Completion"),
subMenu );
subMenu->insertItem( i18n("None"), NoCompletion );
subMenu->insertItem( i18n("Manual"), ShellCompletion );
subMenu->insertItem( i18n("Automatic"), AutoCompletion );
subMenu->insertItem( i18n("Dropdown List"), PopupCompletion );
subMenu->insertItem( i18n("Short Automatic"), ShortAutoCompletion );
subMenu->insertItem( i18n("Dropdown List && Automatic"), PopupAutoCompletion );
subMenu->setAccel( KStdAccel::completion(), ShellCompletion );
KGlobalSettings::Completion mode = completionMode();
subMenu->setItemChecked( NoCompletion,
mode == KGlobalSettings::CompletionNone );
subMenu->setItemChecked( ShellCompletion,
mode == KGlobalSettings::CompletionShell );
subMenu->setItemChecked( PopupCompletion,
mode == KGlobalSettings::CompletionPopup );
subMenu->setItemChecked( AutoCompletion,
mode == KGlobalSettings::CompletionAuto );
subMenu->setItemChecked( ShortAutoCompletion,
mode == KGlobalSettings::CompletionMan );
subMenu->setItemChecked( PopupAutoCompletion,
mode == KGlobalSettings::CompletionPopupAuto );
if ( mode != KGlobalSettings::completionMode() )
{
subMenu->insertSeparator();
subMenu->insertItem( i18n("Default"), Default );
}
}
// ### do we really need this? Yes, Please do not remove! This
// allows applications to extend the popup menu without having to
// inherit from this class! (DA)
emit aboutToShowContextMenu( popup );
return popup;
}
void KLineEdit::completionMenuActivated( int id )
{
KGlobalSettings::Completion oldMode = completionMode();
switch ( id )
{
case Default:
setCompletionMode( KGlobalSettings::completionMode() );
break;
case NoCompletion:
setCompletionMode( KGlobalSettings::CompletionNone );
break;
case AutoCompletion:
setCompletionMode( KGlobalSettings::CompletionAuto );
break;
case ShortAutoCompletion:
setCompletionMode( KGlobalSettings::CompletionMan );
break;
case ShellCompletion:
setCompletionMode( KGlobalSettings::CompletionShell );
break;
case PopupCompletion:
setCompletionMode( KGlobalSettings::CompletionPopup );
break;
case PopupAutoCompletion:
setCompletionMode( KGlobalSettings::CompletionPopupAuto );
break;
default:
return;
}
if ( oldMode != completionMode() )
{
if ( (oldMode == KGlobalSettings::CompletionPopup ||
oldMode == KGlobalSettings::CompletionPopupAuto ) &&
d->completionBox && d->completionBox->isVisible() )
d->completionBox->hide();
emit completionModeChanged( completionMode() );
}
}
void KLineEdit::drawContents( QPainter *p )
{
QLineEdit::drawContents( p );
if ( d->drawClickMsg && !hasFocus() ) {
QPen tmp = p->pen();
p->setPen( palette().color( QPalette::Disabled, QColorGroup::Text ) );
QRect cr = contentsRect();
// Add two pixel margin on the left side
cr.rLeft() += 3;
p->drawText( cr, AlignAuto | AlignVCenter, d->clickMessage );
p->setPen( tmp );
}
}
void KLineEdit::dropEvent(QDropEvent *e)
{
d->drawClickMsg = false;
KURL::List urlList;
if( d->handleURLDrops && KURLDrag::decode( e, urlList ) )
{
QString dropText = text();
KURL::List::ConstIterator it;
for( it = urlList.begin() ; it != urlList.end() ; ++it )
{
if(!dropText.isEmpty())
dropText+=' ';
dropText += (*it).prettyURL();
}
validateAndSet( dropText, dropText.length(), 0, 0);
e->accept();
}
else
QLineEdit::dropEvent(e);
}
bool KLineEdit::eventFilter( QObject* o, QEvent* ev )
{
if( o == this )
{
KCursor::autoHideEventFilter( this, ev );
if ( ev->type() == QEvent::AccelOverride )
{
QKeyEvent *e = static_cast<QKeyEvent *>( ev );
if (overrideAccel (e))
{
e->accept();
return true;
}
}
else if( ev->type() == QEvent::KeyPress )
{
QKeyEvent *e = static_cast<QKeyEvent *>( ev );
if( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter )
{
bool trap = d->completionBox && d->completionBox->isVisible();
bool stopEvent = trap || (d->grabReturnKeyEvents &&
(e->state() == NoButton ||
e->state() == Keypad));
// Qt will emit returnPressed() itself if we return false
if ( stopEvent )
{
emit QLineEdit::returnPressed();
e->accept ();
}
emit returnPressed( displayText() );
if ( trap )
{
d->completionBox->hide();
deselect();
setCursorPosition(text().length());
}
// Eat the event if the user asked for it, or if a completionbox was visible
return stopEvent;
}
}
}
return QLineEdit::eventFilter( o, ev );
}
void KLineEdit::setURLDropsEnabled(bool enable)
{
d->handleURLDrops=enable;
}
bool KLineEdit::isURLDropsEnabled() const
{
return d->handleURLDrops;
}
void KLineEdit::setTrapReturnKey( bool grab )
{
d->grabReturnKeyEvents = grab;
}
bool KLineEdit::trapReturnKey() const
{
return d->grabReturnKeyEvents;
}
void KLineEdit::setURL( const KURL& url )
{
setText( url.prettyURL() );
}
void KLineEdit::setCompletionBox( KCompletionBox *box )
{
if ( d->completionBox )
return;
d->completionBox = box;
if ( handleSignals() )
{
connect( d->completionBox, SIGNAL(highlighted( const QString& )),
SLOT(setTextWorkaround( const QString& )) );
connect( d->completionBox, SIGNAL(userCancelled( const QString& )),
SLOT(userCancelled( const QString& )) );
// TODO: we need our own slot, and to call setModified(true) if Qt4 has that.
connect( d->completionBox, SIGNAL( activated( const QString& )),
SIGNAL(completionBoxActivated( const QString& )) );
}
}
void KLineEdit::userCancelled(const QString & cancelText)
{
if ( completionMode() != KGlobalSettings::CompletionPopupAuto )
{
// TODO: this sets modified==false. But maybe it was true before...
setText(cancelText);
}
else if (hasSelectedText() )
{
if (d->userSelection)
deselect();
else
{
d->autoSuggest=false;
int start,end;
getSelection(&start, &end);
QString s=text().remove(start, end-start+1);
validateAndSet(s,start,s.length(),s.length());
d->autoSuggest=true;
}
}
}
bool KLineEdit::overrideAccel (const QKeyEvent* e)
{
KShortcut scKey;
KKey key( e );
KeyBindingMap keys = getKeyBindings();
if (keys[TextCompletion].isNull())
scKey = KStdAccel::shortcut(KStdAccel::TextCompletion);
else
scKey = keys[TextCompletion];
if (scKey.contains( key ))
return true;
if (keys[NextCompletionMatch].isNull())
scKey = KStdAccel::shortcut(KStdAccel::NextCompletion);
else
scKey = keys[NextCompletionMatch];
if (scKey.contains( key ))
return true;
if (keys[PrevCompletionMatch].isNull())
scKey = KStdAccel::shortcut(KStdAccel::PrevCompletion);
else
scKey = keys[PrevCompletionMatch];
if (scKey.contains( key ))
return true;
// Override all the text manupilation accelerators...
if ( KStdAccel::copy().contains( key ) )
return true;
else if ( KStdAccel::paste().contains( key ) )
return true;
else if ( KStdAccel::cut().contains( key ) )
return true;
else if ( KStdAccel::undo().contains( key ) )
return true;
else if ( KStdAccel::redo().contains( key ) )
return true;
else if (KStdAccel::deleteWordBack().contains( key ))
return true;
else if (KStdAccel::deleteWordForward().contains( key ))
return true;
else if (KStdAccel::forwardWord().contains( key ))
return true;
else if (KStdAccel::backwardWord().contains( key ))
return true;
else if (KStdAccel::beginningOfLine().contains( key ))
return true;
else if (KStdAccel::endOfLine().contains( key ))
return true;
if (d->completionBox && d->completionBox->isVisible ())
{
int key = e->key();
ButtonState state = e->state();
if ((key == Key_Backtab || key == Key_Tab) &&
(state == NoButton || (state & ShiftButton)))
{
return true;
}
}
return false;
}
void KLineEdit::setCompletedItems( const QStringList& items )
{
setCompletedItems( items, true );
}
void KLineEdit::setCompletedItems( const QStringList& items, bool autoSuggest )
{
QString txt;
if ( d->completionBox && d->completionBox->isVisible() ) {
// The popup is visible already - do the matching on the initial string,
// not on the currently selected one.
txt = completionBox()->cancelledText();
} else {
txt = text();
}
if ( !items.isEmpty() &&
!(items.count() == 1 && txt == items.first()) )
{
// create completion box if non-existent
completionBox();
if ( d->completionBox->isVisible() )
{
bool wasSelected = d->completionBox->isSelected( d->completionBox->currentItem() );
const QString currentSelection = d->completionBox->currentText();
d->completionBox->setItems( items );
QListBoxItem* item = d->completionBox->findItem( currentSelection, Qt::ExactMatch );
// If no item is selected, that means the listbox hasn't been manipulated by the user yet,
// because it's not possible otherwise to have no selected item. In such case make
// always the first item current and unselected, so that the current item doesn't jump.
if( !item || !wasSelected )
{
wasSelected = false;
item = d->completionBox->item( 0 );
}
if ( item )
{
d->completionBox->blockSignals( true );
d->completionBox->setCurrentItem( item );
d->completionBox->setSelected( item, wasSelected );
d->completionBox->blockSignals( false );
}
}
else // completion box not visible yet -> show it
{
if ( !txt.isEmpty() )
d->completionBox->setCancelledText( txt );
d->completionBox->setItems( items );
d->completionBox->popup();
}
if ( d->autoSuggest && autoSuggest )
{
int index = items.first().find( txt );
QString newText = items.first().mid( index );
setUserSelection(false);
setCompletedText(newText,true);
}
}
else
{
if ( d->completionBox && d->completionBox->isVisible() )
d->completionBox->hide();
}
}
KCompletionBox * KLineEdit::completionBox( bool create )
{
if ( create && !d->completionBox ) {
setCompletionBox( new KCompletionBox( this, "completion box" ) );
d->completionBox->setFont(font());
}
return d->completionBox;
}
void KLineEdit::setCompletionObject( KCompletion* comp, bool hsig )
{
KCompletion *oldComp = compObj();
if ( oldComp && handleSignals() )
disconnect( oldComp, SIGNAL( matches( const QStringList& )),
this, SLOT( setCompletedItems( const QStringList& )));
if ( comp && hsig )
connect( comp, SIGNAL( matches( const QStringList& )),
this, SLOT( setCompletedItems( const QStringList& )));
KCompletionBase::setCompletionObject( comp, hsig );
}
// QWidget::create() turns off mouse-Tracking which would break auto-hiding
void KLineEdit::create( WId id, bool initializeWindow, bool destroyOldWindow )
{
QLineEdit::create( id, initializeWindow, destroyOldWindow );
KCursor::setAutoHideCursor( this, true, true );
}
void KLineEdit::setUserSelection(bool userSelection)
{
QPalette p = palette();
if (userSelection)
{
p.setColor(QColorGroup::Highlight, d->previousHighlightColor);
p.setColor(QColorGroup::HighlightedText, d->previousHighlightedTextColor);
}
else
{
QColor color=p.color(QPalette::Disabled, QColorGroup::Text);
p.setColor(QColorGroup::HighlightedText, color);
color=p.color(QPalette::Active, QColorGroup::Base);
p.setColor(QColorGroup::Highlight, color);
}
d->userSelection=userSelection;
setPalette(p);
}
void KLineEdit::slotRestoreSelectionColors()
{
if (d->disableRestoreSelection)
return;
setUserSelection(true);
}
void KLineEdit::clear()
{
setText( QString::null );
}
void KLineEdit::setTextWorkaround( const QString& text )
{
setText( text );
end( false ); // force cursor at end
}
QString KLineEdit::originalText() const
{
if ( d->enableSqueezedText && isReadOnly() )
return d->squeezedText;
return text();
}
void KLineEdit::focusInEvent( QFocusEvent* ev)
{
if ( d->drawClickMsg ) {
d->drawClickMsg = false;
update();
}
// Don't selectAll() in QLineEdit::focusInEvent if selection exists
if ( ev->reason() == QFocusEvent::Tab && inputMask().isNull() && hasSelectedText() )
return;
QLineEdit::focusInEvent(ev);
}
void KLineEdit::focusOutEvent( QFocusEvent* ev)
{
if ( text().isEmpty() && !d->clickMessage.isEmpty() ) {
d->drawClickMsg = true;
update();
}
QLineEdit::focusOutEvent( ev );
}
bool KLineEdit::autoSuggest() const
{
return d->autoSuggest;
}
void KLineEdit::setClickMessage( const QString &msg )
{
d->clickMessage = msg;
update();
}
QString KLineEdit::clickMessage() const
{
return d->clickMessage;
}
void KLineEdit::virtual_hook( int id, void* data )
{ KCompletionBase::virtual_hook( id, data ); }
KURL
KLineEdit::mouseDoubleClickEvent
virtual void mouseDoubleClickEvent(QMouseEvent *)
Re-implemented for internal reasons.
Definition: klineedit.cpp:818
KStdAccel::deleteWordBack
const KShortcut & deleteWordBack()
KStdAccel::shortcut
const KShortcut & shortcut(StdAccel id)
KStdAccel::paste
const KShortcut & paste()
KStdAccel::completion
const KShortcut & completion()
KURL::prettyURL
QString prettyURL(int _trailing=0) const
KLineEdit::create
virtual void create(WId=0, bool initializeWindow=true, bool destroyOldWindow=true)
Reimplemented for internal reasons, the API is not affected.
Definition: klineedit.cpp:1287
KCompletionBox
A helper widget for "completion-widgets" (KLineEdit, KComboBox))
Definition: kcompletionbox.h:43
KStdAccel::forwardWord
const KShortcut & forwardWord()
KLineEdit::setCompletionObject
virtual void setCompletionObject(KCompletion *, bool hsig=true)
Reimplemented for internal reasons, the API is not affected.
Definition: klineedit.cpp:1272
KLineEdit::setCompletedText
virtual void setCompletedText(const QString &)
See KCompletionBase::setCompletedText.
Definition: klineedit.cpp:195
KCompletionBase::NextCompletionMatch
KLineEdit::setCompletionBox
void setCompletionBox(KCompletionBox *box)
Set the completion-box to be used in completion mode KGlobalSettings::CompletionPopup.
Definition: klineedit.cpp:1083
KLineEdit::isSqueezedTextEnabled
bool isSqueezedTextEnabled() const
Returns true if text squeezing is enabled.
Definition: klineedit.cpp:305
KLineEdit::trapReturnKey
bool trapReturnKey() const
Definition: klineedit.cpp:1073
KLineEdit::createPopupMenu
virtual QPopupMenu * createPopupMenu()
Re-implemented for internal reasons.
Definition: klineedit.cpp:862
KURLDrag::decode
static bool decode(const QMimeSource *e, KURL::List &urls)
KLineEdit::autoSuggest
bool autoSuggest() const
Whether in current state text should be auto-suggested.
Definition: klineedit.cpp:1364
KLineEdit::clickMessage
QString clickMessage() const
KLineEdit::textRotation
void textRotation(KCompletionBase::KeyBindingType)
Emitted when the text rotation key-bindings are pressed.
KCompletionBase::TextCompletion
KCursor::setAutoHideCursor
static void setAutoHideCursor(QWidget *w, bool enable)
Sets auto-hiding the cursor for widget w.
Definition: kcursor.cpp:218
KLineEdit::setCompletedItems
void setCompletedItems(const QStringList &items)
Sets items into the completion-box if completionMode() is CompletionPopup.
Definition: klineedit.cpp:1195
klocale.h
KStdAccel::cut
const KShortcut & cut()
KLineEdit::setEnableSqueezedText
void setEnableSqueezedText(bool enable)
Enable text squeezing whenever the supplied text is too long.
Definition: klineedit.cpp:300
KLineEdit::contextMenuEvent
virtual void contextMenuEvent(QContextMenuEvent *)
Re-implemented for internal reasons.
Definition: klineedit.cpp:856
KLineEdit::completionBox
KCompletionBox * completionBox(bool create=true)
Definition: klineedit.cpp:1262
KCursor::autoHideEventFilter
static void autoHideEventFilter(QObject *, QEvent *)
KCursor has to install an eventFilter over the widget you want to auto-hide.
Definition: kcursor.cpp:229
KLineEdit::clear
virtual void clear()
Reimplemented to workaround a buggy QLineEdit::clear() (changing the clipboard to the text we just ha...
Definition: klineedit.cpp:1322
KLineEdit::keyPressEvent
virtual void keyPressEvent(QKeyEvent *)
Re-implemented for internal reasons.
Definition: klineedit.cpp:440
KLineEdit::userCancelled
void userCancelled(const QString &cancelText)
Resets the current displayed text.
Definition: klineedit.cpp:1102
KLineEdit::focusOutEvent
virtual void focusOutEvent(QFocusEvent *)
Re-implemented for internal reasons.
Definition: klineedit.cpp:1355
KShortcut
KLineEdit::mousePressEvent
virtual void mousePressEvent(QMouseEvent *)
Re-implemented for internal reasons.
Definition: klineedit.cpp:829
KStdAccel::pasteSelection
const KShortcut & pasteSelection()
KLineEdit::KLineEdit
KLineEdit(const QString &string, QWidget *parent, const char *name=0)
Constructs a KLineEdit object with a default text, a parent, and a name.
Definition: klineedit.cpp:106
KLineEdit::dropEvent
virtual void dropEvent(QDropEvent *)
Re-implemented to handle URI drops.
Definition: klineedit.cpp:983
KCompletionBase::SubstringCompletion
KLineEdit::substringCompletion
void substringCompletion(const QString &)
Emitted when the shortcut for substring completion is pressed.
KCompletionBase::PrevCompletionMatch
KLineEdit::completion
void completion(const QString &)
Emitted when the completion key is pressed.
KCompletion::allMatches
QStringList allMatches()
KStdAccel::redo
const KShortcut & redo()
KCompletionBase::setCompletionMode
virtual void setCompletionMode(KGlobalSettings::Completion mode)
KCompletion
KGlobalSettings::CompletionAuto
KLineEdit::setUserSelection
void setUserSelection(bool userSelection)
Sets the widget in userSelection mode or in automatic completion selection mode.
Definition: klineedit.cpp:1293
KLineEdit::resizeEvent
virtual void resizeEvent(QResizeEvent *)
Re-implemented for internal reasons.
Definition: klineedit.cpp:432
KLineEdit::~KLineEdit
virtual ~KLineEdit()
Destructor.
Definition: klineedit.cpp:118
KCompletionBase::handleSignals
bool handleSignals() const
KLineEdit::setCompletionMode
virtual void setCompletionMode(KGlobalSettings::Completion mode)
Re-implemented from KCompletionBase for internal reasons.
Definition: klineedit.cpp:150
KLineEdit::setSqueezedText
void setSqueezedText(const QString &text)
Squeezes text into the line edit.
Definition: klineedit.cpp:294
KLineEdit::completionBoxActivated
void completionBoxActivated(const QString &)
Emitted whenever the completion box is activated.
KLineEdit::originalText
QString originalText() const
Returns the original text if text squeezing is enabled.
Definition: klineedit.cpp:1333
KLineEdit::setTrapReturnKey
void setTrapReturnKey(bool trap)
By default, KLineEdit recognizes Key_Return and Key_Enter and emits the returnPressed() signals...
Definition: klineedit.cpp:1068
KStdAccel::backwardWord
const KShortcut & backwardWord()
KCompletion::nextMatch
QString nextMatch()
KLineEdit::eventFilter
virtual bool eventFilter(QObject *, QEvent *)
Re-implemented for internal reasons.
Definition: klineedit.cpp:1007
KLineEdit::mouseReleaseEvent
virtual void mouseReleaseEvent(QMouseEvent *)
Re-implemented for internal reasons.
Definition: klineedit.cpp:840
KGlobalSettings::CompletionPopup
KLineEdit::setURLDropsEnabled
void setURLDropsEnabled(bool enable)
Enables/Disables handling of URL drops.
Definition: klineedit.cpp:1058
KConfigGroup
KGlobalSettings::CompletionMan
KLineEdit::setContextMenuEnabled
virtual void setContextMenuEnabled(bool showMenu)
Enables/disables the popup (context) menu.
Definition: klineedit.h:223
KCompletion::makeCompletion
virtual QString makeCompletion(const QString &string)
KLineEdit
An enhanced QLineEdit widget for inputting text.
Definition: klineedit.h:145
KKey
KGlobalSettings::CompletionNone
KStdAccel::endOfLine
const KShortcut & endOfLine()
KLineEdit::copy
virtual void copy() const
Reimplemented for internal reasons, the API is not affected.
Definition: klineedit.cpp:397
KLineEdit::drawContents
virtual void drawContents(QPainter *p)
Re-implemented for internal reasons.
Definition: klineedit.cpp:967
KLineEdit::setURL
void setURL(const KURL &url)
Sets url into the lineedit.
Definition: klineedit.cpp:1078
KGlobalSettings::Completion
Completion
KCompletionBase::setCompletionObject
virtual void setCompletionObject(KCompletion *compObj, bool hsig=true)
KLineEdit::isURLDropsEnabled
bool isURLDropsEnabled() const
Returns true when decoded URL drops are enabled.
Definition: klineedit.cpp:1063
KCompletionBase::emitSignals
bool emitSignals() const
KCompletionBase::KeyBindingType
KeyBindingType
KStdAccel::undo
const KShortcut & undo()
KShortcut::contains
bool contains(const KKey &key) const
KLineEdit::completionModeChanged
void completionModeChanged(KGlobalSettings::Completion)
Emitted when the user changed the completion mode by using the popupmenu.
KCompletionBase::getKeyBindings
KeyBindingMap getKeyBindings() const
KGlobalSettings::CompletionShell
KLineEdit::setClickMessage
void setClickMessage(const QString &msg)
This makes the line edit display a grayed-out hinting text as long as the user didn't enter any text...
Definition: klineedit.cpp:1369
KLineEdit::aboutToShowContextMenu
void aboutToShowContextMenu(QPopupMenu *p)
Emitted before the context menu is displayed.
KGlobalSettings::completionMode
static Completion completionMode()
KLineEdit::makeCompletion
virtual void makeCompletion(const QString &)
Completes the remaining text with a matching one from a given list.
Definition: klineedit.cpp:226
KLineEdit::returnPressed
void returnPressed(const QString &)
Emitted when the user presses the return key.
KStdAccel::deleteWordForward
const KShortcut & deleteWordForward()
KLineEdit::setReadOnly
virtual void setReadOnly(bool)
Re-implemented for internal reasons.
Definition: klineedit.cpp:265
KLineEdit::setText
virtual void setText(const QString &)
Re-implemented to enable text squeezing.
Definition: klineedit.cpp:310
KURL::List
KLineEdit::focusInEvent
virtual void focusInEvent(QFocusEvent *)
Re-implemented for internal reasons.
Definition: klineedit.cpp:1341
KGlobal::config
static KConfig * config()
KCompletionBase::completionMode
KGlobalSettings::Completion completionMode() const
KCompletion::previousMatch
QString previousMatch()
KLineEdit::rotateText
void rotateText(KCompletionBase::KeyBindingType type)
Iterates through all possible matches of the completed text or the history list.
Definition: klineedit.cpp:205
KGlobalSettings::CompletionPopupAuto
KStdAccel::copy
const KShortcut & copy()
KStdAccel::beginningOfLine
const KShortcut & beginningOfLine()
KCompletionBase::compObj
KCompletion * compObj() const

KDE Home | KDE Accessibility Home | Description of Access Keys