You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

2571 lines
70 KiB

// kmcomposewin.cpp
// Author: Markus Wuebben <markus.wuebben@kde.org>
// This code is published under the GPL.
#include <qdir.h>
#undef GrayScale
#undef Color
#include <qprinter.h>
#include <qcombobox.h>
#include <qdragobject.h>
#include <qlistview.h>
#include <qcombobox.h>
#include "kmcomposewin.h"
#include "kmmessage.h"
#include "kmmsgpart.h"
#include "kmsender.h"
#include "kmidentity.h"
#include "kfileio.h"
#include "kbusyptr.h"
#include "kmmsgpartdlg.h"
#include "kpgp.h"
#include "kmaddrbookdlg.h"
#include "kmaddrbook.h"
#include "kmidentity.h"
#include <kabapi.h>
#include <kfontutils.h>
#include <kaction.h>
#include <kstdaction.h>
#include <kedittoolbar.h>
#ifndef KRN
#include "kmmainwin.h"
#include "kmsettings.h"
#include "kfileio.h"
#endif
#include <assert.h>
#include <kapp.h>
#include <kconfig.h>
#include <kiconloader.h>
#include <kmenubar.h>
#include <kstatusbar.h>
#include <ktoolbar.h>
#include <kstdaccel.h>
#include <mimelib/mimepp.h>
#include <kfiledialog.h>
#include <kwin.h>
#include <kglobal.h>
#include <kmessagebox.h>
#include <kspell.h>
#include <qtabdialog.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qlist.h>
#include <qfont.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qregexp.h>
#include <qcursor.h>
#include <qmessagebox.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <klocale.h>
#include <ktempfile.h>
#include <fcntl.h>
#if defined CHARSETS
#include <kcharsets.h>
#include "charsetsDlg.h"
#endif
#ifdef KRN
/* start added for KRN */
#include "krnsender.h"
extern KApplication *app;
extern KBusyPtr *kbp;
extern KRNSender *msgSender;
extern KMIdentity *identity;
extern KMAddrBook *addrBook;
extern KabApi *KABaddrBook;
typedef QList<QWidget> WindowList;
WindowList* windowList=new WindowList;
#define aboutText "KRN"
/* end added for KRN */
#else
#include "kmglobal.h"
#endif
#include "kmcomposewin.moc"
#define HDR_FROM 0x01
#define HDR_REPLY_TO 0x02
#define HDR_TO 0x04
#define HDR_CC 0x08
#define HDR_BCC 0x10
#define HDR_SUBJECT 0x20
#define HDR_NEWSGROUPS 0x40
#define HDR_FOLLOWUP_TO 0x80
#define HDR_IDENTITY 0x100
#define HDR_TRANSPORT 0x200
#define HDR_ALL 0x3ff
#ifdef KRN
#define HDR_STANDARD (HDR_SUBJECT|HDR_NEWSGROUPS)
#else
#define HDR_STANDARD (HDR_SUBJECT|HDR_TO|HDR_CC)
#endif
QString KMComposeWin::mPathAttach = QString::null;
//-----------------------------------------------------------------------------
KMComposeWin::KMComposeWin(KMMessage *aMsg, QString id )
: KMTopLevelWidget (),
mMainWidget(this),
mIdentity(&mMainWidget), mTransport(true, &mMainWidget),
mEdtFrom(this,&mMainWidget), mEdtReplyTo(this,&mMainWidget),
mEdtTo(this,&mMainWidget), mEdtCc(this,&mMainWidget),
mEdtBcc(this,&mMainWidget), mEdtSubject(this,&mMainWidget, "subjectLine"),
mLblIdentity(&mMainWidget), mLblTransport(&mMainWidget),
mLblFrom(&mMainWidget), mLblReplyTo(&mMainWidget), mLblTo(&mMainWidget),
mLblCc(&mMainWidget), mLblBcc(&mMainWidget), mLblSubject(&mMainWidget),
mBtnIdentity(i18n("Sticky"),&mMainWidget),
mBtnTransport(i18n("Sticky"),&mMainWidget),
mBtnTo("...",&mMainWidget), mBtnCc("...",&mMainWidget),
mBtnBcc("...",&mMainWidget), mBtnFrom("...",&mMainWidget),
mBtnReplyTo("...",&mMainWidget),
mId( id )
#ifdef KRN
,mEdtNewsgroups(this,&mMainWidget),mEdtFollowupTo(this,&mMainWidget),
mLblNewsgroups(&mMainWidget),mLblFollowupTo(&mMainWidget)
#endif
{
//setWFlags( WType_TopLevel | WStyle_Dialog );
mDone = false;
mGrid = NULL;
mAtmListBox = NULL;
mAtmList.setAutoDelete(TRUE);
mAutoDeleteMsg = FALSE;
mPathAttach = QString::null;
mEditor = NULL;
mSpellCheckInProgress=FALSE;
setCaption( i18n("Composer") );
setMinimumSize(200,200);
mBtnIdentity.setFocusPolicy(QWidget::NoFocus);
mBtnTransport.setFocusPolicy(QWidget::NoFocus);
mBtnTo.setFocusPolicy(QWidget::NoFocus);
mBtnCc.setFocusPolicy(QWidget::NoFocus);
mBtnBcc.setFocusPolicy(QWidget::NoFocus);
mBtnFrom.setFocusPolicy(QWidget::NoFocus);
mBtnReplyTo.setFocusPolicy(QWidget::NoFocus);
mAtmListBox = new QListView(&mMainWidget, "mAtmListBox");
mAtmListBox->setFocusPolicy(QWidget::NoFocus);
mAtmListBox->addColumn(i18n("Name"), 200);
mAtmListBox->addColumn(i18n("Size"), 80);
mAtmListBox->addColumn(i18n("Encoding"), 120);
mAtmListBox->addColumn(i18n("Type"), 150);
connect(mAtmListBox,
SIGNAL(rightButtonPressed(QListViewItem *, const QPoint &, int)),
SLOT(slotAttachPopupMenu(QListViewItem *, const QPoint &, int)));
readConfig();
setupStatusBar();
setupEditor();
setupActions();
if(mShowToolBar)
toolBar()->show();
else
toolBar()->hide();
connect(&mEdtSubject,SIGNAL(textChanged(const QString&)),
SLOT(slotUpdWinTitle(const QString&)));
connect(&mBtnTo,SIGNAL(clicked()),SLOT(slotAddrBookTo()));
connect(&mBtnCc,SIGNAL(clicked()),SLOT(slotAddrBookCc()));
connect(&mBtnBcc,SIGNAL(clicked()),SLOT(slotAddrBookBcc()));
connect(&mBtnReplyTo,SIGNAL(clicked()),SLOT(slotAddrBookReplyTo()));
connect(&mBtnFrom,SIGNAL(clicked()),SLOT(slotAddrBookFrom()));
connect(&mIdentity,SIGNAL(activated(int)),SLOT(slotIdentityActivated(int)));
mMainWidget.resize(480,510);
setView(&mMainWidget, FALSE);
rethinkFields();
#ifndef KRN
if (useExtEditor) {
mEditor->setExternalEditor(true);
mEditor->setExternalEditorPath(mExtEditor);
}
#endif
#if defined CHARSETS
// As family may change with charset, we must save original settings
mSavedEditorFont=mEditor->font();
#endif
mMsg = NULL;
if (aMsg)
setMsg(aMsg);
mEdtTo.setFocus();
mDone = true;
}
//-----------------------------------------------------------------------------
KMComposeWin::~KMComposeWin()
{
writeConfig();
if (mAutoDeleteMsg && mMsg) delete mMsg;
}
//-----------------------------------------------------------------------------
void KMComposeWin::readConfig(void)
{
KConfig *config = kapp->config();
QString str;
int w, h, maxTransportItems;
config->setGroup("Composer");
mAutoSign = config->readEntry("signature","auto") == "auto";
mShowToolBar = config->readNumEntry("show-toolbar", 1);
mDefEncoding = config->readEntry("encoding", "base64");
mShowHeaders = config->readNumEntry("headers", HDR_STANDARD);
mWordWrap = config->readNumEntry("word-wrap", 1);
mLineBreak = config->readNumEntry("break-at", 78);
mBtnIdentity.setChecked(config->readBoolEntry("sticky-identity", false));
if (mBtnIdentity.isChecked())
mId = config->readEntry("previous-identity", mId );
mBtnTransport.setChecked(config->readBoolEntry("sticky-transport", false));
mTransportHistory = config->readListEntry("transport-history");
maxTransportItems = config->readNumEntry("max-transport-items",10);
if ((mLineBreak == 0) || (mLineBreak > 78))
mLineBreak = 78;
if (mLineBreak < 60)
mLineBreak = 60;
mAutoPgpSign = config->readNumEntry("pgp-auto-sign", 0);
#ifndef KRN
mConfirmSend = config->readBoolEntry("confirm-before-send", false);
#endif
config->setGroup("Reader");
QColor c1=QColor(kapp->palette().normal().text());
QColor c4=QColor(kapp->palette().normal().base());
if (!config->readBoolEntry("defaultColors",TRUE)) {
foreColor = config->readColorEntry("ForegroundColor",&c1);
backColor = config->readColorEntry("BackgroundColor",&c4);
}
else {
foreColor = c1;
backColor = c4;
}
// Color setup
mPalette = palette().copy();
QColorGroup cgrp = mPalette.normal();
QColorGroup ncgrp(foreColor,cgrp.background(),
cgrp.light(),cgrp.dark(), cgrp.mid(), foreColor,
backColor);
mPalette.setNormal(ncgrp);
mPalette.setDisabled(ncgrp);
mPalette.setActive(ncgrp);
mPalette.setInactive(ncgrp);
// mIdentity.setPalette(mPalette);
mTransport.setPalette(mPalette);
mEdtFrom.setPalette(mPalette);
mEdtReplyTo.setPalette(mPalette);
mEdtTo.setPalette(mPalette);
mEdtCc.setPalette(mPalette);
mEdtBcc.setPalette(mPalette);
mEdtSubject.setPalette(mPalette);
mAtmListBox->setPalette(mPalette);
#ifndef KRN
config->setGroup("General");
mExtEditor = config->readEntry("external-editor", DEFAULT_EDITOR_STR);
useExtEditor = config->readBoolEntry("use-external-editor", FALSE);
int headerCount = config->readNumEntry("mime-header-count", 0);
mCustHeaders.clear();
mCustHeaders.setAutoDelete(true);
for (int i = 0; i < headerCount; i++) {
QString thisGroup;
_StringPair *thisItem = new _StringPair;
thisGroup.sprintf("Mime #%d", i);
config->setGroup(thisGroup);
thisItem->name = config->readEntry("name", "");
if ((thisItem->name).length() > 0) {
thisItem->value = config->readEntry("value", "");
mCustHeaders.append(thisItem);
} else {
delete thisItem;
}
}
#endif
config->setGroup("Fonts");
if (!config->readBoolEntry("defaultFonts",TRUE)) {
QString mBodyFontStr;
mBodyFontStr = config->readEntry("body-font", "helvetica-medium-r-12");
mBodyFont = kstrToFont(mBodyFontStr);
}
else
mBodyFont = KGlobalSettings::generalFont();
if (mEditor) mEditor->setFont(mBodyFont);
#if defined CHARSETS
m7BitAscii = config->readNumEntry("7bit-is-ascii",1);
mQuoteUnknownCharacters = config->readNumEntry("quote-unknown",0);
str = config->readEntry("default-charset", "");
if (str.isNull() || str=="default" || !KGlobal::charsets()->isAvailable(str))
mDefaultCharset="default";
else
mDefaultCharset=str;
debug("Default charset: %s", (const char*)mDefaultCharset);
str = config->readEntry("composer-charset", "");
if (str.isNull() || str=="default" || !KGlobal::charsets()->isAvailable(str))
mDefComposeCharset="default";
else
mDefComposeCharset=str;
debug("Default composer charset: %s", (const char*)mDefComposeCharset);
#endif
config->setGroup("Geometry");
str = config->readEntry("composer", "480 510");
sscanf(str.data(), "%d %d", &w, &h);
if (w<200) w=200;
if (h<200) h=200;
resize(w, h);
mIdentity.insertStringList( KMIdentity::identities() );
for (int i=0; i < mIdentity.count(); ++i)
if (mIdentity.text(i) == mId) {
mIdentity.setCurrentItem(i);
break;
}
if (!mBtnTransport.isChecked() || mTransportHistory.isEmpty()) {
QString curTransport;
config->setGroup("sending mail");
if (config->readEntry("Method") == "mail")
curTransport = "file://" + config->readEntry("Mailer");
else
curTransport = "smtp://" + config->readEntry("Smtp Host") + ":" +
config->readEntry("Smtp Port");
mTransportHistory.remove( curTransport );
mTransportHistory.prepend( curTransport );
}
while (mTransportHistory.count() > (uint)maxTransportItems)
mTransportHistory.remove( mTransportHistory.last());
mTransport.insertStringList( mTransportHistory );
}
//-----------------------------------------------------------------------------
void KMComposeWin::writeConfig(void)
{
KConfig *config = kapp->config();
QString str;
config->setGroup("Composer");
config->writeEntry("signature", mAutoSign?"auto":"manual");
config->writeEntry("show-toolbar", mShowToolBar);
config->writeEntry("encoding", mDefEncoding);
config->writeEntry("headers", mShowHeaders);
config->writeEntry("sticky-transport", mBtnTransport.isChecked());
config->writeEntry("sticky-identity", mBtnIdentity.isChecked());
config->writeEntry("previous-identity", mIdentity.currentText() );
mTransportHistory.remove(mTransport.currentText());
mTransportHistory.prepend(mTransport.currentText());
config->writeEntry("transport-history", mTransportHistory );
#if defined CHARSETS
config->writeEntry("7bit-is-ascii",m7BitAscii);
config->writeEntry("quote-unknown",mQuoteUnknownCharacters);
config->writeEntry("default-charset",mDefaultCharset);
config->writeEntry("composer-charset",mDefComposeCharset);
#endif
config->setGroup("Geometry");
str.sprintf("%d %d", width(), height());
config->writeEntry("composer", str);
}
//-----------------------------------------------------------------------------
void KMComposeWin::deadLetter(void)
{
if (!mMsg) return;
// This method is called when KMail crashed, so we better use as
// basic functions as possible here.
applyChanges();
QString msgStr = mMsg->asString();
QString fname = getenv("HOME");
fname += "/dead.letter";
// Security: the file is created in the user's home directory, which
// might be readable by other users. So the file only gets read/write
// permissions for the user himself. Note that we create the file with
// correct permissions, we do not set them after creating the file!
// (dnaber, 2000-02-27):
int fd = open(fname, O_CREAT|O_APPEND|O_WRONLY, S_IWRITE|S_IREAD);
if (fd != -1)
{
QString startStr = "From " + mMsg->from() + " " + mMsg->dateShortStr() + "\n";
::write(fd, startStr.latin1(), startStr.length());
::write(fd, msgStr.latin1(), msgStr.length()); // TODO?: not unicode aware :-(
::write(fd, "\n", 1);
::close(fd);
fprintf(stderr,"appending message to ~/dead.letter\n");
}
else perror("cannot open ~/dead.letter for saving the current message");
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotView(void)
{
if (!mDone)
return; // otherwise called from rethinkFields during the construction
// which is not the intended behavior
int id;
//This sucks awfully, but no, I cannot get an activated(int id) from
// actionContainer()
if (!sender()->isA("KToggleAction"))
return;
KToggleAction *act = (KToggleAction *) sender();
if (act == allFieldsAction)
id = 0;
else if (act == identityAction)
id = HDR_IDENTITY;
else if (act == transportAction)
id = HDR_TRANSPORT;
else if (act == fromAction)
id = HDR_FROM;
else if (act == replyToAction)
id = HDR_REPLY_TO;
else if (act == toAction)
id = HDR_TO;
else if (act == ccAction)
id = HDR_CC;
else if (act == bccAction)
id = HDR_BCC;
else if (act == subjectAction)
id = HDR_SUBJECT;
#ifdef KRN
else if (act == newsgroupsAction)
id = HDR_NEWSGROUPS;
else if (act == followupToAction)
id = HDR_FOLLOWUP_TO;
#endif
else
{
id = 0;
debug("Something is wrong (Oh, yeah?)");
return;
}
// sanders There's a bug here this logic doesn't work if no
// fields are shown and then show all fields is selected.
// Instead of all fields being shown none are.
if (!act->isChecked())
{
// hide header
if (id > 0) mShowHeaders = mShowHeaders & ~id;
else mShowHeaders = abs(mShowHeaders);
}
else
{
// show header
if (id > 0) mShowHeaders |= id;
else mShowHeaders = -abs(mShowHeaders);
}
rethinkFields(true);
}
void KMComposeWin::rethinkFields(bool fromSlot)
{
//This sucks even more but again no ids. sorry (sven)
int mask, row, numRows;
long showHeaders;
if (mShowHeaders < 0)
showHeaders = HDR_ALL;
else
showHeaders = mShowHeaders;
for (mask=1,mNumHeaders=0; mask<=showHeaders; mask<<=1)
if ((showHeaders&mask) != 0) mNumHeaders++;
numRows = mNumHeaders + 2;
if (mGrid) delete mGrid;
mGrid = new QGridLayout(&mMainWidget, numRows, 3, 4, 4);
mGrid->setColStretch(0, 1);
mGrid->setColStretch(1, 100);
mGrid->setColStretch(2, 1);
mGrid->setRowStretch(mNumHeaders, 100);
mEdtList.clear();
row = 0;
debug( "KMComposeWin::rethinkFields" );
if (!fromSlot) allFieldsAction->setChecked(showHeaders==HDR_ALL);
if (!fromSlot) identityAction->setChecked(abs(mShowHeaders)&HDR_IDENTITY);
rethinkHeaderLine(showHeaders,HDR_IDENTITY, row, i18n("&Identity:"),
&mLblIdentity, &mIdentity, &mBtnIdentity);
if (!fromSlot) transportAction->setChecked(abs(mShowHeaders)&HDR_TRANSPORT);
rethinkHeaderLine(showHeaders,HDR_TRANSPORT, row, i18n("Mai&l Transport:"),
&mLblTransport, &mTransport, &mBtnTransport);
if (!fromSlot) fromAction->setChecked(abs(mShowHeaders)&HDR_FROM);
rethinkHeaderLine(showHeaders,HDR_FROM, row, i18n("Fro&m:"),
&mLblFrom, &mEdtFrom, &mBtnFrom);
if (!fromSlot) replyToAction->setChecked(abs(mShowHeaders)&HDR_REPLY_TO);
rethinkHeaderLine(showHeaders,HDR_REPLY_TO,row,i18n("&Reply to:"),
&mLblReplyTo, &mEdtReplyTo, &mBtnReplyTo);
if (!fromSlot) toAction->setChecked(abs(mShowHeaders)&HDR_TO);
rethinkHeaderLine(showHeaders,HDR_TO, row, i18n("&To:"),
&mLblTo, &mEdtTo, &mBtnTo);
if (!fromSlot) ccAction->setChecked(abs(mShowHeaders)&HDR_CC);
rethinkHeaderLine(showHeaders,HDR_CC, row, i18n("&Cc:"),
&mLblCc, &mEdtCc, &mBtnCc);
if (!fromSlot) bccAction->setChecked(abs(mShowHeaders)&HDR_BCC);
rethinkHeaderLine(showHeaders,HDR_BCC, row, i18n("&Bcc:"),
&mLblBcc, &mEdtBcc, &mBtnBcc);
if (!fromSlot) subjectAction->setChecked(abs(mShowHeaders)&HDR_SUBJECT);
rethinkHeaderLine(showHeaders,HDR_SUBJECT, row, i18n("S&ubject:"),
&mLblSubject, &mEdtSubject);
#ifdef KRN
if (!fromSlot) newsgroupsAction->setChecked(abs(mShowHeaders)&HDR_NEWSGROUPS);
rethinkHeaderLine(showHeaders,HDR_NEWSGROUPS, row, i18n("&Newsgroups:"),
&mLblNewsgroups, &mEdtNewsgroups);
if (!fromSlot) followupToAction->setChecked(abs(mShowHeaders)&HDR_FOLLOWUP_TO);
rethinkHeaderLine(showHeaders,HDR_FOLLOWUP_TO, row, i18n("&Followup-To:"),
&mLblFollowupTo, &mEdtFollowupTo);
#endif
assert(row<=mNumHeaders);
mGrid->addMultiCellWidget(mEditor, row, mNumHeaders, 0, 2);
mGrid->addMultiCellWidget(mAtmListBox, mNumHeaders+1, mNumHeaders+1, 0, 2);
if (mAtmList.count() > 0) mAtmListBox->show();
else mAtmListBox->hide();
resize(this->size());
repaint();
mGrid->activate();
identityAction->setEnabled(!allFieldsAction->isChecked());
transportAction->setEnabled(!allFieldsAction->isChecked());
fromAction->setEnabled(!allFieldsAction->isChecked());
replyToAction->setEnabled(!allFieldsAction->isChecked());
toAction->setEnabled(!allFieldsAction->isChecked());
ccAction->setEnabled(!allFieldsAction->isChecked());
bccAction->setEnabled(!allFieldsAction->isChecked());
subjectAction->setEnabled(!allFieldsAction->isChecked());
#ifdef KRN
newsgroupsAction->setEnabled(!allFieldsAction->isChecked());
followupToAction->setEnabled(!allFieldsAction->isChecked());
#endif
}
//-----------------------------------------------------------------------------
void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
const QString aLabelStr, QLabel* aLbl,
QLineEdit* aEdt, QPushButton* aBtn)
{
if (aValue & aMask)
{
aLbl->setText(aLabelStr);
aLbl->adjustSize();
aLbl->resize((int)aLbl->sizeHint().width(),aLbl->sizeHint().height() + 6);
aLbl->setMinimumSize(aLbl->size());
aLbl->show();
aLbl->setBuddy(aEdt);
mGrid->addWidget(aLbl, aRow, 0);
aEdt->setBackgroundColor( backColor );
aEdt->show();
aEdt->setMinimumSize(100, aLbl->height()+2);
aEdt->setMaximumSize(1000, aLbl->height()+2);
mEdtList.append(aEdt);
if (aBtn)
{
mGrid->addWidget(aEdt, aRow, 1);
mGrid->addWidget(aBtn, aRow, 2);
aBtn->setFixedSize(aBtn->sizeHint().width(), aLbl->height());
aBtn->show();
}
else mGrid->addMultiCellWidget(aEdt, aRow, aRow, 1, 2);
aRow++;
}
else
{
aLbl->hide();
aEdt->hide();
if (aBtn) aBtn->hide();
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
const QString aLabelStr, QLabel* aLbl,
QComboBox* aCbx, QCheckBox* aChk)
{
if (aValue & aMask)
{
aLbl->setText(aLabelStr);
aLbl->adjustSize();
aLbl->resize((int)aLbl->sizeHint().width(),aLbl->sizeHint().height() + 6);
aLbl->setMinimumSize(aLbl->size());
aLbl->show();
aLbl->setBuddy(aCbx);
mGrid->addWidget(aLbl, aRow, 0);
// aCbx->setBackgroundColor( backColor );
aCbx->show();
aCbx->setMinimumSize(100, aLbl->height()+2);
aCbx->setMaximumSize(1000, aLbl->height()+2);
mEdtList.append(aCbx);
mGrid->addWidget(aCbx, aRow, 1);
mGrid->addWidget(aChk, aRow, 2);
aChk->setFixedSize(aChk->sizeHint().width(), aLbl->height());
aChk->show();
aRow++;
}
else
{
aLbl->hide();
aCbx->hide();
aChk->hide();
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::setupActions(void)
{
if (kernel->msgSender()->sendImmediate()) //default == send now?
{
//default = send now, alternative = queue
(void) new KAction (i18n("&Send"), QIconSet(BarIcon("send")), CTRL+Key_Return,
this, SLOT(slotSendNow()), actionCollection(),
"send_default");
(void) new KAction (i18n("&Queue"), QIconSet(BarIcon("filemail")), 0,
this, SLOT(slotSendLater()),
actionCollection(), "send_alternative");
}
else //no, default = send later
{
//default = queue, alternative = send now
(void) new KAction (i18n("&Queue"), QIconSet(BarIcon("filemail")),
CTRL+Key_Return,
this, SLOT(slotSendLater()), actionCollection(),
"send_default");
(void) new KAction (i18n("S&end now"), QIconSet(BarIcon("send")), 0,
this, SLOT(slotSendNow()),
actionCollection(), "send_alternative");
}
(void) new KAction (i18n("&Insert File..."), QIconSet(BarIcon("fileopen")), 0,
this, SLOT(slotInsertFile()),
actionCollection(), "insert_file");
(void) new KAction (i18n("&Addressbook..."), QIconSet(BarIcon("contents")),0,
this, SLOT(slotAddrBook()),
actionCollection(), "addresbook");
(void) new KAction (i18n("&New Composer..."), QIconSet(BarIcon("filenew")),
KStdAccel::key(KStdAccel::New),
this, SLOT(slotNewComposer()),
actionCollection(), "new_composer");
#ifndef KRN
(void) new KAction (i18n("Open Mailreader"), /*QIconSet(BarIcon("kmail")),*/
0, this, SLOT(slotNewMailReader()),
actionCollection(), "open_mailreader");
#endif
//KStdAction::save(this, SLOT(), actionCollection(), "save_message");
KStdAction::print (this, SLOT(slotPrint()), actionCollection());
KStdAction::close (this, SLOT(slotClose()), actionCollection());
KStdAction::undo (mEditor, SLOT(undo()), actionCollection());
KStdAction::redo (mEditor, SLOT(redo()), actionCollection());
KStdAction::cut (this, SLOT(slotCut()), actionCollection());
KStdAction::copy (this, SLOT(slotCopy()), actionCollection());
KStdAction::paste (this, SLOT(slotPaste()), actionCollection());
KStdAction::selectAll (this, SLOT(slotMarkAll()), actionCollection());
KStdAction::find (this, SLOT(slotFind()), actionCollection());
KStdAction::replace (this, SLOT(slotReplace()), actionCollection());
KStdAction::spelling (this, SLOT(slotSpellcheck()), actionCollection(), "spellcheck");
(void) new KAction (i18n("Cl&ean Spaces"), 0, this, SLOT(slotCleanSpace()),
actionCollection(), "clean_spaces");
//these are checkable!!!
urgentAction = new KToggleAction (i18n("&Urgent"), 0,
actionCollection(),
"urgent");
confirmDeliveryAction = new KToggleAction (i18n("&Confirm delivery"), 0,
actionCollection(),
"confirm_delivery");
confirmReadAction = new KToggleAction (i18n("&Confirm read"), 0,
actionCollection(), "confirm_read");
(void) new KAction (i18n("&Spellchecker..."), 0, this, SLOT(slotSpellcheckConfig()),
actionCollection(), "setup_spellchecker");
#if defined CHARSETS
(void) new KAction (i18n("&Charsets..."), 0, this, SLOT(slotConfigureCharsets()),
actionCollection(), "charsets");
#endif
KStdAction::configureToolbars(this, SLOT(slotEditToolbars()), actionCollection());
//these are checkable!!!
allFieldsAction = new KToggleAction (i18n("&All Fields"), 0, this,
SLOT(slotView()),
actionCollection(), "show_all_fields");
identityAction = new KToggleAction (i18n("&Identity"), 0, this,
SLOT(slotView()),
actionCollection(), "show_identity");
transportAction = new KToggleAction (i18n("&Mail Transport"), 0, this,
SLOT(slotView()),
actionCollection(), "show_transport");
fromAction = new KToggleAction (i18n("&From"), 0, this,
SLOT(slotView()),
actionCollection(), "show_from");
replyToAction = new KToggleAction (i18n("&Reply to"), 0, this,
SLOT(slotView()),
actionCollection(), "show_reply_to");
toAction = new KToggleAction (i18n("&To"), 0, this,
SLOT(slotView()),
actionCollection(), "show_to");
ccAction = new KToggleAction (i18n("&Cc"), 0, this,
SLOT(slotView()),
actionCollection(), "show_cc");
bccAction = new KToggleAction (i18n("&Bcc"), 0, this,
SLOT(slotView()),
actionCollection(), "show_bcc");
subjectAction = new KToggleAction (i18n("&Subject"), 0, this,
SLOT(slotView()),
actionCollection(), "show_subject");
#ifdef KRN
(void) new KToggleAction (i18n("&Newsgroups"), 0, this,
SLOT(slotView()),
actionCollection(), "show_newsgroups");
(void) new KToggleAction (i18n("&Followup-To"), 0, this,
SLOT(slotView()),
actionCollection(), "show_followup_to");
#endif
//end of checkable
(void) new KAction (i18n("Append S&ignature"), 0, this,
SLOT(slotAppendSignature()),
actionCollection(), "append_signature");
(void) new KAction (i18n("&Attach..."), QIconSet(UserIcon("attach")),
0, this, SLOT(slotAttachFile()),
actionCollection(), "attach");
(void) new KAction (i18n("Attach &Public Key"), 0, this,
SLOT(slotInsertPublicKey()),
actionCollection(), "attach_public_key");
KAction *attachMPK = new KAction (i18n("Attach My &Public Key"), 0, this,
SLOT(slotInsertMyPublicKey()),
actionCollection(), "attach_my_public_key");
KAction *attachPK = new KAction (i18n("&Remove"), 0, this,
SLOT(slotAttachRemove()),
actionCollection(), "remove");
(void) new KAction (i18n("&Save..."), QIconSet(BarIcon("filesave")),0,
this, SLOT(slotAttachSave()),
actionCollection(), "attach_save");
(void) new KAction (i18n("Pr&operties..."), 0, this,
SLOT(slotAttachProperties()),
actionCollection(), "attach_properties");
encryptAction = new KToggleAction (i18n("Encrypt message"),
QIconSet(UserIcon("pub_key_red")), 0,
actionCollection(), "encrypt_message");
signAction = new KToggleAction (i18n("Sign message"),
QIconSet(UserIcon("feather_white")), 0,
actionCollection(), "sign_message");
if(!Kpgp::getKpgp()->havePGP())
{
attachPK->setEnabled(false);
attachMPK->setEnabled(false);
encryptAction->setEnabled(false);
signAction->setEnabled(false);
}
signAction->setChecked(mAutoPgpSign);
createGUI("kmcomposerui.rc");
}
//-----------------------------------------------------------------------------
void KMComposeWin::setupStatusBar(void)
{
statusBar()->addWidget( new QLabel( statusBar(), "" ), 1 );
statusBar()->insertItem(QString(i18n(" Column"))+": ",2,0,true);
statusBar()->insertItem(QString(i18n(" Line"))+": ",1,0,true);
setStatusBar(statusBar());
}
//-----------------------------------------------------------------------------
void KMComposeWin::updateCursorPosition()
{
int col,line;
QString temp;
line = mEditor->currentLine();
col = mEditor->currentColumn();
temp = QString(" %1: %2 ").arg(i18n("Line")).arg(line+1);
statusBar()->changeItem(temp,1);
temp = QString(" %1: %2 ").arg(i18n("Column")).arg(col+1);
statusBar()->changeItem(temp,2);
}
//-----------------------------------------------------------------------------
void KMComposeWin::setupEditor(void)
{
QPopupMenu* menu;
mEditor = new KMEdit(&mMainWidget, this);
mEditor->setModified(FALSE);
//mEditor->setFocusPolicy(QWidget::ClickFocus);
if (mWordWrap)
{
mEditor->setWordWrap( QMultiLineEdit::FixedColumnWidth );
mEditor->setWrapColumnOrWidth(mLineBreak);
}
else
{
mEditor->setWordWrap( QMultiLineEdit::NoWrap );
}
// Font setup
mEditor->setFont(mBodyFont);
// Color setup
mEditor->setPalette(mPalette);
mEditor->setBackgroundColor(backColor);
menu = new QPopupMenu();
//#ifdef BROKEN
menu->insertItem(i18n("Undo"),mEditor,
SLOT(undo()), KStdAccel::key(KStdAccel::Undo));
menu->insertItem(i18n("Redo"),mEditor,
SLOT(redo()), KStdAccel::key(KStdAccel::Redo));
menu->insertSeparator();
//#endif //BROKEN
menu->insertItem(i18n("Cut"), this, SLOT(slotCut()));
menu->insertItem(i18n("Copy"), this, SLOT(slotCopy()));
menu->insertItem(i18n("Paste"), this, SLOT(slotPaste()));
menu->insertItem(i18n("Mark all"),this, SLOT(slotMarkAll()));
menu->insertSeparator();
menu->insertItem(i18n("Find..."), this, SLOT(slotFind()));
menu->insertItem(i18n("Replace..."), this, SLOT(slotReplace()));
mEditor->installRBPopup(menu);
updateCursorPosition();
connect(mEditor,SIGNAL(CursorPositionChanged()),SLOT(updateCursorPosition()));
connect(mEditor,SIGNAL(gotUrlDrop(QDropEvent *)),SLOT(slotDropAction(QDropEvent *)));
}
//-----------------------------------------------------------------------------
void KMComposeWin::verifyWordWrapLengthIsAdequate(const QString &body)
{
int maxLineLength = 0;
int curPos;
int oldPos = 0;
if (mEditor->QMultiLineEdit::wordWrap() == QMultiLineEdit::FixedColumnWidth) {
for (curPos = 0; curPos < (int)body.length(); ++curPos)
if (body[curPos] == '\n') {
if ((curPos - oldPos) > maxLineLength)
maxLineLength = curPos - oldPos;
oldPos = curPos;
}
if ((curPos - oldPos) > maxLineLength)
maxLineLength = curPos - oldPos;
if (mEditor->wrapColumnOrWidth() < maxLineLength) // column
mEditor->setWrapColumnOrWidth(maxLineLength);
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::setMsg(KMMessage* newMsg, bool mayAutoSign)
{
KMMessagePart bodyPart, *msgPart;
int i, num;
//assert(newMsg!=NULL);
if(!newMsg)
{
debug("KMComposeWin::setMsg() : newMsg == NULL!\n");
return;
}
mMsg = newMsg;
mEdtTo.setText(mMsg->to());
mEdtFrom.setText(mMsg->from());
mEdtCc.setText(mMsg->cc());
mEdtSubject.setText(mMsg->subject());
mEdtReplyTo.setText(mMsg->replyTo());
mEdtBcc.setText(mMsg->bcc());
#ifdef KRN
mEdtNewsgroups.setText(mMsg->groups());
mEdtFollowupTo.setText(mMsg->followup());
#endif
if ((mBtnIdentity.isChecked()) && (!mId.isEmpty())) {
KMIdentity ident( mId );
ident.readConfig();
mEdtFrom.setText( ident.fullEmailAddr() );
mEdtReplyTo.setText( ident.replyToAddr() );
}
num = mMsg->numBodyParts();
if (num > 0)
{
QString bodyDecoded;
mMsg->bodyPart(0, &bodyPart);
#if defined CHARSETS
mCharset=bodyPart.charset();
cout<<"Charset: "<<mCharset<<"\n";
if (mCharset==""){
mComposeCharset=mDefComposeCharset;
if (mComposeCharset=="default"
&& KGlobal::charsets()->isAvailable(mDefaultCharset))
mComposeCharset=mDefaultCharset;
}
else if (KGlobal::charsets()->isAvailable(mCharset))
mComposeCharset=mCharset;
else mComposeCharset=mDefComposeCharset;
cout<<"Compose charset: "<<mComposeCharset<<"\n";
// FIXME: We might need a QTextCodec here
#endif
bodyDecoded = QString(bodyPart.bodyDecoded());
verifyWordWrapLengthIsAdequate(bodyDecoded);
mEditor->setText(bodyDecoded);
mEditor->insertLine("\n", -1);
for(i=1; i<num; i++)
{
msgPart = new KMMessagePart;
mMsg->bodyPart(i, msgPart);
addAttach(msgPart);
}
}
#if defined CHARSETS
else{
mCharset=mMsg->charset();
cout<<"mCharset: "<<mCharset<<"\n";
if (mCharset==""){
mComposeCharset=mDefComposeCharset;
if (mComposeCharset=="default"
&& KGlobal::charsets()->isAvailable(mDefaultCharset))
mComposeCharset=mDefaultCharset;
}
else if (KGlobal::charsets()->isAvailable(mCharset))
mComposeCharset=mCharset;
else mComposeCharset=mDefComposeCharset;
cout<<"Compose charset: "<<mComposeCharset<<"\n";
// FIXME: QTextCodec needed?
Editor->setText(QString(mMsg->bodyDecoded()));
}
#else
else {
QString bodyDecoded = QString(mMsg->bodyDecoded());
verifyWordWrapLengthIsAdequate(bodyDecoded);
mEditor->setText(bodyDecoded);
}
#endif
if( mAutoSign && mayAutoSign )
{
//
// Espen 2000-05-16
// Delay the signature appending. It may start a fileseletor.
// Not user friendy if this modal fileseletor opens before the
// composer.
//
QTimer::singleShot( 0, this, SLOT(slotAppendSignature()) );
}
mEditor->setModified(FALSE);
#if defined CHARSETS
setEditCharset();
#endif
}
//-----------------------------------------------------------------------------
bool KMComposeWin::applyChanges(void)
{
QString str, atmntStr;
QString temp, replyAddr;
KMMessagePart bodyPart, *msgPart;
//assert(mMsg!=NULL);
if(!mMsg)
{
debug("KMComposeWin::applyChanges() : mMsg == NULL!\n");
return FALSE;
}
mMsg->setTo(to());
mMsg->setFrom(from());
mMsg->setCc(cc());
mMsg->setSubject(subject());
mMsg->setReplyTo(replyTo());
mMsg->setBcc(bcc());
#ifdef KRN
mMsg->setFollowup(followupTo());
mMsg->setGroups(newsgroups());
#endif
if (!replyTo().isEmpty()) replyAddr = replyTo();
else replyAddr = from();
if (confirmDeliveryAction->isChecked())
mMsg->setHeaderField("Return-Receipt-To", replyAddr);
if (confirmReadAction->isChecked())
mMsg->setHeaderField("X-Chameleon-Return-To", replyAddr);
if (urgentAction->isChecked())
{
mMsg->setHeaderField("X-PRIORITY", "2 (High)");
mMsg->setHeaderField("Priority", "urgent");
}
#ifndef KRN
_StringPair *pCH;
for (pCH = mCustHeaders.first();
pCH != NULL;
pCH = mCustHeaders.next()) {
mMsg->setHeaderField(pCH->name, pCH->value);
}
#endif
if(mAtmList.count() <= 0)
{
mMsg->setAutomaticFields(FALSE);
// If there are no attachments in the list waiting it is a simple
// text message.
if (kernel->msgSender()->sendQuotedPrintable())
{
mMsg->setTypeStr("text");
mMsg->setSubtypeStr("plain");
mMsg->setCteStr("quoted-printable");
str = pgpProcessedMsg();
if (str.isNull()) return FALSE;
#if defined CHARSETS
convertToSend(str);
cout<<"Setting charset to: "<<mCharset<<"\n";
mMsg->setCharset(mCharset);
#endif
mMsg->setBodyEncoded(str);
}
else
{
mMsg->setTypeStr("text");
mMsg->setSubtypeStr("plain");
mMsg->setCteStr("8bit");
str = pgpProcessedMsg();
if (str.isNull()) return FALSE;
#if defined CHARSETS
convertToSend(str);
cout<<"Setting charset to: "<<mCharset<<"\n";
mMsg->setCharset(mCharset);
#endif
mMsg->setBody(str);
}
}
else
{
mMsg->deleteBodyParts();
mMsg->setAutomaticFields(TRUE);
// create informative header for those that have no mime-capable
// email client
mMsg->setBody("This message is in MIME format.\n\n");
// create bodyPart for editor text.
if (kernel->msgSender()->sendQuotedPrintable())
bodyPart.setCteStr("quoted-printable");
else bodyPart.setCteStr("8bit");
bodyPart.setTypeStr("text");
bodyPart.setSubtypeStr("plain");
str = pgpProcessedMsg();
if (str.isNull()) return FALSE;
#if defined CHARSETS
convertToSend(str);
cout<<"Setting charset to: "<<mCharset<<"\n";
mMsg->setCharset(mCharset);
#endif
str.truncate(str.length()); // to ensure str.size()==str.length()+1
bodyPart.setBodyEncoded(QCString(str.ascii()));
mMsg->addBodyPart(&bodyPart);
// Since there is at least one more attachment create another bodypart
for (msgPart=mAtmList.first(); msgPart; msgPart=mAtmList.next())
mMsg->addBodyPart(msgPart);
}
if (!mAutoDeleteMsg) mEditor->setModified(FALSE);
// remove fields that contain no data (e.g. an empty Cc: or Bcc:)
mMsg->cleanupHeader();
return TRUE;
}
//-----------------------------------------------------------------------------
bool KMComposeWin::queryClose ()
{
int rc;
if(mEditor->isModified())
{
rc = KMessageBox::warningContinueCancel(this,
i18n("Close and discard\nedited message?"),
i18n("Close message"), i18n("&Discard"));
if (rc == KMessageBox::Cancel)
return false;
}
return true;
}
bool KMComposeWin::queryExit ()
{
return true;
}
//-----------------------------------------------------------------------------
const QString KMComposeWin::pgpProcessedMsg(void)
{
Kpgp *pgp = Kpgp::getKpgp();
bool doSign = signAction->isChecked();
bool doEncrypt = encryptAction->isChecked();
QString _to, receiver;
int index, lastindex;
QStrList persons;
if (!doSign && !doEncrypt) return mEditor->brokenText();
pgp->setMessage(mEditor->brokenText());
if (!doEncrypt)
{
if(pgp->sign()) return pgp->message();
}
else
{
// encrypting
_to = to().copy();
if(!cc().isEmpty()) _to += "," + cc();
if(!bcc().isEmpty()) _to += "," + bcc();
lastindex = -1;
do
{
index = _to.find(",",lastindex+1);
receiver = _to.mid(lastindex+1, index<0 ? 255 : index-lastindex-1);
if (!receiver.isEmpty())
{
persons.append(receiver);
}
lastindex = index;
}
while (lastindex > 0);
if(pgp->encryptFor(persons, doSign))
return pgp->message();
}
// in case of an error we end up here
//warning(i18n("Error during PGP:") + QString("\n") +
// pgp->lastErrorMsg());
return QString::null;
}
//-----------------------------------------------------------------------------
void KMComposeWin::addAttach(const QString aUrl)
{
QString name;
QByteArray str;
KMMessagePart* msgPart;
KMMsgPartDlg dlg;
int i;
// load the file
kernel->kbp()->busy();
str = kFileToBytes(aUrl,FALSE);
if (str.isNull())
{
kernel->kbp()->idle();
return;
}
// create message part
i = aUrl.findRev('/');
name = (i>=0 ? aUrl.mid(i+1, 256) : aUrl);
msgPart = new KMMessagePart;
msgPart->setName(name);
msgPart->setCteStr(mDefEncoding);
msgPart->setBodyEncoded(str);
msgPart->magicSetType();
msgPart->setContentDisposition("attachment; filename=\""+name+"\"");
// show properties dialog
kernel->kbp()->idle();
dlg.setMsgPart(msgPart);
if (!dlg.exec())
{
delete msgPart;
return;
}
// add the new attachment to the list
addAttach(msgPart);
rethinkFields(); //work around initial-size bug in Qt-1.32
}
//-----------------------------------------------------------------------------
void KMComposeWin::addAttach(const KMMessagePart* msgPart)
{
mAtmList.append(msgPart);
// show the attachment listbox if it does not up to now
if (mAtmList.count()==1)
{
mGrid->setRowStretch(mNumHeaders+1, 50);
mAtmListBox->setMinimumSize(100, 80);
mAtmListBox->setMaximumHeight( 100 );
mAtmListBox->show();
resize(size());
}
// add a line in the attachment listbox
QListViewItem *lvi = new QListViewItem(mAtmListBox);
msgPartToItem(msgPart, lvi);
mAtmItemList.append(lvi);
}
//-----------------------------------------------------------------------------
void KMComposeWin::msgPartToItem(const KMMessagePart* msgPart,
QListViewItem *lvi)
{
unsigned int len;
QString lenStr;
assert(msgPart != NULL);
len = msgPart->size();
if (len > 9999) lenStr.sprintf("%uK", (len>>10));
else lenStr.sprintf("%u", len);
lvi->setText(0, msgPart->name());
lvi->setText(1, lenStr);
lvi->setText(2, msgPart->contentTransferEncodingStr());
lvi->setText(3, msgPart->typeStr() + "/" + msgPart->subtypeStr());
}
//-----------------------------------------------------------------------------
void KMComposeWin::removeAttach(const QString aUrl)
{
int idx;
KMMessagePart* msgPart;
for(idx=0,msgPart=mAtmList.first(); msgPart;
msgPart=mAtmList.next(),idx++) {
if (msgPart->name() == aUrl) {
removeAttach(idx);
return;
}
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::removeAttach(int idx)
{
mAtmList.remove(idx);
delete mAtmItemList.take(idx);
if (mAtmList.count()<=0)
{
mAtmListBox->hide();
mGrid->setRowStretch(mNumHeaders+1, 0);
mAtmListBox->setMinimumSize(0, 0);
resize(size());
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::addrBookSelInto(KMLineEdit* aLineEdit)
{
if (kernel->useKAB()) {
if(kernel->KABaddrBook()!=0)
{
if(kernel->KABaddrBook()->addressbook()->noOfEntries()==0)
{
KMessageBox::information
(this,
i18n("Your address book does not contain entries."),
i18n("No addresses"));
} else {
QString address;
AddressBook::Entry entry;
KabKey key;
for(;;)
{
if(!kernel->KABaddrBook()->exec()) break; // rejected
switch(kernel->KABaddrBook()->getEntry(entry, key))
{
case AddressBook::NoError: // an entry has been selected
// ----- a test:
if(entry.emails.isEmpty())
{ // may be allow to enter one?
KMessageBox::information
(this,
i18n("This address has no email address.\n"
"Please try another one."),
i18n("No email addresses"));
continue;
} else {
// ----- assemble address string:
// here you see how to use the AddressBook
// object from the KabApi:
kernel->KABaddrBook()->addressbook()->literalName
(entry, address);
if(entry.emails.count()>1)
{ // select one of the addresses:
// ... WORK_TO_DO
// append selected address to address:
address=address + " <" + entry.emails.first()
+">";
} else {
address=address + " <" + entry.emails.first()
+">";
}
aLineEdit->setText(address);
}
break;
default:
KMessageBox::information
(this,
i18n("Some error occured while browsing the address book."),
i18n("Error"));
}
break;
}
}
}
}
else {
KMAddrBookSelDlg dlg(kernel->addrBook());
QString txt;
//assert(aLineEdit!=NULL);
if(!aLineEdit)
{
debug("KMComposeWin::addrBookSelInto() : aLineEdit == NULL\n");
return;
}
if (dlg.exec()==QDialog::Rejected) return;
txt = QString(aLineEdit->text()).stripWhiteSpace();
if (!txt.isEmpty())
{
if (txt.right(1).at(0)!=',') txt += ", ";
else txt += ' ';
}
aLineEdit->setText(txt + dlg.address());
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotAddrBook()
{
if (!kernel->useKAB()) {
KMAddrBookEditDlg dlg( kernel->addrBook(), this );
dlg.exec();
}
else
debug("KMComposeWin::slotAddrBook: not implemented.");
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotAddrBookFrom()
{
addrBookSelInto(&mEdtFrom);
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotAddrBookReplyTo()
{
addrBookSelInto(&mEdtReplyTo);
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotAddrBookTo()
{
addrBookSelInto(&mEdtTo);
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotAddrBookCc()
{
addrBookSelInto(&mEdtCc);
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotAddrBookBcc()
{
addrBookSelInto(&mEdtBcc);
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotAttachFile()
{
// Create File Dialog and return selected file
// We will not care about any permissions, existence or whatsoever in
// this function.
if (mPathAttach.isEmpty()) mPathAttach = QDir::currentDirPath();
KFileDialog fdlg(mPathAttach, "*", this, NULL, TRUE);
fdlg.setCaption(i18n("Attach File"));
if (!fdlg.exec()) return;
KURL u = fdlg.selectedURL();
mPathAttach = u.directory();
if(u.filename().isEmpty()) return;
addAttach(u.path());
mEditor->setModified(TRUE);
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotInsertFile()
{
QString str;
int col, line;
if (mPathAttach.isEmpty()) mPathAttach = QDir::currentDirPath();
KFileDialog fdlg(mPathAttach, "*", this, NULL, TRUE);
fdlg.setCaption(i18n("Include File"));
if (!fdlg.exec()) return;
KURL u = fdlg.selectedURL();
mPathAttach = u.directory();
if (u.filename().isEmpty()) return;
if( !u.isLocalFile() )
{
KMessageBox::sorry( 0L, i18n( "Only local files are supported." ) );
return;
}
str = kFileToString(u.path(), TRUE, TRUE);
if (str.isEmpty()) return;
mEditor->getCursorPosition(&line, &col);
mEditor->insertAt(QCString(str), line, col);
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotInsertMyPublicKey()
{
QString str, name;
KMMessagePart* msgPart;
// load the file
kernel->kbp()->busy();
str=Kpgp::getKpgp()->getAsciiPublicKey(mMsg->from());
if (str.isNull())
{
kernel->kbp()->idle();
return;
}
// create message part
msgPart = new KMMessagePart;
msgPart->setName(i18n("my pgp key"));
msgPart->setCteStr(mDefEncoding);
msgPart->setTypeStr("application");
msgPart->setSubtypeStr("pgp-keys");
msgPart->setBodyEncoded(QCString(str.ascii()));
msgPart->setContentDisposition("attachment; filename=public_key.asc");
// add the new attachment to the list
addAttach(msgPart);
rethinkFields(); //work around initial-size bug in Qt-1.32
kernel->kbp()->idle();
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotInsertPublicKey()
{
QString str, name;
KMMessagePart* msgPart;
Kpgp *pgp;
pgp=Kpgp::getKpgp();
str=pgp->getAsciiPublicKey(
KpgpKey::getKeyName(this, pgp->keys()));
// create message part
msgPart = new KMMessagePart;
msgPart->setName(i18n("pgp key"));
msgPart->setCteStr(mDefEncoding);
msgPart->setTypeStr("application");
msgPart->setSubtypeStr("pgp-keys");
msgPart->setBodyEncoded(QCString(str.ascii()));
msgPart->setContentDisposition("attachment; filename=public_key.asc");
// add the new attachment to the list
addAttach(msgPart);
rethinkFields(); //work around initial-size bug in Qt-1.32
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotAttachPopupMenu(QListViewItem *, const QPoint &, int)
{
QPopupMenu *menu = new QPopupMenu;
menu->insertItem(i18n("View..."), this, SLOT(slotAttachView()));
menu->insertItem(i18n("Save..."), this, SLOT(slotAttachSave()));
menu->insertItem(i18n("Properties..."),
this, SLOT(slotAttachProperties()));
menu->insertItem(i18n("Remove"), this, SLOT(slotAttachRemove()));
menu->insertSeparator();
menu->insertItem(i18n("Attach..."), this, SLOT(slotAttachFile()));
menu->popup(QCursor::pos());
}
//-----------------------------------------------------------------------------
int KMComposeWin::currentAttachmentNum()
{
int idx = -1;
QListIterator<QListViewItem> it(mAtmItemList);
for ( int i = 0; it.current(); ++it, ++i )
if (*it == mAtmListBox->currentItem()) {
idx = i;
break;
}
return idx;
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotAttachProperties()
{
KMMsgPartDlg dlg;
KMMessagePart* msgPart;
int idx = currentAttachmentNum();
if (idx < 0) return;
msgPart = mAtmList.at(idx);
dlg.setMsgPart(msgPart);
if (dlg.exec())
{
// values may have changed, so recreate the listbox line
msgPartToItem(msgPart, mAtmItemList.at(idx));
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotAttachView()
{
QString str, pname;
KMMessagePart* msgPart;
QMultiLineEdit* edt = new QMultiLineEdit;
int idx = currentAttachmentNum();
if (idx < 0) return;
msgPart = mAtmList.at(idx);
pname = msgPart->name();
if (pname.isEmpty()) pname=msgPart->contentDescription();
if (pname.isEmpty()) pname="unnamed";
kernel->kbp()->busy();
str = QCString(msgPart->bodyDecoded());
edt->setCaption(i18n("View Attachment: ") + pname);
edt->insertLine(str);
edt->setReadOnly(TRUE);
edt->show();
kernel->kbp()->idle();
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotAttachSave()
{
KMMessagePart* msgPart;
QString fileName, pname;
int idx = currentAttachmentNum();
if (idx < 0) return;
msgPart = mAtmList.at(idx);
pname = msgPart->name();
if (pname.isEmpty()) pname="unnamed";
if (mPathAttach.isEmpty()) mPathAttach = QDir::currentDirPath();
KURL url = KFileDialog::getSaveURL(mPathAttach, "*", NULL, pname);
if( url.isEmpty() )
return;
if( !url.isLocalFile() )
{
KMessageBox::sorry( 0L, i18n( "Only local files supported yet." ) );
return;
}
fileName = url.path();
kByteArrayToFile(msgPart->bodyDecoded(), fileName, TRUE);
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotAttachRemove()
{
int idx = currentAttachmentNum();
if (idx >= 0)
{
removeAttach(idx);
mEditor->setModified(TRUE);
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotToggleToolBar()
{
enableToolBar(KToolBar::Toggle);
mShowToolBar = !mShowToolBar;
repaint();
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotFind()
{
mEditor->search();
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotReplace()
{
mEditor->replace();
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotCut()
{
QWidget* fw = focusWidget();
if (!fw) return;
if (fw->inherits("KEdit"))
((QMultiLineEdit*)fw)->cut();
else if (fw->inherits("KMLineEdit"))
((KMLineEdit*)fw)->cut();
else debug("wrong focus widget");
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotCopy()
{
QWidget* fw = focusWidget();
if (!fw) return;
#ifdef KeyPress
#undef KeyPress
#endif
QKeyEvent k(QEvent::KeyPress, Key_C , 0 , ControlButton);
kapp->notify(fw, &k);
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotPaste()
{
QWidget* fw = focusWidget();
if (!fw) return;
#ifdef KeyPress
#undef KeyPress
#endif
QKeyEvent k(QEvent::KeyPress, Key_V , 0 , ControlButton);
kapp->notify(fw, &k);
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotMarkAll()
{
QWidget* fw = focusWidget();
if (!fw) return;
if (fw->inherits("QLineEdit"))
((QLineEdit*)fw)->selectAll();
else if (fw->inherits("QMultiLineEdit"))
((QMultiLineEdit*)fw)->selectAll();
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotClose()
{
close(FALSE);
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotNewComposer()
{
KMComposeWin* win;
KMMessage* msg = new KMMessage;
msg->initHeader();
win = new KMComposeWin(msg);
win->show();
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotNewMailReader()
{
#ifndef KRN
KMMainWin *kmmwin = new KMMainWin(NULL);
kmmwin->show();
//d->resize(d->size());
#endif
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotToDo()
{
warning(i18n("Sorry, but this feature\nis still missing"));
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotUpdWinTitle(const QString& text)
{
if (text.isEmpty())
setCaption("("+QString(i18n("unnamed"))+")");
else setCaption(text);
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotPrint()
{
QPrinter printer;
QPainter paint;
QString str;
if (printer.setup(this))
{
paint.begin(&printer);
str += i18n("To:");
str += " \n";
str += to();
str += "\n";
str += i18n("Subject:");
str += " \n";
str += subject();
str += i18n("Date:");
str += " \n\n";
str += mEditor->brokenText();
str += "\n";
//str.replace(QRegExp("\n"),"\n");
paint.drawText(30,30,str);
paint.end();
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotDropAction(QDropEvent *e)
{
QString file;
QStringList fileList;
QStringList::Iterator it;
if(QUriDrag::canDecode(e) && QUriDrag::decodeLocalFiles( e, fileList )) {
for (it = fileList.begin(); it != fileList.end(); ++it) {
(*it).replace(QRegExp("file:"),"");
addAttach(*it);
}
}
else
KMessageBox::sorry( 0L, i18n( "Only local files are supported." ) );
}
//----------------------------------------------------------------------------
void KMComposeWin::doSend(int aSendNow)
{
bool sentOk;
kernel->kbp()->busy();
//applyChanges(); // is called twice otherwise. Lars
mMsg->setDateToday();
mMsg->setHeaderField("X-KMail-Transport", mTransport.currentText());
sentOk = (applyChanges() && kernel->msgSender()->send(mMsg, aSendNow));
kernel->kbp()->idle();
if (sentOk)
{
mAutoDeleteMsg = FALSE;
close();
}
}
//----------------------------------------------------------------------------
void KMComposeWin::slotSendLater()
{
doSend(FALSE);
}
//----------------------------------------------------------------------------
void KMComposeWin::slotSendNow()
{
#ifndef KRN
if (mConfirmSend) {
switch(QMessageBox::information(&mMainWidget,
i18n("Send Confirmation"),
i18n("About to send email..."),
i18n("Send &Now"),
i18n("Send &Later"),
i18n("&Cancel"),
0,
2)) {
case 0: // send now
doSend(TRUE);
break;
case 1: // send later
doSend(FALSE);
break;
case 2: // cancel
break;
default:
; // whoa something weird happened here!
}
return;
}
#endif
doSend(TRUE);
}
void KMComposeWin::slotAppendSignature()
{
QString identStr = "unknown";
if( !mId.isEmpty() && KMIdentity::identities().contains( mId ) )
{
identStr = mId;
}
bool mod = mEditor->isModified();
KMIdentity ident( identStr );
ident.readConfig();
QString sigText = ident.signature();
if( sigText.isEmpty() && ident.useSignatureFile() )
{
// open a file dialog and let the user choose manually
#warning KFileDialog misses localfiles only flag.
KFileDialog dlg( QDir::homeDirPath(), QString::null, this, 0, TRUE );
dlg.setCaption(i18n("Choose Signature File"));
if( !dlg.exec() )
{
return;
}
KURL url = dlg.selectedURL();
if( url.isEmpty() )
{
return;
}
if( !url.isLocalFile() )
{
KMessageBox::sorry( 0L, i18n( "Only local files are supported." ) );
return;
}
QString sigFileName = url.path();
sigText = kFileToString(sigFileName, TRUE);
ident.setSignatureFile(sigFileName);
ident.writeConfig(true);
}
mOldSigText = sigText;
if( !sigText.isEmpty() )
{
/* actually "\n-- \n" (note the space) is a convention for attaching
signatures and we should respect it: */
mEditor->insertLine("-- ", -1);
mEditor->insertLine(sigText, -1);
mEditor->setModified(mod);
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotHelp()
{
kapp->invokeHTMLHelp("","");
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotCleanSpace()
{
if (!mEditor) return;
mEditor->cleanWhiteSpace();
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotSpellcheck()
{
if (mSpellCheckInProgress) return;
mSpellCheckInProgress=TRUE;
/*
connect (mEditor, SIGNAL (spellcheck_progress (unsigned)),
this, SLOT (spell_progress (unsigned)));
*/
if(mEditor){
connect (mEditor, SIGNAL (spellcheck_done()),
this, SLOT (slotSpellcheckDone ()));
mEditor->spellcheck();
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotSpellcheckDone()
{
debug( "spell check complete" );
mSpellCheckInProgress=FALSE;
statusBar()->changeItem(i18n("Spellcheck complete."),0);
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotConfigureCharsets()
{
#if defined CHARSETS
CharsetsDlg *dlg=new CharsetsDlg((const char*)mCharset,
(const char*)mComposeCharset,
m7BitAscii,mQuoteUnknownCharacters);
connect(dlg,SIGNAL( setCharsets(const char *,const char *,bool,bool,bool) )
,this,SLOT(slotSetCharsets(const char *,const char dlg->show();
*,bool,bool,bool)));
delete dlg;
#endif
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotSetCharsets(const char *message,const char *composer,
bool ascii,bool quote,bool def)
{
// prevent warning
(void)message;
(void)composer;
(void)ascii;
(void)quote;
(void)def;
#if defined CHARSETS
mCharset=message;
m7BitAscii=ascii;
mComposeCharset=composer;
mQuoteUnknownCharacters=quote;
if (def)
{
mDefaultCharset=message;
mDefComposeCharset=composer;
}
setEditCharset();
#endif
}
#if defined CHARSETS
//-----------------------------------------------------------------------------
bool KMComposeWin::is8Bit(const QString str)
{
const char *ptr=str;
while(*ptr)
{
if ( (*ptr)&0x80 ) return TRUE;
else if ( (*ptr)=='&' && ptr[1]=='#' )
{
int code=atoi(ptr+2);
if (code>0x7f) return TRUE;
}
ptr++;
}
return FALSE;
}
//-----------------------------------------------------------------------------
void KMComposeWin::convertToSend(const QString str)
{
cout<<"Converting to send...\n";
if (m7BitAscii && !is8Bit(str))
{
mCharset="us-ascii";
return;
}
if (mCharset=="")
{
if (mDefaultCharset=="default")
mCharset=KGlobal::charsets()->charsetForLocale();
else mCharset=mDefaultCharset;
}
cout<<"mCharset: "<<mCharset<<"\n";
}
//-----------------------------------------------------------------------------
void KMComposeWin::setEditCharset()
{
QFont fnt=mSavedEditorFont;
if (mComposeCharset=="default")
mComposeCharset=KGlobal::charsets()->charsetForLocale();
cout<<"Setting font to: "<<mComposeCharset<<"\n";
KGlobal::charsets()->setQFont(fnt, mComposeCharset);
mEditor->setFont(fnt);
}
#endif //CHARSETS
//-----------------------------------------------------------------------------
void KMComposeWin::focusNextPrevEdit(const QWidget* aCur, bool aNext)
{
QWidget* cur;
if (!aCur)
{
cur=mEdtList.last();
}
else
{
for (cur=mEdtList.first(); aCur!=cur && cur; cur=mEdtList.next())
;
if (!cur) return;
if (aNext) cur = mEdtList.next();
else cur = mEdtList.prev();
}
if (cur) cur->setFocus();
else if (aNext) mEditor->setFocus(); //Key up from first doea nothing (sven)
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotIdentityActivated(int)
{
QString identStr = mIdentity.currentText();
if (!KMIdentity::identities().contains(identStr))
return;
KMIdentity ident(identStr);
ident.readConfig();
if(!ident.fullEmailAddr().isNull())
mEdtFrom.setText(ident.fullEmailAddr());
if(!ident.replyToAddr().isNull())
mEdtReplyTo.setText(ident.replyToAddr());
if (ident.organization().isEmpty())
mMsg->removeHeaderField("Organization");
else
mMsg->setHeaderField("Organization", ident.organization());
QString edtText = mEditor->text();
int pos = edtText.findRev(mOldSigText);
if ((pos > 0) && (pos + mOldSigText.length() == edtText.length())) {
bool mod = mEditor->isModified();
edtText.truncate(pos);
edtText.append(ident.signature());
mEditor->setText(edtText);
mEditor->setModified(mod);
mOldSigText = ident.signature();
}
mId = identStr;
}
//=============================================================================
//
// Class KMLineEdit
//
//=============================================================================
KMLineEdit::KMLineEdit(KMComposeWin* composer, QWidget *parent,
const char *name): KMLineEditInherited(parent,name)
{
mComposer = composer;
installEventFilter(this);
connect (this, SIGNAL(completion()), this, SLOT(slotCompletion()));
}
//-----------------------------------------------------------------------------
KMLineEdit::~KMLineEdit()
{
removeEventFilter(this);
}
//-----------------------------------------------------------------------------
bool KMLineEdit::eventFilter(QObject*, QEvent* e)
{
#ifdef KeyPress
#undef KeyPress
#endif
if (e->type() == QEvent::KeyPress)
{
QKeyEvent* k = (QKeyEvent*)e;
if (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)
{
mComposer->focusNextPrevEdit(this,TRUE);
return TRUE;
}
if (k->state()==ControlButton && k->key() == Key_Right)
{
if ((int)strlen(text()) == cursorPosition()) // at End?
{
emit completion();
cursorAtEnd();
return TRUE;
}
return FALSE;
}
if (k->key() == Key_Up)
{
mComposer->focusNextPrevEdit(this,FALSE); // Go up
return TRUE;
}
if (k->key() == Key_Down)
{
mComposer->focusNextPrevEdit(this,TRUE); // Go down
return TRUE;
}
// ---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;
}
//-----------------------------------------------------------------------------
void KMLineEdit::cursorAtEnd()
{
QKeyEvent ev( QEvent::KeyPress, Key_End, 0, 0 );
QLineEdit::keyPressEvent( &ev );
}
//-----------------------------------------------------------------------------
void KMLineEdit::copy()
{
QString t = markedText();
QApplication::clipboard()->setText(t);
}
//-----------------------------------------------------------------------------
void KMLineEdit::cut()
{
if(hasMarkedText())
{
QString t = markedText();
QKeyEvent k(QEvent::KeyPress, Key_D, 0, ControlButton);
keyPressEvent(&k);
QApplication::clipboard()->setText(t);
}
}
//-----------------------------------------------------------------------------
void KMLineEdit::paste()
{
QKeyEvent k(QEvent::KeyPress, Key_V, 0, ControlButton);
keyPressEvent(&k);
}
//-----------------------------------------------------------------------------
void KMLineEdit::markAll()
{
selectAll();
}
//-----------------------------------------------------------------------------
void KMLineEdit::slotCompletion()
{
QString t;
QString Name(name());
if (Name == "subjectLine")
{
//mComposer->focusNextPrevEdit(this,TRUE); //IMHO, it is useless now (sven)
return;
}
QPopupMenu pop;
int n;
KMAddrBook adb;
adb.readConfig();
if(adb.load() == IO_FatalError)
return;
QString s(text());
QString prevAddr;
n = s.findRev(',');
if (n>=0)
{
prevAddr = s.left(n+1) + ' ';
s = s.mid(n+1,255).stripWhiteSpace();
}
//s.append("*");
//QRegExp regexp(s.data(), FALSE, TRUE);
n=0;
for (QString a=adb.first(); a; a=adb.next())
{
//t.setStr(a);
//if (t.contains(regexp))
if (QString(a).find(s,0,false) >= 0)
{
pop.insertItem(a);
n++;
}
}
if (n > 1)
{
int id;
pop.popup(parentWidget()->mapToGlobal(QPoint(x(), y()+height())));
pop.setActiveItem(pop.idAt(0));
id = pop.exec();
if (id!=-1)
{
setText(prevAddr + pop.text(id));
//mComposer->focusNextPrevEdit(this,TRUE);
}
}
else if (n==1)
{
setText(prevAddr + pop.text(pop.idAt(0)));
//mComposer->focusNextPrevEdit(this,TRUE);
}
setFocus();
cursorAtEnd();
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotSpellcheckConfig()
{
KWin kwin;
QTabDialog qtd (this, "tabdialog", true);
KSpellConfig mKSpellConfig (&qtd);
qtd.addTab (&mKSpellConfig, "Spellchecker");
qtd.setCancelButton ();
kwin.setIcons (qtd.winId(), kapp->icon(), kapp->miniIcon());
if (qtd.exec())
mKSpellConfig.writeGlobalSettings();
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotEditToolbars()
{
KEditToolbar dlg(actionCollection(), "kmcomposerui.rc");
if (dlg.exec() == true)
{
createGUI("kmcomposerui.rc");
}
}
//=============================================================================
//
// Class KMEdit
//
//=============================================================================
KMEdit::KMEdit(QWidget *parent, KMComposeWin* composer,
const char *name):
KMEditInherited(parent, name)
{
initMetaObject();
mComposer = composer;
installEventFilter(this);
#ifndef KRN
extEditor = false; // the default is to use ourself
#endif
mKSpell = NULL;
}
//-----------------------------------------------------------------------------
KMEdit::~KMEdit()
{
removeEventFilter(this);
if (mKSpell) delete mKSpell;
}
//-----------------------------------------------------------------------------
QString KMEdit::brokenText() const
{
QString temp;
for (int i = 0; i < numLines(); ++i) {
temp += *getString(i);
if (i + 1 < numLines())
temp += '\n';
}
return temp;
}
//-----------------------------------------------------------------------------
bool KMEdit::eventFilter(QObject*, QEvent* e)
{
if (e->type() == QEvent::KeyPress)
{
QKeyEvent *k = (QKeyEvent*)e;
#ifndef KRN
if (extEditor) {
if (k->key() == Key_Up)
{
mComposer->focusNextPrevEdit(0, false); //take me up
return TRUE;
}
QRegExp repFn("\\%f");
QString sysLine = mExtEditor;
KTempFile tmpFile;
QString tmpName = tmpFile.name();
tmpFile.setAutoDelete(true);
fprintf(tmpFile.fstream(), "%s", (const char *)text());
tmpFile.close();
// replace %f in the system line
sysLine.replace(repFn, tmpName);
system((const char *)sysLine);
setAutoUpdate(false);
clear();
// read data back in from file
insertLine(kFileToString(tmpName, TRUE, FALSE), -1);
// QFile mailFile(tmpName);
// while (!mailFile.atEnd()) {
// QString oneLine;
// mailFile.readLine(oneLine, 1024);
// insertLine(oneLine, -1);
// }
// setModified(true);
// mailFile.close();
setAutoUpdate(true);
repaint();
return TRUE;
} else {
#endif
if (k->key()==Key_Tab)
{
int col, row;
getCursorPosition(&row, &col);
insertAt(" ", row, col); // insert tab character '\t'
emit CursorPositionChanged();
return TRUE;
}
// ---sven's Arrow key navigation start ---
// Key Up in first line takes you to Subject line.
if (k->key() == Key_Up && currentLine() == 0)
{
mComposer->focusNextPrevEdit(0, false); //take me up
return TRUE;
}
// ---sven's Arrow key navigation end ---
#ifndef KRN
}
#endif
}
return FALSE;
}
//-----------------------------------------------------------------------------
void KMEdit::spellcheck()
{
mKSpell = new KSpell(this, i18n("Spellcheck - KMail"), this,
SLOT(slotSpellcheck2(KSpell*)));
connect (mKSpell, SIGNAL( death()),
this, SLOT (slotSpellDone()));
connect (mKSpell, SIGNAL (misspelling (QString, QStringList *, unsigned)),
this, SLOT (misspelling (QString, QStringList *, unsigned)));
connect (mKSpell, SIGNAL (corrected (QString, QString, unsigned)),
this, SLOT (corrected (QString, QString, unsigned)));
connect (mKSpell, SIGNAL (done(const QString &)),
this, SLOT (slotSpellResult (const QString&)));
}
//-----------------------------------------------------------------------------
void KMEdit::slotSpellcheck2(KSpell*)
{
spellcheck_start();
//we're going to want to ignore quoted-message lines...
mKSpell->check(text());
}
//-----------------------------------------------------------------------------
void KMEdit::slotSpellResult(const QString &aNewText)
{
spellcheck_stop();
if (mKSpell->dlgResult() == 0)
{
setText(aNewText);
}
mKSpell->cleanUp();
}
//-----------------------------------------------------------------------------
void KMEdit::slotSpellDone()
{
KSpell::spellStatus status = mKSpell->status();
delete mKSpell;
mKSpell = 0;
if (status == KSpell::Error)
{
KMessageBox::sorry(this, i18n("ISpell could not be started.\n Please make sure you have ISpell properly configured and in your PATH."));
}
else if (status == KSpell::Crashed)
{
spellcheck_stop();
KMessageBox::sorry(this, i18n("ISpell seems to have crashed."));
}
else
{
emit spellcheck_done();
}
}