2 KNode, the KDE newsreader
3 Copyright (c) 1999-2006 the KNode authors.
4 See file AUTHORS for details
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 You should have received a copy of the GNU General Public License
11 along with this program; if not, write to the Free Software Foundation,
12 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
15 #include "kncomposer.h"
17 #include <KPIMUtils/Email>
18 #include <KPIMIdentities/Identity>
19 #include <KPIMIdentities/IdentityManager>
20 #include <QVBoxLayout>
22 #include <QtDBus/QtDBus>
23 #include <qgroupbox.h>
24 #include "libkdepim/recentaddresses.h"
25 using KPIM::RecentAddresses
;
26 #include <akonadi/contact/emailaddressselectiondialog.h>
27 #include <kcharsets.h>
28 #include <kmessagebox.h>
29 #include <kactioncollection.h>
30 #include <kstandardaction.h>
31 #include <kshortcutsdialog.h>
32 #include <kedittoolbar.h>
35 #include <kcombobox.h>
36 #include <ktemporaryfile.h>
37 #include <libkpgp/kpgpblock.h>
38 #include <kcompletionbox.h>
39 #include <kxmlguifactory.h>
40 #include <kstatusbar.h>
42 #include <kselectaction.h>
43 #include <ktoggleaction.h>
44 #include "kngroupselectdialog.h"
45 #include "utilities.h"
46 #include "knglobals.h"
47 #include "knmainwidget.h"
48 #include "knaccountmanager.h"
49 #include "knnntpaccount.h"
51 #include "kncomposerview.h"
52 #include "utils/locale.h"
54 using namespace KNode::Utilities
;
55 using namespace KNode::Composer
;
58 KNLineEdit::KNLineEdit( View
*parent
, bool useCompletion
)
59 : KABC::AddressLineEdit( parent
, useCompletion
),
60 composerView( parent
)
64 KNLineEdit::KNLineEdit( QWidget
*parent
, bool useCompletion
)
65 : KABC::AddressLineEdit( parent
, useCompletion
)
70 void KNLineEdit::contextMenuEvent( QContextMenuEvent
*e
)
72 QMenu
*popup
= KLineEdit::createStandardContextMenu();
73 popup
->addSeparator();
74 popup
->addAction( i18n( "Edit Recent Addresses..." ),
75 this, SLOT(editRecentAddresses()) );
76 popup
->exec( e
->globalPos() );
80 void KNLineEdit::editRecentAddresses()
82 KPIM::RecentAddressDialog
dlg( this );
83 dlg
.setAddresses( RecentAddresses::self( knGlobals
.config() )->addresses() );
85 RecentAddresses::self( knGlobals
.config() )->clear();
86 QStringList addrList
= dlg
.addresses();
87 QStringList::Iterator it
;
88 for ( it
= addrList
.begin(); it
!= addrList
.end(); ++it
)
89 RecentAddresses::self( knGlobals
.config() )->add( *it
);
95 void KNLineEdit::loadAddresses()
97 KABC::AddressLineEdit::loadAddresses();
99 QStringList recent
= RecentAddresses::self(knGlobals
.config())->addresses();
100 QStringList::Iterator it
= recent
.begin();
101 for ( ; it
!= recent
.end(); ++it
)
105 void KNLineEdit::keyPressEvent(QKeyEvent
*e
)
107 // ---sven's Return is same Tab and arrow key navigation start ---
108 if ((e
->key() == Qt::Key_Enter
|| e
->key() == Qt::Key_Return
) &&
109 !completionBox()->isVisible())
111 composerView
->focusNextPrevEdit( this, true );
114 if (e
->key() == Qt::Key_Up
)
116 composerView
->focusNextPrevEdit( this, false ); // Go up
119 if (e
->key() == Qt::Key_Down
)
121 composerView
->focusNextPrevEdit( this, true ); // Go down
124 // ---sven's Return is same Tab and arrow key navigation end ---
125 KABC::AddressLineEdit::keyPressEvent(e
);
129 KNLineEditSpell::KNLineEditSpell( View
*parent
, bool useCompletion
)
130 : KNLineEdit( parent
, useCompletion
)
134 KNLineEditSpell::KNLineEditSpell( QWidget
*parent
, bool useCompletion
)
135 : KNLineEdit( parent
, useCompletion
)
139 void KNLineEditSpell::highLightWord( unsigned int length
, unsigned int pos
)
141 setSelection ( pos
, length
);
144 void KNLineEditSpell::spellCheckDone( const QString
&s
)
150 void KNLineEditSpell::spellCheckerMisspelling( const QString
&_text
, const QStringList
&, unsigned int pos
)
152 highLightWord( _text
.length(),pos
);
155 void KNLineEditSpell::spellCheckerCorrected( const QString
&old
, const QString
&corr
, unsigned int pos
)
159 setSelection ( pos
, old
.length() );
161 setSelection ( pos
, corr
.length() );
166 KNComposer::KNComposer( KNLocalArticle::Ptr a
, const QString
&text
, const QString
&unwraped
, bool firstEdit
, bool dislikesCopies
, bool createCopy
, bool allowMail
)
167 : KXmlGuiWindow(0), r_esult(CRsave
), a_rticle(a
),
169 n_eeds8Bit(true), v_alidated(false), a_uthorDislikesMailCopies(dislikesCopies
), e_xternalEdited(false), e_xternalEditor(0),
170 e_ditorTempfile(0), a_ttChanged(false),
171 mFirstEdit( firstEdit
)
173 setObjectName( "composerWindow" );
175 if( knGlobals
.componentData().isValid() )
176 setComponentData( knGlobals
.componentData() );
178 // activate dnd of attachments...
179 setAcceptDrops(true);
182 v_iew
= new View( this );
183 setCentralWidget(v_iew
);
185 connect( v_iew
, SIGNAL(closeExternalEditor()), this, SLOT(slotCancelEditor()) );
188 KStatusBar
*sb
=statusBar();
189 sb
->insertItem( QString(), 1, 1 ); // type
190 sb
->setItemAlignment( 1, Qt::AlignLeft
| Qt::AlignVCenter
);
191 sb
->insertItem( QString(), 2, 1 ); // charset
192 sb
->setItemAlignment( 2, Qt::AlignLeft
| Qt::AlignVCenter
);
193 sb
->insertItem( QString(), 3, 1 ); // write mode
194 sb
->setItemAlignment(3, Qt::AlignCenter
| Qt::AlignVCenter
);
195 sb
->insertItem( QString(), 4, 1 ); // column
196 sb
->setItemAlignment(4, Qt::AlignCenter
| Qt::AlignVCenter
);
197 sb
->insertItem( QString(), 5, 1 ); // line
198 sb
->setItemAlignment( 5, Qt::AlignCenter
| Qt::AlignVCenter
);
199 connect(v_iew
->editor(), SIGNAL(cursorPositionChanged()), SLOT(slotUpdateCursorPos()));
200 connect(v_iew
->editor(), SIGNAL(insertModeChanged()), SLOT(slotUpdateStatusBar()));
202 QDBusConnection::sessionBus().registerObject( "/Composer", this, QDBusConnection::ExportScriptableSlots
);
203 //------------------------------- <Actions> --------------------------------------
206 KAction
*action
= actionCollection()->addAction("send_now");
207 action
->setIcon(KIcon("mail-send"));
208 action
->setText(i18n("&Send Now"));
209 connect(action
, SIGNAL(triggered(bool)), SLOT(slotSendNow()));
210 action
->setShortcut(QKeySequence(Qt::CTRL
+ Qt::Key_Return
));
212 action
= actionCollection()->addAction("send_later");
213 action
->setIcon(KIcon("mail-queue"));
214 action
->setText(i18n("Send &Later"));
215 connect(action
, SIGNAL(triggered(bool)), SLOT(slotSendLater()));
217 action
= actionCollection()->addAction("save_as_draft");
218 action
->setIcon(KIcon("document-save"));
219 action
->setText(i18n("Save as &Draft"));
220 connect(action
, SIGNAL(triggered(bool)), SLOT(slotSaveAsDraft()));
222 action
= actionCollection()->addAction("art_delete");
223 action
->setIcon(KIcon("edit-delete"));
224 action
->setText(i18n("D&elete"));
225 connect(action
, SIGNAL(triggered(bool)), SLOT(slotArtDelete()));
227 KStandardAction::close(this, SLOT(close()),actionCollection());
230 KStandardAction::undo(this, SLOT(slotUndo()), actionCollection());
231 KStandardAction::redo(this, SLOT(slotRedo()), actionCollection());
233 KStandardAction::cut(this, SLOT(slotCut()), actionCollection());
236 KStandardAction::copy(this, SLOT(slotCopy()), actionCollection());
238 KStandardAction::pasteText(this, SLOT(slotPaste()), actionCollection());
240 action
= actionCollection()->addAction("paste_quoted");
241 action
->setText(i18n("Paste as &Quotation"));
242 connect(action
, SIGNAL(triggered(bool)), v_iew
->editor(), SLOT(slotPasteAsQuotation()));
244 KStandardAction::selectAll(this, SLOT(slotSelectAll()), actionCollection());
246 KStandardAction::find(v_iew
->editor(), SLOT(slotFind()), actionCollection());
247 KStandardAction::findNext(v_iew
->editor(), SLOT(slotFindNext()), actionCollection());
249 KStandardAction::replace(v_iew
->editor(), SLOT(slotReplace()), actionCollection());
252 action
= actionCollection()->addAction("append_signature");
253 action
->setText(i18n("Append &Signature"));
254 connect( action
, SIGNAL(triggered(bool)), v_iew
, SLOT(appendSignature()) );
256 action
= actionCollection()->addAction("insert_file");
257 action
->setText(i18n("&Insert File..."));
258 connect(action
, SIGNAL(triggered(bool)), SLOT(slotInsertFile()));
260 action
= actionCollection()->addAction("insert_file_boxed");
261 action
->setText(i18n("Insert File (in a &box)..."));
262 connect(action
, SIGNAL(triggered(bool)), SLOT(slotInsertFileBoxed()));
264 action
= actionCollection()->addAction("attach_file");
265 action
->setIcon(KIcon("mail-attachment"));
266 action
->setText(i18n("Attach &File..."));
267 connect(action
, SIGNAL(triggered(bool)), SLOT(slotAttachFile()));
269 a_ctPGPsign
= actionCollection()->add
<KToggleAction
>("sign_article");
270 a_ctPGPsign
->setText(i18n("Sign Article with &PGP"));
271 a_ctPGPsign
->setIcon(KIcon("document-sign"));
273 a_ctRemoveAttachment
= actionCollection()->addAction("remove_attachment");
274 a_ctRemoveAttachment
->setText(i18n("&Remove"));
275 connect( a_ctRemoveAttachment
, SIGNAL(triggered(bool)), v_iew
, SLOT(removeCurrentAttachment()) );
277 a_ctAttachmentProperties
= actionCollection()->addAction("attachment_properties");
278 a_ctAttachmentProperties
->setText(i18n("&Properties"));
279 connect( a_ctAttachmentProperties
, SIGNAL(triggered(bool)), v_iew
, SLOT(editCurrentAttachment()) );
283 a_ctDoPost
= actionCollection()->add
<KToggleAction
>("send_news");
284 a_ctDoPost
->setIcon(KIcon("document-new"));
285 a_ctDoPost
->setText(i18n("Send &News Article"));
286 connect(a_ctDoPost
, SIGNAL(triggered(bool)), SLOT(slotToggleDoPost()));
288 a_ctDoMail
= actionCollection()->add
<KToggleAction
>("send_mail");
289 a_ctDoMail
->setIcon(KIcon("mail-send"));
290 a_ctDoMail
->setText(i18n("Send E&mail"));
291 a_ctDoMail
->setEnabled(allowMail
);
292 connect(a_ctDoMail
, SIGNAL(triggered(bool)), SLOT(slotToggleDoMail()));
294 a_ctSetCharset
= actionCollection()->add
<KSelectAction
>("set_charset");
295 a_ctSetCharset
->setText(i18n("Set &Charset"));
296 a_ctSetCharset
->setItems( Locale::encodings() );
297 a_ctSetCharset
->setShortcutConfigurable(false);
298 connect(a_ctSetCharset
, SIGNAL(triggered(QString
)),
299 this, SLOT(slotSetCharset(QString
)));
301 a_ctSetCharsetKeyb
= actionCollection()->addAction("set_charset_keyboard");
302 a_ctSetCharsetKeyb
->setText(i18n("Set Charset"));
303 connect(a_ctSetCharsetKeyb
, SIGNAL(triggered(bool)), SLOT(slotSetCharsetKeyboard()));
304 addAction( a_ctSetCharsetKeyb
);
307 a_ctWordWrap
= actionCollection()->add
<KToggleAction
>("toggle_wordwrap");
308 a_ctWordWrap
->setText(i18n("&Word Wrap"));
309 connect(a_ctWordWrap
, SIGNAL(triggered(bool)), SLOT(slotToggleWordWrap()));
311 a_ctAutoSpellChecking
= new KToggleAction( KIcon( "tools-check-spelling" ), i18n("&Automatic Spellchecking"), this );
312 actionCollection()->addAction( "options_auto_spellchecking", a_ctAutoSpellChecking
);
313 a_ctAutoSpellChecking
->setChecked( knGlobals
.settings()->autoSpellChecking() );
314 slotUpdateCheckSpellChecking( knGlobals
.settings()->autoSpellChecking() );
315 slotAutoSpellCheckingToggled();
316 connect(a_ctAutoSpellChecking
, SIGNAL(triggered(bool)), SLOT(slotAutoSpellCheckingToggled()));
317 connect( v_iew
->editor(), SIGNAL(checkSpellingChanged(bool)), this, SLOT(slotUpdateCheckSpellChecking(bool)));
322 action
= actionCollection()->addAction("tools_quote");
323 action
->setText(i18n("Add &Quote Characters"));
324 connect(action
, SIGNAL(triggered(bool)), v_iew
->editor(), SLOT(slotAddQuotes()));
326 action
= actionCollection()->addAction("tools_unquote");
327 action
->setText(i18n("&Remove Quote Characters"));
328 connect(action
, SIGNAL(triggered(bool)), v_iew
->editor(), SLOT(slotRemoveQuotes()));
330 action
= actionCollection()->addAction("tools_box");
331 action
->setText(i18n("Add &Box"));
332 connect(action
, SIGNAL(triggered(bool)), v_iew
->editor(), SLOT(slotAddBox()));
334 action
= actionCollection()->addAction("tools_unbox");
335 action
->setText(i18n("Re&move Box"));
336 connect(action
, SIGNAL(triggered(bool)), v_iew
->editor(), SLOT(slotRemoveBox()));
338 QAction
*undoRewrap
= actionCollection()->addAction("tools_undoRewrap");
339 undoRewrap
->setText(i18n("Get &Original Text (not re-wrapped)"));
340 connect(undoRewrap
, SIGNAL(triggered(bool)), SLOT(slotUndoRewrap()));
341 undoRewrap
->setEnabled(!u_nwraped
.isNull());
343 QAction
*rot13
= actionCollection()->addAction("tools_rot13");
344 rot13
->setIcon(KIcon("document-encrypt"));
345 rot13
->setText(i18n("S&cramble (Rot 13)"));
346 connect(rot13
, SIGNAL(triggered(bool)), v_iew
->editor(), SLOT(slotRot13()));
347 rot13
->setEnabled(false);
348 connect(v_iew
->editor(), SIGNAL(copyAvailable(bool)), rot13
, SLOT(setEnabled(bool)));
350 a_ctExternalEditor
= actionCollection()->addAction("external_editor");
351 a_ctExternalEditor
->setIcon(KIcon("system-run"));
352 a_ctExternalEditor
->setText(i18n("Start &External Editor"));
353 connect(a_ctExternalEditor
, SIGNAL(triggered(bool)), SLOT(slotExternalEditor()));
355 a_ctSpellCheck
= KStandardAction::spelling ( v_iew
->editor(), SLOT(checkSpelling()), actionCollection());
358 createStandardStatusBarAction();
359 setStandardToolBarMenuEnabled(true);
361 KStandardAction::keyBindings(this, SLOT(slotConfKeys()), actionCollection());
363 KStandardAction::configureToolbars(this, SLOT(slotConfToolbar()), actionCollection());
365 KStandardAction::preferences(knGlobals
.top
, SLOT(slotSettings()), actionCollection());
368 createGUI("kncomposerui.rc");
370 //---------------------------------- </Actions> ----------------------------------------
375 //apply configuration
378 if (createCopy
&& (m_ode
==news
)) {
379 a_ctDoMail
->setChecked(true);
383 v_iew
->completeSetup( firstEdit
, m_ode
);
385 // restore window & toolbar configuration
386 resize(535,450); // default optimized for 800x600
387 applyMainWindowSettings(knGlobals
.config()->group("composerWindow_options"));
389 // starting the external editor
390 if ( knGlobals
.settings()->useExternalEditor() )
391 slotExternalEditor();
395 KNComposer::~KNComposer()
397 // prevent slotEditorFinished from being called
399 e_xternalEditor
->disconnect();
400 delete e_xternalEditor
; // this also kills the editor process if it's still running
402 delete e_ditorTempfile
;
404 saveMainWindowSettings(knGlobals
.config()->group("composerWindow_options"));
406 KNGlobals::self()->settings()->setAutoSpellChecking( a_ctAutoSpellChecking
->isChecked() );
407 KNGlobals::self()->settings()->writeConfig();
410 void KNComposer::slotUpdateCheckSpellChecking(bool _b
)
412 a_ctAutoSpellChecking
->setChecked(_b
);
416 void KNComposer::slotUndo()
418 QWidget
* fw
= focusWidget();
421 if (fw
->inherits("KTextEdit"))
422 ((KTextEdit
*)fw
)->undo();
423 else if (fw
->inherits("QLineEdit"))
424 ((QLineEdit
*)fw
)->undo();
427 void KNComposer::slotRedo()
429 QWidget
* fw
= focusWidget();
432 if (fw
->inherits("KTextEdit"))
433 ((KTextEdit
*)fw
)->redo();
434 else if (fw
->inherits("QLineEdit"))
435 ((QLineEdit
*)fw
)->redo();
438 void KNComposer::slotCut()
440 QWidget
* fw
= focusWidget();
443 if (fw
->inherits("KTextEdit"))
444 ((KTextEdit
*)fw
)->cut();
445 else if (fw
->inherits("QLineEdit"))
446 ((QLineEdit
*)fw
)->cut();
447 else kDebug(5003) <<"wrong focus widget";
450 void KNComposer::slotCopy()
452 QWidget
* fw
= focusWidget();
455 if (fw
->inherits("KTextEdit"))
456 ((KTextEdit
*)fw
)->copy();
457 else if (fw
->inherits("QLineEdit"))
458 ((QLineEdit
*)fw
)->copy();
459 else kDebug(5003) <<"wrong focus widget";
464 void KNComposer::slotPaste()
466 QWidget
* fw
= focusWidget();
469 if (fw
->inherits("KTextEdit"))
470 ((KTextEdit
*)fw
)->paste();
471 else if (fw
->inherits("QLineEdit"))
472 ((QLineEdit
*)fw
)->paste();
473 else kDebug(5003) <<"wrong focus widget";
476 void KNComposer::slotSelectAll()
478 QWidget
* fw
= focusWidget();
481 if (fw
->inherits("QLineEdit"))
482 ((QLineEdit
*)fw
)->selectAll();
483 else if (fw
->inherits("KTextEdit"))
484 ((KTextEdit
*)fw
)->selectAll();
488 void KNComposer::setConfig(bool onlyFonts
)
491 a_ctWordWrap
->setChecked( knGlobals
.settings()->wordWrap() );
492 slotToggleWordWrap();
494 a_ctAutoSpellChecking
->setChecked( knGlobals
.settings()->autoSpellChecking() );
495 Kpgp::Module
*pgp
= Kpgp::Module::getKpgp();
496 a_ctPGPsign
->setEnabled(pgp
->usePGP());
499 v_iew
->setComposingFont( knGlobals
.settings()->composerFont() );
501 slotUpdateStatusBar();
505 void KNComposer::setMessageMode(MessageMode mode
)
508 a_ctDoPost
->setChecked(m_ode
!=mail
);
509 a_ctDoMail
->setChecked(m_ode
!=news
);
510 v_iew
->setMessageMode(m_ode
);
513 QString s
= v_iew
->editor()->document ()->begin()->text ();
514 if (m_ode
== news_mail
) {
515 if (!s
.contains(i18n("<posted & mailed>"))) {
516 QTextCursor
cursor(v_iew
->editor()->document ()->begin());
517 cursor
.setPosition(0);
518 cursor
.insertText(i18n("<posted & mailed>\n\n"));
519 v_iew
->editor()->setTextCursor(cursor
);
522 if (s
== i18n("<posted & mailed>")) {
523 v_iew
->editor()->removeLine(0);
524 if (v_iew
->editor()->textLine(0).isEmpty())
525 v_iew
->editor()->removeLine(0);
529 slotUpdateStatusBar();
533 bool KNComposer::hasValidData()
539 if ( KPIMUtils::isValidAddress( v_iew
->from() ) != KPIMUtils::AddressOk
) {
540 KMessageBox::sorry( this, i18n( "Your email address does not appears to be valid. Please modify it." ) );
544 if ( v_iew
->subject().isEmpty() ) {
545 KMessageBox::sorry(this, i18n("Please enter a subject."));
548 if ( !n_eeds8Bit
&& !KMime::isUsAscii( v_iew
->subject() ) ) {
553 int groupCount
= v_iew
->groups().count();
554 if ( groupCount
== 0 ) {
555 KMessageBox::sorry(this, i18n("Please enter a newsgroup."));
560 KMessageBox::sorry(this, i18n("You are crossposting to more than 12 newsgroups.\nPlease remove all newsgroups in which your article is off-topic."));
565 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?"),
566 QString(), KGuiItem(i18n("&Send")), KGuiItem(i18nc("edit article","&Edit")) ) != KMessageBox::Yes
)
569 int fupCount
= v_iew
->followupTo().count();
570 if ( fupCount
== 0 && groupCount
> 2 ) {
571 if ( KMessageBox::warningYesNo( this,
572 i18n("You are crossposting to more than two newsgroups.\n"
573 "Please use the \"Followup-To\" header to direct the replies "
574 "to your article into one group.\n"
575 "Do you want to re-edit the article or send it anyway?"),
576 QString(), KGuiItem(i18n("&Send")), KGuiItem(i18nc("edit article","&Edit")), "missingFollowUpTo" )
577 != KMessageBox::Yes
)
582 KMessageBox::sorry(this, i18n("You are directing replies to more than 12 newsgroups.\nPlease remove some newsgroups from the \"Followup-To\" header."));
587 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?"),
588 QString(), KGuiItem(i18n("&Send")),KGuiItem(i18nc("edit article","&Edit")) ) != KMessageBox::Yes
)
593 if ( v_iew
->emailRecipient().isEmpty() ) {
594 KMessageBox::sorry(this, i18n("Please enter the email address."));
597 if ( !n_eeds8Bit
&& !KMime::isUsAscii( v_iew
->emailRecipient() ) ) {
603 bool firstLine
= true;
605 bool longLine
= false;
606 bool hasAttributionLine
= false;
610 QStringList text
= v_iew
->editor()->toWrappedPlainText().split('\n');
612 for (QStringList::Iterator it
= text
.begin(); it
!= text
.end(); ++it
) {
614 if (!n_eeds8Bit
&& !KMime::isUsAscii(*it
))
617 if (*it
== "-- ") { // signature text
618 for (++it
; it
!= text
.end(); ++it
) {
620 if (!n_eeds8Bit
&& !KMime::isUsAscii(*it
))
624 if((*it
).length()>80) {
631 if(!(*it
).isEmpty()) {
636 if (firstLine
) hasAttributionLine
= true;
639 if((*it
).length()>80) {
646 if (n_eeds8Bit
&& ( mCharset
.toLower()=="us-ascii" )) {
647 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."));
652 KMessageBox::sorry(this, i18n("You cannot post an empty message."));
656 if ((textLines
>1)&&(notQuoted
==1)) {
657 if (hasAttributionLine
)
658 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?"),
659 QString(), KGuiItem(i18n("&Send")), KGuiItem(i18nc("edit article","&Edit")) ) != KMessageBox::Yes
)
663 KMessageBox::sorry(this, i18n("You cannot post an article consisting\n"
664 "entirely of quoted text."));
670 if ( KMessageBox::warningYesNo( this,
671 i18n("Your article contains lines longer than 80 characters.\n"
672 "Do you want to re-edit the article or send it anyway?"),
673 QString(), KGuiItem(i18n("&Send")),
674 KGuiItem(i18nc("edit article","&Edit")) ) != KMessageBox::Yes
)
678 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?"),
679 QString(), KGuiItem(i18n("&Send")), KGuiItem(i18nc("edit article","&Edit")) ) != KMessageBox::Yes
)
683 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."),
684 QString(), "longSignatureWarning" );
686 // check if article can be signed
687 if ( a_ctPGPsign
->isChecked() ) {
688 // try to get the signing key
689 QByteArray signingKey
= KNGlobals::self()->settings()->identity().pgpSigningKey();
690 KNNntpAccount::Ptr acc
= knGlobals
.accountManager()->account( a_rticle
->serverId() );
692 KMime::Headers::Newsgroups
*grps
= a_rticle
->newsgroups();
693 if ( !grps
->isEmpty() ) {
694 KNGroup::Ptr grp
= knGlobals
.groupManager()->group( grps
->groups().first(), acc
);
695 if ( grp
&& !grp
->identity().isNull() ) {
696 signingKey
= grp
->identity().pgpSigningKey();
697 } else if ( !acc
->identity().isNull() ) {
698 signingKey
= acc
->identity().pgpSigningKey();
703 // the article can only be signed if we have a key
704 if (signingKey
.isEmpty()) {
705 if ( KMessageBox::warningContinueCancel( this,
706 i18n("You have not configured your preferred "
708 "please specify it in the global "
709 "identity configuration,\n"
710 "in the account properties or in the "
711 "group properties.\n"
712 "The article will be sent unsigned." ),
713 QString(), KGuiItem(i18n( "Send Unsigned" )),
714 KStandardGuiItem::cancel(), "sendUnsignedDialog" )
715 == KMessageBox::Cancel
)
725 bool KNComposer::applyChanges()
727 KMime::Content
*text
=0;
728 bool result
= true; // no error occurs ?
731 // Identity (for later edition)
732 const KPIMIdentities::Identity identity
= KNGlobals::self()->identityManager()->identityForUoid( v_iew
->selectedIdentity() );
733 if ( !identity
.isNull() ) {
734 KMime::Headers::Generic
*xKnodeIdentity
= new KMime::Headers::Generic( "X-KNode-Identity",
736 QByteArray::number( identity
.uoid() ) );
737 a_rticle
->setHeader( xKnodeIdentity
);
741 if ( KPIMUtils::isValidAddress( v_iew
->from() ) != KPIMUtils::AddressOk
) {
744 // FIXME: if v_iew->from() is not valid, the following call is a
745 // no-op: the content of the from keeps its previous value! (thanks KMime)
746 a_rticle
->from()->fromUnicodeString( v_iew
->from(), mCharset
.toLatin1() );
749 if ( KPIMUtils::isValidAddress( identity
.replyToAddr() ) == KPIMUtils::AddressOk
) {
750 a_rticle
->replyTo()->fromUnicodeString( identity
.replyToAddr(), mCharset
.toLatin1() );
752 a_rticle
->removeHeader( "Reply-To" );
756 if ( !identity
.property( "Mail-Copies-To" ).toString().trimmed().isEmpty() ) {
757 a_rticle
->mailCopiesTo()->fromUnicodeString( identity
.property( "Mail-Copies-To" ).toString(), mCharset
.toLatin1() );
759 a_rticle
->removeHeader( "Mail-Copies-To" );
763 if ( !identity
.organization().trimmed().isEmpty() ) {
764 a_rticle
->organization()->fromUnicodeString( identity
.organization(), mCharset
.toLatin1() );
766 a_rticle
->removeHeader( "Organization" );
770 a_rticle
->date()->setDateTime( KDateTime::currentLocalDateTime() ); //set current date+time
773 a_rticle
->subject()->fromUnicodeString( v_iew
->subject(), mCharset
.toLatin1() );
777 a_rticle
->newsgroups()->fromUnicodeString( v_iew
->groups().join( QString( ',' ) ), KMime::Headers::Latin1
);
778 a_rticle
->setDoPost(true);
780 a_rticle
->setDoPost(false);
781 a_rticle
->removeHeader( "Newsgroups" );
786 a_rticle
->to()->fromUnicodeString( v_iew
->emailRecipient(), mCharset
.toLatin1() );
787 a_rticle
->setDoMail(true);
789 a_rticle
->setDoMail(false);
790 a_rticle
->removeHeader( "To" );
791 a_rticle
->removeHeader( "Cc" );
795 if ( a_rticle
->doPost() && !v_iew
->followupTo().isEmpty() ) {
796 a_rticle
->followUpTo()->fromUnicodeString( v_iew
->followupTo().join( QString( ',' ) ), KMime::Headers::Latin1
);
798 a_rticle
->removeHeader("Followup-To");
804 const QList
<KNAttachment::Ptr
> l
= v_iew
->attachments();
805 foreach ( const KNAttachment::Ptr a
, l
) {
806 if(a
->hasChanged()) {
808 a
->updateContentInfo();
810 a
->attach( a_rticle
.get() );
815 for ( QList
<KNAttachment::Ptr
>::Iterator it
= mDeletedAttachments
.begin(); it
!= mDeletedAttachments
.end(); ++it
)
816 if ( (*it
)->isAttached() )
817 (*it
)->detach( a_rticle
.get() );
819 text
=a_rticle
->textContent();
822 text
=new KMime::Content();
823 KMime::Headers::ContentType
*type
=text
->contentType();
824 KMime::Headers::ContentTransferEncoding
*enc
=text
->contentTransferEncoding();
825 type
->setMimeType("text/plain");
826 enc
->setDecoded(true);
828 a_rticle
->addContent(text
, true);
834 text
->contentType()->setCharset( mCharset
.toLatin1() );
835 if ( knGlobals
.settings()->allow8BitBody() )
836 text
->contentTransferEncoding()->setEncoding(KMime::Headers::CE8Bit
);
838 text
->contentTransferEncoding()->setEncoding(KMime::Headers::CEquPr
);
840 setCharset( "us-ascii" ); // fall back to us-ascii
841 text
->contentType()->setCharset( mCharset
.toLatin1() );
842 text
->contentTransferEncoding()->setEncoding(KMime::Headers::CE7Bit
);
844 } else { // save as draft
845 text
->contentType()->setCharset( mCharset
.toLatin1() );
846 if ( mCharset
.toLower()=="us-ascii" ) {
847 text
->contentTransferEncoding()->setEncoding(KMime::Headers::CE7Bit
);
849 text
->contentTransferEncoding()->setEncoding( knGlobals
.settings()->allow8BitBody()
850 ? KMime::Headers::CE8Bit
: KMime::Headers::CEquPr
);
854 QString tmp
= v_iew
->editor()->toWrappedPlainText();
856 // Sign article if needed
857 if ( a_ctPGPsign
->isChecked() ) {
858 QByteArray signingKey
= identity
.pgpSigningKey();
859 if (!signingKey
.isEmpty()) {
860 QString tmpText
= tmp
;
863 QTextCodec
*codec
=KGlobal::charsets()->codecForName( mCharset
, ok
);
864 if(!ok
) // no suitable codec found => try local settings and hope the best ;-)
865 codec
=KGlobal::locale()->codecForEncoding();
867 block
.setText( codec
->fromUnicode(tmpText
) );
868 kDebug(5003) <<"signing article from" << article()->from()->addresses();
869 if( block
.clearsign( signingKey
, codec
->name() ) == Kpgp::Ok
) {
870 QByteArray result
= block
.text();
871 tmp
= codec
->toUnicode(result
.data(), result
.length() );
878 text
->fromUnicodeString(tmp
);
880 //text is set and all attached contents have been assembled => now set lines
881 a_rticle
->lines()->setNumberOfLines(a_rticle
->lineCount());
883 a_rticle
->assemble();
884 a_rticle
->updateListItem();
889 void KNComposer::setCharset( const QString
&charset
)
891 mCharset
= Locale::toMimeCharset( charset
);
892 slotUpdateStatusBar();
896 void KNComposer::closeEvent(QCloseEvent
*e
)
898 if(!v_iew
->editor()->document()->isModified() && !a_ttChanged
) { // nothing to save, don't show nag screen
899 if(a_rticle
->id()==-1)
905 switch ( KMessageBox::warningYesNoCancel( this, i18n("Do you want to save this article in the draft folder?"),
906 QString(), KStandardGuiItem::save(), KStandardGuiItem::discard() ) ) {
907 case KMessageBox::Yes
:
910 case KMessageBox::No
:
911 if (a_rticle
->id()==-1) r_esult
=CRdel
;
912 else r_esult
=CRcancel
;
921 emit
composerDone(this);
922 // we're dead at this point, don't access members!
926 void KNComposer::initData(const QString
&text
)
929 KPIMIdentities::IdentityManager
*idManager
= KNGlobals::self()->identityManager();
930 KPIMIdentities::Identity identity
= idManager
->defaultIdentity();
931 KMime::Headers::Base
* xKnodeIdentity
= a_rticle
->headerByType( "X-KNode-Identity" );
932 if ( xKnodeIdentity
&& !xKnodeIdentity
->isEmpty() ) {
933 uint uoid
= xKnodeIdentity
->asUnicodeString().toUInt();
934 // Note: this ensure the identity exists even if it was removed
935 identity
= idManager
->identityForUoidOrDefault( uoid
);
937 v_iew
->setIdentity( identity
.uoid() );
940 KMime::Headers::From
*from
= a_rticle
->from( false );
942 v_iew
->setFrom( from
->asUnicodeString() );
944 v_iew
->setFrom( identity
.fullEmailAddr() );
948 if(a_rticle
->subject()->isEmpty())
949 slotSubjectChanged( QString() );
951 v_iew
->setSubject( a_rticle
->subject()->asUnicodeString() );
954 KMime::Headers::Newsgroups
*hNewsgroup
= a_rticle
->newsgroups( false );
955 if ( hNewsgroup
&& !hNewsgroup
->isEmpty() ) {
956 v_iew
->setGroups( hNewsgroup
->asUnicodeString() );
960 KMime::Headers::To
*hTo
= a_rticle
->to( false );
961 if ( hTo
&& !hTo
->isEmpty() ) {
962 v_iew
->setEmailRecipient( hTo
->asUnicodeString() );
966 KMime::Headers::FollowUpTo
*fup2
=a_rticle
->followUpTo(false);
967 if( fup2
&& !fup2
->isEmpty() ) {
968 v_iew
->setFollowupTo( fup2
->asUnicodeString() );
971 KMime::Content
*textContent
=a_rticle
->textContent();
976 s
= textContent
->decodedText();
980 v_iew
->editor()->setText(s
);
982 // initialize the charset select action
984 setCharset( textContent
->contentType()->charset() );
986 setCharset( knGlobals
.settings()->charset() );
989 QString charsetDesc
= KGlobal::charsets()->descriptionForEncoding( mCharset
);
990 a_ctSetCharset
->setCurrentItem( a_ctSetCharset
->items().indexOf( charsetDesc
) );
992 // initialize the message type select action
993 if (a_rticle
->doPost() && a_rticle
->doMail())
996 if (a_rticle
->doPost())
1000 setMessageMode(m_ode
);
1002 if(a_rticle
->contentType()->isMultipart()) {
1003 v_iew
->showAttachmentView();
1004 const KMime::Content::List attList
= a_rticle
->attachments();
1005 foreach ( KMime::Content
*c
, attList
) {
1006 v_iew
->addAttachment( KNAttachment::Ptr( new KNAttachment( c
) ) );
1011 // inserts at cursor position if clear is false, replaces content otherwise
1012 // puts the file content into a box if box==true
1013 // "file" is already open for reading
1014 void KNComposer::insertFile( QFile
*file
, bool clear
, bool box
, const QString
&boxTitle
)
1018 QTextCodec
*codec
=KGlobal::charsets()->codecForName( mCharset
, ok
);
1019 QTextStream
ts(file
);
1023 temp
= QString::fromLatin1(",----[ %1 ]\n").arg(boxTitle
);
1025 if (box
&& (v_iew
->editor()->wordWrapMode()!=QTextOption::NoWrap
)) {
1026 int wrapAt
= v_iew
->editor()->lineWrapColumnOrWidth();
1029 while(!ts
.atEnd()) {
1035 temp
+=KNHelper::rewrapStringList(lst
, wrapAt
, '|', false, true);
1037 while(!ts
.atEnd()) {
1040 temp
+=ts
.readLine();
1046 temp
+= QString::fromLatin1("`----");
1049 v_iew
->editor()->setText(temp
);
1051 v_iew
->editor()->insertPlainText(temp
);
1055 // ask for a filename, handle network urls
1056 void KNComposer::insertFile(bool clear
, bool box
)
1058 KNLoadHelper
helper(this);
1059 QFile
*file
= helper
.getFile(i18n("Insert File"));
1064 url
= helper
.getURL();
1066 if (url
.isLocalFile())
1067 boxName
= url
.toLocalFile();
1069 boxName
= url
.prettyUrl();
1071 insertFile(file
,clear
,box
,boxName
);
1076 //-------------------------------- <Actions> ------------------------------------
1079 void KNComposer::addRecentAddress()
1081 if ( m_ode
== mail
|| m_ode
== news_mail
) {
1082 RecentAddresses::self( knGlobals
.config() )->add( v_iew
->emailRecipient() );
1086 void KNComposer::slotSendNow()
1090 emit
composerDone(this);
1094 void KNComposer::slotSendLater()
1096 r_esult
=CRsendLater
;
1098 emit
composerDone(this);
1102 void KNComposer::slotSaveAsDraft()
1106 emit
composerDone(this);
1110 void KNComposer::slotArtDelete()
1113 emit
composerDone(this);
1117 void KNComposer::slotInsertFile()
1119 insertFile(false,false);
1123 void KNComposer::slotInsertFileBoxed()
1125 insertFile(false,true);
1128 void KNComposer::slotAttachFile()
1130 KNLoadHelper
*helper
= new KNLoadHelper(this);
1132 if (helper
->getFile(i18n("Attach File"))) {
1133 if ( !v_iew
->isAttachmentViewVisible() ) {
1134 KNHelper::saveWindowSize("composer", size());
1135 v_iew
->showAttachmentView();
1137 v_iew
->addAttachment( KNAttachment::Ptr( new KNAttachment( helper
) ) );
1145 void KNComposer::slotAttachmentRemoved( KNAttachment::Ptr attachment
, bool last
)
1151 if ( attachment
->isAttached() ) {
1152 mDeletedAttachments
.append( attachment
);
1156 KNHelper::saveWindowSize( "composerAtt", size() );
1157 v_iew
->hideAttachmentView();
1163 void KNComposer::slotAttachmentChanged()
1170 void KNComposer::slotToggleDoPost()
1172 if (a_ctDoPost
->isChecked()) {
1173 if (a_ctDoMail
->isChecked())
1178 if (a_ctDoMail
->isChecked())
1181 a_ctDoPost
->setChecked(true); //revert
1185 setMessageMode(m_ode
);
1189 void KNComposer::slotToggleDoMail()
1191 if (a_ctDoMail
->isChecked()) {
1192 if (a_uthorDislikesMailCopies
) {
1193 if ( KMessageBox::warningContinueCancel( this, i18n("The poster does not want a mail copy of your reply (Mail-Copies-To: nobody);\nplease respect their request."),
1194 QString(), KGuiItem(i18n("&Send Copy")) ) != KMessageBox::Continue
) {
1195 a_ctDoMail
->setChecked(false); //revert
1202 if ( knGlobals
.settings()->useExternalMailer() ) {
1203 QString s
= v_iew
->editor()->textLine(0);
1204 if (!s
.contains(i18n("<posted & mailed>")))
1205 v_iew
->editor()->insertAt(i18n("<posted & mailed>\n\n"),0,0);
1207 QStringList textLines
= v_iew
->editor()->processedText();
1208 for (QStringList::Iterator it
= textLines
.begin(); it
!= textLines
.end(); ++it
) {
1209 if (*it
== "-- ") // try to be smart, don't include the signature,
1210 break; // kmail will append one, too.
1213 knGlobals
.artFactory
->sendMailExternal( v_iew
->t_o
->text(), v_iew
->subject(), tmp
);
1214 a_ctDoMail
->setChecked(false); //revert
1218 if (a_ctDoMail
->isChecked()) {
1219 if (a_ctDoPost
->isChecked())
1224 if (a_ctDoPost
->isChecked())
1227 a_ctDoMail
->setChecked(true); //revert
1231 setMessageMode(m_ode
);
1235 void KNComposer::slotSetCharset(const QString
&s
)
1240 QString charset
= KGlobal::charsets()->encodingForName( s
);
1241 setCharset( charset
);
1245 void KNComposer::slotSetCharsetKeyboard()
1247 int newCS
= KNHelper::selectDialog(this, i18n("Select Charset"), a_ctSetCharset
->items(), a_ctSetCharset
->currentItem());
1249 a_ctSetCharset
->setCurrentItem(newCS
);
1250 QString charset
= KGlobal::charsets()->encodingForName( a_ctSetCharset
->items()[ newCS
] );
1251 setCharset( charset
);
1256 void KNComposer::slotToggleWordWrap()
1258 if ( a_ctWordWrap
->isChecked() )
1259 v_iew
->editor()->enableWordWrap( knGlobals
.settings()->maxLineLength() );
1261 v_iew
->editor()->disableWordWrap();
1264 void KNComposer::slotAutoSpellCheckingToggled()
1266 v_iew
->editor()->setCheckSpellingEnabled( a_ctAutoSpellChecking
->isChecked() );
1270 void KNComposer::slotUndoRewrap()
1272 if (KMessageBox::warningContinueCancel( this, i18n("This will replace all text you have written.")) == KMessageBox::Continue
) {
1273 v_iew
->editor()->setText(u_nwraped
);
1274 v_iew
->appendSignature();
1278 void KNComposer::slotExternalEditor()
1280 if(e_xternalEditor
) // in progress...
1283 QString editorCommand
= knGlobals
.settings()->externalEditor();
1285 if(editorCommand
.isEmpty())
1286 KMessageBox::sorry(this, i18n("No editor configured.\nPlease do this in the settings dialog."));
1288 delete e_ditorTempfile
;
1289 e_ditorTempfile
=new KTemporaryFile();
1291 if(!e_ditorTempfile
->open()) {
1292 KNHelper::displayTempFileError(this);
1293 delete e_ditorTempfile
;
1299 QTextCodec
*codec
=KGlobal::charsets()->codecForName( mCharset
, ok
);
1301 QString tmp
= v_iew
->editor()->toWrappedPlainText();
1303 QByteArray local
= codec
->fromUnicode(tmp
);
1304 e_ditorTempfile
->write(local
.data(),local
.length());
1305 e_ditorTempfile
->flush();
1307 if(!e_ditorTempfile
->open()) {
1308 KNHelper::displayTempFileError(this);
1309 delete e_ditorTempfile
;
1314 e_xternalEditor
=new KProcess();
1316 // construct command line...
1317 QStringList command
= editorCommand
.split(' ', QString::SkipEmptyParts
);
1318 bool filenameAdded
=false;
1319 for ( QStringList::Iterator it
= command
.begin(); it
!= command
.end(); ++it
) {
1320 if ((*it
).contains("%f")) {
1321 (*it
).replace(QRegExp("%f"),e_ditorTempfile
->fileName());
1324 (*e_xternalEditor
) << (*it
);
1326 if(!filenameAdded
) // no %f in the editor command
1327 (*e_xternalEditor
) << e_ditorTempfile
->fileName();
1329 connect(e_xternalEditor
, SIGNAL(finished(int,QProcess::ExitStatus
)),this, SLOT(slotEditorFinished(int,QProcess::ExitStatus
)));
1330 e_xternalEditor
->start();
1331 if(!e_xternalEditor
->waitForStarted()) {
1332 KMessageBox::error(this, i18n("Unable to start external editor.\nPlease check your configuration in the settings dialog."));
1333 delete e_xternalEditor
;
1335 delete e_ditorTempfile
;
1340 a_ctExternalEditor
->setEnabled(false); // block other edit action while the editor is running...
1341 a_ctSpellCheck
->setEnabled(false);
1342 v_iew
->showExternalNotification();
1345 void KNComposer::slotUpdateStatusBar()
1349 case news
: typeDesc
= i18n("News Article");
1351 case mail
: typeDesc
= i18n("Email");
1353 default : typeDesc
= i18n("News Article & Email");
1355 QString overwriteDesc
;
1356 if (v_iew
->editor()->overwriteMode ())
1357 overwriteDesc
= i18n(" OVR ");
1359 overwriteDesc
= i18n(" INS ");
1361 statusBar()->changeItem(i18n(" Type: %1 ", typeDesc
), 1);
1362 statusBar()->changeItem(i18n(" Charset: %1 ", mCharset
), 2);
1363 statusBar()->changeItem(overwriteDesc
, 3);
1364 statusBar()->changeItem(i18n(" Column: %1 ", v_iew
->editor()->columnNumber () + 1), 4);
1365 statusBar()->changeItem(i18n(" Line: %1 ", v_iew
->editor()->linePosition() + 1), 5);
1369 void KNComposer::slotUpdateCursorPos()
1371 statusBar()->changeItem(i18n(" Column: %1 ", v_iew
->editor()->columnNumber () + 1), 4);
1372 statusBar()->changeItem(i18n(" Line: %1 ", v_iew
->editor()->linePosition() + 1), 5);
1376 void KNComposer::slotConfKeys()
1378 KShortcutsDialog::configure(actionCollection(), KShortcutsEditor::LetterShortcutsAllowed
, this, true);
1382 void KNComposer::slotConfToolbar()
1384 saveMainWindowSettings(knGlobals
.config()->group( "composerWindow_options") );
1385 KEditToolBar
dlg(guiFactory(),this);
1386 connect(&dlg
,SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig()));
1390 void KNComposer::slotNewToolbarConfig()
1392 createGUI("kncomposerui.rc");
1394 applyMainWindowSettings(knGlobals
.config()->group("composerWindow_options"));
1397 //-------------------------------- </Actions> -----------------------------------
1400 void KNComposer::slotSubjectChanged(const QString
&t
)
1403 QString subject
= t
;
1404 subject
.replace( '\n', ' ' );
1405 subject
.replace( '\r', ' ' );
1406 if ( subject
!= t
) // setText() sets the cursor to the end
1407 v_iew
->setSubject( subject
);
1409 if( !subject
.isEmpty() )
1410 setCaption( subject
);
1412 setCaption( i18n("No Subject") );
1416 void KNComposer::slotToBtnClicked()
1418 Akonadi::EmailAddressSelectionDialog
dlg( this );
1419 dlg
.view()->view()->setSelectionMode( QAbstractItemView::MultiSelection
);
1424 QStringList addresses
;
1425 foreach ( const Akonadi::EmailAddressSelection
&selection
, dlg
.selectedAddresses() )
1426 addresses
<< selection
.quotedEmail();
1428 QString to
= v_iew
->emailRecipient();
1429 if ( !to
.isEmpty() )
1431 to
+= addresses
.join( ", " );
1433 v_iew
->setEmailRecipient( to
);
1437 void KNComposer::slotGroupsBtnClicked()
1439 int id
=a_rticle
->serverId();
1440 KNNntpAccount::Ptr nntp
;
1443 nntp
=knGlobals
.accountManager()->account(id
);
1446 nntp
=knGlobals
.accountManager()->first();
1449 KMessageBox::error(this, i18n("You have no valid news accounts configured."));
1450 v_iew
->setGroups( QString() );
1455 a_rticle
->setServerId(nntp
->id());
1457 KNGroupSelectDialog
*dlg
= new KNGroupSelectDialog( this, nntp
, v_iew
->groups() );
1459 connect( dlg
, SIGNAL(loadList(KNNntpAccount::Ptr
)),
1460 knGlobals
.groupManager(), SLOT(slotLoadGroupList(KNNntpAccount::Ptr
)) );
1461 connect( KNGlobals::self()->groupManager(), SIGNAL(newListReady(KNGroupListData::Ptr
)),
1462 dlg
, SLOT(slotReceiveList(KNGroupListData::Ptr
)) );
1465 v_iew
->setGroups( dlg
->selectedGroups() );
1470 void KNComposer::slotEditorFinished(int, QProcess::ExitStatus exitStatus
)
1472 if(exitStatus
== QProcess::NormalExit
) {
1473 e_ditorTempfile
->flush();
1474 e_ditorTempfile
->seek(0);
1475 insertFile(e_ditorTempfile
, true);
1476 e_xternalEdited
=true;
1479 slotCancelEditor(); // cleanup...
1483 void KNComposer::slotCancelEditor()
1485 if (e_xternalEditor
)
1486 e_xternalEditor
->deleteLater(); // this also kills the editor process if it's still running
1488 delete e_ditorTempfile
;
1491 a_ctExternalEditor
->setEnabled(true);
1492 a_ctSpellCheck
->setEnabled(true);
1493 v_iew
->hideExternalNotification();
1497 void KNComposer::slotAttachmentPopup( const QPoint
&point
)
1499 QMenu
*menu
= static_cast<QMenu
*>( factory()->container( "attachment_popup", this ) );
1501 menu
->popup( point
);
1505 void KNComposer::dragEnterEvent( QDragEnterEvent
*event
)
1507 if ( KUrl::List::canDecode( event
->mimeData() ) ) {
1508 event
->setDropAction( Qt::CopyAction
);
1513 void KNComposer::dropEvent( QDropEvent
*event
)
1515 KUrl::List urls
= KUrl::List::fromMimeData( event
->mimeData() );
1517 foreach ( const KUrl
&url
, urls
) {
1518 KNLoadHelper
*helper
= new KNLoadHelper(this);
1520 if (helper
->setURL(url
)) {
1521 if ( !v_iew
->isAttachmentViewVisible() ) {
1522 KNHelper::saveWindowSize("composer", size());
1523 v_iew
->showAttachmentView();
1525 v_iew
->addAttachment( KNAttachment::Ptr( new KNAttachment( helper
) ) );
1534 //=====================================================================================
1537 KNComposer::AttachmentPropertiesDlg::AttachmentPropertiesDlg( KNAttachment::Ptr a
, QWidget
*parent
) :
1538 KDialog( parent
), a_ttachment(a
),
1539 n_onTextAsText(false)
1542 setCaption( i18n("Attachment Properties") );
1543 setButtons( Help
| Ok
| Cancel
);
1544 QWidget
*page
=new QWidget(this);
1545 setMainWidget(page
);
1546 QVBoxLayout
*topL
=new QVBoxLayout(page
);
1549 QGroupBox
*fileGB
= new QGroupBox( i18n("File"), page
);
1550 QGridLayout
*fileL
=new QGridLayout(fileGB
);
1551 fileL
->setSpacing(5);
1552 fileL
->setMargin(15);
1554 fileL
->addItem( new QSpacerItem( 0, fontMetrics().lineSpacing()-9), 0, 0 );
1555 fileL
->addWidget(new QLabel(i18n("Name:"), fileGB
) ,1,0);
1556 fileL
->addWidget(new QLabel(QString("<b>%1</b>").arg(a
->name()), fileGB
), 1,1, Qt::AlignLeft
);
1557 fileL
->addWidget(new QLabel(i18n("Size:"), fileGB
), 2,0);
1558 fileL
->addWidget(new QLabel(a
->contentSize(), fileGB
), 2,1, Qt::AlignLeft
);
1560 fileL
->setColumnStretch(1,1);
1561 topL
->addWidget(fileGB
);
1564 QGroupBox
*mimeGB
= new QGroupBox( i18n("Mime"), page
);
1565 QGridLayout
*mimeL
=new QGridLayout(mimeGB
);
1566 mimeL
->setSpacing(5);
1567 mimeL
->setMargin(15);
1569 mimeL
->addItem( new QSpacerItem( 0, fontMetrics().lineSpacing()-9), 0, 0 );
1570 m_imeType
=new KLineEdit(mimeGB
);
1571 m_imeType
->setText(a
->mimeType());
1572 mimeL
->addWidget(m_imeType
, 1,1);
1573 QLabel
*label
= new QLabel(i18n("&Mime-Type:"), mimeGB
);
1574 label
->setBuddy(m_imeType
);
1575 mimeL
->addWidget(label
, 1,0);
1577 d_escription
=new KLineEdit(mimeGB
);
1578 d_escription
->setText(a
->description());
1579 mimeL
->addWidget(d_escription
, 2,1);
1580 label
=new QLabel(i18n("&Description:"), mimeGB
);
1581 label
->setBuddy(d_escription
);
1582 mimeL
->addWidget(label
, 2,0);
1584 e_ncoding
=new QComboBox(mimeGB
);
1585 e_ncoding
->setEditable(false);
1586 e_ncoding
->addItem("7Bit");
1587 e_ncoding
->addItem("8Bit");
1588 e_ncoding
->addItem("quoted-printable");
1589 e_ncoding
->addItem("base64");
1590 if(a
->isFixedBase64()) {
1591 e_ncoding
->setCurrentIndex(3);
1592 e_ncoding
->setEnabled(false);
1595 e_ncoding
->setCurrentIndex(a
->cte());
1596 mimeL
->addWidget(e_ncoding
, 3,1);
1597 label
=new QLabel(i18n("&Encoding:"), mimeGB
);
1598 label
->setBuddy(e_ncoding
);
1599 mimeL
->addWidget(label
, 3,0);
1601 mimeL
->setColumnStretch(1,1);
1602 topL
->addWidget(mimeGB
);
1605 connect(m_imeType
, SIGNAL(textChanged(QString
)),
1606 this, SLOT(slotMimeTypeTextChanged(QString
)));
1609 setFixedHeight(sizeHint().height());
1610 KNHelper::restoreWindowSize("attProperties", this, QSize(300,250));
1611 setHelp("anc-knode-editor-advanced");
1615 KNComposer::AttachmentPropertiesDlg::~AttachmentPropertiesDlg()
1617 KNHelper::saveWindowSize("attProperties", this->size());
1621 void KNComposer::AttachmentPropertiesDlg::apply()
1623 a_ttachment
->setDescription(d_escription
->text());
1624 a_ttachment
->setMimeType(m_imeType
->text());
1625 a_ttachment
->setCte(e_ncoding
->currentIndex());
1629 void KNComposer::AttachmentPropertiesDlg::accept()
1631 if ( m_imeType
->text().indexOf('/') == -1 ) {
1632 KMessageBox::sorry(this, i18n("You have set an invalid mime-type.\nPlease change it."));
1635 else if ( n_onTextAsText
&& m_imeType
->text().indexOf( "text/", 0, Qt::CaseInsensitive
) != -1 &&
1636 KMessageBox::warningContinueCancel(this,
1637 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?")
1638 ) == KMessageBox::Cancel
) return;
1640 // update the attachment
1647 void KNComposer::AttachmentPropertiesDlg::slotMimeTypeTextChanged(const QString
&text
)
1649 enableButtonOk( !text
.isEmpty() );
1650 if(text
.left(5)!="text/") {
1651 n_onTextAsText
=a_ttachment
->isFixedBase64();
1652 e_ncoding
->setCurrentIndex(3);
1653 e_ncoding
->setEnabled(false);
1656 e_ncoding
->setCurrentIndex(a_ttachment
->cte());
1657 e_ncoding
->setEnabled(true);
1662 //--------------------------------
1664 #include "kncomposer.moc"
1666 // kate: space-indent on; indent-width 2;