mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 18:32:51 +00:00
1665 lines
50 KiB
C++
1665 lines
50 KiB
C++
/*
|
|
KNode, the KDE newsreader
|
|
Copyright (c) 1999-2006 the KNode authors.
|
|
See file AUTHORS for details
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software Foundation,
|
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
|
|
*/
|
|
|
|
#include "kncomposer.h"
|
|
|
|
#include <KPIMUtils/Email>
|
|
#include <KPIMIdentities/Identity>
|
|
#include <KPIMIdentities/IdentityManager>
|
|
#include <QVBoxLayout>
|
|
#include <QLabel>
|
|
#include <QtDBus/QtDBus>
|
|
#include <qgroupbox.h>
|
|
#include "libkdepim/addressline/recentaddresses.h"
|
|
using KPIM::RecentAddresses;
|
|
#include <akonadi/contact/emailaddressselectiondialog.h>
|
|
#include <kcharsets.h>
|
|
#include <kmessagebox.h>
|
|
#include <kactioncollection.h>
|
|
#include <kstandardaction.h>
|
|
#include <kshortcutsdialog.h>
|
|
#include <kedittoolbar.h>
|
|
#include <kmenu.h>
|
|
#include <kdebug.h>
|
|
#include <kcombobox.h>
|
|
#include <ktemporaryfile.h>
|
|
#include <libkpgp/kpgpblock.h>
|
|
#include <kcompletionbox.h>
|
|
#include <kxmlguifactory.h>
|
|
#include <kstatusbar.h>
|
|
#include <klocale.h>
|
|
#include <kselectaction.h>
|
|
#include <ktoggleaction.h>
|
|
#include "kngroupselectdialog.h"
|
|
#include "utilities.h"
|
|
#include "knglobals.h"
|
|
#include "knmainwidget.h"
|
|
#include "knaccountmanager.h"
|
|
#include "knnntpaccount.h"
|
|
#include "settings.h"
|
|
#include "kncomposerview.h"
|
|
#include "utils/locale.h"
|
|
|
|
using namespace KNode::Utilities;
|
|
using namespace KNode::Composer;
|
|
|
|
|
|
KNLineEdit::KNLineEdit( View *parent, bool useCompletion )
|
|
: KABC::AddressLineEdit( parent, useCompletion ),
|
|
composerView( parent )
|
|
{
|
|
}
|
|
|
|
KNLineEdit::KNLineEdit( QWidget *parent, bool useCompletion )
|
|
: KABC::AddressLineEdit( parent, useCompletion ), composerView(0)
|
|
{
|
|
}
|
|
|
|
|
|
void KNLineEdit::contextMenuEvent( QContextMenuEvent*e )
|
|
{
|
|
QMenu *popup = KLineEdit::createStandardContextMenu();
|
|
popup->addSeparator();
|
|
popup->addAction( i18n( "Edit Recent Addresses..." ),
|
|
this, SLOT(editRecentAddresses()) );
|
|
popup->exec( e->globalPos() );
|
|
delete popup;
|
|
}
|
|
|
|
void KNLineEdit::editRecentAddresses()
|
|
{
|
|
KPIM::RecentAddressDialog dlg( this );
|
|
dlg.setAddresses( RecentAddresses::self( knGlobals.config() )->addresses() );
|
|
if ( dlg.exec() ) {
|
|
RecentAddresses::self( knGlobals.config() )->clear();
|
|
QStringList addrList = dlg.addresses();
|
|
QStringList::Iterator it;
|
|
for ( it = addrList.begin(); it != addrList.end(); ++it )
|
|
RecentAddresses::self( knGlobals.config() )->add( *it );
|
|
|
|
loadAddresses();
|
|
}
|
|
}
|
|
|
|
void KNLineEdit::loadAddresses()
|
|
{
|
|
KABC::AddressLineEdit::loadAddresses();
|
|
|
|
QStringList recent = RecentAddresses::self(knGlobals.config())->addresses();
|
|
QStringList::Iterator it = recent.begin();
|
|
for ( ; it != recent.end(); ++it )
|
|
addAddress( *it );
|
|
}
|
|
|
|
void KNLineEdit::keyPressEvent(QKeyEvent *e)
|
|
{
|
|
// ---sven's Return is same Tab and arrow key navigation start ---
|
|
if ((e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) &&
|
|
!completionBox()->isVisible())
|
|
{
|
|
composerView->focusNextPrevEdit( this, true );
|
|
return;
|
|
}
|
|
if (e->key() == Qt::Key_Up)
|
|
{
|
|
composerView->focusNextPrevEdit( this, false ); // Go up
|
|
return;
|
|
}
|
|
if (e->key() == Qt::Key_Down)
|
|
{
|
|
composerView->focusNextPrevEdit( this, true ); // Go down
|
|
return;
|
|
}
|
|
// ---sven's Return is same Tab and arrow key navigation end ---
|
|
KABC::AddressLineEdit::keyPressEvent(e);
|
|
}
|
|
|
|
|
|
KNLineEditSpell::KNLineEditSpell( View *parent, bool useCompletion )
|
|
: KNLineEdit( parent, useCompletion )
|
|
{
|
|
}
|
|
|
|
KNLineEditSpell::KNLineEditSpell( QWidget *parent, bool useCompletion )
|
|
: KNLineEdit( parent, useCompletion )
|
|
{
|
|
}
|
|
|
|
void KNLineEditSpell::highLightWord( unsigned int length, unsigned int pos )
|
|
{
|
|
setSelection ( pos, length );
|
|
}
|
|
|
|
void KNLineEditSpell::spellCheckDone( const QString &s )
|
|
{
|
|
if( s != text() )
|
|
setText( s );
|
|
}
|
|
|
|
void KNLineEditSpell::spellCheckerMisspelling( const QString &_text, const QStringList &, unsigned int pos)
|
|
{
|
|
highLightWord( _text.length(),pos );
|
|
}
|
|
|
|
void KNLineEditSpell::spellCheckerCorrected( const QString &old, const QString &corr, unsigned int pos)
|
|
{
|
|
if( old!= corr )
|
|
{
|
|
setSelection ( pos, old.length() );
|
|
insert( corr );
|
|
setSelection ( pos, corr.length() );
|
|
}
|
|
}
|
|
|
|
|
|
KNComposer::KNComposer( KNLocalArticle::Ptr a, const QString &text, const QString &unwraped, bool firstEdit, bool dislikesCopies, bool createCopy, bool allowMail )
|
|
: KXmlGuiWindow(0), r_esult(CRsave), a_rticle(a),
|
|
u_nwraped(unwraped),
|
|
n_eeds8Bit(true), v_alidated(false), a_uthorDislikesMailCopies(dislikesCopies), e_xternalEdited(false), e_xternalEditor(0),
|
|
e_ditorTempfile(0), a_ttChanged(false),
|
|
mFirstEdit( firstEdit )
|
|
{
|
|
setObjectName( "composerWindow" );
|
|
|
|
if( knGlobals.componentData().isValid() )
|
|
setComponentData( knGlobals.componentData() );
|
|
|
|
// activate dnd of attachments...
|
|
setAcceptDrops(true);
|
|
|
|
//init v_iew
|
|
v_iew = new View( this );
|
|
setCentralWidget(v_iew);
|
|
|
|
connect( v_iew, SIGNAL(closeExternalEditor()), this, SLOT(slotCancelEditor()) );
|
|
|
|
//statusbar
|
|
KStatusBar *sb=statusBar();
|
|
sb->insertItem( QString(), 1, 1 ); // type
|
|
sb->setItemAlignment( 1, Qt::AlignLeft | Qt::AlignVCenter );
|
|
sb->insertItem( QString(), 2, 1 ); // charset
|
|
sb->setItemAlignment( 2, Qt::AlignLeft | Qt::AlignVCenter );
|
|
sb->insertItem( QString(), 3, 1 ); // write mode
|
|
sb->setItemAlignment(3, Qt::AlignCenter | Qt::AlignVCenter );
|
|
sb->insertItem( QString(), 4, 1 ); // column
|
|
sb->setItemAlignment(4, Qt::AlignCenter | Qt::AlignVCenter );
|
|
sb->insertItem( QString(), 5, 1 ); // line
|
|
sb->setItemAlignment( 5, Qt::AlignCenter | Qt::AlignVCenter );
|
|
connect(v_iew->editor(), SIGNAL(cursorPositionChanged()), SLOT(slotUpdateCursorPos()));
|
|
connect(v_iew->editor(), SIGNAL(insertModeChanged()), SLOT(slotUpdateStatusBar()));
|
|
|
|
QDBusConnection::sessionBus().registerObject( "/Composer", this, QDBusConnection::ExportScriptableSlots );
|
|
//------------------------------- <Actions> --------------------------------------
|
|
|
|
//file menu
|
|
KAction *action = actionCollection()->addAction("send_now");
|
|
action->setIcon(KIcon("mail-send"));
|
|
action->setText(i18n("&Send Now"));
|
|
connect(action, SIGNAL(triggered(bool)), SLOT(slotSendNow()));
|
|
action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
|
|
|
|
action = actionCollection()->addAction("send_later");
|
|
action->setIcon(KIcon("mail-queue"));
|
|
action->setText(i18n("Send &Later"));
|
|
connect(action, SIGNAL(triggered(bool)), SLOT(slotSendLater()));
|
|
|
|
action = actionCollection()->addAction("save_as_draft");
|
|
action->setIcon(KIcon("document-save"));
|
|
action->setText(i18n("Save as &Draft"));
|
|
connect(action, SIGNAL(triggered(bool)), SLOT(slotSaveAsDraft()));
|
|
|
|
action = actionCollection()->addAction("art_delete");
|
|
action->setIcon(KIcon("edit-delete"));
|
|
action->setText(i18n("D&elete"));
|
|
connect(action, SIGNAL(triggered(bool)), SLOT(slotArtDelete()));
|
|
|
|
KStandardAction::close(this, SLOT(close()),actionCollection());
|
|
|
|
//edit menu
|
|
KStandardAction::undo(this, SLOT(slotUndo()), actionCollection());
|
|
KStandardAction::redo(this, SLOT(slotRedo()), actionCollection());
|
|
|
|
KStandardAction::cut(this, SLOT(slotCut()), actionCollection());
|
|
|
|
|
|
KStandardAction::copy(this, SLOT(slotCopy()), actionCollection());
|
|
|
|
KStandardAction::pasteText(this, SLOT(slotPaste()), actionCollection());
|
|
|
|
action = actionCollection()->addAction("paste_quoted");
|
|
action->setText(i18n("Paste as &Quotation"));
|
|
connect(action, SIGNAL(triggered(bool)), v_iew->editor(), SLOT(slotPasteAsQuotation()));
|
|
|
|
KStandardAction::selectAll(this, SLOT(slotSelectAll()), actionCollection());
|
|
|
|
KStandardAction::find(v_iew->editor(), SLOT(slotFind()), actionCollection());
|
|
KStandardAction::findNext(v_iew->editor(), SLOT(slotFindNext()), actionCollection());
|
|
|
|
KStandardAction::replace(v_iew->editor(), SLOT(slotReplace()), actionCollection());
|
|
|
|
//attach menu
|
|
action = actionCollection()->addAction("append_signature");
|
|
action->setText(i18n("Append &Signature"));
|
|
connect( action, SIGNAL(triggered(bool)), v_iew, SLOT(appendSignature()) );
|
|
|
|
action = actionCollection()->addAction("insert_file");
|
|
action->setText(i18n("&Insert File..."));
|
|
connect(action, SIGNAL(triggered(bool)), SLOT(slotInsertFile()));
|
|
|
|
action = actionCollection()->addAction("insert_file_boxed");
|
|
action->setText(i18n("Insert File (in a &box)..."));
|
|
connect(action, SIGNAL(triggered(bool)), SLOT(slotInsertFileBoxed()));
|
|
|
|
action = actionCollection()->addAction("attach_file");
|
|
action->setIcon(KIcon("mail-attachment"));
|
|
action->setText(i18n("Attach &File..."));
|
|
connect(action, SIGNAL(triggered(bool)), SLOT(slotAttachFile()));
|
|
|
|
a_ctPGPsign = actionCollection()->add<KToggleAction>("sign_article");
|
|
a_ctPGPsign->setText(i18n("Sign Article with &PGP"));
|
|
a_ctPGPsign->setIcon(KIcon("document-sign"));
|
|
|
|
a_ctRemoveAttachment = actionCollection()->addAction("remove_attachment");
|
|
a_ctRemoveAttachment->setText(i18n("&Remove"));
|
|
connect( a_ctRemoveAttachment, SIGNAL(triggered(bool)), v_iew, SLOT(removeCurrentAttachment()) );
|
|
|
|
a_ctAttachmentProperties = actionCollection()->addAction("attachment_properties");
|
|
a_ctAttachmentProperties->setText(i18n("&Properties"));
|
|
connect( a_ctAttachmentProperties, SIGNAL(triggered(bool)), v_iew, SLOT(editCurrentAttachment()) );
|
|
|
|
//options menu
|
|
|
|
a_ctDoPost = actionCollection()->add<KToggleAction>("send_news");
|
|
a_ctDoPost->setIcon(KIcon("document-new"));
|
|
a_ctDoPost->setText(i18n("Send &News Article"));
|
|
connect(a_ctDoPost, SIGNAL(triggered(bool)), SLOT(slotToggleDoPost()));
|
|
|
|
a_ctDoMail = actionCollection()->add<KToggleAction>("send_mail");
|
|
a_ctDoMail->setIcon(KIcon("mail-send"));
|
|
a_ctDoMail->setText(i18n("Send E&mail"));
|
|
a_ctDoMail->setEnabled(allowMail);
|
|
connect(a_ctDoMail, SIGNAL(triggered(bool)), SLOT(slotToggleDoMail()));
|
|
|
|
a_ctSetCharset = actionCollection()->add<KSelectAction>("set_charset");
|
|
a_ctSetCharset->setText(i18n("Set &Charset"));
|
|
a_ctSetCharset->setItems( Locale::encodings() );
|
|
a_ctSetCharset->setShortcutConfigurable(false);
|
|
connect(a_ctSetCharset, SIGNAL(triggered(QString)),
|
|
this, SLOT(slotSetCharset(QString)));
|
|
|
|
a_ctSetCharsetKeyb = actionCollection()->addAction("set_charset_keyboard");
|
|
a_ctSetCharsetKeyb->setText(i18n("Set Charset"));
|
|
connect(a_ctSetCharsetKeyb, SIGNAL(triggered(bool)), SLOT(slotSetCharsetKeyboard()));
|
|
addAction( a_ctSetCharsetKeyb );
|
|
|
|
|
|
a_ctWordWrap = actionCollection()->add<KToggleAction>("toggle_wordwrap");
|
|
a_ctWordWrap->setText(i18n("&Word Wrap"));
|
|
connect(a_ctWordWrap, SIGNAL(triggered(bool)), SLOT(slotToggleWordWrap()));
|
|
|
|
a_ctAutoSpellChecking = new KToggleAction( KIcon( "tools-check-spelling" ), i18n("&Automatic Spellchecking"), this );
|
|
actionCollection()->addAction( "options_auto_spellchecking", a_ctAutoSpellChecking );
|
|
a_ctAutoSpellChecking->setChecked( knGlobals.settings()->autoSpellChecking() );
|
|
slotUpdateCheckSpellChecking( knGlobals.settings()->autoSpellChecking() );
|
|
slotAutoSpellCheckingToggled();
|
|
connect(a_ctAutoSpellChecking, SIGNAL(triggered(bool)), SLOT(slotAutoSpellCheckingToggled()));
|
|
connect( v_iew->editor(), SIGNAL(checkSpellingChanged(bool)), this, SLOT(slotUpdateCheckSpellChecking(bool)));
|
|
|
|
|
|
//tools menu
|
|
|
|
action = actionCollection()->addAction("tools_quote");
|
|
action->setText(i18n("Add &Quote Characters"));
|
|
connect(action, SIGNAL(triggered(bool)), v_iew->editor(), SLOT(slotAddQuotes()));
|
|
|
|
action = actionCollection()->addAction("tools_unquote");
|
|
action->setText(i18n("&Remove Quote Characters"));
|
|
connect(action, SIGNAL(triggered(bool)), v_iew->editor(), SLOT(slotRemoveQuotes()));
|
|
|
|
action = actionCollection()->addAction("tools_box");
|
|
action->setText(i18n("Add &Box"));
|
|
connect(action, SIGNAL(triggered(bool)), v_iew->editor(), SLOT(slotAddBox()));
|
|
|
|
action = actionCollection()->addAction("tools_unbox");
|
|
action->setText(i18n("Re&move Box"));
|
|
connect(action, SIGNAL(triggered(bool)), v_iew->editor(), SLOT(slotRemoveBox()));
|
|
|
|
QAction *undoRewrap = actionCollection()->addAction("tools_undoRewrap");
|
|
undoRewrap->setText(i18n("Get &Original Text (not re-wrapped)"));
|
|
connect(undoRewrap, SIGNAL(triggered(bool)), SLOT(slotUndoRewrap()));
|
|
undoRewrap->setEnabled(!u_nwraped.isNull());
|
|
|
|
QAction *rot13 = actionCollection()->addAction("tools_rot13");
|
|
rot13->setIcon(KIcon("document-encrypt"));
|
|
rot13->setText(i18n("S&cramble (Rot 13)"));
|
|
connect(rot13, SIGNAL(triggered(bool)), v_iew->editor(), SLOT(slotRot13()));
|
|
rot13->setEnabled(false);
|
|
connect(v_iew->editor(), SIGNAL(copyAvailable(bool)), rot13, SLOT(setEnabled(bool)));
|
|
|
|
a_ctExternalEditor = actionCollection()->addAction("external_editor");
|
|
a_ctExternalEditor->setIcon(KIcon("system-run"));
|
|
a_ctExternalEditor->setText(i18n("Start &External Editor"));
|
|
connect(a_ctExternalEditor, SIGNAL(triggered(bool)), SLOT(slotExternalEditor()));
|
|
|
|
a_ctSpellCheck = KStandardAction::spelling ( v_iew->editor(), SLOT(checkSpelling()), actionCollection());
|
|
|
|
//settings menu
|
|
createStandardStatusBarAction();
|
|
setStandardToolBarMenuEnabled(true);
|
|
|
|
KStandardAction::keyBindings(this, SLOT(slotConfKeys()), actionCollection());
|
|
|
|
KStandardAction::configureToolbars(this, SLOT(slotConfToolbar()), actionCollection());
|
|
|
|
KStandardAction::preferences(knGlobals.top, SLOT(slotSettings()), actionCollection());
|
|
|
|
|
|
createGUI("kncomposerui.rc");
|
|
|
|
//---------------------------------- </Actions> ----------------------------------------
|
|
|
|
//init
|
|
initData(text);
|
|
|
|
//apply configuration
|
|
setConfig(false);
|
|
|
|
if (createCopy && (m_ode==news)) {
|
|
a_ctDoMail->setChecked(true);
|
|
slotToggleDoMail();
|
|
}
|
|
|
|
v_iew->completeSetup( firstEdit, m_ode );
|
|
|
|
// restore window & toolbar configuration
|
|
resize(535,450); // default optimized for 800x600
|
|
applyMainWindowSettings(knGlobals.config()->group("composerWindow_options"));
|
|
|
|
// starting the external editor
|
|
if ( knGlobals.settings()->useExternalEditor() )
|
|
slotExternalEditor();
|
|
}
|
|
|
|
|
|
KNComposer::~KNComposer()
|
|
{
|
|
// prevent slotEditorFinished from being called
|
|
if (e_xternalEditor)
|
|
e_xternalEditor->disconnect();
|
|
delete e_xternalEditor; // this also kills the editor process if it's still running
|
|
|
|
delete e_ditorTempfile;
|
|
|
|
saveMainWindowSettings(knGlobals.config()->group("composerWindow_options"));
|
|
|
|
KNGlobals::self()->settings()->setAutoSpellChecking( a_ctAutoSpellChecking->isChecked() );
|
|
KNGlobals::self()->settings()->writeConfig();
|
|
}
|
|
|
|
void KNComposer::slotUpdateCheckSpellChecking(bool _b)
|
|
{
|
|
a_ctAutoSpellChecking->setChecked(_b);
|
|
}
|
|
|
|
|
|
void KNComposer::slotUndo()
|
|
{
|
|
QWidget* fw = focusWidget();
|
|
if (!fw) return;
|
|
|
|
if (fw->inherits("KTextEdit"))
|
|
((KTextEdit*)fw)->undo();
|
|
else if (fw->inherits("QLineEdit"))
|
|
((QLineEdit*)fw)->undo();
|
|
}
|
|
|
|
void KNComposer::slotRedo()
|
|
{
|
|
QWidget* fw = focusWidget();
|
|
if (!fw) return;
|
|
|
|
if (fw->inherits("KTextEdit"))
|
|
((KTextEdit*)fw)->redo();
|
|
else if (fw->inherits("QLineEdit"))
|
|
((QLineEdit*)fw)->redo();
|
|
}
|
|
|
|
void KNComposer::slotCut()
|
|
{
|
|
QWidget* fw = focusWidget();
|
|
if (!fw) return;
|
|
|
|
if (fw->inherits("KTextEdit"))
|
|
((KTextEdit*)fw)->cut();
|
|
else if (fw->inherits("QLineEdit"))
|
|
((QLineEdit*)fw)->cut();
|
|
else kDebug(5003) <<"wrong focus widget";
|
|
}
|
|
|
|
void KNComposer::slotCopy()
|
|
{
|
|
QWidget* fw = focusWidget();
|
|
if (!fw) return;
|
|
|
|
if (fw->inherits("KTextEdit"))
|
|
((KTextEdit*)fw)->copy();
|
|
else if (fw->inherits("QLineEdit"))
|
|
((QLineEdit*)fw)->copy();
|
|
else kDebug(5003) <<"wrong focus widget";
|
|
|
|
}
|
|
|
|
|
|
void KNComposer::slotPaste()
|
|
{
|
|
QWidget* fw = focusWidget();
|
|
if (!fw) return;
|
|
|
|
if (fw->inherits("KTextEdit"))
|
|
((KTextEdit*)fw)->paste();
|
|
else if (fw->inherits("QLineEdit"))
|
|
((QLineEdit*)fw)->paste();
|
|
else kDebug(5003) <<"wrong focus widget";
|
|
}
|
|
|
|
void KNComposer::slotSelectAll()
|
|
{
|
|
QWidget* fw = focusWidget();
|
|
if (!fw) return;
|
|
|
|
if (fw->inherits("QLineEdit"))
|
|
((QLineEdit*)fw)->selectAll();
|
|
else if (fw->inherits("KTextEdit"))
|
|
((KTextEdit*)fw)->selectAll();
|
|
}
|
|
|
|
|
|
void KNComposer::setConfig(bool onlyFonts)
|
|
{
|
|
if (!onlyFonts) {
|
|
a_ctWordWrap->setChecked( knGlobals.settings()->wordWrap() );
|
|
slotToggleWordWrap();
|
|
|
|
a_ctAutoSpellChecking->setChecked( knGlobals.settings()->autoSpellChecking() );
|
|
Kpgp::Module *pgp = Kpgp::Module::getKpgp();
|
|
a_ctPGPsign->setEnabled(pgp->usePGP());
|
|
}
|
|
|
|
v_iew->setComposingFont( knGlobals.settings()->composerFont() );
|
|
|
|
slotUpdateStatusBar();
|
|
}
|
|
|
|
|
|
void KNComposer::setMessageMode(MessageMode mode)
|
|
{
|
|
m_ode = mode;
|
|
a_ctDoPost->setChecked(m_ode!=mail);
|
|
a_ctDoMail->setChecked(m_ode!=news);
|
|
v_iew->setMessageMode(m_ode);
|
|
//Laurent fixme
|
|
#if 0
|
|
QString s = v_iew->editor()->document ()->begin().text ();
|
|
if (m_ode == news_mail) {
|
|
if (!s.contains(i18n("<posted & mailed>"))) {
|
|
QTextCursor cursor(v_iew->editor()->document ()->begin());
|
|
cursor.setPosition(0);
|
|
cursor.insertText(i18n("<posted & mailed>\n\n"));
|
|
v_iew->editor()->setTextCursor(cursor);
|
|
}
|
|
} else {
|
|
if (s == i18n("<posted & mailed>")) {
|
|
v_iew->editor()->removeLine(0);
|
|
if (v_iew->editor()->textLine(0).isEmpty())
|
|
v_iew->editor()->removeLine(0);
|
|
}
|
|
}
|
|
#endif
|
|
slotUpdateStatusBar();
|
|
}
|
|
|
|
|
|
bool KNComposer::hasValidData()
|
|
{
|
|
v_alidated=false;
|
|
n_eeds8Bit=false;
|
|
|
|
// header checks
|
|
if ( KPIMUtils::isValidAddress( v_iew->from() ) != KPIMUtils::AddressOk ) {
|
|
KMessageBox::sorry( this, i18n( "Your email address does not appears to be valid. Please modify it." ) );
|
|
return false;
|
|
}
|
|
|
|
if ( v_iew->subject().isEmpty() ) {
|
|
KMessageBox::sorry(this, i18n("Please enter a subject."));
|
|
return false;
|
|
}
|
|
if ( !n_eeds8Bit && !KMime::isUsAscii( v_iew->subject() ) ) {
|
|
n_eeds8Bit=true;
|
|
}
|
|
|
|
if (m_ode != mail) {
|
|
int groupCount = v_iew->groups().count();
|
|
if ( groupCount == 0 ) {
|
|
KMessageBox::sorry(this, i18n("Please enter a newsgroup."));
|
|
return false;
|
|
}
|
|
|
|
if (groupCount>12) {
|
|
KMessageBox::sorry(this, i18n("You are crossposting to more than 12 newsgroups.\nPlease remove all newsgroups in which your article is off-topic."));
|
|
return false;
|
|
}
|
|
|
|
if (groupCount>5)
|
|
if ( KMessageBox::warningYesNo( this, i18n("You are crossposting to more than five newsgroups.\nPlease reconsider whether this is really useful\nand remove groups in which your article is off-topic.\nDo you want to re-edit the article or send it anyway?"),
|
|
QString(), KGuiItem(i18n("&Send")), KGuiItem(i18nc("edit article","&Edit")) ) != KMessageBox::Yes )
|
|
return false;
|
|
|
|
int fupCount = v_iew->followupTo().count();
|
|
if ( fupCount == 0 && groupCount > 2 ) {
|
|
if ( KMessageBox::warningYesNo( this,
|
|
i18n("You are crossposting to more than two newsgroups.\n"
|
|
"Please use the \"Followup-To\" header to direct the replies "
|
|
"to your article into one group.\n"
|
|
"Do you want to re-edit the article or send it anyway?"),
|
|
QString(), KGuiItem(i18n("&Send")), KGuiItem(i18nc("edit article","&Edit")), "missingFollowUpTo" )
|
|
!= KMessageBox::Yes )
|
|
return false;
|
|
}
|
|
|
|
if (fupCount>12) {
|
|
KMessageBox::sorry(this, i18n("You are directing replies to more than 12 newsgroups.\nPlease remove some newsgroups from the \"Followup-To\" header."));
|
|
return false;
|
|
}
|
|
|
|
if (fupCount>5)
|
|
if ( KMessageBox::warningYesNo( this, i18n("You are directing replies to more than five newsgroups.\nPlease reconsider whether this is really useful.\nDo you want to re-edit the article or send it anyway?"),
|
|
QString(), KGuiItem(i18n("&Send")),KGuiItem(i18nc("edit article","&Edit")) ) != KMessageBox::Yes )
|
|
return false;
|
|
}
|
|
|
|
if (m_ode != news) {
|
|
if ( v_iew->emailRecipient().isEmpty() ) {
|
|
KMessageBox::sorry(this, i18n("Please enter the email address."));
|
|
return false;
|
|
}
|
|
if ( !n_eeds8Bit && !KMime::isUsAscii( v_iew->emailRecipient() ) ) {
|
|
n_eeds8Bit=true;
|
|
}
|
|
}
|
|
|
|
//GNKSA body checks
|
|
bool firstLine = true;
|
|
bool empty = true;
|
|
bool longLine = false;
|
|
bool hasAttributionLine = false;
|
|
int sigLength = 0;
|
|
int notQuoted = 0;
|
|
int textLines = 0;
|
|
QStringList text = v_iew->editor()->toWrappedPlainText().split('\n');
|
|
|
|
for (QStringList::Iterator it = text.begin(); it != text.end(); ++it) {
|
|
|
|
if (!n_eeds8Bit && !KMime::isUsAscii(*it))
|
|
n_eeds8Bit=true;
|
|
|
|
if (*it == "-- ") { // signature text
|
|
for (++it; it != text.end(); ++it) {
|
|
|
|
if (!n_eeds8Bit && !KMime::isUsAscii(*it))
|
|
n_eeds8Bit=true;
|
|
|
|
sigLength++;
|
|
if((*it).length()>80) {
|
|
longLine = true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(!(*it).isEmpty()) {
|
|
empty = false;
|
|
textLines++;
|
|
if ((*it)[0]!='>') {
|
|
notQuoted++;
|
|
if (firstLine) hasAttributionLine = true;
|
|
}
|
|
}
|
|
if((*it).length()>80) {
|
|
longLine = true;
|
|
}
|
|
|
|
firstLine = false;
|
|
}
|
|
|
|
if (n_eeds8Bit && ( mCharset.toLower()=="us-ascii" )) {
|
|
KMessageBox::sorry(this, i18n("Your message contains characters which are not included\nin the \"us-ascii\" character set; please choose\na suitable character set from the \"Options\" menu."));
|
|
return false;
|
|
}
|
|
|
|
if (empty) {
|
|
KMessageBox::sorry(this, i18n("You cannot post an empty message."));
|
|
return false;
|
|
}
|
|
|
|
if ((textLines>1)&&(notQuoted==1)) {
|
|
if (hasAttributionLine)
|
|
if ( KMessageBox::warningYesNo( this, i18n("Your article seems to consist entirely of quoted text;\ndo you want to re-edit the article or send it anyway?"),
|
|
QString(), KGuiItem(i18n("&Send")), KGuiItem(i18nc("edit article","&Edit")) ) != KMessageBox::Yes )
|
|
return false;
|
|
} else {
|
|
if (notQuoted==0) {
|
|
KMessageBox::sorry(this, i18n("You cannot post an article consisting\n"
|
|
"entirely of quoted text."));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (longLine)
|
|
if ( KMessageBox::warningYesNo( this,
|
|
i18n("Your article contains lines longer than 80 characters.\n"
|
|
"Do you want to re-edit the article or send it anyway?"),
|
|
QString(), KGuiItem(i18n("&Send")),
|
|
KGuiItem(i18nc("edit article","&Edit")) ) != KMessageBox::Yes )
|
|
return false;
|
|
|
|
if (sigLength>8) {
|
|
if ( KMessageBox::warningYesNo( this, i18n("Your signature is more than 8 lines long.\nYou should shorten it to match the widely accepted limit of 4 lines.\nDo you want to re-edit the article or send it anyway?"),
|
|
QString(), KGuiItem(i18n("&Send")), KGuiItem(i18nc("edit article","&Edit")) ) != KMessageBox::Yes )
|
|
return false;
|
|
} else
|
|
if (sigLength>4)
|
|
KMessageBox::information( this, i18n("Your signature exceeds the widely-accepted limit of 4 lines:\nplease consider shortening your signature;\notherwise, you will probably annoy your readers."),
|
|
QString(), "longSignatureWarning" );
|
|
|
|
// check if article can be signed
|
|
if ( a_ctPGPsign->isChecked() ) {
|
|
// try to get the signing key
|
|
QByteArray signingKey = KNGlobals::self()->settings()->identity().pgpSigningKey();
|
|
KNNntpAccount::Ptr acc = knGlobals.accountManager()->account( a_rticle->serverId() );
|
|
if ( acc ) {
|
|
KMime::Headers::Newsgroups *grps = a_rticle->newsgroups();
|
|
if ( !grps->isEmpty() ) {
|
|
KNGroup::Ptr grp = knGlobals.groupManager()->group( grps->groups().first(), acc );
|
|
if ( grp && !grp->identity().isNull() ) {
|
|
signingKey = grp->identity().pgpSigningKey();
|
|
} else if ( !acc->identity().isNull() ) {
|
|
signingKey = acc->identity().pgpSigningKey();
|
|
}
|
|
}
|
|
}
|
|
|
|
// the article can only be signed if we have a key
|
|
if (signingKey.isEmpty()) {
|
|
if ( KMessageBox::warningContinueCancel( this,
|
|
i18n("You have not configured your preferred "
|
|
"signing key yet;\n"
|
|
"please specify it in the global "
|
|
"identity configuration,\n"
|
|
"in the account properties or in the "
|
|
"group properties.\n"
|
|
"The article will be sent unsigned." ),
|
|
QString(), KGuiItem(i18n( "Send Unsigned" )),
|
|
KStandardGuiItem::cancel(), "sendUnsignedDialog" )
|
|
== KMessageBox::Cancel )
|
|
return false;
|
|
}
|
|
}
|
|
|
|
v_alidated=true;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool KNComposer::applyChanges()
|
|
{
|
|
KMime::Content *text=0;
|
|
bool result = true; // no error occurs ?
|
|
|
|
|
|
// Identity (for later edition)
|
|
const KPIMIdentities::Identity identity = KNGlobals::self()->identityManager()->identityForUoid( v_iew->selectedIdentity() );
|
|
if ( !identity.isNull() ) {
|
|
KMime::Headers::Generic *xKnodeIdentity = new KMime::Headers::Generic( "X-KNode-Identity",
|
|
a_rticle.get(),
|
|
QByteArray::number( identity.uoid() ) );
|
|
a_rticle->setHeader( xKnodeIdentity );
|
|
}
|
|
|
|
//From
|
|
if ( KPIMUtils::isValidAddress( v_iew->from() ) != KPIMUtils::AddressOk ) {
|
|
result = false;
|
|
}
|
|
// FIXME: if v_iew->from() is not valid, the following call is a
|
|
// no-op: the content of the from keeps its previous value! (thanks KMime)
|
|
a_rticle->from()->fromUnicodeString( v_iew->from(), mCharset.toLatin1() );
|
|
|
|
//Reply-To
|
|
if ( KPIMUtils::isValidAddress( identity.replyToAddr() ) == KPIMUtils::AddressOk ) {
|
|
a_rticle->replyTo()->fromUnicodeString( identity.replyToAddr(), mCharset.toLatin1() );
|
|
} else {
|
|
a_rticle->removeHeader( "Reply-To" );
|
|
}
|
|
|
|
//Mail-Copies-To
|
|
if ( !identity.property( "Mail-Copies-To" ).toString().trimmed().isEmpty() ) {
|
|
a_rticle->mailCopiesTo()->fromUnicodeString( identity.property( "Mail-Copies-To" ).toString(), mCharset.toLatin1() );
|
|
} else {
|
|
a_rticle->removeHeader( "Mail-Copies-To" );
|
|
}
|
|
|
|
//Organization
|
|
if ( !identity.organization().trimmed().isEmpty() ) {
|
|
a_rticle->organization()->fromUnicodeString( identity.organization(), mCharset.toLatin1() );
|
|
} else {
|
|
a_rticle->removeHeader( "Organization" );
|
|
}
|
|
|
|
//Date
|
|
a_rticle->date()->setDateTime( KDateTime::currentLocalDateTime() ); //set current date+time
|
|
|
|
//Subject
|
|
a_rticle->subject()->fromUnicodeString( v_iew->subject(), mCharset.toLatin1() );
|
|
|
|
//Newsgroups
|
|
if (m_ode != mail) {
|
|
a_rticle->newsgroups()->fromUnicodeString( v_iew->groups().join( QString( ',' ) ), KMime::Headers::Latin1 );
|
|
a_rticle->setDoPost(true);
|
|
} else {
|
|
a_rticle->setDoPost(false);
|
|
a_rticle->removeHeader( "Newsgroups" );
|
|
}
|
|
|
|
//To
|
|
if (m_ode != news) {
|
|
a_rticle->to()->fromUnicodeString( v_iew->emailRecipient(), mCharset.toLatin1() );
|
|
a_rticle->setDoMail(true);
|
|
} else {
|
|
a_rticle->setDoMail(false);
|
|
a_rticle->removeHeader( "To" );
|
|
a_rticle->removeHeader( "Cc" );
|
|
}
|
|
|
|
//Followup-To
|
|
if ( a_rticle->doPost() && !v_iew->followupTo().isEmpty() ) {
|
|
a_rticle->followUpTo()->fromUnicodeString( v_iew->followupTo().join( QString( ',' ) ), KMime::Headers::Latin1 );
|
|
} else {
|
|
a_rticle->removeHeader("Followup-To");
|
|
}
|
|
|
|
|
|
// Attachments
|
|
if ( a_ttChanged ) {
|
|
const QList<KNAttachment::Ptr> l = v_iew->attachments();
|
|
foreach ( const KNAttachment::Ptr a, l ) {
|
|
if(a->hasChanged()) {
|
|
if(a->isAttached())
|
|
a->updateContentInfo();
|
|
else
|
|
a->attach( a_rticle.get() );
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( QList<KNAttachment::Ptr>::Iterator it = mDeletedAttachments.begin(); it != mDeletedAttachments.end(); ++it )
|
|
if ( (*it)->isAttached() )
|
|
(*it)->detach( a_rticle.get() );
|
|
|
|
text=a_rticle->textContent();
|
|
|
|
if(!text) {
|
|
text=new KMime::Content();
|
|
KMime::Headers::ContentType *type=text->contentType();
|
|
KMime::Headers::ContentTransferEncoding *enc=text->contentTransferEncoding();
|
|
type->setMimeType("text/plain");
|
|
enc->setDecoded(true);
|
|
text->assemble();
|
|
a_rticle->addContent(text, true);
|
|
}
|
|
|
|
//set text
|
|
if (v_alidated) {
|
|
if (n_eeds8Bit) {
|
|
text->contentType()->setCharset( mCharset.toLatin1() );
|
|
if ( knGlobals.settings()->allow8BitBody() )
|
|
text->contentTransferEncoding()->setEncoding(KMime::Headers::CE8Bit);
|
|
else
|
|
text->contentTransferEncoding()->setEncoding(KMime::Headers::CEquPr);
|
|
} else {
|
|
setCharset( "us-ascii" ); // fall back to us-ascii
|
|
text->contentType()->setCharset( mCharset.toLatin1() );
|
|
text->contentTransferEncoding()->setEncoding(KMime::Headers::CE7Bit);
|
|
}
|
|
} else { // save as draft
|
|
text->contentType()->setCharset( mCharset.toLatin1() );
|
|
if ( mCharset.toLower()=="us-ascii" ) {
|
|
text->contentTransferEncoding()->setEncoding(KMime::Headers::CE7Bit);
|
|
} else {
|
|
text->contentTransferEncoding()->setEncoding( knGlobals.settings()->allow8BitBody()
|
|
? KMime::Headers::CE8Bit : KMime::Headers::CEquPr );
|
|
}
|
|
}
|
|
|
|
QString tmp = v_iew->editor()->toWrappedPlainText();
|
|
|
|
// Sign article if needed
|
|
if ( a_ctPGPsign->isChecked() ) {
|
|
QByteArray signingKey = identity.pgpSigningKey();
|
|
if (!signingKey.isEmpty()) {
|
|
QString tmpText = tmp;
|
|
Kpgp::Block block;
|
|
bool ok=true;
|
|
QTextCodec *codec=KGlobal::charsets()->codecForName( mCharset, ok);
|
|
if(!ok) // no suitable codec found => try local settings and hope the best ;-)
|
|
codec=KGlobal::locale()->codecForEncoding();
|
|
|
|
block.setText( codec->fromUnicode(tmpText) );
|
|
kDebug(5003) <<"signing article from" << article()->from()->addresses();
|
|
if( block.clearsign( signingKey, codec->name() ) == Kpgp::Ok ) {
|
|
QByteArray result = block.text();
|
|
tmp = codec->toUnicode(result.data(), result.length() );
|
|
} else {
|
|
result = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
text->fromUnicodeString(tmp);
|
|
|
|
//text is set and all attached contents have been assembled => now set lines
|
|
a_rticle->lines()->setNumberOfLines(a_rticle->lineCount());
|
|
|
|
a_rticle->assemble();
|
|
a_rticle->updateListItem();
|
|
|
|
return result;
|
|
}
|
|
|
|
void KNComposer::setCharset( const QString &charset )
|
|
{
|
|
mCharset = Locale::toMimeCharset( charset );
|
|
slotUpdateStatusBar();
|
|
}
|
|
|
|
|
|
void KNComposer::closeEvent(QCloseEvent *e)
|
|
{
|
|
if(!v_iew->editor()->document()->isModified() && !a_ttChanged) { // nothing to save, don't show nag screen
|
|
if(a_rticle->id()==-1)
|
|
r_esult=CRdel;
|
|
else
|
|
r_esult=CRcancel;
|
|
}
|
|
else {
|
|
switch ( KMessageBox::warningYesNoCancel( this, i18n("Do you want to save this article in the draft folder?"),
|
|
QString(), KStandardGuiItem::save(), KStandardGuiItem::discard() ) ) {
|
|
case KMessageBox::Yes :
|
|
r_esult=CRsave;
|
|
break;
|
|
case KMessageBox::No :
|
|
if (a_rticle->id()==-1) r_esult=CRdel;
|
|
else r_esult=CRcancel;
|
|
break;
|
|
default: // cancel
|
|
e->ignore();
|
|
return;
|
|
}
|
|
}
|
|
|
|
e->accept();
|
|
emit composerDone(this);
|
|
// we're dead at this point, don't access members!
|
|
}
|
|
|
|
|
|
void KNComposer::initData(const QString &text)
|
|
{
|
|
// Identity
|
|
KPIMIdentities::IdentityManager *idManager = KNGlobals::self()->identityManager();
|
|
KPIMIdentities::Identity identity = idManager->defaultIdentity();
|
|
KMime::Headers::Base* xKnodeIdentity = a_rticle->headerByType( "X-KNode-Identity" );
|
|
if ( xKnodeIdentity && !xKnodeIdentity->isEmpty() ) {
|
|
uint uoid = xKnodeIdentity->asUnicodeString().toUInt();
|
|
// Note: this ensure the identity exists even if it was removed
|
|
identity = idManager->identityForUoidOrDefault( uoid );
|
|
}
|
|
v_iew->setIdentity( identity.uoid() );
|
|
|
|
//From
|
|
KMime::Headers::From *from = a_rticle->from( false );
|
|
if ( from ) {
|
|
v_iew->setFrom( from->asUnicodeString() );
|
|
} else {
|
|
v_iew->setFrom( identity.fullEmailAddr() );
|
|
}
|
|
|
|
//Subject
|
|
if(a_rticle->subject()->isEmpty())
|
|
slotSubjectChanged( QString() );
|
|
else
|
|
v_iew->setSubject( a_rticle->subject()->asUnicodeString() );
|
|
|
|
//Newsgroups
|
|
KMime::Headers::Newsgroups *hNewsgroup = a_rticle->newsgroups( false );
|
|
if ( hNewsgroup && !hNewsgroup->isEmpty() ) {
|
|
v_iew->setGroups( hNewsgroup->asUnicodeString() );
|
|
}
|
|
|
|
//To
|
|
KMime::Headers::To *hTo = a_rticle->to( false );
|
|
if ( hTo && !hTo->isEmpty() ) {
|
|
v_iew->setEmailRecipient( hTo->asUnicodeString() );
|
|
}
|
|
|
|
//Followup-To
|
|
KMime::Headers::FollowUpTo *fup2=a_rticle->followUpTo(false);
|
|
if( fup2 && !fup2->isEmpty() ) {
|
|
v_iew->setFollowupTo( fup2->asUnicodeString() );
|
|
}
|
|
|
|
KMime::Content *textContent=a_rticle->textContent();
|
|
QString s;
|
|
|
|
if(text.isEmpty()) {
|
|
if(textContent)
|
|
s = textContent->decodedText();
|
|
} else
|
|
s = text;
|
|
|
|
v_iew->editor()->setText(s);
|
|
|
|
// initialize the charset select action
|
|
if(textContent) {
|
|
setCharset( textContent->contentType()->charset() );
|
|
} else {
|
|
setCharset( knGlobals.settings()->charset() );
|
|
}
|
|
|
|
QString charsetDesc = KGlobal::charsets()->descriptionForEncoding( mCharset );
|
|
a_ctSetCharset->setCurrentItem( a_ctSetCharset->items().indexOf( charsetDesc ) );
|
|
|
|
// initialize the message type select action
|
|
if (a_rticle->doPost() && a_rticle->doMail())
|
|
m_ode = news_mail;
|
|
else
|
|
if (a_rticle->doPost())
|
|
m_ode = news;
|
|
else
|
|
m_ode = mail;
|
|
setMessageMode(m_ode);
|
|
|
|
if(a_rticle->contentType()->isMultipart()) {
|
|
v_iew->showAttachmentView();
|
|
const KMime::Content::List attList = a_rticle->attachments();
|
|
foreach ( KMime::Content *c, attList ) {
|
|
v_iew->addAttachment( KNAttachment::Ptr( new KNAttachment( c ) ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
// inserts at cursor position if clear is false, replaces content otherwise
|
|
// puts the file content into a box if box==true
|
|
// "file" is already open for reading
|
|
void KNComposer::insertFile( QFile *file, bool clear, bool box, const QString &boxTitle )
|
|
{
|
|
QString temp;
|
|
bool ok=true;
|
|
QTextCodec *codec=KGlobal::charsets()->codecForName( mCharset, ok);
|
|
QTextStream ts(file);
|
|
ts.setCodec(codec);
|
|
|
|
if (box)
|
|
temp = QString::fromLatin1(",----[ %1 ]\n").arg(boxTitle);
|
|
//Laurent fixme
|
|
if (box && (v_iew->editor()->wordWrapMode()!=QTextOption::NoWrap)) {
|
|
int wrapAt = v_iew->editor()->lineWrapColumnOrWidth();
|
|
QStringList lst;
|
|
QString line;
|
|
while(!ts.atEnd()) {
|
|
line=ts.readLine();
|
|
if (!ts.atEnd())
|
|
line+='\n';
|
|
lst.append(line);
|
|
}
|
|
temp+=KNHelper::rewrapStringList(lst, wrapAt, '|', false, true);
|
|
} else {
|
|
while(!ts.atEnd()) {
|
|
if (box)
|
|
temp+="| ";
|
|
temp+=ts.readLine();
|
|
if (!ts.atEnd())
|
|
temp += '\n';
|
|
}
|
|
}
|
|
if (box)
|
|
temp += QString::fromLatin1("`----");
|
|
|
|
if(clear)
|
|
v_iew->editor()->setText(temp);
|
|
else
|
|
v_iew->editor()->insertPlainText(temp);
|
|
}
|
|
|
|
|
|
// ask for a filename, handle network urls
|
|
void KNComposer::insertFile(bool clear, bool box)
|
|
{
|
|
KNLoadHelper helper(this);
|
|
QFile *file = helper.getFile(i18n("Insert File"));
|
|
KUrl url;
|
|
QString boxName;
|
|
|
|
if (file) {
|
|
url = helper.getURL();
|
|
|
|
if (url.isLocalFile())
|
|
boxName = url.toLocalFile();
|
|
else
|
|
boxName = url.prettyUrl();
|
|
|
|
insertFile(file,clear,box,boxName);
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------- <Actions> ------------------------------------
|
|
|
|
|
|
void KNComposer::addRecentAddress()
|
|
{
|
|
if ( m_ode == mail || m_ode == news_mail ) {
|
|
RecentAddresses::self( knGlobals.config() )->add( v_iew->emailRecipient() );
|
|
}
|
|
}
|
|
|
|
void KNComposer::slotSendNow()
|
|
{
|
|
r_esult=CRsendNow;
|
|
addRecentAddress();
|
|
emit composerDone(this);
|
|
}
|
|
|
|
|
|
void KNComposer::slotSendLater()
|
|
{
|
|
r_esult=CRsendLater;
|
|
addRecentAddress();
|
|
emit composerDone(this);
|
|
}
|
|
|
|
|
|
void KNComposer::slotSaveAsDraft()
|
|
{
|
|
r_esult=CRsave;
|
|
addRecentAddress();
|
|
emit composerDone(this);
|
|
}
|
|
|
|
|
|
void KNComposer::slotArtDelete()
|
|
{
|
|
r_esult=CRdelAsk;
|
|
emit composerDone(this);
|
|
}
|
|
|
|
|
|
void KNComposer::slotInsertFile()
|
|
{
|
|
insertFile(false,false);
|
|
}
|
|
|
|
|
|
void KNComposer::slotInsertFileBoxed()
|
|
{
|
|
insertFile(false,true);
|
|
}
|
|
|
|
void KNComposer::slotAttachFile()
|
|
{
|
|
KNLoadHelper *helper = new KNLoadHelper(this);
|
|
|
|
if (helper->getFile(i18n("Attach File"))) {
|
|
if ( !v_iew->isAttachmentViewVisible() ) {
|
|
KNHelper::saveWindowSize("composer", size());
|
|
v_iew->showAttachmentView();
|
|
}
|
|
v_iew->addAttachment( KNAttachment::Ptr( new KNAttachment( helper ) ) );
|
|
a_ttChanged=true;
|
|
} else {
|
|
delete helper;
|
|
}
|
|
}
|
|
|
|
|
|
void KNComposer::slotAttachmentRemoved( KNAttachment::Ptr attachment, bool last )
|
|
{
|
|
if( !attachment ) {
|
|
return;
|
|
}
|
|
|
|
if ( attachment->isAttached() ) {
|
|
mDeletedAttachments.append( attachment );
|
|
}
|
|
|
|
if ( last ) {
|
|
KNHelper::saveWindowSize( "composerAtt", size() );
|
|
v_iew->hideAttachmentView();
|
|
}
|
|
|
|
a_ttChanged = true;
|
|
}
|
|
|
|
void KNComposer::slotAttachmentChanged()
|
|
{
|
|
a_ttChanged = true;
|
|
}
|
|
|
|
|
|
|
|
void KNComposer::slotToggleDoPost()
|
|
{
|
|
if (a_ctDoPost->isChecked()) {
|
|
if (a_ctDoMail->isChecked())
|
|
m_ode=news_mail;
|
|
else
|
|
m_ode=news;
|
|
} else {
|
|
if (a_ctDoMail->isChecked())
|
|
m_ode=mail;
|
|
else { // invalid
|
|
a_ctDoPost->setChecked(true); //revert
|
|
return;
|
|
}
|
|
}
|
|
setMessageMode(m_ode);
|
|
}
|
|
|
|
|
|
void KNComposer::slotToggleDoMail()
|
|
{
|
|
if (a_ctDoMail->isChecked()) {
|
|
if (a_uthorDislikesMailCopies) {
|
|
if ( KMessageBox::warningContinueCancel( this, i18n("The poster does not want a mail copy of your reply (Mail-Copies-To: nobody);\nplease respect their request."),
|
|
QString(), KGuiItem(i18n("&Send Copy")) ) != KMessageBox::Continue ) {
|
|
a_ctDoMail->setChecked(false); //revert
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
//Laurent fix me
|
|
#if 0
|
|
if ( knGlobals.settings()->useExternalMailer() ) {
|
|
QString s = v_iew->editor()->textLine(0);
|
|
if (!s.contains(i18n("<posted & mailed>")))
|
|
v_iew->editor()->insertAt(i18n("<posted & mailed>\n\n"),0,0);
|
|
QString tmp;
|
|
QStringList textLines = v_iew->editor()->processedText();
|
|
for (QStringList::Iterator it = textLines.begin(); it != textLines.end(); ++it) {
|
|
if (*it == "-- ") // try to be smart, don't include the signature,
|
|
break; // kmail will append one, too.
|
|
tmp+=*it+'\n';
|
|
}
|
|
knGlobals.artFactory->sendMailExternal( v_iew->t_o->text(), v_iew->subject(), tmp );
|
|
a_ctDoMail->setChecked(false); //revert
|
|
return;
|
|
} else {
|
|
#endif
|
|
if (a_ctDoMail->isChecked()) {
|
|
if (a_ctDoPost->isChecked())
|
|
m_ode=news_mail;
|
|
else
|
|
m_ode=mail;
|
|
} else {
|
|
if (a_ctDoPost->isChecked())
|
|
m_ode=news;
|
|
else { // invalid
|
|
a_ctDoMail->setChecked(true); //revert
|
|
return;
|
|
}
|
|
}
|
|
setMessageMode(m_ode);
|
|
}
|
|
|
|
|
|
void KNComposer::slotSetCharset(const QString &s)
|
|
{
|
|
if(s.isEmpty())
|
|
return;
|
|
|
|
QString charset = KGlobal::charsets()->encodingForName( s );
|
|
setCharset( charset );
|
|
}
|
|
|
|
|
|
void KNComposer::slotSetCharsetKeyboard()
|
|
{
|
|
int newCS = KNHelper::selectDialog(this, i18n("Select Charset"), a_ctSetCharset->items(), a_ctSetCharset->currentItem());
|
|
if (newCS != -1) {
|
|
a_ctSetCharset->setCurrentItem(newCS);
|
|
QString charset = KGlobal::charsets()->encodingForName( a_ctSetCharset->items()[ newCS ] );
|
|
setCharset( charset );
|
|
}
|
|
}
|
|
|
|
|
|
void KNComposer::slotToggleWordWrap()
|
|
{
|
|
if ( a_ctWordWrap->isChecked() )
|
|
v_iew->editor()->enableWordWrap( knGlobals.settings()->maxLineLength() );
|
|
else
|
|
v_iew->editor()->disableWordWrap();
|
|
}
|
|
|
|
void KNComposer::slotAutoSpellCheckingToggled()
|
|
{
|
|
v_iew->editor()->setCheckSpellingEnabled( a_ctAutoSpellChecking->isChecked() );
|
|
}
|
|
|
|
|
|
void KNComposer::slotUndoRewrap()
|
|
{
|
|
if (KMessageBox::warningContinueCancel( this, i18n("This will replace all text you have written.")) == KMessageBox::Continue) {
|
|
v_iew->editor()->setText(u_nwraped);
|
|
v_iew->appendSignature();
|
|
}
|
|
}
|
|
|
|
void KNComposer::slotExternalEditor()
|
|
{
|
|
if(e_xternalEditor) // in progress...
|
|
return;
|
|
|
|
QString editorCommand = knGlobals.settings()->externalEditor();
|
|
|
|
if(editorCommand.isEmpty())
|
|
KMessageBox::sorry(this, i18n("No editor configured.\nPlease do this in the settings dialog."));
|
|
|
|
delete e_ditorTempfile;
|
|
e_ditorTempfile=new KTemporaryFile();
|
|
|
|
if(!e_ditorTempfile->open()) {
|
|
KNHelper::displayTempFileError(this);
|
|
delete e_ditorTempfile;
|
|
e_ditorTempfile=0;
|
|
return;
|
|
}
|
|
|
|
bool ok=true;
|
|
QTextCodec *codec=KGlobal::charsets()->codecForName( mCharset, ok );
|
|
|
|
QString tmp = v_iew->editor()->toWrappedPlainText();
|
|
|
|
QByteArray local = codec->fromUnicode(tmp);
|
|
e_ditorTempfile->write(local.data(),local.length());
|
|
e_ditorTempfile->flush();
|
|
|
|
if(!e_ditorTempfile->open()) {
|
|
KNHelper::displayTempFileError(this);
|
|
delete e_ditorTempfile;
|
|
e_ditorTempfile=0;
|
|
return;
|
|
}
|
|
|
|
e_xternalEditor=new KProcess();
|
|
|
|
// construct command line...
|
|
QStringList command = editorCommand.split(' ', QString::SkipEmptyParts);
|
|
bool filenameAdded=false;
|
|
for ( QStringList::Iterator it = command.begin(); it != command.end(); ++it ) {
|
|
if ((*it).contains("%f")) {
|
|
(*it).replace(QRegExp("%f"),e_ditorTempfile->fileName());
|
|
filenameAdded=true;
|
|
}
|
|
(*e_xternalEditor) << (*it);
|
|
}
|
|
if(!filenameAdded) // no %f in the editor command
|
|
(*e_xternalEditor) << e_ditorTempfile->fileName();
|
|
|
|
connect(e_xternalEditor, SIGNAL(finished(int,QProcess::ExitStatus)),this, SLOT(slotEditorFinished(int,QProcess::ExitStatus)));
|
|
e_xternalEditor->start();
|
|
if(!e_xternalEditor->waitForStarted()) {
|
|
KMessageBox::error(this, i18n("Unable to start external editor.\nPlease check your configuration in the settings dialog."));
|
|
delete e_xternalEditor;
|
|
e_xternalEditor=0;
|
|
delete e_ditorTempfile;
|
|
e_ditorTempfile=0;
|
|
return;
|
|
}
|
|
|
|
a_ctExternalEditor->setEnabled(false); // block other edit action while the editor is running...
|
|
a_ctSpellCheck->setEnabled(false);
|
|
v_iew->showExternalNotification();
|
|
}
|
|
|
|
void KNComposer::slotUpdateStatusBar()
|
|
{
|
|
QString typeDesc;
|
|
switch (m_ode) {
|
|
case news: typeDesc = i18n("News Article");
|
|
break;
|
|
case mail: typeDesc = i18n("Email");
|
|
break;
|
|
default : typeDesc = i18n("News Article & Email");
|
|
}
|
|
QString overwriteDesc;
|
|
if (v_iew->editor()->overwriteMode ())
|
|
overwriteDesc = i18n(" OVR ");
|
|
else
|
|
overwriteDesc = i18n(" INS ");
|
|
|
|
statusBar()->changeItem(i18n(" Type: %1 ", typeDesc), 1);
|
|
statusBar()->changeItem(i18n(" Charset: %1 ", mCharset ), 2);
|
|
statusBar()->changeItem(overwriteDesc, 3);
|
|
statusBar()->changeItem(i18n(" Column: %1 ", v_iew->editor()->columnNumber () + 1), 4);
|
|
statusBar()->changeItem(i18n(" Line: %1 ", v_iew->editor()->linePosition() + 1), 5);
|
|
}
|
|
|
|
|
|
void KNComposer::slotUpdateCursorPos()
|
|
{
|
|
statusBar()->changeItem(i18n(" Column: %1 ", v_iew->editor()->columnNumber () + 1), 4);
|
|
statusBar()->changeItem(i18n(" Line: %1 ", v_iew->editor()->linePosition() + 1), 5);
|
|
}
|
|
|
|
|
|
void KNComposer::slotConfKeys()
|
|
{
|
|
KShortcutsDialog::configure(actionCollection(), KShortcutsEditor::LetterShortcutsAllowed, this, true);
|
|
}
|
|
|
|
|
|
void KNComposer::slotConfToolbar()
|
|
{
|
|
saveMainWindowSettings(knGlobals.config()->group( "composerWindow_options") );
|
|
KEditToolBar dlg(guiFactory(),this);
|
|
connect(&dlg,SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig()));
|
|
dlg.exec();
|
|
}
|
|
|
|
void KNComposer::slotNewToolbarConfig()
|
|
{
|
|
createGUI("kncomposerui.rc");
|
|
|
|
applyMainWindowSettings(knGlobals.config()->group("composerWindow_options"));
|
|
}
|
|
|
|
//-------------------------------- </Actions> -----------------------------------
|
|
|
|
|
|
void KNComposer::slotSubjectChanged(const QString &t)
|
|
{
|
|
// replace newlines
|
|
QString subject = t;
|
|
subject.replace( '\n', ' ' );
|
|
subject.replace( '\r', ' ' );
|
|
if ( subject != t ) // setText() sets the cursor to the end
|
|
v_iew->setSubject( subject );
|
|
// update caption
|
|
if( !subject.isEmpty() )
|
|
setCaption( subject );
|
|
else
|
|
setCaption( i18n("No Subject") );
|
|
}
|
|
|
|
|
|
void KNComposer::slotToBtnClicked()
|
|
{
|
|
Akonadi::EmailAddressSelectionDialog dlg( this );
|
|
dlg.view()->view()->setSelectionMode( QAbstractItemView::MultiSelection );
|
|
|
|
if ( !dlg.exec() )
|
|
return;
|
|
|
|
QStringList addresses;
|
|
foreach ( const Akonadi::EmailAddressSelection &selection, dlg.selectedAddresses() )
|
|
addresses << selection.quotedEmail();
|
|
|
|
QString to = v_iew->emailRecipient();
|
|
if ( !to.isEmpty() )
|
|
to += ", ";
|
|
to += addresses.join( ", " );
|
|
|
|
v_iew->setEmailRecipient( to );
|
|
}
|
|
|
|
|
|
void KNComposer::slotGroupsBtnClicked()
|
|
{
|
|
int id=a_rticle->serverId();
|
|
KNNntpAccount::Ptr nntp;
|
|
|
|
if(id!=-1)
|
|
nntp=knGlobals.accountManager()->account(id);
|
|
|
|
if(!nntp)
|
|
nntp=knGlobals.accountManager()->first();
|
|
|
|
if(!nntp) {
|
|
KMessageBox::error(this, i18n("You have no valid news accounts configured."));
|
|
v_iew->setGroups( QString() );
|
|
return;
|
|
}
|
|
|
|
if(id==-1)
|
|
a_rticle->setServerId(nntp->id());
|
|
|
|
KNGroupSelectDialog *dlg = new KNGroupSelectDialog( this, nntp, v_iew->groups() );
|
|
|
|
connect( dlg, SIGNAL(loadList(KNNntpAccount::Ptr)),
|
|
knGlobals.groupManager(), SLOT(slotLoadGroupList(KNNntpAccount::Ptr)) );
|
|
connect( KNGlobals::self()->groupManager(), SIGNAL(newListReady(KNGroupListData::Ptr)),
|
|
dlg, SLOT(slotReceiveList(KNGroupListData::Ptr)) );
|
|
|
|
if(dlg->exec())
|
|
v_iew->setGroups( dlg->selectedGroups() );
|
|
|
|
delete dlg;
|
|
}
|
|
|
|
void KNComposer::slotEditorFinished(int, QProcess::ExitStatus exitStatus)
|
|
{
|
|
if(exitStatus == QProcess::NormalExit) {
|
|
e_ditorTempfile->flush();
|
|
e_ditorTempfile->seek(0);
|
|
insertFile(e_ditorTempfile, true);
|
|
e_xternalEdited=true;
|
|
}
|
|
|
|
slotCancelEditor(); // cleanup...
|
|
}
|
|
|
|
|
|
void KNComposer::slotCancelEditor()
|
|
{
|
|
if (e_xternalEditor)
|
|
e_xternalEditor->deleteLater(); // this also kills the editor process if it's still running
|
|
e_xternalEditor=0;
|
|
delete e_ditorTempfile;
|
|
e_ditorTempfile=0;
|
|
|
|
a_ctExternalEditor->setEnabled(true);
|
|
a_ctSpellCheck->setEnabled(true);
|
|
v_iew->hideExternalNotification();
|
|
}
|
|
|
|
|
|
void KNComposer::slotAttachmentPopup( const QPoint &point )
|
|
{
|
|
QMenu *menu = static_cast<QMenu*>( factory()->container( "attachment_popup", this ) );
|
|
if ( menu ) {
|
|
menu->popup( point );
|
|
}
|
|
}
|
|
|
|
void KNComposer::dragEnterEvent( QDragEnterEvent *event )
|
|
{
|
|
if ( KUrl::List::canDecode( event->mimeData() ) ) {
|
|
event->setDropAction( Qt::CopyAction );
|
|
event->accept();
|
|
}
|
|
}
|
|
|
|
void KNComposer::dropEvent( QDropEvent *event )
|
|
{
|
|
KUrl::List urls = KUrl::List::fromMimeData( event->mimeData() );
|
|
|
|
foreach ( const KUrl &url, urls ) {
|
|
KNLoadHelper *helper = new KNLoadHelper(this);
|
|
|
|
if (helper->setURL(url)) {
|
|
if ( !v_iew->isAttachmentViewVisible() ) {
|
|
KNHelper::saveWindowSize("composer", size());
|
|
v_iew->showAttachmentView();
|
|
}
|
|
v_iew->addAttachment( KNAttachment::Ptr( new KNAttachment( helper ) ) );
|
|
a_ttChanged=true;
|
|
} else {
|
|
delete helper;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//=====================================================================================
|
|
|
|
|
|
KNComposer::AttachmentPropertiesDlg::AttachmentPropertiesDlg( KNAttachment::Ptr a, QWidget *parent ) :
|
|
KDialog( parent ), a_ttachment(a),
|
|
n_onTextAsText(false)
|
|
{
|
|
//init GUI
|
|
setCaption( i18n("Attachment Properties") );
|
|
setButtons( Help | Ok | Cancel );
|
|
QWidget *page=new QWidget(this);
|
|
setMainWidget(page);
|
|
QVBoxLayout *topL=new QVBoxLayout(page);
|
|
|
|
//file info
|
|
QGroupBox *fileGB = new QGroupBox( i18n("File"), page );
|
|
QGridLayout *fileL=new QGridLayout(fileGB);
|
|
fileL->setSpacing(5);
|
|
fileL->setMargin(15);
|
|
|
|
fileL->addItem( new QSpacerItem( 0, fontMetrics().lineSpacing()-9), 0, 0 );
|
|
fileL->addWidget(new QLabel(i18n("Name:"), fileGB) ,1,0);
|
|
fileL->addWidget(new QLabel(QString("<b>%1</b>").arg(a->name()), fileGB), 1,1, Qt::AlignLeft);
|
|
fileL->addWidget(new QLabel(i18n("Size:"), fileGB), 2,0);
|
|
fileL->addWidget(new QLabel(a->contentSize(), fileGB), 2,1, Qt::AlignLeft);
|
|
|
|
fileL->setColumnStretch(1,1);
|
|
topL->addWidget(fileGB);
|
|
|
|
//mime info
|
|
QGroupBox *mimeGB = new QGroupBox( i18n("Mime"), page );
|
|
QGridLayout *mimeL=new QGridLayout(mimeGB);
|
|
mimeL->setSpacing(5);
|
|
mimeL->setMargin(15);
|
|
|
|
mimeL->addItem( new QSpacerItem( 0, fontMetrics().lineSpacing()-9), 0, 0 );
|
|
m_imeType=new KLineEdit(mimeGB);
|
|
m_imeType->setText(a->mimeType());
|
|
mimeL->addWidget(m_imeType, 1,1);
|
|
QLabel *label = new QLabel(i18n("&Mime-Type:"), mimeGB);
|
|
label->setBuddy(m_imeType);
|
|
mimeL->addWidget(label, 1,0);
|
|
|
|
d_escription=new KLineEdit(mimeGB);
|
|
d_escription->setText(a->description());
|
|
mimeL->addWidget(d_escription, 2,1);
|
|
label=new QLabel(i18n("&Description:"), mimeGB);
|
|
label->setBuddy(d_escription);
|
|
mimeL->addWidget(label, 2,0);
|
|
|
|
e_ncoding=new QComboBox(mimeGB);
|
|
e_ncoding->setEditable(false);
|
|
e_ncoding->addItem("7Bit");
|
|
e_ncoding->addItem("8Bit");
|
|
e_ncoding->addItem("quoted-printable");
|
|
e_ncoding->addItem("base64");
|
|
if(a->isFixedBase64()) {
|
|
e_ncoding->setCurrentIndex(3);
|
|
e_ncoding->setEnabled(false);
|
|
}
|
|
else
|
|
e_ncoding->setCurrentIndex(a->cte());
|
|
mimeL->addWidget(e_ncoding, 3,1);
|
|
label=new QLabel(i18n("&Encoding:"), mimeGB);
|
|
label->setBuddy(e_ncoding);
|
|
mimeL->addWidget(label, 3,0);
|
|
|
|
mimeL->setColumnStretch(1,1);
|
|
topL->addWidget(mimeGB);
|
|
|
|
//connections
|
|
connect(m_imeType, SIGNAL(textChanged(QString)),
|
|
this, SLOT(slotMimeTypeTextChanged(QString)));
|
|
|
|
//finish GUI
|
|
setFixedHeight(sizeHint().height());
|
|
KNHelper::restoreWindowSize("attProperties", this, QSize(300,250));
|
|
setHelp("anc-knode-editor-advanced");
|
|
}
|
|
|
|
|
|
KNComposer::AttachmentPropertiesDlg::~AttachmentPropertiesDlg()
|
|
{
|
|
KNHelper::saveWindowSize("attProperties", this->size());
|
|
}
|
|
|
|
|
|
void KNComposer::AttachmentPropertiesDlg::apply()
|
|
{
|
|
a_ttachment->setDescription(d_escription->text());
|
|
a_ttachment->setMimeType(m_imeType->text());
|
|
a_ttachment->setCte(e_ncoding->currentIndex());
|
|
}
|
|
|
|
|
|
void KNComposer::AttachmentPropertiesDlg::accept()
|
|
{
|
|
if ( m_imeType->text().indexOf('/') == -1 ) {
|
|
KMessageBox::sorry(this, i18n("You have set an invalid mime-type.\nPlease change it."));
|
|
return;
|
|
}
|
|
else if ( n_onTextAsText && m_imeType->text().indexOf( "text/", 0, Qt::CaseInsensitive ) != -1 &&
|
|
KMessageBox::warningContinueCancel(this,
|
|
i18n("You have changed the mime-type of this non-textual attachment\nto text. This might cause an error while loading or encoding the file.\nProceed?")
|
|
) == KMessageBox::Cancel) return;
|
|
|
|
// update the attachment
|
|
apply();
|
|
|
|
KDialog::accept();
|
|
}
|
|
|
|
|
|
void KNComposer::AttachmentPropertiesDlg::slotMimeTypeTextChanged(const QString &text)
|
|
{
|
|
enableButtonOk( !text.isEmpty() );
|
|
if(text.left(5)!="text/") {
|
|
n_onTextAsText=a_ttachment->isFixedBase64();
|
|
e_ncoding->setCurrentIndex(3);
|
|
e_ncoding->setEnabled(false);
|
|
}
|
|
else {
|
|
e_ncoding->setCurrentIndex(a_ttachment->cte());
|
|
e_ncoding->setEnabled(true);
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------
|
|
|
|
|
|
// kate: space-indent on; indent-width 2;
|