[prev in list] [next in list] [prev in thread] [next in thread]
List: kmail-devel
Subject: address completion
From: Carsten Pfeiffer <carpdjih () cetus ! zrz ! tu-berlin ! de>
Date: 2001-05-24 1:29:22
[Download RAW message or body]
Hiya,
here's a quick patch that adds {auto,short-auto,popup,shell}-completion
support to kmail's composer.
Not sure if the From and Reply-To edits should use the same completion-items
as the others tho (or at all).
It also
- removes some obsolete methods
- moves some methods around (there were KMComposeWin methods in between
KMLineEdit methods)
- cleans up some things
The bottom of the patch is not very readable -- diff couldn't come up with a
better one, not even with -d.
And yes, the old Ctrl-T completion is still available, too.
Currently, the entire address is completed/shown, not just the name without
email-address (a la Outlook). I would need some input if we want that, or not
and some more information about how it works. Does completion in Outlook only
work with names, or also email-addresses? Does it resolve email-addresses to
names? I need some use-cases, if we want that.
Cheers,
Carsten Pfeiffer
["completion.patch" (text/x-c)]
? completion.patch
Index: kmcomposewin.cpp
===================================================================
RCS file: /home/kde/kdenetwork/kmail/kmcomposewin.cpp,v
retrieving revision 1.338
diff -u -p -B -w -d -r1.338 kmcomposewin.cpp
--- kmcomposewin.cpp 2001/05/20 19:16:16 1.338
+++ kmcomposewin.cpp 2001/05/24 01:21:44
@@ -29,6 +29,8 @@
#include <kabapi.h>
#include <kaction.h>
#include <kcharsets.h>
+#include <kcompletion.h>
+#include <kcompletionbox.h>
#include <kcursor.h>
#include <kstdaction.h>
#include <kedittoolbar.h>
@@ -151,6 +153,17 @@ KMComposeWin::KMComposeWin(KMMessage *aM
connect(&mBtnFrom,SIGNAL(clicked()),SLOT(slotAddrBookFrom()));
connect(&mIdentity,SIGNAL(activated(int)),SLOT(slotIdentityActivated(int)));
+ connect(&mEdtTo,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
+ SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
+ connect(&mEdtCc,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
+ SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
+ connect(&mEdtBcc,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
+ SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
+ connect(&mEdtReplyTo,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
+ SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
+ connect(&mEdtFrom,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
+ SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
+
mMainWidget.resize(480,510);
setCentralWidget(&mMainWidget);
rethinkFields();
@@ -312,6 +325,14 @@ void KMComposeWin::readConfig(void)
mAutoPgpSign = config->readNumEntry("pgp-auto-sign", 0);
mConfirmSend = config->readBoolEntry("confirm-before-send", false);
+ int mode = config->readNumEntry("Completion Mode",
+ KGlobalSettings::completionMode() );
+ mEdtFrom.setCompletionMode( (KGlobalSettings::Completion) mode );
+ mEdtReplyTo.setCompletionMode( (KGlobalSettings::Completion) mode );
+ mEdtTo.setCompletionMode( (KGlobalSettings::Completion) mode );
+ mEdtCc.setCompletionMode( (KGlobalSettings::Completion) mode );
+ mEdtBcc.setCompletionMode( (KGlobalSettings::Completion) mode );
+
readColorConfig();
{ // area for config group "General"
@@ -1355,7 +1376,7 @@ void KMComposeWin::addrBookSelInto(KMLin
return;
}
if (dlg.exec()==QDialog::Rejected) return;
- txt = QString(aLineEdit->text()).stripWhiteSpace();
+ txt = aLineEdit->text().stripWhiteSpace();
if (!txt.isEmpty())
{
if (txt.right(1).at(0)!=',') txt += ", ";
@@ -2252,20 +2273,120 @@ void KMComposeWin::slotIdentityActivated
mId = identStr;
}
+//-----------------------------------------------------------------------------
+void KMComposeWin::slotSpellcheckConfig()
+{
+ KWin kwin;
+ QTabDialog qtd (this, "tabdialog", true);
+ KSpellConfig mKSpellConfig (&qtd);
+
+ qtd.addTab (&mKSpellConfig, i18n("Spellchecker"));
+ qtd.setCancelButton ();
+
+ kwin.setIcons (qtd.winId(), kapp->icon(), kapp->miniIcon());
+
+ if (qtd.exec())
+ mKSpellConfig.writeGlobalSettings();
+}
+
+//-----------------------------------------------------------------------------
+void KMComposeWin::slotToggleToolBar()
+{
+ if(toolBar("mainToolBar")->isVisible())
+ toolBar("mainToolBar")->hide();
+ else
+ toolBar("mainToolBar")->show();
+}
+
+void KMComposeWin::slotToggleStatusBar()
+{
+ if (statusBar()->isVisible())
+ statusBar()->hide();
+ else
+ statusBar()->show();
+}
+
+void KMComposeWin::slotEditToolbars()
+{
+ KEditToolbar dlg(actionCollection(), "kmcomposerui.rc");
+
+ if (dlg.exec() == true)
+ {
+ createGUI("kmcomposerui.rc");
+ toolbarAction->setChecked(!toolBar()->isHidden());
+ }
+}
+
+void KMComposeWin::slotEditKeys()
+{
+ KKeyDialog::configureKeys(actionCollection(), xmlFile(), true, this);
+}
+void KMComposeWin::setReplyFocus( bool hasMessage )
+{
+ mEditor->setFocus();
+ if ( hasMessage )
+ mEditor->setCursorPosition( 1, 0 );
+}
+
+void KMComposeWin::slotCompletionModeChanged( KGlobalSettings::Completion mode)
+{
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver cs( config, "Composer" );
+ config->writeEntry( "Completion Mode", (int) mode );
+ config->sync(); // maybe not?
+
+ // sync all the lineedits to the same completion mode
+ mEdtFrom.setCompletionMode( mode );
+ mEdtReplyTo.setCompletionMode( mode );
+ mEdtTo.setCompletionMode( mode );
+ mEdtCc.setCompletionMode( mode );
+ mEdtBcc.setCompletionMode( mode );
+}
+
//=============================================================================
//
// Class KMLineEdit
//
//=============================================================================
+
+KCompletion * KMLineEdit::s_completion = 0L;
+bool KMLineEdit::s_addressesDirty = false;
+
KMLineEdit::KMLineEdit(KMComposeWin* composer, QWidget *parent,
const char *name): KMLineEditInherited(parent,name)
{
mComposer = composer;
+ if ( !s_completion ) {
+ s_completion = new KCompletion();
+ s_completion->setOrder( KCompletion::Sorted );
+ }
installEventFilter(this);
+ if ( useCompletion() )
+ {
+ setCompletionObject( s_completion, false ); // we handle it ourself
+ connect( this, SIGNAL( completion(const QString&)),
+ this, SLOT(slotCompletion() ));
+
+ // old-style completion via Ctrl-T
connect (this, SIGNAL(completion()), this, SLOT(slotCompletion()));
+
+ KCompletionBox *box = completionBox();
+ // ### this disconnect has to be fixed in kdeui
+ disconnect( box, SIGNAL( highlighted( const QString& )),
+ this, SLOT( setText( const QString& )));
+ connect( box, SIGNAL( highlighted( const QString& )),
+ this, SLOT( slotPopupCompletion( const QString& ) ));
+
+
+ // Whenever a new KMLineEdit is created (== a new composer is created),
+ // we set a dirty flag to reload the addresses upon the first completion.
+ // The address completions are shared between all KMLineEdits.
+ // Is there a signal that tells us about addressbook updates?
+ s_addressesDirty = true;
+ }
}
@@ -2277,7 +2398,7 @@ KMLineEdit::~KMLineEdit()
//-----------------------------------------------------------------------------
-bool KMLineEdit::eventFilter(QObject*, QEvent* e)
+bool KMLineEdit::eventFilter(QObject *o, QEvent *e)
{
#ifdef KeyPress
#undef KeyPress
@@ -2287,21 +2408,23 @@ bool KMLineEdit::eventFilter(QObject*, Q
{
QKeyEvent* k = (QKeyEvent*)e;
- if (k->state()==ControlButton && k->key()==Key_T)
+ if (completionMode() == KGlobalSettings::CompletionNone &&
+ k->state()==ControlButton && k->key()==Key_T)
{
emit completion();
cursorAtEnd();
return TRUE;
}
// ---sven's Return is same Tab and arrow key navigation start ---
- if (k->key() == Key_Enter || k->key() == Key_Return)
+ if (k->key() == Key_Enter || k->key() == Key_Return &&
+ !completionBox()->isVisible())
{
mComposer->focusNextPrevEdit(this,TRUE);
return TRUE;
}
if (k->state()==ControlButton && k->key() == Key_Right)
{
- if ((int)strlen(text()) == cursorPosition()) // at End?
+ if ((int)text().length() == cursorPosition()) // at End?
{
emit completion();
cursorAtEnd();
@@ -2321,31 +2444,15 @@ bool KMLineEdit::eventFilter(QObject*, Q
}
// ---sven's Return is same Tab and arrow key navigation end ---
- }
- else if (e->type() == QEvent::MouseButtonPress)
- {
- QMouseEvent* me = (QMouseEvent*)e;
- if (me->button() == RightButton)
- {
- QPopupMenu* p = new QPopupMenu;
- p->insertItem(i18n("Cut"),this,SLOT(cut()));
- p->insertItem(i18n("Copy"),this,SLOT(copy()));
- p->insertItem(i18n("Paste"),this,SLOT(paste()));
- p->insertItem(i18n("Mark all"),this,SLOT(markAll()));
- setFocus();
- p->popup(QCursor::pos());
- return TRUE;
}
- }
- return FALSE;
+ return KMLineEditInherited::eventFilter(o, e);
}
//-----------------------------------------------------------------------------
void KMLineEdit::cursorAtEnd()
{
- QKeyEvent ev( QEvent::KeyPress, Key_End, 0, 0 );
- QLineEdit::keyPressEvent( &ev );
+ setCursorPosition( text().length() );
}
@@ -2355,190 +2462,176 @@ void KMLineEdit::undo()
keyPressEvent( &k );
}
-//-----------------------------------------------------------------------------
-void KMLineEdit::copy()
+bool KMLineEdit::useCompletion() const
{
- QString t = markedText();
- QApplication::clipboard()->setText(t);
+ // feel free to make this a bit more flexible :)
+ return !name() || qstrncmp(name(), "subjectLine", 11) != 0;
}
//-----------------------------------------------------------------------------
-void KMLineEdit::cut()
-{
- if(hasMarkedText())
+void KMLineEdit::slotCompletion()
{
- QString t = markedText();
- QKeyEvent k(QEvent::KeyPress, Key_D, 0, ControlButton);
- keyPressEvent(&k);
- QApplication::clipboard()->setText(t);
- }
-}
+ if ( !useCompletion() )
+ return;
-//-----------------------------------------------------------------------------
-void KMLineEdit::paste()
+ QString s(text());
+ QString prevAddr;
+ int n = s.findRev(',');
+ if (n>= 0)
{
- QKeyEvent k(QEvent::KeyPress, Key_V, 0, ControlButton);
- keyPressEvent(&k);
+ prevAddr = s.left(n+1) + ' ';
+ s = s.mid(n+1,255).stripWhiteSpace();
}
-//-----------------------------------------------------------------------------
-void KMLineEdit::markAll()
+ KCompletionBox *box = completionBox();
+
+ if ( s.isEmpty() )
{
- selectAll();
+ box->hide();
+ return;
}
-//-----------------------------------------------------------------------------
-void KMLineEdit::slotCompletion()
-{
- QString t;
- QString Name(name());
+ KGlobalSettings::Completion mode = completionMode();
- if (Name == "subjectLine")
- {
- //mComposer->focusNextPrevEdit(this,TRUE); //IMHO, it is useless now (sven)
+ if ( s_addressesDirty )
+ loadAddresses();
- return;
- }
+ QString match;
+ int curPos = cursorPosition();
+ if ( mode != KGlobalSettings::CompletionNone )
+ match = s_completion->makeCompletion( s );
- QPopupMenu pop;
- int n;
+ // kdDebug() << "** completion for: " << s << " : " << match << endl;
- KMAddrBook adb;
- adb.readConfig();
+ switch ( mode )
+ {
+ case KGlobalSettings::CompletionPopup:
+ {
+ if ( !match.isNull() && match != s )
+ {
+ m_previousAddresses = prevAddr;
+ box->clear();
+ box->insertStringList( s_completion->allMatches( s ));
+ box->popup();
+ }
+ else
+ box->hide();
- if(adb.load() == IO_FatalError)
- return;
+ break;
+ }
- QString s(text());
- QString prevAddr;
- n = s.findRev(',');
- if (n>=0)
+ case KGlobalSettings::CompletionShell:
{
- prevAddr = s.left(n+1) + ' ';
- s = s.mid(n+1,255).stripWhiteSpace();
+ if ( !match.isNull() && match != s )
+ {
+ setText( prevAddr + match );
+ cursorAtEnd();
+ }
+ break;
}
- n=0;
- if (!KMAddrBookExternal::useKAB())
- for (QString a=adb.first(); a; a=adb.next())
+ case KGlobalSettings::CompletionMan: // Short-Auto in fact
+ case KGlobalSettings::CompletionAuto:
{
- if (QString(a).find(s,0,false) >= 0)
+ if ( !match.isNull() && match != s )
{
- pop.insertItem(a);
- n++;
+ QString adds = prevAddr + match;
+ validateAndSet( adds, curPos, curPos, adds.length() );
}
+ break;
}
- else {
- QStringList addresses;
- KabBridge::addresses(&addresses);
+
+ default: // fall through
+ case KGlobalSettings::CompletionNone:
+ {
+ QPopupMenu pop;
+
+ QStringList addresses = s_completion->items();
QStringList::Iterator it = addresses.begin();
for (; it != addresses.end(); ++it)
{
if ((*it).find(s,0,false) >= 0)
- {
pop.insertItem(*it);
- n++;
- }
- }
}
- if (n > 1)
+ if (pop.count() > 1)
{
int id;
pop.popup(parentWidget()->mapToGlobal(QPoint(x(), y()+height())));
pop.setActiveItem(pop.idAt(0));
id = pop.exec();
- if (id!=-1)
- {
+ if (id > -1)
setText(prevAddr + pop.text(id));
- //mComposer->focusNextPrevEdit(this,TRUE);
}
- }
- else if (n==1)
+ else if (pop.count() == 1)
{
setText(prevAddr + pop.text(pop.idAt(0)));
- //mComposer->focusNextPrevEdit(this,TRUE);
}
setFocus();
cursorAtEnd();
+ break;
}
-
-//-----------------------------------------------------------------------------
-void KMLineEdit::dropEvent(QDropEvent *e)
-{
- QStrList uriList;
- if(QUriDrag::canDecode(e) && QUriDrag::decode( e, uriList ))
- {
- QString ct = text();
- for (QStrListIterator it(uriList); it; ++it)
- {
- if (!ct.isEmpty()) ct.append(", ");
- KURL u(*it);
- if (u.protocol() == "mailto") ct.append(QString::fromUtf8(u.path()));
- else ct.append(QString::fromUtf8(*it));
- }
- setText(ct);
}
- else QLineEdit::dropEvent(e);
}
-//-----------------------------------------------------------------------------
-void KMComposeWin::slotSpellcheckConfig()
+void KMLineEdit::slotPopupCompletion( const QString& completion )
{
-
- KWin kwin;
- QTabDialog qtd (this, "tabdialog", true);
- KSpellConfig mKSpellConfig (&qtd);
-
- qtd.addTab (&mKSpellConfig, i18n("Spellchecker"));
- qtd.setCancelButton ();
-
- kwin.setIcons (qtd.winId(), kapp->icon(), kapp->miniIcon());
-
- if (qtd.exec())
- mKSpellConfig.writeGlobalSettings();
+ setText( m_previousAddresses + completion );
+ cursorAtEnd();
}
//-----------------------------------------------------------------------------
-void KMComposeWin::slotToggleToolBar()
+void KMLineEdit::loadAddresses()
{
- if(toolBar("mainToolBar")->isVisible())
- toolBar("mainToolBar")->hide();
- else
- toolBar("mainToolBar")->show();
-}
+ s_completion->clear();
+ s_addressesDirty = false;
-void KMComposeWin::slotToggleStatusBar()
-{
- if (statusBar()->isVisible())
- statusBar()->hide();
- else
- statusBar()->show();
-}
+ KMAddrBook adb;
+ adb.readConfig();
-void KMComposeWin::slotEditToolbars()
-{
- KEditToolbar dlg(actionCollection(), "kmcomposerui.rc");
+ if(adb.load() == IO_FatalError)
+ return;
- if (dlg.exec() == true)
+ if (!KMAddrBookExternal::useKAB()) {
+ for (QString a = adb.first(); !a.isEmpty(); a = adb.next())
{
- createGUI("kmcomposerui.rc");
- toolbarAction->setChecked(!toolBar()->isHidden());
+ s_completion->addItem( a );
+ // kdDebug() << "** 1 adding: " << a << endl;
}
}
-void KMComposeWin::slotEditKeys()
+ else {
+ QStringList addresses;
+ KabBridge::addresses(&addresses);
+ QStringList::Iterator it = addresses.begin();
+ for (; it != addresses.end(); ++it)
{
- KKeyDialog::configureKeys(actionCollection(), xmlFile(), true, this);
+ s_completion->addItem( *it );
+ // kdDebug() << "** 2 adding: " << *it << endl;
}
+ }
+}
-void KMComposeWin::setReplyFocus( bool hasMessage )
+
+//-----------------------------------------------------------------------------
+void KMLineEdit::dropEvent(QDropEvent *e)
{
- mEditor->setFocus();
- if ( hasMessage )
- mEditor->setCursorPosition( 1, 0 );
+ QStrList uriList;
+ if(QUriDrag::canDecode(e) && QUriDrag::decode( e, uriList ))
+ {
+ QString ct = text();
+ for (QStrListIterator it(uriList); it; ++it)
+ {
+ if (!ct.isEmpty()) ct.append(", ");
+ KURL u(*it);
+ if (u.protocol() == "mailto") ct.append(QString::fromUtf8(u.path()));
+ else ct.append(QString::fromUtf8(*it));
+ }
+ setText(ct);
+ }
+ else QLineEdit::dropEvent(e);
}
Index: kmcomposewin.h
===================================================================
RCS file: /home/kde/kdenetwork/kmail/kmcomposewin.h,v
retrieving revision 1.113
diff -u -p -B -w -d -r1.113 kmcomposewin.h
--- kmcomposewin.h 2001/05/16 20:16:47 1.113
+++ kmcomposewin.h 2001/05/24 01:21:44
@@ -14,8 +14,9 @@
#include <qpalette.h>
#include <qfont.h>
#include <keditcl.h>
-#include <qlineedit.h>
+#include <klineedit.h>
#include <kio/job.h>
+#include <kglobalsettings.h>
#include "kmmsgpart.h"
#include "kmmsgbase.h"
@@ -36,7 +37,7 @@ class QListView;
class QListViewItem;
class QPopupMenu;
class QPushButton;
-class KDNDDropZone;
+class KCompletion;
class KEdit;
class KMComposeWin;
class KMMessage;
@@ -59,8 +60,8 @@ class KMEdit: public KEdit
{
Q_OBJECT
public:
- KMEdit(QWidget *parent=NULL,KMComposeWin* composer=NULL,
- const char *name=NULL);
+ KMEdit(QWidget *parent=0L,KMComposeWin* composer=0L,
+ const char *name=0L);
virtual ~KMEdit();
/**
@@ -98,36 +99,43 @@ private:
//-----------------------------------------------------------------------------
-#define KMLineEditInherited QLineEdit
-class KMLineEdit : public QLineEdit
+#define KMLineEditInherited KLineEdit
+class KMLineEdit : public KLineEdit
{
Q_OBJECT
public:
- KMLineEdit(KMComposeWin* composer = NULL, QWidget *parent = NULL,
- const char *name = NULL);
+ KMLineEdit(KMComposeWin* composer, QWidget *parent = 0L,
+ const char *name = 0L);
virtual ~KMLineEdit();
- /** Set cursor to end of line. */
- void cursorAtEnd();
-
signals:
- /** Emitted when Ctrl-. (period) is pressed. */
+ /** Emitted when Ctrl-T is pressed. */
void completion();
public slots:
void undo();
- void copy();
- void cut();
- void paste();
- void markAll();
- void slotCompletion();
+ /** Set cursor to end of line. */
+ void cursorAtEnd();
protected:
virtual bool eventFilter(QObject*, QEvent*);
virtual void dropEvent(QDropEvent *e);
KMComposeWin* mComposer;
-protected:
+
+private slots:
+ void slotCompletion();
+ void slotPopupCompletion( const QString& );
+
+private:
+ void loadAddresses();
+ bool useCompletion() const;
+
+ QString m_previousAddresses;
+
+ static bool s_addressesDirty;
+ static KCompletion *s_completion;
+
};
@@ -140,7 +148,7 @@ class KMComposeWin : public KMTopLevelWi
friend class KMHeaders; // needed for the digest forward
public:
- KMComposeWin(KMMessage* msg=NULL, QString id = "unknown" );
+ KMComposeWin(KMMessage* msg=0L, QString id = "unknown" );
~KMComposeWin();
/** Add descriptions to the encodings in the list */
@@ -371,7 +379,6 @@ protected:
KMEdit* mEditor;
QGridLayout* mGrid;
- //KDNDDropZone *mDropZone;
KMMessage *mMsg;
QListView *mAtmListBox;
QList<QListViewItem> mAtmItemList;
@@ -410,6 +417,9 @@ protected:
QString mCharset;
QString mDefCharset;
QFont mSavedEditorFont;
+
+private slots:
+ void slotCompletionModeChanged( KGlobalSettings::Completion );
private:
QColor foreColor,backColor;
_______________________________________________
Kmail Developers mailing list
Kmail@master.kde.org
http://master.kde.org/mailman/listinfo/kmail
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic