2 KNode, the KDE newsreader
3 Copyright (c) 1999-2007 the KNode authors.
4 See file AUTHORS for details
5 Copyright (c) 2010 Olivier Trichet <nive@nivalis.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11 You should have received a copy of the GNU General Public License
12 along with this program; if not, write to the Free Software Foundation,
13 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
16 #include "kncomposerview.h"
18 #include "kncomposereditor.h"
19 #include "knglobals.h"
23 #include <KPIMIdentities/IdentityCombo>
24 #include <KPIMIdentities/Identity>
25 #include <KPIMIdentities/IdentityManager>
26 #include <KPIMUtils/Email>
33 View::View( KNComposer
*composer
)
34 : QSplitter( Qt::Vertical
, composer
),
35 mAttachmentSetup( false )
39 setChildrenCollapsible( false );
40 mAttachmentWidget
->hide();
43 mFromEdit
->setView( this );
44 mFromEdit
->enableCompletion( false );
45 mEdtList
.append( mFromEdit
);
49 mToEdit
->setView( this );
50 mToEdit
->enableCompletion( true );
51 mEdtList
.append( mToEdit
);
52 connect( mToButton
, SIGNAL(clicked(bool)),
53 parent(), SLOT(slotToBtnClicked()) );
56 mGroupsEdit
->setView( this );
57 mGroupsEdit
->enableCompletion( false );
58 mEdtList
.append( mGroupsEdit
);
59 connect( mGroupsEdit
, SIGNAL(editingFinished()),
60 this, SLOT(slotGroupsChanged()) );
61 connect( mGroupsButton
, SIGNAL(clicked()),
62 parent(), SLOT(slotGroupsBtnClicked()) );
65 connect( mFollowuptoEdit
, SIGNAL(focused()),
66 this, SLOT(hideFollowuptoHint()) );
69 mSubjectEdit
->setView( this );
70 mSubjectEdit
->enableCompletion( false );
71 mEdtList
.append( mSubjectEdit
);
72 connect( mSubjectEdit
, SIGNAL(textChanged(QString
)),
73 parent(), SLOT(slotSubjectChanged(QString
)) );
76 mEditor
->switchToPlainText();
77 mEditor
->setMinimumHeight(50);
79 connect( mExternalKillSwitch
, SIGNAL(clicked(bool)),
80 this, SIGNAL(closeExternalEditor()) );
81 hideExternalNotification();
82 mExternalKillSwitch
->setIcon( KIcon( "application-exit" ) );
85 connect( mIdentitySelector
, SIGNAL(identityChanged(uint
)),
86 this, SLOT(slotIdentityChanged(uint
)) );
87 setIdentity( KNGlobals::self()->identityManager()->defaultIdentity().uoid() );
93 if ( mAttachmentsList
->topLevelItemCount() > 0 ) { // The attachment view was visible
94 KConfigGroup
conf( knGlobals
.config(), "POSTNEWS");
96 conf
.writeEntry("Att_Splitter",sizes()); // save splitter pos
98 QList
<int> lst
; // save header sizes
99 QHeaderView
*h
= mAttachmentsList
->header();
100 for ( int i
= 0 ; i
< h
->count() ; ++i
) {
101 lst
<< h
->sectionSize(i
);
103 conf
.writeEntry("Att_Headers",lst
);
108 void View::completeSetup( bool firstEdit
, KNComposer::MessageMode mode
)
111 // now we place the cursor at the end of the quoted text / below the attribution line
112 if ( KNGlobals::self()->settings()->cursorOnTop() ) {
113 // FIXME: hack: counting the number of \n\n to catch end of introduction (see KNArticleFactory::createReply())
114 int dbleLfCount
= KNGlobals::self()->settings()->intro().count( "%L%L" );
115 const QString text
= mEditor
->textOrHtml();
117 while ( dbleLfCount
>= 0 ) {
118 pos
= text
.indexOf( QLatin1String( "\n\n" ), pos
);
122 mEditor
->setCursorPositionFromStart( pos
- 1 );
124 mEditor
->setCursorPositionFromStart( mEditor
->document()->characterCount() - 1 );
127 if ( knGlobals
.settings()->appendOwnSignature() ) {
131 mEditor
->setCursorPositionFromStart( 0 );
133 mEditor
->document()->setModified( false );
135 setMessageMode( mode
);
139 if ( mSubjectEdit
->text().length() == 0 ) {
140 mSubjectEdit
->setFocus();
142 if ( mGroupsEdit
->text().length() == 0 && mode
== KNComposer::news
) {
143 mGroupsEdit
->setFocus();
145 if ( mToEdit
->text().length() == 0 && mode
== KNComposer::mail
) {
151 void View::focusNextPrevEdit( const QWidget
*aCur
, bool aNext
)
153 QList
<QWidget
*>::Iterator it
;
156 it
= --( mEdtList
.end() );
158 for ( QList
<QWidget
*>::Iterator it2
= mEdtList
.begin(); it2
!= mEdtList
.end(); ++it2
) {
159 if ( (*it2
) == aCur
) {
164 if ( it
== mEdtList
.end() )
169 if ( it
!= mEdtList
.begin() )
175 if ( it
!= mEdtList
.end() ) {
176 if ( (*it
)->isVisible() )
182 void View::setComposingFont( const QFont
&font
)
184 mSubjectEdit
->setFont( font
);
185 mToEdit
->setFont( font
);
186 mGroupsEdit
->setFont( font
);
187 mFollowuptoEdit
->setFont( font
);
188 mEditor
->setFontForWholeText( font
);
192 void View::setMessageMode( KNComposer::MessageMode mode
)
194 showTo( mode
!= KNComposer::news
);
196 showGroups( mode
!= KNComposer::mail
);
197 showFollowupto( mode
!= KNComposer::mail
);
201 uint
View::selectedIdentity() const
203 return mIdentitySelector
->currentIdentity();
206 void View::setIdentity( uint uoid
)
208 mIdentitySelector
->setCurrentIdentity( uoid
);
209 // mIdentitySelector will emit its identityChanged(uint) signal
210 // that is connected to slotIdentityChanged(uint)
213 void View::slotIdentityChanged( uint uoid
)
215 KPIMIdentities::IdentityManager
*im
= KNGlobals::self()->identityManager();
216 KPIMIdentities::Identity identity
= im
->identityForUoid( uoid
);
217 setFrom( identity
.fullEmailAddr() );
218 if ( KPIMUtils::isValidAddress( from() ) != KPIMUtils::AddressOk
) {
224 const QString
View::from()
226 return mFromEdit
->text();
229 void View::setFrom( const QString
& from
)
231 mFromEdit
->setText( from
);
235 const QStringList
View::groups() const
237 const QRegExp r
= QRegExp( "\\s*,\\s*", Qt::CaseInsensitive
, QRegExp::RegExp2
);
238 return mGroupsEdit
->text().split( r
, QString::SkipEmptyParts
);
241 void View::setGroups( const QString
&groups
)
243 mGroupsEdit
->setText( groups
);
244 slotGroupsChanged(); // update the followup-to
247 void View::slotGroupsChanged()
249 QStringList groupsList
= groups();
250 int groupsCount
= groupsList
.size();
251 groupsList
.append( QString() );
253 const QString currFup2
= mFollowuptoEdit
->currentText();
254 int i
= groupsList
.indexOf( currFup2
);
256 groupsList
.prepend( currFup2
);
258 groupsList
.move( i
, 0 );
261 mFollowuptoEdit
->clear();
262 mFollowuptoEdit
->addItems( groupsList
);
264 // Display an hint about fu2
265 if ( groupsCount
> 1 ) {
266 displayFollowuptoHint();
268 hideFollowuptoHint();
273 const QString
View::emailRecipient() const
275 return mToEdit
->text();
278 void View::setEmailRecipient( const QString
& to
)
280 mToEdit
->setText( to
);
284 const QStringList
View::followupTo() const
286 const QRegExp r
= QRegExp( "\\s*,\\s*", Qt::CaseInsensitive
, QRegExp::RegExp2
);
287 return mFollowuptoEdit
->currentText().split( r
, QString::SkipEmptyParts
);
290 void View::setFollowupTo( const QString
&followupTo
)
292 hideFollowuptoHint();
293 mFollowuptoEdit
->setEditText( followupTo
);
296 void View::displayFollowuptoHint()
298 const QString hint
= i18nc( "@info/plain This message is place, as an inactive text, in the Followup-To "
299 "line edit of the message composer when the user select more than one "
300 "group to post his/her message.",
301 "Choose an appropriate group to redirect replies..." );
302 if ( mFollowuptoEdit
->currentText().isEmpty() ) {
303 QLineEdit
*l
= mFollowuptoEdit
->lineEdit();
304 QPalette palette
= l
->palette();
305 KColorScheme::adjustForeground( palette
, KColorScheme::InactiveText
);
306 l
->setPalette( palette
);
311 void View::hideFollowuptoHint()
313 const QString hint
= i18nc( "@info/plain This message is place, as an inactive text, in the Followup-To "
314 "line edit of the message composer when the user select more than one "
315 "group to post his/her message.",
316 "Choose an appropriate group to redirect replies..." );
317 if ( mFollowuptoEdit
->currentText() == hint
) {
318 QLineEdit
*l
= mFollowuptoEdit
->lineEdit();
319 QPalette palette
= l
->palette();
320 KColorScheme::adjustForeground( palette
, KColorScheme::NormalText
);
321 l
->setPalette( palette
);
322 l
->setText( QString() );
327 const QString
View::subject() const
329 return mSubjectEdit
->text();
332 void View::setSubject( const QString
&subject
)
334 mSubjectEdit
->setText( subject
);
338 KNComposerEditor
* View::editor() const
345 void View::appendSignature()
347 KPIMIdentities::IdentityManager
*im
= KNGlobals::self()->identityManager();
348 KPIMIdentities::Identity identity
= im
->identityForUoid( selectedIdentity() );
349 identity
.signature().insertIntoTextEdit( KPIMIdentities::Signature::End
,
350 KPIMIdentities::Signature::AddSeparator
,
356 void View::showIdentity( bool show
)
358 mIdentitySelectorLabel
->setVisible( show
);
359 mIdentitySelector
->setVisible( show
);
362 void View::showFrom( bool show
)
364 mFromLabel
->setVisible( show
);
365 mFromEdit
->setVisible( show
);
368 void View::showTo( bool show
)
370 mToLabel
->setVisible( show
);
371 mToEdit
->setVisible( show
);
372 mToButton
->setVisible( show
);
375 void View::showGroups( bool show
)
377 mGroupsLabel
->setVisible( show
);
378 mGroupsEdit
->setVisible( show
);
379 mGroupsButton
->setVisible( show
);
382 void View::showFollowupto( bool show
)
384 mFollowuptoLabel
->setVisible( show
);
385 mFollowuptoEdit
->setVisible( show
);
388 void View::showSubject( bool show
)
390 mSubjetLabel
->setVisible( show
);
391 mSubjectEdit
->setVisible( show
);
396 void View::showAttachmentView()
398 if ( !mAttachmentSetup
) {
399 mAttachmentSetup
= true;
402 connect( mAttachmentsList
, SIGNAL(itemSelectionChanged()),
403 this, SLOT(slotAttachmentSelectionChanged()) );
405 connect( mAttachmentsList
, SIGNAL(contextMenuRequested(QPoint
)),
406 parent(), SLOT(slotAttachmentPopup(QPoint
)) );
408 connect( mAttachmentsList
, SIGNAL(deletePressed()),
409 this, SLOT(removeCurrentAttachment()) );
410 connect( mAttachmentsList
, SIGNAL(attachmentRemoved(KNAttachment::Ptr
,bool)),
411 parent(), SLOT(slotAttachmentRemoved(KNAttachment::Ptr
,bool)) );
413 connect( mAttachmentsList
, SIGNAL(itemDoubleClicked(QTreeWidgetItem
*,int)),
414 mAttachmentsList
, SLOT(editCurrentAttachment()) );
415 connect( mAttachmentsList
, SIGNAL(returnPressed()),
416 mAttachmentsList
, SLOT(editCurrentAttachment()) );
417 connect( mAttachmentsList
, SIGNAL(itemChanged(QTreeWidgetItem
*,int)),
418 parent(), SLOT(slotAttachmentChanged()) );
421 connect( mAttachmentAddButton
, SIGNAL(clicked()),
422 parent(), SLOT(slotAttachFile()) );
424 mAttachmentRemoveButton
->setEnabled( false );
425 connect( mAttachmentRemoveButton
, SIGNAL(clicked()),
426 this, SLOT(removeCurrentAttachment()) );
428 mAttachmentPropertiesButton
->setEnabled( false );
429 connect( mAttachmentPropertiesButton
, SIGNAL(clicked()),
430 mAttachmentsList
, SLOT(editCurrentAttachment()) );
433 if ( !mAttachmentWidget
->isVisible() ) {
434 mAttachmentWidget
->show();
436 KConfigGroup
conf(knGlobals
.config(), "POSTNEWS");
438 QList
<int> lst
= conf
.readEntry("Att_Splitter",QList
<int>());
443 lst
=conf
.readEntry("Att_Headers",QList
<int>());
444 QHeaderView
*h
= mAttachmentsList
->header();
445 if ( lst
.count() == h
->count() ) {
446 for( int i
= 0 ; i
< h
->count() ; ++i
) {
447 h
->resizeSection( i
, lst
[ i
] );
453 void View::hideAttachmentView()
455 mAttachmentWidget
->hide();
458 void View::addAttachment( KNAttachment::Ptr attachment
)
460 AttachmentViewItem
*item
= new AttachmentViewItem( mAttachmentsList
, attachment
);
461 mAttachmentsList
->addTopLevelItem( item
);
464 const QList
<KNAttachment::Ptr
> View::attachments() const
466 return mAttachmentsList
->attachments();
469 void View::removeCurrentAttachment()
471 mAttachmentsList
->removeCurrentAttachment();
474 void View::editCurrentAttachment()
476 mAttachmentsList
->editCurrentAttachment();
479 void View::slotAttachmentSelectionChanged()
481 bool e
= !mAttachmentsList
->selectedItems().isEmpty();
482 mAttachmentRemoveButton
->setEnabled( e
);
483 mAttachmentPropertiesButton
->setEnabled( e
);
488 void View::showExternalNotification()
490 mEditorsStack
->setCurrentWidget( mExternalEditorNotification
);
494 void View::hideExternalNotification()
496 mEditorsStack
->setCurrentWidget( mEditor
);
500 } // namespace Composer