TDE personal information management applications
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5422 lines
188 KiB

// -*- mode: C++; c-file-style: "gnu" -*-
// kmcomposewin.cpp
// Author: Markus Wuebben <markus.wuebben@kde.org>
// This code is published under the GPL.
#undef GrayScale
#undef Color
#include <config.h>
#define REALLY_WANT_KMCOMPOSEWIN_H
#include "kmcomposewin.h"
#undef REALLY_WANT_KMCOMPOSEWIN_H
#include "kmedit.h"
#include "kmlineeditspell.h"
#include "kmatmlistview.h"
#include "kmmainwin.h"
#include "kmreadermainwin.h"
#include "messagesender.h"
#include "kmmsgpartdlg.h"
#include <kpgpblock.h>
#include <kaddrbook.h>
#include "kmaddrbook.h"
#include "kmmsgdict.h"
#include "kmfolderimap.h"
#include "kmfoldermgr.h"
#include "kmfoldercombobox.h"
#include "kmtransport.h"
#include "kmcommands.h"
#include "kcursorsaver.h"
#include "partNode.h"
#include "encodingdetector.h"
#include "attachmentlistview.h"
#include "transportmanager.h"
using KMail::AttachmentListView;
#include "dictionarycombobox.h"
using KMail::DictionaryComboBox;
#include "addressesdialog.h"
using KPIM::AddressesDialog;
#include "addresseeemailselection.h"
using KPIM::AddresseeEmailSelection;
using KPIM::AddresseeSelectorDialog;
#include <maillistdrag.h>
using KPIM::MailListDrag;
#include "recentaddresses.h"
using TDERecentAddress::RecentAddresses;
#include "kleo_util.h"
#include "stl_util.h"
#include "recipientseditor.h"
#include "editorwatcher.h"
#include "attachmentcollector.h"
#include "objecttreeparser.h"
#include "kmfoldermaildir.h"
#include <libkpimidentities/identitymanager.h>
#include <libkpimidentities/identitycombo.h>
#include <libkpimidentities/identity.h>
#include <libtdepim/tdefileio.h>
#include <libemailfunctions/email.h>
#include <kleo/cryptobackendfactory.h>
#include <kleo/exportjob.h>
#include <kleo/specialjob.h>
#include <ui/progressdialog.h>
#include <ui/keyselectiondialog.h>
#include <gpgmepp/context.h>
#include <gpgmepp/key.h>
#include <tdeio/netaccess.h>
#include "tdelistboxdialog.h"
#include "messagecomposer.h"
#include "chiasmuskeyselector.h"
#include <kcharsets.h>
#include <tdecompletionbox.h>
#include <kcursor.h>
#include <kcombobox.h>
#include <tdestdaccel.h>
#include <tdepopupmenu.h>
#include <kedittoolbar.h>
#include <kkeydialog.h>
#include <kdebug.h>
#include <tdefiledialog.h>
#include <twin.h>
#include <kinputdialog.h>
#include <tdemessagebox.h>
#include <kurldrag.h>
#include <tdeio/scheduler.h>
#include <tdetempfile.h>
#include <tdelocale.h>
#include <tdeapplication.h>
#include <kstatusbar.h>
#include <tdeaction.h>
#include <kstdaction.h>
#include <kdirwatch.h>
#include <kstdguiitem.h>
#include <kiconloader.h>
#include <kpushbutton.h>
#include <kuserprofile.h>
#include <krun.h>
#include <ktempdir.h>
#include <kstandarddirs.h>
//#include <keditlistbox.h>
#include "globalsettings.h"
#include "replyphrases.h"
#include <tdespell.h>
#include <tdespelldlg.h>
#include <spellingfilter.h>
#include <ksyntaxhighlighter.h>
#include <kcolordialog.h>
#include <kzip.h>
#include <ksavefile.h>
#include <tqtabdialog.h>
#include <tqregexp.h>
#include <tqbuffer.h>
#include <tqtooltip.h>
#include <tqtextcodec.h>
#include <tqheader.h>
#include <tqwhatsthis.h>
#include <tqfontdatabase.h>
#include <mimelib/mimepp.h>
#include <algorithm>
#include <memory>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <assert.h>
#include "kmcomposewin.moc"
#include "snippetwidget.h"
KMail::Composer * KMail::makeComposer( KMMessage * msg, uint identitiy ) {
return KMComposeWin::create( msg, identitiy );
}
KMail::Composer * KMComposeWin::create( KMMessage * msg, uint identitiy ) {
return new KMComposeWin( msg, identitiy );
}
//-----------------------------------------------------------------------------
KMComposeWin::KMComposeWin( KMMessage *aMsg, uint id )
: MailComposerIface(), KMail::Composer( "kmail-composer#" ),
mSpellCheckInProgress( false ),
mDone( false ),
mAtmModified( false ),
mAtmSelectNew( 0 ),
mMsg( 0 ),
mAttachMenu( 0 ),
mSigningAndEncryptionExplicitlyDisabled( false ),
mFolder( 0 ),
mUseHTMLEditor( false ),
mId( id ),
mAttachPK( 0 ), mAttachMPK( 0 ),
mAttachRemoveAction( 0 ), mAttachSaveAction( 0 ), mAttachPropertiesAction( 0 ),
mAppendSignatureAction( 0 ), mPrependSignatureAction( 0 ), mInsertSignatureAction( 0 ),
mSignAction( 0 ), mEncryptAction( 0 ), mRequestMDNAction( 0 ),
mUrgentAction( 0 ), mAllFieldsAction( 0 ), mFromAction( 0 ),
mReplyToAction( 0 ), mToAction( 0 ), mCcAction( 0 ), mBccAction( 0 ),
mSubjectAction( 0 ),
mIdentityAction( 0 ), mTransportAction( 0 ), mFccAction( 0 ),
mWordWrapAction( 0 ), mFixedFontAction( 0 ), mAutoSpellCheckingAction( 0 ),
mDictionaryAction( 0 ), mSnippetAction( 0 ),
mEncodingAction( 0 ),
mCryptoModuleAction( 0 ),
mEncryptChiasmusAction( 0 ),
mEncryptWithChiasmus( false ),
mComposer( 0 ),
mLabelWidth( 0 ),
mAutoSaveTimer( 0 ), mLastAutoSaveErrno( 0 ),
mSignatureStateIndicator( 0 ), mEncryptionStateIndicator( 0 ),
mPreserveUserCursorPosition( false ),
mPreventFccOverwrite( false ),
mCheckForRecipients( true ),
mCheckForForgottenAttachments( true ),
mIgnoreStickyFields( false )
{
mClassicalRecipients = GlobalSettings::self()->recipientsEditorType() ==
GlobalSettings::EnumRecipientsEditorType::Classic;
mSubjectTextWasSpellChecked = false;
if (kmkernel->xmlGuiInstance())
setInstance( kmkernel->xmlGuiInstance() );
mMainWidget = new TQWidget(this);
// splitter between the headers area and the actual editor
mHeadersToEditorSplitter = new TQSplitter( Qt::Vertical, mMainWidget, "mHeadersToEditorSplitter" );
mHeadersToEditorSplitter->setChildrenCollapsible( false );
mHeadersArea = new TQWidget( mHeadersToEditorSplitter );
mHeadersArea->setSizePolicy( mHeadersToEditorSplitter->sizePolicy().horData(), TQSizePolicy::Maximum );
TQVBoxLayout *v = new TQVBoxLayout( mMainWidget );
v->addWidget( mHeadersToEditorSplitter );
mIdentity = new KPIM::IdentityCombo(kmkernel->identityManager(), mHeadersArea);
TQToolTip::add( mIdentity,
i18n( "Select an identity for this message" ) );
mDictionaryCombo = new DictionaryComboBox( mHeadersArea );
TQToolTip::add( mDictionaryCombo,
i18n( "Select the dictionary to use when spell-checking this message" ) );
mFcc = new KMFolderComboBox(mHeadersArea);
mFcc->showOutboxFolder( false );
TQToolTip::add( mFcc,
i18n( "Select the sent-mail folder where a copy of this message will be saved" ) );
mTransport = new TQComboBox(true, mHeadersArea);
TQToolTip::add( mTransport,
i18n( "Select the outgoing account to use for sending this message" ) );
mEdtFrom = new KMLineEdit(false,mHeadersArea, "fromLine");
TQToolTip::add( mEdtFrom,
i18n( "Set the \"From:\" email address for this message" ) );
mEdtReplyTo = new KMLineEdit(true,mHeadersArea, "replyToLine");
TQToolTip::add( mEdtReplyTo,
i18n( "Set the \"Reply-To:\" email address for this message" ) );
connect(mEdtReplyTo,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
if ( mClassicalRecipients ) {
mRecipientsEditor = 0;
mEdtTo = new KMLineEdit(true,mHeadersArea, "toLine");
mEdtCc = new KMLineEdit(true,mHeadersArea, "ccLine");
mEdtBcc = new KMLineEdit(true,mHeadersArea, "bccLine");
mLblTo = new TQLabel(mHeadersArea);
mLblCc = new TQLabel(mHeadersArea);
mLblBcc = new TQLabel(mHeadersArea);
mBtnTo = new TQPushButton("...",mHeadersArea);
mBtnCc = new TQPushButton("...",mHeadersArea);
mBtnBcc = new TQPushButton("...",mHeadersArea);
//mBtnFrom = new TQPushButton("...",mHeadersArea);
TQString tip = i18n("Select email address(es)");
TQToolTip::add( mBtnTo, tip );
TQToolTip::add( mBtnCc, tip );
TQToolTip::add( mBtnBcc, tip );
mBtnTo->setFocusPolicy(TQ_NoFocus);
mBtnCc->setFocusPolicy(TQ_NoFocus);
mBtnBcc->setFocusPolicy(TQ_NoFocus);
//mBtnFrom->setFocusPolicy(TQ_NoFocus);
connect(mBtnTo,TQT_SIGNAL(clicked()),TQT_SLOT(slotAddrBookTo()));
connect(mBtnCc,TQT_SIGNAL(clicked()),TQT_SLOT(slotAddrBookTo()));
connect(mBtnBcc,TQT_SIGNAL(clicked()),TQT_SLOT(slotAddrBookTo()));
//connect(mBtnFrom,TQT_SIGNAL(clicked()),TQT_SLOT(slotAddrBookFrom()));
connect(mEdtTo,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
connect(mEdtCc,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
connect(mEdtBcc,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
mEdtTo->setFocus();
} else {
mEdtTo = 0;
mEdtCc = 0;
mEdtBcc = 0;
mLblTo = 0;
mLblCc = 0;
mLblBcc = 0;
mBtnTo = 0;
mBtnCc = 0;
mBtnBcc = 0;
//mBtnFrom = 0;
mRecipientsEditor = new RecipientsEditor( mHeadersArea );
connect( mRecipientsEditor,
TQT_SIGNAL( completionModeChanged( TDEGlobalSettings::Completion ) ),
TQT_SLOT( slotCompletionModeChanged( TDEGlobalSettings::Completion ) ) );
connect( mRecipientsEditor, TQT_SIGNAL(sizeHintChanged()), TQT_SLOT(recipientEditorSizeHintChanged()) );
mRecipientsEditor->setFocus();
}
mEdtSubject = new KMLineEditSpell(false,mHeadersArea, "subjectLine");
TQToolTip::add( mEdtSubject,
i18n( "Set a subject for this message" ) );
mLblIdentity = new TQLabel( i18n("&Identity:"), mHeadersArea );
mDictionaryLabel = new TQLabel( i18n("&Dictionary:"), mHeadersArea );
mLblFcc = new TQLabel( i18n("&Sent-Mail folder:"), mHeadersArea );
mLblTransport = new TQLabel( i18n("&Mail transport:"), mHeadersArea );
mLblFrom = new TQLabel( i18n("sender address field", "&From:"), mHeadersArea );
mLblReplyTo = new TQLabel( i18n("&Reply to:"), mHeadersArea );
mLblSubject = new TQLabel( i18n("S&ubject:"), mHeadersArea );
TQString sticky = i18n("Sticky");
mBtnIdentity = new TQCheckBox(sticky,mHeadersArea);
TQToolTip::add( mBtnIdentity,
i18n( "Use the selected value as your identity for future messages" ) );
mBtnFcc = new TQCheckBox(sticky,mHeadersArea);
TQToolTip::add( mBtnFcc,
i18n( "Use the selected value as your sent-mail folder for future messages" ) );
mBtnTransport = new TQCheckBox(sticky,mHeadersArea);
TQToolTip::add( mBtnTransport,
i18n( "Use the selected value as your outgoing account for future messages" ) );
mBtnDictionary = new TQCheckBox( sticky, mHeadersArea );
TQToolTip::add( mBtnDictionary,
i18n( "Use the selected value as your dictionary for future messages" ) );
//setWFlags( WType_TopLevel | WStyle_Dialog );
mHtmlMarkup = GlobalSettings::self()->useHtmlMarkup();
mShowHeaders = GlobalSettings::self()->headers();
mDone = false;
mGrid = 0;
mAtmListView = 0;
mAtmList.setAutoDelete(true);
mAtmTempList.setAutoDelete(true);
mAtmModified = false;
mAutoDeleteMsg = false;
mFolder = 0;
mAutoCharset = true;
mFixedFontAction = 0;
mTempDir = 0;
// the attachment view is separated from the editor by a splitter
mSplitter = new TQSplitter( Qt::Vertical, mHeadersToEditorSplitter, "mSplitter" );
mSplitter->setChildrenCollapsible( false );
mSnippetSplitter = new TQSplitter( Qt::Horizontal, mSplitter, "mSnippetSplitter");
mSnippetSplitter->setChildrenCollapsible( false );
TQWidget *editorAndCryptoStateIndicators = new TQWidget( mSnippetSplitter );
TQVBoxLayout *vbox = new TQVBoxLayout( editorAndCryptoStateIndicators );
TQHBoxLayout *hbox = new TQHBoxLayout( vbox );
{
mSignatureStateIndicator = new TQLabel( editorAndCryptoStateIndicators );
mSignatureStateIndicator->setAlignment( TQt::AlignHCenter );
hbox->addWidget( mSignatureStateIndicator );
TDEConfigGroup reader( KMKernel::config(), "Reader" );
TQPalette p( mSignatureStateIndicator->palette() );
TQColor defaultSignedColor( 0x40, 0xFF, 0x40 ); // light green // pgp ok, trusted key
TQColor defaultEncryptedColor( 0x00, 0x80, 0xFF ); // light blue // pgp encrypted
p.setColor( TQColorGroup::Background, reader.readColorEntry( "PGPMessageOkKeyOk", &defaultSignedColor ) );
mSignatureStateIndicator->setPalette( p );
mEncryptionStateIndicator = new TQLabel( editorAndCryptoStateIndicators );
mEncryptionStateIndicator->setAlignment( TQt::AlignHCenter );
hbox->addWidget( mEncryptionStateIndicator );
p.setColor( TQColorGroup::Background, reader.readColorEntry( "PGPMessageEncr" , &defaultEncryptedColor ) );
mEncryptionStateIndicator->setPalette( p );
}
mEditor = new KMEdit( editorAndCryptoStateIndicators, this, mDictionaryCombo->spellConfig() );
vbox->addWidget( mEditor );
mSnippetWidget = new SnippetWidget( mEditor, actionCollection(), mSnippetSplitter );
mSnippetWidget->setShown( GlobalSettings::self()->showSnippetManager() );
// mSplitter->moveToFirst( editorAndCryptoStateIndicators );
mSplitter->setOpaqueResize( true );
mEditor->initializeAutoSpellChecking();
mEditor->setTextFormat(TQt::PlainText);
mEditor->setAcceptDrops( true );
TQWhatsThis::add( mBtnIdentity,
GlobalSettings::self()->stickyIdentityItem()->whatsThis() );
TQWhatsThis::add( mBtnFcc,
GlobalSettings::self()->stickyFccItem()->whatsThis() );
TQWhatsThis::add( mBtnTransport,
GlobalSettings::self()->stickyTransportItem()->whatsThis() );
TQWhatsThis::add( mBtnTransport,
GlobalSettings::self()->stickyDictionaryItem()->whatsThis() );
mSpellCheckInProgress=false;
setCaption( i18n("Composer") );
setMinimumSize(200,200);
mBtnIdentity->setFocusPolicy(TQ_NoFocus);
mBtnFcc->setFocusPolicy(TQ_NoFocus);
mBtnTransport->setFocusPolicy(TQ_NoFocus);
mBtnDictionary->setFocusPolicy( TQ_NoFocus );
mAtmListView = new AttachmentListView( this, mSplitter,
"attachment list view" );
mAtmListView->setSelectionMode( TQListView::Extended );
mAtmListView->addColumn( i18n("Name"), 200 );
mAtmListView->addColumn( i18n("Size"), 80 );
mAtmListView->addColumn( i18n("Encoding"), 120 );
int atmColType = mAtmListView->addColumn( i18n("Type"), 120 );
// Stretch "Type".
mAtmListView->header()->setStretchEnabled( true, atmColType );
mAtmEncryptColWidth = 80;
mAtmSignColWidth = 80;
mAtmCompressColWidth = 100;
mAtmColCompress = mAtmListView->addColumn( i18n("Compress"),
mAtmCompressColWidth );
mAtmColEncrypt = mAtmListView->addColumn( i18n("Encrypt"),
mAtmEncryptColWidth );
mAtmColSign = mAtmListView->addColumn( i18n("Sign"),
mAtmSignColWidth );
mAtmListView->setColumnWidth( mAtmColEncrypt, 0 );
mAtmListView->setColumnWidth( mAtmColSign, 0 );
mAtmListView->setAllColumnsShowFocus( true );
connect( mAtmListView,
TQT_SIGNAL( doubleClicked( TQListViewItem* ) ),
TQT_SLOT( slotAttachEdit() ) );
connect( mAtmListView,
TQT_SIGNAL( rightButtonPressed( TQListViewItem*, const TQPoint&, int ) ),
TQT_SLOT( slotAttachPopupMenu( TQListViewItem*, const TQPoint&, int ) ) );
connect( mAtmListView,
TQT_SIGNAL( selectionChanged() ),
TQT_SLOT( slotUpdateAttachActions() ) );
connect( mAtmListView,
TQT_SIGNAL( attachmentDeleted() ),
TQT_SLOT( slotAttachRemove() ) );
connect( mAtmListView,
TQT_SIGNAL( dragStarted() ),
TQT_SLOT( slotAttachmentDragStarted() ) );
mAttachMenu = 0;
readConfig();
setupStatusBar();
setupActions();
setupEditor();
slotUpdateSignatureAndEncrypionStateIndicators();
applyMainWindowSettings(KMKernel::config(), "Composer");
connect( mEdtSubject, TQT_SIGNAL( subjectTextSpellChecked() ),
TQT_SLOT( slotSubjectTextSpellChecked() ) );
connect(mEdtSubject,TQT_SIGNAL(textChanged(const TQString&)),
TQT_SLOT(slotUpdWinTitle(const TQString&)));
connect(mIdentity,TQT_SIGNAL(identityChanged(uint)),
TQT_SLOT(slotIdentityChanged(uint)));
connect( kmkernel->identityManager(), TQT_SIGNAL(changed(uint)),
TQT_SLOT(slotIdentityChanged(uint)));
connect(mEdtFrom,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
connect(kmkernel->folderMgr(),TQT_SIGNAL(folderRemoved(KMFolder*)),
TQT_SLOT(slotFolderRemoved(KMFolder*)));
connect(kmkernel->imapFolderMgr(),TQT_SIGNAL(folderRemoved(KMFolder*)),
TQT_SLOT(slotFolderRemoved(KMFolder*)));
connect(kmkernel->dimapFolderMgr(),TQT_SIGNAL(folderRemoved(KMFolder*)),
TQT_SLOT(slotFolderRemoved(KMFolder*)));
connect( kmkernel, TQT_SIGNAL( configChanged() ),
TQT_TQOBJECT(this), TQT_SLOT( slotConfigChanged() ) );
connect (mEditor, TQT_SIGNAL (spellcheck_done(int)),
this, TQT_SLOT (slotSpellcheckDone (int)));
connect (mEditor, TQT_SIGNAL( attachPNGImageData(const TQByteArray &) ),
this, TQT_SLOT ( slotAttachPNGImageData(const TQByteArray &) ) );
connect (mEditor, TQT_SIGNAL( focusChanged(bool) ),
this, TQT_SLOT (editorFocusChanged(bool)) );
mMainWidget->resize(480,510);
setCentralWidget(mMainWidget);
rethinkFields();
if ( !mClassicalRecipients ) {
// This is ugly, but if it isn't called the line edits in the recipients
// editor aren't wide enough until the first resize event comes.
rethinkFields();
}
if ( GlobalSettings::self()->useExternalEditor() ) {
mEditor->setUseExternalEditor(true);
mEditor->setExternalEditorPath( GlobalSettings::self()->externalEditor() );
}
initAutoSave();
slotUpdateSignatureActions();
mMsg = 0;
if (aMsg)
setMsg(aMsg);
fontChanged( mEditor->currentFont() ); // set toolbar buttons to correct values
mDone = true;
}
//-----------------------------------------------------------------------------
KMComposeWin::~KMComposeWin()
{
writeConfig();
if (mFolder && mMsg)
{
mAutoDeleteMsg = false;
mFolder->addMsg(mMsg);
// Ensure that the message is correctly and fully parsed
mFolder->unGetMsg( mFolder->count() - 1 );
}
if (mAutoDeleteMsg) {
delete mMsg;
mMsg = 0;
}
TQMap<TDEIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.begin();
while ( it != mMapAtmLoadData.end() )
{
TDEIO::Job *job = it.key();
mMapAtmLoadData.remove( it );
job->kill();
it = mMapAtmLoadData.begin();
}
deleteAll( mComposedMessages );
for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
delete *it;
}
}
void KMComposeWin::setAutoDeleteWindow( bool f )
{
if ( f )
setWFlags( getWFlags() | WDestructiveClose );
else
setWFlags( getWFlags() & ~WDestructiveClose );
}
//-----------------------------------------------------------------------------
void KMComposeWin::send(int how)
{
switch (how) {
case 1:
slotSendNow();
break;
default:
case 0:
// TODO: find out, what the default send method is and send it this way
case 2:
slotSendLater();
break;
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::addAttachmentsAndSend(const KURL::List &urls, const TQString &/*comment*/, int how)
{
if (urls.isEmpty())
{
send(how);
return;
}
mAttachFilesSend = how;
mAttachFilesPending = urls;
connect(this, TQT_SIGNAL(attachmentAdded(const KURL&, bool)), TQT_SLOT(slotAttachedFile(const KURL&)));
for( KURL::List::ConstIterator itr = urls.begin(); itr != urls.end(); ++itr ) {
if (!addAttach( *itr ))
mAttachFilesPending.remove(mAttachFilesPending.find(*itr)); // only remove one copy of the url
}
if (mAttachFilesPending.isEmpty() && mAttachFilesSend == how)
{
send(mAttachFilesSend);
mAttachFilesSend = -1;
}
}
void KMComposeWin::slotAttachedFile(const KURL &url)
{
if (mAttachFilesPending.isEmpty())
return;
mAttachFilesPending.remove(mAttachFilesPending.find(url)); // only remove one copy of url
if (mAttachFilesPending.isEmpty())
{
send(mAttachFilesSend);
mAttachFilesSend = -1;
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::addAttachment(KURL url,TQString /*comment*/)
{
addAttach(url);
}
//-----------------------------------------------------------------------------
void KMComposeWin::addAttachment(const TQString &name,
const TQCString &/*cte*/,
const TQByteArray &data,
const TQCString &type,
const TQCString &subType,
const TQCString &paramAttr,
const TQString &paramValue,
const TQCString &contDisp)
{
if (!data.isEmpty()) {
KMMessagePart *msgPart = new KMMessagePart;
msgPart->setName(name);
if( type == "message" && subType == "rfc822" ) {
msgPart->setMessageBody( data );
} else {
TQValueList<int> dummy;
msgPart->setBodyAndGuessCte(data, dummy,
kmkernel->msgSender()->sendQuotedPrintable());
}
msgPart->setTypeStr(type);
msgPart->setSubtypeStr(subType);
msgPart->setParameter(paramAttr,paramValue);
msgPart->setContentDisposition(contDisp);
addAttach(msgPart);
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::slotAttachPNGImageData(const TQByteArray &image)
{
bool ok;
TQString attName = KInputDialog::getText( "KMail", i18n("Name of the attachment:"), TQString(), &ok, this );
if ( !ok )
return;
if ( !attName.lower().endsWith(".png") ) attName += ".png";
addAttachment( attName, "base64", image, "image", "png", TQCString(), TQString(), TQCString() );
}
//-----------------------------------------------------------------------------
void KMComposeWin::setBody(TQString body)
{
mEditor->setText(body);
}
//-----------------------------------------------------------------------------
bool KMComposeWin::event(TQEvent *e)
{
if (e->type() == TQEvent::ApplicationPaletteChange)
{
readColorConfig();
}
return KMail::Composer::event(e);
}
//-----------------------------------------------------------------------------
void KMComposeWin::readColorConfig(void)
{
if ( GlobalSettings::self()->useDefaultColors() ) {
mForeColor = TQColor(kapp->palette().active().text());
mBackColor = TQColor(kapp->palette().active().base());
} else {
mForeColor = GlobalSettings::self()->foregroundColor();
mBackColor = GlobalSettings::self()->backgroundColor();
}
// Color setup
mPalette = kapp->palette();
TQColorGroup cgrp = mPalette.active();
cgrp.setColor( TQColorGroup::Base, mBackColor);
cgrp.setColor( TQColorGroup::Text, mForeColor);
mPalette.setDisabled(cgrp);
mPalette.setActive(cgrp);
mPalette.setInactive(cgrp);
mEdtFrom->setPalette(mPalette);
mEdtReplyTo->setPalette(mPalette);
if ( mClassicalRecipients ) {
mEdtTo->setPalette(mPalette);
mEdtCc->setPalette(mPalette);
mEdtBcc->setPalette(mPalette);
}
mEdtSubject->setPalette(mPalette);
mTransport->setPalette(mPalette);
mEditor->setPalette(mPalette);
mFcc->setPalette(mPalette);
}
//-----------------------------------------------------------------------------
void KMComposeWin::readConfig( bool reload /* = false */ )
{
mDefCharset = KMMessage::defaultCharset();
mBtnIdentity->setChecked( GlobalSettings::self()->stickyIdentity() );
if (mBtnIdentity->isChecked()) {
mId = (GlobalSettings::self()->previousIdentity()!=0) ?
GlobalSettings::self()->previousIdentity() : mId;
}
mBtnFcc->setChecked( GlobalSettings::self()->stickyFcc() );
mBtnTransport->setChecked( GlobalSettings::self()->stickyTransport() );
mBtnDictionary->setChecked( GlobalSettings::self()->stickyDictionary() );
TQStringList transportHistory = GlobalSettings::self()->transportHistory();
TQString currentTransport = GlobalSettings::self()->currentTransport();
mEdtFrom->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
mEdtReplyTo->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
if ( mClassicalRecipients ) {
mEdtTo->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
mEdtCc->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
mEdtBcc->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
}
else
mRecipientsEditor->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
readColorConfig();
if ( GlobalSettings::self()->useDefaultFonts() ) {
mBodyFont = TDEGlobalSettings::generalFont();
mFixedFont = TDEGlobalSettings::fixedFont();
} else {
mBodyFont = GlobalSettings::self()->composerFont();
mFixedFont = GlobalSettings::self()->fixedFont();
}
slotUpdateFont();
mEdtFrom->setFont(mBodyFont);
mEdtReplyTo->setFont(mBodyFont);
if ( mClassicalRecipients ) {
mEdtTo->setFont(mBodyFont);
mEdtCc->setFont(mBodyFont);
mEdtBcc->setFont(mBodyFont);
}
mEdtSubject->setFont(mBodyFont);
if ( !reload ) {
TQSize siz = GlobalSettings::self()->composerSize();
if (siz.width() < 200) siz.setWidth(200);
if (siz.height() < 200) siz.setHeight(200);
resize(siz);
if ( !GlobalSettings::self()->snippetSplitterPosition().isEmpty() ) {
mSnippetSplitter->setSizes( GlobalSettings::self()->snippetSplitterPosition() );
} else {
TQValueList<int> defaults;
defaults << (int)(width() * 0.8) << (int)(width() * 0.2);
mSnippetSplitter->setSizes( defaults );
}
}
mIdentity->setCurrentIdentity( mId );
kdDebug(5006) << "KMComposeWin::readConfig. " << mIdentity->currentIdentityName() << endl;
const KPIM::Identity & ident =
kmkernel->identityManager()->identityForUoid( mIdentity->currentIdentity() );
mTransport->clear();
mTransport->insertStringList( KMTransportInfo::availableTransports() );
while ( transportHistory.count() > (uint)GlobalSettings::self()->maxTransportEntries() )
transportHistory.remove( transportHistory.last() );
mTransport->insertStringList( transportHistory );
mTransport->setCurrentText( GlobalSettings::self()->defaultTransport() );
if ( mBtnTransport->isChecked() ) {
setTransport( currentTransport );
}
if ( mBtnDictionary->isChecked() ) {
mDictionaryCombo->setCurrentByDictionaryName( GlobalSettings::self()->previousDictionary() );
} else {
mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
}
TQString fccName = "";
if ( mBtnFcc->isChecked() ) {
fccName = GlobalSettings::self()->previousFcc();
} else if ( !ident.fcc().isEmpty() ) {
fccName = ident.fcc();
}
setFcc( fccName );
}
//-----------------------------------------------------------------------------
void KMComposeWin::writeConfig(void)
{
GlobalSettings::self()->setHeaders( mShowHeaders );
GlobalSettings::self()->setStickyFcc( mBtnFcc->isChecked() );
if ( !mIgnoreStickyFields ) {
GlobalSettings::self()->setCurrentTransport( mTransport->currentText() );
GlobalSettings::self()->setStickyTransport( mBtnTransport->isChecked() );
GlobalSettings::self()->setStickyDictionary( mBtnDictionary->isChecked() );
GlobalSettings::self()->setStickyIdentity( mBtnIdentity->isChecked() );
GlobalSettings::self()->setPreviousIdentity( mIdentity->currentIdentity() );
}
GlobalSettings::self()->setPreviousFcc( mFcc->getFolder()->idString() );
GlobalSettings::self()->setPreviousDictionary( mDictionaryCombo->currentDictionaryName() );
GlobalSettings::self()->setAutoSpellChecking(
mAutoSpellCheckingAction->isChecked() );
TQStringList transportHistory = GlobalSettings::self()->transportHistory();
transportHistory.remove(mTransport->currentText());
if (KMTransportInfo::availableTransports().findIndex(mTransport
->currentText()) == -1) {
transportHistory.prepend(mTransport->currentText());
}
GlobalSettings::self()->setTransportHistory( transportHistory );
GlobalSettings::self()->setUseFixedFont( mFixedFontAction->isChecked() );
GlobalSettings::self()->setUseHtmlMarkup( mHtmlMarkup );
GlobalSettings::self()->setComposerSize( size() );
GlobalSettings::self()->setShowSnippetManager( mSnippetAction->isChecked() );
TDEConfigGroupSaver saver( KMKernel::config(), "Geometry" );
saveMainWindowSettings( KMKernel::config(), "Composer" );
GlobalSettings::setSnippetSplitterPosition( mSnippetSplitter->sizes() );
// make sure config changes are written to disk, cf. bug 127538
GlobalSettings::self()->writeConfig();
}
//-----------------------------------------------------------------------------
void KMComposeWin::autoSaveMessage()
{
kdDebug(5006) << k_funcinfo << endl;
if ( !mMsg || mComposer || mAutoSaveFilename.isEmpty() )
return;
kdDebug(5006) << k_funcinfo << "autosaving message" << endl;
if ( mAutoSaveTimer )
mAutoSaveTimer->stop();
connect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
TQT_TQOBJECT(this), TQT_SLOT( slotContinueAutoSave() ) );
// This method is called when KMail crashed, so don't try signing/encryption
// and don't disable controls because it is also called from a timer and
// then the disabling is distracting.
applyChanges( true, true );
// Don't continue before the applyChanges is done!
}
void KMComposeWin::slotContinueAutoSave()
{
disconnect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
TQT_TQOBJECT(this), TQT_SLOT( slotContinueAutoSave() ) );
// Ok, it's done now - continue dead letter saving
if ( mComposedMessages.isEmpty() ) {
kdDebug(5006) << "Composing the message failed." << endl;
return;
}
KMMessage *msg = mComposedMessages.first();
if ( !msg ) // a bit of extra defensiveness
return;
kdDebug(5006) << k_funcinfo << "opening autoSaveFile " << mAutoSaveFilename
<< endl;
const TQString filename =
KMKernel::localDataPath() + "autosave/cur/" + mAutoSaveFilename;
KSaveFile autoSaveFile( filename, 0600 );
int status = autoSaveFile.status();
kdDebug(5006) << k_funcinfo << "autoSaveFile.status() = " << status << endl;
if ( status == 0 ) { // no error
kdDebug(5006) << "autosaving message in " << filename << endl;
int fd = autoSaveFile.handle();
const DwString& msgStr = msg->asDwString();
if ( ::write( fd, msgStr.data(), msgStr.length() ) == -1 )
status = errno;
}
if ( status == 0 ) {
kdDebug(5006) << k_funcinfo << "closing autoSaveFile" << endl;
autoSaveFile.close();
mLastAutoSaveErrno = 0;
}
else {
kdDebug(5006) << k_funcinfo << "autosaving failed" << endl;
autoSaveFile.abort();
if ( status != mLastAutoSaveErrno ) {
// don't show the same error message twice
KMessageBox::queuedMessageBox( 0, KMessageBox::Sorry,
i18n("Autosaving the message as %1 "
"failed.\n"
"Reason: %2" )
.arg( filename, strerror( status ) ),
i18n("Autosaving Failed") );
mLastAutoSaveErrno = status;
}
}
if ( autoSaveInterval() > 0 )
updateAutoSave();
}
//-----------------------------------------------------------------------------
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 (!TQT_TQOBJECT_CONST(sender())->isA("TDEToggleAction"))
return;
TDEToggleAction *act = (TDEToggleAction *) sender();
if (act == mAllFieldsAction)
id = 0;
else if (act == mIdentityAction)
id = HDR_IDENTITY;
else if (act == mTransportAction)
id = HDR_TRANSPORT;
else if (act == mFromAction)
id = HDR_FROM;
else if (act == mReplyToAction)
id = HDR_REPLY_TO;
else if (act == mToAction)
id = HDR_TO;
else if (act == mCcAction)
id = HDR_CC;
else if (act == mBccAction)
id = HDR_BCC;
else if (act == mSubjectAction)
id = HDR_SUBJECT;
else if (act == mFccAction)
id = HDR_FCC;
else if ( act == mDictionaryAction )
id = HDR_DICTIONARY;
else
{
id = 0;
kdDebug(5006) << "Something is wrong (Oh, yeah?)" << endl;
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);
}
int KMComposeWin::calcColumnWidth(int which, long allShowing, int width)
{
if ( (allShowing & which) == 0 )
return width;
TQLabel *w;
if ( which == HDR_IDENTITY )
w = mLblIdentity;
else if ( which == HDR_DICTIONARY )
w = mDictionaryLabel;
else if ( which == HDR_FCC )
w = mLblFcc;
else if ( which == HDR_TRANSPORT )
w = mLblTransport;
else if ( which == HDR_FROM )
w = mLblFrom;
else if ( which == HDR_REPLY_TO )
w = mLblReplyTo;
else if ( which == HDR_SUBJECT )
w = mLblSubject;
else
return width;
w->setBuddy( mEditor ); // set dummy so we don't calculate width of '&' for this label.
w->adjustSize();
w->show();
return TQMAX( width, w->sizeHint().width() );
}
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 + 1;
delete mGrid;
mGrid = new TQGridLayout( mHeadersArea, numRows, 3, KDialogBase::marginHint()/2, KDialogBase::spacingHint());
mGrid->setColStretch(0, 1);
mGrid->setColStretch(1, 100);
mGrid->setColStretch(2, 1);
mGrid->setRowStretch( mNumHeaders + 1, 100 );
row = 0;
kdDebug(5006) << "KMComposeWin::rethinkFields" << endl;
if (mRecipientsEditor)
mLabelWidth = mRecipientsEditor->setFirstColumnWidth( 0 );
mLabelWidth = calcColumnWidth( HDR_IDENTITY, showHeaders, mLabelWidth );
mLabelWidth = calcColumnWidth( HDR_DICTIONARY, showHeaders, mLabelWidth );
mLabelWidth = calcColumnWidth( HDR_FCC, showHeaders, mLabelWidth );
mLabelWidth = calcColumnWidth( HDR_TRANSPORT, showHeaders, mLabelWidth );
mLabelWidth = calcColumnWidth( HDR_FROM, showHeaders, mLabelWidth );
mLabelWidth = calcColumnWidth( HDR_REPLY_TO, showHeaders, mLabelWidth );
mLabelWidth = calcColumnWidth( HDR_SUBJECT, showHeaders, mLabelWidth );
if (!fromSlot) mAllFieldsAction->setChecked(showHeaders==HDR_ALL);
if (!fromSlot) mIdentityAction->setChecked(abs(mShowHeaders)&HDR_IDENTITY);
rethinkHeaderLine(showHeaders,HDR_IDENTITY, row,
mLblIdentity, mIdentity, mBtnIdentity);
if (!fromSlot) mDictionaryAction->setChecked(abs(mShowHeaders)&HDR_DICTIONARY);
rethinkHeaderLine(showHeaders,HDR_DICTIONARY, row,
mDictionaryLabel, mDictionaryCombo, mBtnDictionary );
if (!fromSlot) mFccAction->setChecked(abs(mShowHeaders)&HDR_FCC);
rethinkHeaderLine(showHeaders,HDR_FCC, row,
mLblFcc, mFcc, mBtnFcc);
if (!fromSlot) mTransportAction->setChecked(abs(mShowHeaders)&HDR_TRANSPORT);
rethinkHeaderLine(showHeaders,HDR_TRANSPORT, row,
mLblTransport, mTransport, mBtnTransport);
if (!fromSlot) mFromAction->setChecked(abs(mShowHeaders)&HDR_FROM);
rethinkHeaderLine(showHeaders,HDR_FROM, row,
mLblFrom, mEdtFrom /*, mBtnFrom */ );
TQWidget *prevFocus = mEdtFrom;
if (!fromSlot) mReplyToAction->setChecked(abs(mShowHeaders)&HDR_REPLY_TO);
rethinkHeaderLine(showHeaders,HDR_REPLY_TO,row,
mLblReplyTo, mEdtReplyTo, 0);
if ( showHeaders & HDR_REPLY_TO ) {
prevFocus = connectFocusMoving( prevFocus, mEdtReplyTo );
}
if ( mClassicalRecipients ) {
if (!fromSlot) mToAction->setChecked(abs(mShowHeaders)&HDR_TO);
rethinkHeaderLine(showHeaders, HDR_TO, row,
mLblTo, mEdtTo, mBtnTo,
i18n("Primary Recipients"),
i18n("<qt>The email addresses you put "
"in this field receive a copy of the email.</qt>"));
if ( showHeaders & HDR_TO ) {
prevFocus = connectFocusMoving( prevFocus, mEdtTo );
}
if (!fromSlot) mCcAction->setChecked(abs(mShowHeaders)&HDR_CC);
rethinkHeaderLine(showHeaders, HDR_CC, row,
mLblCc, mEdtCc, mBtnCc,
i18n("Additional Recipients"),
i18n("<qt>The email addresses you put "
"in this field receive a copy of the email. "
"Technically it is the same thing as putting all the "
"addresses in the <b>To:</b> field but differs in "
"that it usually symbolises the receiver of the "
"Carbon Copy (CC) is a listener, not the main "
"recipient.</qt>"));
if ( showHeaders & HDR_CC ) {
prevFocus = connectFocusMoving( prevFocus, mEdtCc );
}
if (!fromSlot) mBccAction->setChecked(abs(mShowHeaders)&HDR_BCC);
rethinkHeaderLine(showHeaders,HDR_BCC, row,
mLblBcc, mEdtBcc, mBtnBcc,
i18n("Hidden Recipients"),
i18n("<qt>Essentially the same thing "
"as the <b>Copy To:</b> field but differs in that "
"all other recipients do not see who receives a "
"blind copy.</qt>"));
if ( showHeaders & HDR_BCC ) {
prevFocus = connectFocusMoving( prevFocus, mEdtBcc );
}
} else {
mGrid->addMultiCellWidget( mRecipientsEditor, row, row, 0, 2 );
++row;
if ( showHeaders & HDR_REPLY_TO ) {
connect( mEdtReplyTo, TQT_SIGNAL( focusDown() ), mRecipientsEditor,
TQT_SLOT( setFocusTop() ) );
} else {
connect( mEdtFrom, TQT_SIGNAL( focusDown() ), mRecipientsEditor,
TQT_SLOT( setFocusTop() ) );
}
if ( showHeaders & HDR_REPLY_TO ) {
connect( mRecipientsEditor, TQT_SIGNAL( focusUp() ), mEdtReplyTo, TQT_SLOT( setFocus() ) );
} else {
connect( mRecipientsEditor, TQT_SIGNAL( focusUp() ), mEdtFrom, TQT_SLOT( setFocus() ) );
}
connect( mRecipientsEditor, TQT_SIGNAL( focusDown() ), mEdtSubject,
TQT_SLOT( setFocus() ) );
connect( mEdtSubject, TQT_SIGNAL( focusUp() ), mRecipientsEditor,
TQT_SLOT( setFocusBottom() ) );
prevFocus = mRecipientsEditor;
}
if (!fromSlot) mSubjectAction->setChecked(abs(mShowHeaders)&HDR_SUBJECT);
rethinkHeaderLine(showHeaders,HDR_SUBJECT, row,
mLblSubject, mEdtSubject);
connectFocusMoving( mEdtSubject, mEditor );
assert(row<=mNumHeaders);
if( !mAtmList.isEmpty() )
mAtmListView->show();
else
mAtmListView->hide();
resize(this->size());
repaint();
mHeadersArea->setMaximumHeight( mHeadersArea->sizeHint().height() );
mGrid->activate();
mHeadersArea->show();
slotUpdateAttachActions();
mIdentityAction->setEnabled(!mAllFieldsAction->isChecked());
mDictionaryAction->setEnabled( !mAllFieldsAction->isChecked() );
mTransportAction->setEnabled(!mAllFieldsAction->isChecked());
mFromAction->setEnabled(!mAllFieldsAction->isChecked());
if ( mReplyToAction ) mReplyToAction->setEnabled(!mAllFieldsAction->isChecked());
if ( mToAction ) mToAction->setEnabled(!mAllFieldsAction->isChecked());
if ( mCcAction ) mCcAction->setEnabled(!mAllFieldsAction->isChecked());
if ( mBccAction ) mBccAction->setEnabled(!mAllFieldsAction->isChecked());
mFccAction->setEnabled(!mAllFieldsAction->isChecked());
mSubjectAction->setEnabled(!mAllFieldsAction->isChecked());
if (mRecipientsEditor)
mRecipientsEditor->setFirstColumnWidth( mLabelWidth );
}
TQWidget *KMComposeWin::connectFocusMoving( TQWidget *prev, TQWidget *next )
{
connect( prev, TQT_SIGNAL( focusDown() ), next, TQT_SLOT( setFocus() ) );
connect( next, TQT_SIGNAL( focusUp() ), prev, TQT_SLOT( setFocus() ) );
return next;
}
//-----------------------------------------------------------------------------
void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
TQLabel* aLbl,
TQLineEdit* aEdt, TQPushButton* aBtn,
const TQString &toolTip, const TQString &whatsThis )
{
if (aValue & aMask)
{
if ( !toolTip.isEmpty() )
TQToolTip::add( aLbl, toolTip );
if ( !whatsThis.isEmpty() )
TQWhatsThis::add( aLbl, whatsThis );
aLbl->setFixedWidth( mLabelWidth );
aLbl->setBuddy(aEdt);
mGrid->addWidget(aLbl, aRow, 0);
aEdt->setBackgroundColor( mBackColor );
aEdt->show();
if (aBtn) {
mGrid->addWidget(aEdt, aRow, 1);
mGrid->addWidget(aBtn, aRow, 2);
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,
TQLabel* aLbl,
TQComboBox* aCbx, TQCheckBox* aChk)
{
if (aValue & aMask)
{
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->show();
aCbx->setMinimumSize(100, aLbl->height()+2);
mGrid->addWidget(aCbx, aRow, 1);
if ( aChk ) {
mGrid->addWidget(aChk, aRow, 2);
aChk->setFixedSize(aChk->sizeHint().width(), aLbl->height());
aChk->show();
}
aRow++;
}
else
{
aLbl->hide();
aCbx->hide();
if ( aChk )
aChk->hide();
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::getTransportMenu()
{
TQStringList availTransports;
mActNowMenu->clear();
mActLaterMenu->clear();
availTransports = KMail::TransportManager::transportNames();
TQStringList::Iterator it;
int id = 0;
for(it = availTransports.begin(); it != availTransports.end() ; ++it, id++)
{
mActNowMenu->insertItem((*it).replace("&", "&&"), id);
mActLaterMenu->insertItem((*it).replace("&", "&&"), id);
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::setupActions(void)
{
TDEActionMenu *actActionNowMenu, *actActionLaterMenu;
if (kmkernel->msgSender()->sendImmediate()) //default == send now?
{
//default = send now, alternative = queue
( void ) new TDEAction( i18n("&Send Mail"), "mail_send", CTRL+Key_Return,
TQT_TQOBJECT(this), TQT_SLOT(slotSendNow()), actionCollection(),"send_default");
// FIXME: change to mail_send_via icon when this exits.
actActionNowMenu = new TDEActionMenu (i18n("&Send Mail Via"), "mail_send",
actionCollection(), "send_default_via" );
(void) new TDEAction (i18n("Send &Later"), "queue", 0, TQT_TQOBJECT(this),
TQT_SLOT(slotSendLater()), actionCollection(),"send_alternative");
actActionLaterMenu = new TDEActionMenu (i18n("Send &Later Via"), "queue",
actionCollection(), "send_alternative_via" );
}
else //no, default = send later
{
//default = queue, alternative = send now
(void) new TDEAction (i18n("Send &Later"), "queue",
CTRL+Key_Return,
TQT_TQOBJECT(this), TQT_SLOT(slotSendLater()), actionCollection(),"send_default");
actActionLaterMenu = new TDEActionMenu (i18n("Send &Later Via"), "queue",
actionCollection(), "send_default_via" );
( void ) new TDEAction( i18n("&Send Mail"), "mail_send", 0,
TQT_TQOBJECT(this), TQT_SLOT(slotSendNow()), actionCollection(),"send_alternative");
// FIXME: change to mail_send_via icon when this exits.
actActionNowMenu = new TDEActionMenu (i18n("&Send Mail Via"), "mail_send",
actionCollection(), "send_alternative_via" );
}
// needed for sending "default transport"
actActionNowMenu->setDelayed(true);
actActionLaterMenu->setDelayed(true);
connect( actActionNowMenu, TQT_SIGNAL( activated() ), this,
TQT_SLOT( slotSendNow() ) );
connect( actActionLaterMenu, TQT_SIGNAL( activated() ), this,
TQT_SLOT( slotSendLater() ) );
mActNowMenu = actActionNowMenu->popupMenu();
mActLaterMenu = actActionLaterMenu->popupMenu();
connect( mActNowMenu, TQT_SIGNAL( activated( int ) ), this,
TQT_SLOT( slotSendNowVia( int ) ) );
connect( mActNowMenu, TQT_SIGNAL( aboutToShow() ), this,
TQT_SLOT( getTransportMenu() ) );
connect( mActLaterMenu, TQT_SIGNAL( activated( int ) ), this,
TQT_SLOT( slotSendLaterVia( int ) ) );
connect( mActLaterMenu, TQT_SIGNAL( aboutToShow() ), this,
TQT_SLOT( getTransportMenu() ) );
(void) new TDEAction (i18n("Save as &Draft"), "filesave", 0,
TQT_TQOBJECT(this), TQT_SLOT(slotSaveDraft()),
actionCollection(), "save_in_drafts");
(void) new TDEAction (i18n("Save as &Template"), "filesave", 0,
TQT_TQOBJECT(this), TQT_SLOT(slotSaveTemplate()),
actionCollection(), "save_in_templates");
(void) new TDEAction (i18n("&Insert File..."), "fileopen", 0,
TQT_TQOBJECT(this), TQT_SLOT(slotInsertFile()),
actionCollection(), "insert_file");
mRecentAction = new TDERecentFilesAction (i18n("&Insert File Recent"),
"fileopen", 0,
TQT_TQOBJECT(this), TQT_SLOT(slotInsertRecentFile(const KURL&)),
actionCollection(), "insert_file_recent");
mRecentAction->loadEntries( KMKernel::config() );
(void) new TDEAction (i18n("&Address Book"), "contents",0,
TQT_TQOBJECT(this), TQT_SLOT(slotAddrBook()),
actionCollection(), "addressbook");
(void) new TDEAction (i18n("&New Composer"), "mail_new",
TDEStdAccel::shortcut(TDEStdAccel::New),
TQT_TQOBJECT(this), TQT_SLOT(slotNewComposer()),
actionCollection(), "new_composer");
(void) new TDEAction (i18n("New Main &Window"), "window_new", 0,
TQT_TQOBJECT(this), TQT_SLOT(slotNewMailReader()),
actionCollection(), "open_mailreader");
if ( !mClassicalRecipients ) {
new TDEAction( i18n("Select &Recipients..."), CTRL + Key_L, TQT_TQOBJECT(mRecipientsEditor),
TQT_SLOT( selectRecipients() ), actionCollection(), "select_recipients" );
new TDEAction( i18n("Save &Distribution List..."), 0, TQT_TQOBJECT(mRecipientsEditor),
TQT_SLOT( saveDistributionList() ), actionCollection(),
"save_distribution_list" );
}
//KStdAction::save(TQT_TQOBJECT(this), TQT_SLOT(), actionCollection(), "save_message");
KStdAction::print (TQT_TQOBJECT(this), TQT_SLOT(slotPrint()), actionCollection());
KStdAction::close (TQT_TQOBJECT(this), TQT_SLOT(slotClose()), actionCollection());
KStdAction::undo (TQT_TQOBJECT(this), TQT_SLOT(slotUndo()), actionCollection());
KStdAction::redo (TQT_TQOBJECT(this), TQT_SLOT(slotRedo()), actionCollection());
KStdAction::cut (TQT_TQOBJECT(this), TQT_SLOT(slotCut()), actionCollection());
KStdAction::copy (TQT_TQOBJECT(this), TQT_SLOT(slotCopy()), actionCollection());
KStdAction::pasteText (TQT_TQOBJECT(this), TQT_SLOT(slotPasteClipboard()), actionCollection());
KStdAction::selectAll (TQT_TQOBJECT(this), TQT_SLOT(slotMarkAll()), actionCollection());
KStdAction::find (TQT_TQOBJECT(this), TQT_SLOT(slotFind()), actionCollection());
KStdAction::findNext(TQT_TQOBJECT(this), TQT_SLOT(slotSearchAgain()), actionCollection());
KStdAction::replace (TQT_TQOBJECT(this), TQT_SLOT(slotReplace()), actionCollection());
KStdAction::spelling (TQT_TQOBJECT(this), TQT_SLOT(slotSpellcheck()), actionCollection(), "spellcheck");
mPasteQuotation = new TDEAction (i18n("Pa&ste as Quotation"),0,TQT_TQOBJECT(this),TQT_SLOT( slotPasteClipboardAsQuotation()),
actionCollection(), "paste_quoted");
(void) new TDEAction (i18n("Paste as Attac&hment"),0,TQT_TQOBJECT(this),TQT_SLOT( slotPasteClipboardAsAttachment()),
actionCollection(), "paste_att");
TDEAction * addq = new TDEAction(i18n("Add &Quote Characters"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotAddQuotes()), actionCollection(), "tools_quote");
connect( mEditor, TQT_SIGNAL(selectionAvailable(bool)),
addq, TQT_SLOT(setEnabled(bool)) );
TDEAction * remq = new TDEAction(i18n("Re&move Quote Characters"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotRemoveQuotes()), actionCollection(), "tools_unquote");
connect( mEditor, TQT_SIGNAL(selectionAvailable(bool)),
remq, TQT_SLOT(setEnabled(bool)) );
(void) new TDEAction (i18n("Cl&ean Spaces"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotCleanSpace()),
actionCollection(), "clean_spaces");
mFixedFontAction = new TDEToggleAction( i18n("Use Fi&xed Font"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotUpdateFont()), actionCollection(), "toggle_fixedfont" );
mFixedFontAction->setChecked( GlobalSettings::self()->useFixedFont() );
//these are checkable!!!
mUrgentAction = new TDEToggleAction (i18n("&Urgent"), 0,
actionCollection(),
"urgent");
mRequestMDNAction = new TDEToggleAction ( i18n("&Request Disposition Notification"), 0,
actionCollection(),
"options_request_mdn");
mRequestMDNAction->setChecked(GlobalSettings::self()->requestMDN());
//----- Message-Encoding Submenu
mEncodingAction = new TDESelectAction( i18n( "Se&t Encoding" ), "charset",
0, TQT_TQOBJECT(this), TQT_SLOT(slotSetCharset() ),
actionCollection(), "charsets" );
mWordWrapAction = new TDEToggleAction (i18n("&Wordwrap"), 0,
actionCollection(), "wordwrap");
mWordWrapAction->setChecked(GlobalSettings::self()->wordWrap());
connect(mWordWrapAction, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotWordWrapToggled(bool)));
mSnippetAction = new TDEToggleAction ( i18n("&Snippets"), 0,
actionCollection(), "snippets");
connect(mSnippetAction, TQT_SIGNAL(toggled(bool)), mSnippetWidget, TQT_SLOT(setShown(bool)) );
mSnippetAction->setChecked( GlobalSettings::self()->showSnippetManager() );
mAutoSpellCheckingAction =
new TDEToggleAction( i18n( "&Automatic Spellchecking" ), "spellcheck", 0,
actionCollection(), "options_auto_spellchecking" );
const bool spellChecking = GlobalSettings::self()->autoSpellChecking();
mAutoSpellCheckingAction->setEnabled( !GlobalSettings::self()->useExternalEditor() );
mAutoSpellCheckingAction->setChecked( !GlobalSettings::self()->useExternalEditor() && spellChecking );
slotAutoSpellCheckingToggled( !GlobalSettings::self()->useExternalEditor() && spellChecking );
connect( mAutoSpellCheckingAction, TQT_SIGNAL( toggled( bool ) ),
TQT_TQOBJECT(this), TQT_SLOT( slotAutoSpellCheckingToggled( bool ) ) );
TQStringList encodings = KMMsgBase::supportedEncodings(true);
encodings.prepend( i18n("Auto-Detect"));
mEncodingAction->setItems( encodings );
mEncodingAction->setCurrentItem( -1 );
//these are checkable!!!
markupAction = new TDEToggleAction (i18n("Formatting (HTML)"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotToggleMarkup()),
actionCollection(), "html");
mAllFieldsAction = new TDEToggleAction (i18n("&All Fields"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotView()),
actionCollection(), "show_all_fields");
mIdentityAction = new TDEToggleAction (i18n("&Identity"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotView()),
actionCollection(), "show_identity");
mDictionaryAction = new TDEToggleAction (i18n("&Dictionary"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotView()),
actionCollection(), "show_dictionary");
mFccAction = new TDEToggleAction (i18n("&Sent-Mail Folder"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotView()),
actionCollection(), "show_fcc");
mTransportAction = new TDEToggleAction (i18n("&Mail Transport"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotView()),
actionCollection(), "show_transport");
mFromAction = new TDEToggleAction (i18n("&From"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotView()),
actionCollection(), "show_from");
mReplyToAction = new TDEToggleAction (i18n("&Reply To"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotView()),
actionCollection(), "show_reply_to");
if ( mClassicalRecipients ) {
mToAction = new TDEToggleAction (i18n("&To"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotView()),
actionCollection(), "show_to");
mCcAction = new TDEToggleAction (i18n("&CC"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotView()),
actionCollection(), "show_cc");
mBccAction = new TDEToggleAction (i18n("&BCC"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotView()),
actionCollection(), "show_bcc");
}
mSubjectAction = new TDEToggleAction (i18n("S&ubject"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotView()),
actionCollection(), "show_subject");
//end of checkable
mAppendSignatureAction = new TDEAction (i18n("Append S&ignature"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotAppendSignature()),
actionCollection(), "append_signature");
mPrependSignatureAction = new TDEAction (i18n("Prepend S&ignature"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotPrependSignature()),
actionCollection(), "prepend_signature");
mInsertSignatureAction = new TDEAction (i18n("Insert Signature At C&ursor Position"), "edit", 0, TQT_TQOBJECT(this),
TQT_SLOT(slotInsertSignatureAtCursor()),
actionCollection(), "insert_signature_at_cursor_position");
mAttachPK = new TDEAction (i18n("Attach &Public Key..."), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotInsertPublicKey()),
actionCollection(), "attach_public_key");
mAttachMPK = new TDEAction (i18n("Attach &My Public Key"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotInsertMyPublicKey()),
actionCollection(), "attach_my_public_key");
(void) new TDEAction (i18n("&Attach File..."), "attach",
0, TQT_TQOBJECT(this), TQT_SLOT(slotAttachFile()),
actionCollection(), "attach");
mAttachRemoveAction = new TDEAction (i18n("&Remove Attachment"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotAttachRemove()),
actionCollection(), "remove");
mAttachSaveAction = new TDEAction (i18n("&Save Attachment As..."), "filesave",0,
TQT_TQOBJECT(this), TQT_SLOT(slotAttachSave()),
actionCollection(), "attach_save");
mAttachPropertiesAction = new TDEAction (i18n("Attachment Pr&operties"), 0, TQT_TQOBJECT(this),
TQT_SLOT(slotAttachProperties()),
actionCollection(), "attach_properties");
setStandardToolBarMenuEnabled(true);
KStdAction::keyBindings(TQT_TQOBJECT(this), TQT_SLOT(slotEditKeys()), actionCollection());
KStdAction::configureToolbars(TQT_TQOBJECT(this), TQT_SLOT(slotEditToolbars()), actionCollection());
KStdAction::preferences(kmkernel, TQT_SLOT(slotShowConfigurationDialog()), actionCollection());
(void) new TDEAction (i18n("&Spellchecker..."), 0, TQT_TQOBJECT(this), TQT_SLOT(slotSpellcheckConfig()),
actionCollection(), "setup_spellchecker");
if ( Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" ) ) {
TDEToggleAction * a = new TDEToggleAction( i18n( "Encrypt Message with Chiasmus..." ),
"chidecrypted", 0, actionCollection(),
"encrypt_message_chiasmus" );
a->setCheckedState( KGuiItem( i18n( "Encrypt Message with Chiasmus..." ), "chiencrypted" ) );
mEncryptChiasmusAction = a;
connect( mEncryptChiasmusAction, TQT_SIGNAL(toggled(bool)),
TQT_TQOBJECT(this), TQT_SLOT(slotEncryptChiasmusToggled(bool)) );
} else {
mEncryptChiasmusAction = 0;
}
mEncryptAction = new TDEToggleAction (i18n("&Encrypt Message"),
"decrypted", 0,
actionCollection(), "encrypt_message");
mSignAction = new TDEToggleAction (i18n("&Sign Message"),
"signature", 0,
actionCollection(), "sign_message");
// get PGP user id for the chosen identity
const KPIM::Identity & ident =
kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
// PENDING(marc): check the uses of this member and split it into
// smime/openpgp and or enc/sign, if necessary:
mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
mLastEncryptActionState = false;
mLastSignActionState = GlobalSettings::self()->pgpAutoSign();
// "Attach public key" is only possible if OpenPGP support is available:
mAttachPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() );
// "Attach my public key" is only possible if OpenPGP support is
// available and the user specified his key for the current identity:
mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
!ident.pgpEncryptionKey().isEmpty() );
if ( !Kleo::CryptoBackendFactory::instance()->openpgp() && !Kleo::CryptoBackendFactory::instance()->smime() ) {
// no crypto whatsoever
mEncryptAction->setEnabled( false );
setEncryption( false );
mSignAction->setEnabled( false );
setSigning( false );
} else {
const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp()
&& !ident.pgpSigningKey().isEmpty();
const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime()
&& !ident.smimeSigningKey().isEmpty();
setEncryption( false );
setSigning( ( canOpenPGPSign || canSMIMESign ) && GlobalSettings::self()->pgpAutoSign() );
}
connect(mEncryptAction, TQT_SIGNAL(toggled(bool)),
TQT_SLOT(slotEncryptToggled( bool )));
connect(mSignAction, TQT_SIGNAL(toggled(bool)),
TQT_SLOT(slotSignToggled( bool )));
TQStringList l;
for ( int i = 0 ; i < numCryptoMessageFormats ; ++i )
l.push_back( Kleo::cryptoMessageFormatToLabel( cryptoMessageFormats[i] ) );
mCryptoModuleAction = new TDESelectAction( i18n( "&Cryptographic Message Format" ), 0,
TQT_TQOBJECT(this), TQT_SLOT(slotSelectCryptoModule()),
actionCollection(), "options_select_crypto" );
mCryptoModuleAction->setItems( l );
mCryptoModuleAction->setCurrentItem( format2cb( ident.preferredCryptoMessageFormat() ) );
mCryptoModuleAction->setToolTip( i18n( "Select a cryptographic format for this message" ) );
slotSelectCryptoModule( true /* initialize */ );
TQStringList styleItems;
styleItems << i18n( "Standard" );
styleItems << i18n( "Bulleted List (Disc)" );
styleItems << i18n( "Bulleted List (Circle)" );
styleItems << i18n( "Bulleted List (Square)" );
styleItems << i18n( "Ordered List (Decimal)" );
styleItems << i18n( "Ordered List (Alpha lower)" );
styleItems << i18n( "Ordered List (Alpha upper)" );
listAction = new TDESelectAction( i18n( "Select Style" ), 0, actionCollection(),
"text_list" );
listAction->setItems( styleItems );
listAction->setToolTip( i18n( "Select a list style" ) );
connect( listAction, TQT_SIGNAL( activated( const TQString& ) ),
TQT_SLOT( slotListAction( const TQString& ) ) );
fontAction = new TDEFontAction( "Select Font", 0, actionCollection(),
"text_font" );
fontAction->setToolTip( i18n( "Select a font" ) );
connect( fontAction, TQT_SIGNAL( activated( const TQString& ) ),
TQT_SLOT( slotFontAction( const TQString& ) ) );
fontSizeAction = new TDEFontSizeAction( "Select Size", 0, actionCollection(),
"text_size" );
fontSizeAction->setToolTip( i18n( "Select a font size" ) );
connect( fontSizeAction, TQT_SIGNAL( fontSizeChanged( int ) ),
TQT_SLOT( slotSizeAction( int ) ) );
alignLeftAction = new TDEToggleAction (i18n("Align Left"), "text_left", 0,
TQT_TQOBJECT(this), TQT_SLOT(slotAlignLeft()), actionCollection(),
"align_left");
alignLeftAction->setChecked( true );
alignRightAction = new TDEToggleAction (i18n("Align Right"), "text_right", 0,
TQT_TQOBJECT(this), TQT_SLOT(slotAlignRight()), actionCollection(),
"align_right");
alignCenterAction = new TDEToggleAction (i18n("Align Center"), "text_center", 0,
TQT_TQOBJECT(this), TQT_SLOT(slotAlignCenter()), actionCollection(),
"align_center");
textBoldAction = new TDEToggleAction( i18n("&Bold"), "text_bold", CTRL+Key_B,
TQT_TQOBJECT(this), TQT_SLOT(slotTextBold()),
actionCollection(), "text_bold");
textItalicAction = new TDEToggleAction( i18n("&Italic"), "text_italic", CTRL+Key_I,
TQT_TQOBJECT(this), TQT_SLOT(slotTextItalic()),
actionCollection(), "text_italic");
textUnderAction = new TDEToggleAction( i18n("&Underline"), "text_under", CTRL+Key_U,
TQT_TQOBJECT(this), TQT_SLOT(slotTextUnder()),
actionCollection(), "text_under");
actionFormatReset = new TDEAction( i18n( "Reset Font Settings" ), "eraser", 0,
TQT_TQOBJECT(this), TQT_SLOT( slotFormatReset() ),
actionCollection(), "format_reset");
actionFormatColor = new TDEAction( i18n( "Text Color..." ), "colorize", 0,
TQT_TQOBJECT(this), TQT_SLOT( slotTextColor() ),
actionCollection(), "format_color");
// editorFocusChanged(false);
createGUI("kmcomposerui.rc");
connect( toolBar("htmlToolBar"), TQT_SIGNAL( visibilityChanged(bool) ),
TQT_TQOBJECT(this), TQT_SLOT( htmlToolBarVisibilityChanged(bool) ) );
// In Kontact, this entry would read "Configure Kontact", but bring
// up KMail's config dialog. That's sensible, though, so fix the label.
TDEAction* configureAction = actionCollection()->action("options_configure" );
if ( configureAction )
configureAction->setText( i18n("Configure KMail..." ) );
}
//-----------------------------------------------------------------------------
void KMComposeWin::setupStatusBar(void)
{
statusBar()->insertItem("", 0, 1);
statusBar()->setItemAlignment(0, AlignLeft | AlignVCenter);
statusBar()->insertItem(i18n( " Spellcheck: %1 ").arg( " " ), 3, 0, true );
statusBar()->insertItem(i18n( " Column: %1 ").arg(" "), 2, 0, true);
statusBar()->insertItem(i18n( " Line: %1 ").arg(" "), 1, 0, true);
}
//-----------------------------------------------------------------------------
void KMComposeWin::updateCursorPosition()
{
int col,line;
TQString temp;
line = mEditor->currentLine();
col = mEditor->currentColumn();
temp = i18n(" Line: %1 ").arg(line+1);
statusBar()->changeItem(temp,1);
temp = i18n(" Column: %1 ").arg(col+1);
statusBar()->changeItem(temp,2);
}
//-----------------------------------------------------------------------------
void KMComposeWin::setupEditor(void)
{
//TQPopupMenu* menu;
mEditor->setModified(false);
TQFontMetrics fm(mBodyFont);
mEditor->setTabStopWidth(fm.width(TQChar(' ')) * 8);
//mEditor->setFocusPolicy(TQWidget::ClickFocus);
slotWordWrapToggled( GlobalSettings::self()->wordWrap() );
// Font setup
slotUpdateFont();
/* installRBPopup() is broken in tdelibs, we should wait for
the new klibtextedit (dnaber, 2002-01-01)
menu = new TQPopupMenu(this);
//#ifdef BROKEN
menu->insertItem(i18n("Undo"),mEditor,
TQT_SLOT(undo()), TDEStdAccel::shortcut(TDEStdAccel::Undo));
menu->insertItem(i18n("Redo"),mEditor,
TQT_SLOT(redo()), TDEStdAccel::shortcut(TDEStdAccel::Redo));
menu->insertSeparator();
//#endif //BROKEN
menu->insertItem(i18n("Cut"), this, TQT_SLOT(slotCut()));
menu->insertItem(i18n("Copy"), this, TQT_SLOT(slotCopy()));
menu->insertItem(i18n("Paste"), this, TQT_SLOT(slotPasteClipboard()));
menu->insertItem(i18n("Mark All"),this, TQT_SLOT(slotMarkAll()));
menu->insertSeparator();
menu->insertItem(i18n("Find..."), this, TQT_SLOT(slotFind()));
menu->insertItem(i18n("Replace..."), this, TQT_SLOT(slotReplace()));
menu->insertSeparator();
menu->insertItem(i18n("Fixed Font Widths"), this, TQT_SLOT(slotUpdateFont()));
mEditor->installRBPopup(menu);
*/
updateCursorPosition();
connect(mEditor,TQT_SIGNAL(CursorPositionChanged()),TQT_SLOT(updateCursorPosition()));
connect( mEditor, TQT_SIGNAL( currentFontChanged( const TQFont & ) ),
TQT_TQOBJECT(this), TQT_SLOT( fontChanged( const TQFont & ) ) );
connect( mEditor, TQT_SIGNAL( currentAlignmentChanged( int ) ),
TQT_TQOBJECT(this), TQT_SLOT( alignmentChanged( int ) ) );
}
//-----------------------------------------------------------------------------
static TQString cleanedUpHeaderString( const TQString & s )
{
// remove invalid characters from the header strings
TQString res( s );
res.replace( '\r', "" );
res.replace( '\n', " " );
return res.stripWhiteSpace();
}
//-----------------------------------------------------------------------------
TQString KMComposeWin::subject() const
{
return cleanedUpHeaderString( mEdtSubject->text() );
}
//-----------------------------------------------------------------------------
TQString KMComposeWin::to() const
{
if ( mEdtTo ) {
return cleanedUpHeaderString( mEdtTo->text() );
} else if ( mRecipientsEditor ) {
return mRecipientsEditor->recipientString( Recipient::To );
} else {
return TQString();
}
}
//-----------------------------------------------------------------------------
TQString KMComposeWin::cc() const
{
if ( mEdtCc && !mEdtCc->isHidden() ) {
return cleanedUpHeaderString( mEdtCc->text() );
} else if ( mRecipientsEditor ) {
return mRecipientsEditor->recipientString( Recipient::Cc );
} else {
return TQString();
}
}
//-----------------------------------------------------------------------------
TQString KMComposeWin::bcc() const
{
if ( mEdtBcc && !mEdtBcc->isHidden() ) {
return cleanedUpHeaderString( mEdtBcc->text() );
} else if ( mRecipientsEditor ) {
return mRecipientsEditor->recipientString( Recipient::Bcc );
} else {
return TQString();
}
}
//-----------------------------------------------------------------------------
TQString KMComposeWin::from() const
{
return cleanedUpHeaderString( mEdtFrom->text() );
}
//-----------------------------------------------------------------------------
TQString KMComposeWin::replyTo() const
{
if ( mEdtReplyTo ) {
return cleanedUpHeaderString( mEdtReplyTo->text() );
} else {
return TQString();
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::verifyWordWrapLengthIsAdequate(const TQString &body)
{
int maxLineLength = 0;
int curPos;
int oldPos = 0;
if (mEditor->TQTextEdit::wordWrap() == TQTextEdit::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::decryptOrStripOffCleartextSignature( TQCString& body )
{
TQPtrList<Kpgp::Block> pgpBlocks;
TQStrList nonPgpBlocks;
if( Kpgp::Module::prepareMessageForDecryption( body,
pgpBlocks, nonPgpBlocks ) )
{
// Only decrypt/strip off the signature if there is only one OpenPGP
// block in the message
if( pgpBlocks.count() == 1 )
{
Kpgp::Block* block = pgpBlocks.first();
if( ( block->type() == Kpgp::PgpMessageBlock ) ||
( block->type() == Kpgp::ClearsignedBlock ) )
{
if( block->type() == Kpgp::PgpMessageBlock )
// try to decrypt this OpenPGP block
block->decrypt();
else
// strip off the signature
block->verify();
body = nonPgpBlocks.first()
+ block->text()
+ nonPgpBlocks.last();
}
}
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::setTransport( const TQString & transport )
{
kdDebug(5006) << "KMComposeWin::setTransport( \"" << transport << "\" )" << endl;
// Don't change the transport combobox if transport is empty
if ( transport.isEmpty() )
return;
bool transportFound = false;
for ( int i = 0; i < mTransport->count(); ++i ) {
if ( mTransport->text(i) == transport ) {
transportFound = true;
mTransport->setCurrentItem(i);
kdDebug(5006) << "transport found, it's no. " << i << " in the list" << endl;
break;
}
}
if ( !transportFound ) { // unknown transport
kdDebug(5006) << "unknown transport \"" << transport << "\"" << endl;
if ( transport.startsWith("smtp://") || transport.startsWith("smtps://") ||
transport.startsWith("file://") ) {
// set custom transport
mTransport->setEditText( transport );
}
else {
// neither known nor custom transport -> use default transport
mTransport->setCurrentText( GlobalSettings::self()->defaultTransport() );
}
}
}
//-----------------------------------------------------------------------------
void KMComposeWin::setMsg(KMMessage* newMsg, bool mayAutoSign,
bool allowDecryption, bool isModified)
{
//assert(newMsg!=0);
if(!newMsg)
{
kdDebug(5006) << "KMComposeWin::setMsg() : newMsg == 0!" << endl;
return;
}
mMsg = newMsg;
KPIM::IdentityManager * im = kmkernel->identityManager();
mEdtFrom->setText(mMsg->from());
mEdtReplyTo->setText(mMsg->replyTo());
if ( mClassicalRecipients ) {
mEdtTo->setText(mMsg->to());
mEdtCc->setText(mMsg->cc());
mEdtBcc->setText(mMsg->bcc());
} else {
mRecipientsEditor->setRecipientString( mMsg->to(), Recipient::To );
mRecipientsEditor->setRecipientString( mMsg->cc(), Recipient::Cc );
mRecipientsEditor->setRecipientString( mMsg->bcc(), Recipient::Bcc );
mRecipientsEditor->setFocusBottom();
}
mEdtSubject->setText(mMsg->subject());
const bool stickyIdentity = mBtnIdentity->isChecked() && !mIgnoreStickyFields;
const bool messageHasIdentity = !newMsg->headerField("X-KMail-Identity").isEmpty();
if (!stickyIdentity && messageHasIdentity)
mId = newMsg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
// don't overwrite the header values with identity specific values
// unless the identity is sticky
if ( !stickyIdentity ) {
disconnect(mIdentity,TQT_SIGNAL(identityChanged(uint)),
TQT_TQOBJECT(this), TQT_SLOT(slotIdentityChanged(uint)));
}
// load the mId into the gui, sticky or not, without emitting
mIdentity->setCurrentIdentity( mId );
const uint idToApply = mId;
if ( !stickyIdentity ) {
connect(mIdentity,TQT_SIGNAL(identityChanged(uint)),
TQT_TQOBJECT(this), TQT_SLOT(slotIdentityChanged(uint)));
} else {
// load the message's state into the mId, without applying it to the gui
// that's so we can detect that the id changed (because a sticky was set)
// on apply()
if ( messageHasIdentity )
mId = newMsg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
else
mId = im->defaultIdentity().uoid();
}
// manually load the identity's value into the fields; either the one from the
// messge, where appropriate, or the one from the sticky identity. What's in
// mId might have changed meanwhile, thus the save value
slotIdentityChanged( idToApply );
const KPIM::Identity & ident = im->identityForUoid( mIdentity->currentIdentity() );
// check for the presence of a DNT header, indicating that MDN's were
// requested
TQString mdnAddr = newMsg->headerField("Disposition-Notification-To");
mRequestMDNAction->setChecked( ( !mdnAddr.isEmpty() &&
im->thatIsMe( mdnAddr ) ) ||
GlobalSettings::self()->requestMDN() );
// check for presence of a priority header, indicating urgent mail:
mUrgentAction->setChecked( newMsg->isUrgent() );
if (!ident.isXFaceEnabled() || ident.xface().isEmpty())
mMsg->removeHeaderField("X-Face");
else
{
TQString xface = ident.xface();
if (!xface.isEmpty())
{
int numNL = ( xface.length() - 1 ) / 70;
for ( int i = numNL; i > 0; --i )
xface.insert( i*70, "\n\t" );
mMsg->setHeaderField("X-Face", xface);
}
}
// enable/disable encryption if the message was/wasn't encrypted
switch ( mMsg->encryptionState() ) {
case KMMsgFullyEncrypted: // fall through
case KMMsgPartiallyEncrypted:
mLastEncryptActionState = true;
break;
case KMMsgNotEncrypted:
mLastEncryptActionState = false;
break;
default: // nothing
break;
}
// enable/disable signing if the message was/wasn't signed
switch ( mMsg->signatureState() ) {
case KMMsgFullySigned: // fall through
case KMMsgPartiallySigned:
mLastSignActionState = true;
break;
case KMMsgNotSigned:
mLastSignActionState = false;
break;
default: // nothing
break;
}
// if these headers are present, the state of the message should be overruled
if ( mMsg->headers().FindField( "X-KMail-SignatureActionEnabled" ) )
mLastSignActionState = (mMsg->headerField( "X-KMail-SignatureActionEnabled" ) == "true");
if ( mMsg->headers().FindField( "X-KMail-EncryptActionEnabled" ) )
mLastEncryptActionState = (mMsg->headerField( "X-KMail-EncryptActionEnabled" ) == "true");
if ( mMsg->headers().FindField( "X-KMail-CryptoMessageFormat" ) )
mCryptoModuleAction->setCurrentItem( format2cb( static_cast<Kleo::CryptoMessageFormat>(
mMsg->headerField( "X-KMail-CryptoMessageFormat" ).toInt() ) ) );
mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
if ( Kleo::CryptoBackendFactory::instance()->openpgp() || Kleo::CryptoBackendFactory::instance()->smime() ) {
const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp()
&& !ident.pgpSigningKey().isEmpty();
const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime()
&& !ident.smimeSigningKey().isEmpty();
setEncryption( mLastEncryptActionState );
setSigning( ( canOpenPGPSign || canSMIMESign ) && mLastSignActionState );
}
slotUpdateSignatureAndEncrypionStateIndicators();
// "Attach my public key" is only possible if the user uses OpenPGP
// support and he specified his key:
mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
!ident.pgpEncryptionKey().isEmpty() );
TQString transport = newMsg->headerField("X-KMail-Transport");
const bool stickyTransport = mBtnTransport->isChecked() && !mIgnoreStickyFields;
if (!stickyTransport && !transport.isEmpty()) {
setTransport( transport );
}
// If we are using the default transport, and the originating account name of the original message matches the name of a valid transport, use setTransport() to set it
// See Bug 1239
if (transport.isEmpty() && !mMsg->originatingAccountName().isEmpty()) {
TQString transportCandidate = mMsg->originatingAccountName();
bool transportFound = false;
for ( int i = 0; i < mTransport->count(); ++i ) {
if ( mTransport->text(i) == transportCandidate ) {
transportFound = true;
setTransport(transportCandidate);
break;
}
}
}
if (!mBtnFcc->isChecked())
{
if (!mMsg->fcc().isEmpty())
setFcc(mMsg->fcc());
else
setFcc(ident.fcc());
}
const bool stickyDictionary = mBtnDictionary->isChecked() && !mIgnoreStickyFields;
if ( !stickyDictionary ) {
mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
}
partNode * root = partNode::fromMessage( mMsg );
KMail::ObjectTreeParser otp; // all defaults are ok
otp.parseObjectTree( root );
KMail::AttachmentCollector ac;
ac.collectAttachmentsFrom( root );
for ( std::vector<partNode*>::const_iterator it = ac.attachments().begin() ; it != ac.attachments().end() ; ++it )
addAttach( new KMMessagePart( (*it)->msgPart() ) );
mEditor->setText( otp.textualContent() );
mCharset = otp.textualContentCharset();
if ( partNode * n = root->findType( DwMime::kTypeText, DwMime::kSubtypeHtml ) )
if ( partNode * p = n->parentNode() )
if ( p->hasType( DwMime::kTypeMultipart ) &&
p->hasSubType( DwMime::kSubtypeAlternative ) )
if ( mMsg->headerField( "X-KMail-Markup" ) == "true" ) {
toggleMarkup( true );
// get cte decoded body part
mCharset = n->msgPart().charset();
TQCString bodyDecoded = n->msgPart().bodyDecoded();
// respect html part charset
const TQTextCodec *codec = KMMsgBase::codecForName( mCharset );
if ( codec ) {
mEditor->setText( codec->toUnicode( bodyDecoded ) );
} else {
mEditor->setText( TQString::fromLocal8Bit( bodyDecoded ) );
}
}
if ( mCharset.isEmpty() )
mCharset = mMsg->charset();
if ( mCharset.isEmpty() )
mCharset = mDefCharset;
setCharset( mCharset );
/* Handle the special case of non-mime mails */
if ( mMsg->numBodyParts() == 0 && otp.textualContent().isEmpty() ) {
mCharset=mMsg->charset();
if ( mCharset.isEmpty() || mCharset == "default" )
mCharset = mDefCharset;
TQCString bodyDecoded = mMsg->bodyDecoded();
if( allowDecryption )
decryptOrStripOffCleartextSignature( bodyDecoded );
const TQTextCodec *codec = KMMsgBase::codecForName(mCharset);
if (codec) {
mEditor->setText(codec->toUnicode(bodyDecoded));
} else
mEditor->setText(TQString::fromLocal8Bit(bodyDecoded));
}
#ifdef BROKEN_FOR_OPAQUE_SIGNED_OR_ENCRYPTED_MAILS
const int num = mMsg->numBodyParts();
kdDebug(5006) << "KMComposeWin::setMsg() mMsg->numBodyParts="
<< mMsg->numBodyParts() << endl;
if ( num > 0 ) {
KMMessagePart bodyPart;
int firstAttachment = 0;
mMsg->bodyPart(1, &bodyPart);
if ( bodyPart.typeStr().lower() == "text" &&
bodyPart.subtypeStr().lower() == "html" ) {
// check whether we are inside a mp/al body part
partNode *root = partNode::fromMessage( mMsg );
partNode *node = root->findType( DwMime::kTypeText,
DwMime::kSubtypeHtml );
if ( node && node->parentNode() &&
node->parentNode()->hasType( DwMime::kTypeMultipart ) &&
node->parentNode()->hasSubType( DwMime::kSubtypeAlternative ) ) {
// we have a mp/al body part with a text and an html body
kdDebug(5006) << "KMComposeWin::setMsg() : text/html found" << endl;
firstAttachment = 2;
if ( mMsg->headerField( "X-KMail-Markup" ) == "true" )
toggleMarkup( true );
}
delete root; root = 0;
}
if ( firstAttachment == 0 ) {
mMsg->bodyPart(0, &bodyPart);
if ( bodyPart.typeStr().lower() == "text" ) {
// we have a mp/mx body with a text body
kdDebug(5006) << "KMComposeWin::setMsg() : text/* found" << endl;
firstAttachment = 1;
}
}
if ( firstAttachment != 0 ) // there's text to show
{
mCharset = bodyPart.charset();
if ( mCharset.isEmpty() || mCharset == "default" )
mCharset = mDefCharset;
TQCString bodyDecoded = bodyPart.bodyDecoded();
if( allowDecryption )
decryptOrStripOffCleartextSignature( bodyDecoded );
// As nobody seems to know the purpose of the following line and
// as it breaks word wrapping of long lines if drafts with attachments
// are opened for editting in the composer (cf. Bug#41102) I comment it
// out. Ingo, 2002-04-21
//verifyWordWrapLengthIsAdequate(bodyDecoded);
const TQTextCodec *codec = KMMsgBase::codecForName(mCharset);
if (codec)
mEditor->setText(codec->toUnicode(bodyDecoded));
else
mEditor->setText(TQString::fromLocal8Bit(bodyDecoded));
//mEditor->insertLine("\n", -1); <-- why ?
} else mEditor->setText("");
for( int i = firstAttachment; i < num; ++i )
{
KMMessagePart *msgPart = new KMMessagePart;
mMsg->bodyPart(i, msgPart);
TQCString mimeType = msgPart->typeStr().lower() + '/'
+ msgPart->subtypeStr().lower();
// don't add the detached signature as attachment when editting a
// PGP/MIME signed message
if( mimeType != "application/pgp-signature" ) {
addAttach(msgPart);
}
}
} else{
mCharset=mMsg->charset();
if ( mCharset.isEmpty() || mCharset == "default" )
mCharset = mDefCharset;
TQCString bodyDecoded = mMsg->bodyDecoded();
if( allowDecryption )
decryptOrStripOffCleartextSignature( bodyDecoded );
const TQTextCodec *codec = KMMsgBase::codecForName(mCharset);
if (codec) {
mEditor->setText(codec->toUnicode(bodyDecoded));
} else
mEditor->setText(TQString::fromLocal8Bit(bodyDecoded));
}
setCharset(mCharset);
#endif // BROKEN_FOR_OPAQUE_SIGNED_OR_ENCRYPTED_MAILS
if( (GlobalSettings::self()->autoTextSignature()=="auto") && 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.
//
//TQTimer::singleShot( 200, this, TQT_SLOT(slotAppendSignature()) );
if ( GlobalSettings::self()->prependSignature() ) {
TQTimer::singleShot( 0, this, TQT_SLOT(slotPrependSignature()) );
} else {
TQTimer::singleShot( 0, this, TQT_SLOT(slotAppendSignature()) );
}
}
if ( mMsg->getCursorPos() > 0 ) {
// The message has a cursor position explicitly set, so avoid
// changing it when appending the signature.
mPreserveUserCursorPosition = true;
}
setModified( isModified );
// do this even for new messages
mEditor->setCursorPositionFromStart( (unsigned int) mMsg->getCursorPos() );
// honor "keep reply in this folder" setting even when the identity is changed later on
mPreventFccOverwrite = ( !newMsg->fcc().isEmpty() && ident.fcc() != newMsg->fcc() );
}
//-----------------------------------------------------------------------------
void KMComposeWin::setFcc( const TQString &idString )
{
// check if the sent-mail folder still exists
if ( ! idString.isEmpty() && kmkernel->findFolderById( idString ) ) {
mFcc->setFolder( idString );
} else {
mFcc->setFolder( kmkernel->sentFolder() );
}
}
//-----------------------------------------------------------------------------
bool KMComposeWin::isModified() const
{
return ( mEditor->isModified() ||
mEdtFrom->edited() ||
( mEdtReplyTo && mEdtReplyTo->edited() ) ||
( mEdtTo && mEdtTo->edited() ) ||
( mEdtCc && mEdtCc->edited() ) ||
( mEdtBcc && mEdtBcc->edited() ) ||
( mRecipientsEditor && mRecipientsEditor->isModified() ) ||
mEdtSubject->edited() ||
mAtmModified ||
( mTransport->lineEdit() && mTransport->lineEdit()->edited() ) );
}
//-----------------------------------------------------------------------------
void KMComposeWin::setModified( bool modified )
{
mEditor->setModified( modified );
if ( !modified ) {
mEdtFrom->setEdited( false );
if ( mEdtReplyTo ) mEdtReplyTo->setEdited( false );
if ( mEdtTo ) mEdtTo->setEdited( false );
if ( mEdtCc ) mEdtCc->setEdited( false );
if ( mEdtBcc ) mEdtBcc->setEdited( false );
if ( mRecipientsEditor ) mRecipientsEditor->clearModified();
mEdtSubject->setEdited( false );