/* -*- c++ -*- Copyright 2008 Thomas McGuire Copyright 2008 Edwin Schepers Copyright 2004 Marc Mutz This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "signatureconfigurator.h" #include "identity.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KPIMIdentities; namespace KPIMIdentities { /** Private class that helps to provide binary compatibility between releases. @internal */ //@cond PRIVATE class SignatureConfigurator::Private { public: Private( SignatureConfigurator *parent ); void init(); SignatureConfigurator *q; bool inlinedHtml; QString imageLocation; }; //@endcond SignatureConfigurator::Private::Private( SignatureConfigurator *parent ) :q( parent ), inlinedHtml( true ) { } void SignatureConfigurator::Private::init() { // tmp. vars: QLabel * label; QWidget * page; QHBoxLayout * hlay; QVBoxLayout * vlay; QVBoxLayout * page_vlay; vlay = new QVBoxLayout( q ); vlay->setObjectName( QLatin1String("main layout") ); vlay->setMargin( 0 ); // "enable signatue" checkbox: q->mEnableCheck = new QCheckBox( i18n( "&Enable signature" ), q ); q->mEnableCheck->setWhatsThis( i18n( "Check this box if you want KMail to append a signature to mails " "written with this identity." ) ); vlay->addWidget( q->mEnableCheck ); // "obtain signature text from" combo and label: hlay = new QHBoxLayout(); // inherits spacing vlay->addLayout( hlay ); q->mSourceCombo = new KComboBox( q ); q->mSourceCombo->setEditable( false ); q->mSourceCombo->setWhatsThis( i18n( "Click on the widgets below to obtain help on the input methods." ) ); q->mSourceCombo->setEnabled( false ); // since !mEnableCheck->isChecked() q->mSourceCombo->addItems( QStringList() << i18nc( "continuation of \"obtain signature text from\"", "Input Field Below" ) << i18nc( "continuation of \"obtain signature text from\"", "File" ) << i18nc( "continuation of \"obtain signature text from\"", "Output of Command" ) ); label = new QLabel( i18n( "Obtain signature &text from:" ), q ); label->setBuddy( q->mSourceCombo ); label->setEnabled( false ); // since !mEnableCheck->isChecked() hlay->addWidget( label ); hlay->addWidget( q->mSourceCombo, 1 ); // widget stack that is controlled by the source combo: QStackedWidget * widgetStack = new QStackedWidget( q ); widgetStack->setEnabled( false ); // since !mEnableCheck->isChecked() vlay->addWidget( widgetStack, 1 ); q->connect( q->mSourceCombo, SIGNAL(currentIndexChanged(int)), widgetStack, SLOT(setCurrentIndex(int)) ); q->connect( q->mSourceCombo, SIGNAL(highlighted(int)), widgetStack, SLOT(setCurrentIndex(int)) ); // connects for the enabling of the widgets depending on // signatureEnabled: q->connect( q->mEnableCheck, SIGNAL(toggled(bool)), q->mSourceCombo, SLOT(setEnabled(bool)) ); q->connect( q->mEnableCheck, SIGNAL(toggled(bool)), widgetStack, SLOT(setEnabled(bool)) ); q->connect( q->mEnableCheck, SIGNAL(toggled(bool)), label, SLOT(setEnabled(bool)) ); // The focus might be still in the widget that is disabled q->connect( q->mEnableCheck, SIGNAL(clicked()), q->mEnableCheck, SLOT(setFocus()) ); int pageno = 0; // page 0: input field for direct entering: page = new QWidget( widgetStack ); widgetStack->insertWidget( pageno, page ); page_vlay = new QVBoxLayout( page ); #ifndef QT_NO_TOOLBAR q->mEditToolBar = new KToolBar( q ); q->mEditToolBar->setToolButtonStyle( Qt::ToolButtonIconOnly ); page_vlay->addWidget( q->mEditToolBar, 0 ); q->mFormatToolBar = new KToolBar( q ); q->mFormatToolBar->setToolButtonStyle( Qt::ToolButtonIconOnly ); page_vlay->addWidget( q->mFormatToolBar, 1 ); #endif q->mTextEdit = new KPIMTextEdit::TextEdit( q ); static_cast( q->mTextEdit )->enableImageActions(); static_cast( q->mTextEdit )->enableInsertHtmlActions(); static_cast( q->mTextEdit )->enableInsertTableActions(); page_vlay->addWidget( q->mTextEdit, 2 ); q->mTextEdit->setWhatsThis( i18n( "Use this field to enter an arbitrary static signature." ) ); // exclude SupportToPlainText. q->mTextEdit->setRichTextSupport( KRichTextWidget::FullTextFormattingSupport | KRichTextWidget::FullListSupport | KRichTextWidget::SupportAlignment | KRichTextWidget::SupportRuleLine | KRichTextWidget::SupportHyperlinks | KRichTextWidget::SupportFormatPainting ); // Fill the toolbars. KActionCollection *actionCollection = new KActionCollection( q ); q->mTextEdit->createActions( actionCollection ); #ifndef QT_NO_TOOLBAR q->mEditToolBar->addAction( actionCollection->action( QLatin1String("format_text_bold") ) ); q->mEditToolBar->addAction( actionCollection->action( QLatin1String("format_text_italic") ) ); q->mEditToolBar->addAction( actionCollection->action( QLatin1String("format_text_underline") ) ); q->mEditToolBar->addAction( actionCollection->action( QLatin1String("format_text_strikeout") ) ); q->mEditToolBar->addAction( actionCollection->action( QLatin1String("format_text_foreground_color") ) ); q->mEditToolBar->addAction( actionCollection->action( QLatin1String("format_text_background_color") ) ); q->mEditToolBar->addAction( actionCollection->action( QLatin1String("format_font_family") ) ); q->mEditToolBar->addAction( actionCollection->action( QLatin1String("format_font_size") ) ); q->mEditToolBar->addAction( actionCollection->action( QLatin1String("format_reset") ) ); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("format_list_style") ) ); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("format_list_indent_more") ) ); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("format_list_indent_less") ) ); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("format_list_indent_less") ) ); q->mFormatToolBar->addSeparator(); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("format_align_left") ) ); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("format_align_center") ) ); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("format_align_right") ) ); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("format_align_justify") ) ); q->mFormatToolBar->addSeparator(); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("insert_horizontal_rule") ) ); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("manage_link") ) ); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("format_painter") ) ); q->mFormatToolBar->addSeparator(); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("add_image") ) ); q->mFormatToolBar->addSeparator(); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("insert_html") ) ); q->mFormatToolBar->addAction( actionCollection->action( QLatin1String("insert_table" )) ); #endif hlay = new QHBoxLayout(); // inherits spacing page_vlay->addLayout( hlay ); q->mHtmlCheck = new QCheckBox( i18n( "&Use HTML" ), page ); q->connect( q->mHtmlCheck, SIGNAL(clicked()), q, SLOT(slotSetHtml()) ); hlay->addWidget( q->mHtmlCheck ); inlinedHtml = true; widgetStack->setCurrentIndex( 0 ); // since mSourceCombo->currentItem() == 0 // page 1: "signature file" requester, label, "edit file" button: ++pageno; page = new QWidget( widgetStack ); widgetStack->insertWidget( pageno, page ); // force sequential numbers (play safe) page_vlay = new QVBoxLayout( page ); page_vlay->setMargin( 0 ); hlay = new QHBoxLayout(); // inherits spacing page_vlay->addLayout( hlay ); q->mFileRequester = new KUrlRequester( page ); q->mFileRequester->setWhatsThis( i18n( "Use this requester to specify a text file that contains your " "signature. It will be read every time you create a new mail or " "append a new signature." ) ); label = new QLabel( i18n( "S&pecify file:" ), page ); label->setBuddy( q->mFileRequester ); hlay->addWidget( label ); hlay->addWidget( q->mFileRequester, 1 ); q->mFileRequester->button()->setAutoDefault( false ); q->connect( q->mFileRequester, SIGNAL(textChanged(QString)), q, SLOT(slotEnableEditButton(QString)) ); q->mEditButton = new QPushButton( i18n( "Edit &File" ), page ); q->mEditButton->setWhatsThis( i18n( "Opens the specified file in a text editor." ) ); q->connect( q->mEditButton, SIGNAL(clicked()), q, SLOT(slotEdit()) ); q->mEditButton->setAutoDefault( false ); q->mEditButton->setEnabled( false ); // initially nothing to edit hlay->addWidget( q->mEditButton ); page_vlay->addStretch( 1 ); // spacer // page 2: "signature command" requester and label: ++pageno; page = new QWidget( widgetStack ); widgetStack->insertWidget( pageno, page ); page_vlay = new QVBoxLayout( page ); page_vlay->setMargin( 0 ); hlay = new QHBoxLayout(); // inherits spacing page_vlay->addLayout( hlay ); q->mCommandEdit = new KLineEdit( page ); q->mCommandEdit->setClearButtonShown( true ); q->mCommandEdit->setCompletionObject( new KShellCompletion() ); q->mCommandEdit->setAutoDeleteCompletionObject( true ); q->mCommandEdit->setWhatsThis( i18n( "You can add an arbitrary command here, either with or without path " "depending on whether or not the command is in your Path. For every " "new mail, KMail will execute the command and use what it outputs (to " "standard output) as a signature. Usual commands for use with this " "mechanism are \"fortune\" or \"ksig -random\"." ) ); label = new QLabel( i18n( "S&pecify command:" ), page ); label->setBuddy( q->mCommandEdit ); hlay->addWidget( label ); hlay->addWidget( q->mCommandEdit, 1 ); page_vlay->addStretch( 1 ); // spacer } SignatureConfigurator::SignatureConfigurator( QWidget * parent ) : QWidget( parent ), d( new Private( this ) ) { d->init(); } SignatureConfigurator::~SignatureConfigurator() { delete d; } bool SignatureConfigurator::isSignatureEnabled() const { return mEnableCheck->isChecked(); } void SignatureConfigurator::setSignatureEnabled( bool enable ) { mEnableCheck->setChecked( enable ); } Signature::Type SignatureConfigurator::signatureType() const { switch ( mSourceCombo->currentIndex() ) { case 0: return Signature::Inlined; case 1: return Signature::FromFile; case 2: return Signature::FromCommand; default: return Signature::Disabled; } } void SignatureConfigurator::setSignatureType( Signature::Type type ) { int idx = 0; switch ( type ) { case Signature::Inlined: idx = 0; break; case Signature::FromFile: idx = 1; break; case Signature::FromCommand: idx = 2; break; default: idx = 0; break; }; mSourceCombo->setCurrentIndex( idx ); } void SignatureConfigurator::setInlineText( const QString & text ) { mTextEdit->setTextOrHtml( text ); } QString SignatureConfigurator::fileURL() const { QString file = mFileRequester->url().path(); // Force the filename to be relative to ~ instead of $PWD depending // on the rest of the code (KRun::run in Edit and KFileItem on save) if ( !file.isEmpty() && QFileInfo( file ).isRelative() ) { file = QDir::home().absolutePath() + QDir::separator() + file; } return file; } void SignatureConfigurator::setFileURL( const QString & url ) { mFileRequester->setUrl( QUrl(url) ); } QString SignatureConfigurator::commandURL() const { return mCommandEdit->text(); } void SignatureConfigurator::setCommandURL( const QString & url ) { mCommandEdit->setText( url ); } Signature SignatureConfigurator::signature() const { Signature sig; const Signature::Type sigType = signatureType(); switch ( sigType ) { case Signature::Inlined: sig.setInlinedHtml( d->inlinedHtml ); sig.setText( d->inlinedHtml ? asCleanedHTML() : mTextEdit->textOrHtml() ); if ( d->inlinedHtml ) { if ( !d->imageLocation.isEmpty() ) { sig.setImageLocation( d->imageLocation ); } KPIMTextEdit::ImageWithNameList images = static_cast< KPIMTextEdit::TextEdit*>( mTextEdit )->imagesWithName(); foreach ( const KPIMTextEdit::ImageWithNamePtr &image, images ) { sig.addImage( image->image, image->name ); } } break; case Signature::FromCommand: sig.setUrl( commandURL(), true ); break; case Signature::FromFile: sig.setUrl( fileURL(), false ); break; case Signature::Disabled: /* do nothing */ break; } sig.setEnabledSignature( isSignatureEnabled() ); sig.setType( sigType ); return sig; } void SignatureConfigurator::setSignature( const Signature & sig ) { setSignatureType( sig.type() ); setSignatureEnabled( sig.isEnabledSignature() ); if ( sig.isInlinedHtml() ) { mHtmlCheck->setCheckState( Qt::Checked ); } else { mHtmlCheck->setCheckState( Qt::Unchecked ); } slotSetHtml(); // Let insertIntoTextEdit() handle setting the text, as that function also adds the images. mTextEdit->clear(); KPIMTextEdit::TextEdit * const pimEdit = static_cast( mTextEdit ); sig.insertIntoTextEdit( KPIMIdentities::Signature::Start, KPIMIdentities::Signature::AddNothing, pimEdit, true ); if ( sig.type() == Signature::FromFile ) { setFileURL( sig.url() ); } else { setFileURL( QString() ); } if ( sig.type() == Signature::FromCommand ) { setCommandURL( sig.url() ); } else { setCommandURL( QString() ); } } void SignatureConfigurator::slotEnableEditButton( const QString & url ) { mEditButton->setDisabled( url.trimmed().isEmpty() ); } void SignatureConfigurator::slotEdit() { QString url = fileURL(); // slotEnableEditButton should prevent this assert from being hit: assert( !url.isEmpty() ); (void)KRun::runUrl( KUrl( url ), QString::fromLatin1( "text/plain" ), this ); } QString SignatureConfigurator::asCleanedHTML() const { QString text = mTextEdit->toHtml(); // Beautiful little hack to find the html headers produced by Qt. QTextDocument textDocument; QString html = textDocument.toHtml(); // Now remove each line from the text, the result is clean html. foreach ( const QString& line, html.split( QLatin1Char('\n') ) ) { text.remove( line + QLatin1Char('\n') ); } return text; } // "use HTML"-checkbox (un)checked void SignatureConfigurator::slotSetHtml() { if ( mHtmlCheck->checkState() == Qt::Unchecked ) { mHtmlCheck->setText( i18n( "&Use HTML" ) ); #ifndef QT_NO_TOOLBAR mEditToolBar->setVisible( false ); mEditToolBar->setEnabled( false ); mFormatToolBar->setVisible( false ); mFormatToolBar->setEnabled( false ); #endif mTextEdit->switchToPlainText(); d->inlinedHtml = false; } else { mHtmlCheck->setText( i18n( "&Use HTML (disabling removes formatting)" ) ); d->inlinedHtml = true; #ifndef QT_NO_TOOLBAR mEditToolBar->setVisible( true ); mEditToolBar->setEnabled( true ); mFormatToolBar->setVisible( true ); mFormatToolBar->setEnabled( true ); #endif mTextEdit->enableRichTextMode(); } } void SignatureConfigurator::setImageLocation ( const QString& path ) { d->imageLocation = path; } void SignatureConfigurator::setImageLocation( const Identity &identity ) { const QString dir = QString::fromLatin1( "emailidentities/%1/" ).arg( QString::number( identity.uoid() ) ); setImageLocation( KStandardDirs::locateLocal( "data", dir ) ); } }