22 #include "signature.h"
26 #include <kmessagebox.h>
27 #include <kconfiggroup.h>
30 #include <KRichTextEdit>
31 #include <kpimutils/kfileio.h>
34 #include <QSharedPointer>
38 #include <QtCore/QDir>
39 #include <kpimtextedit/textedit.h>
41 using namespace KPIMIdentities;
43 class SignaturePrivate
55 typedef QSharedPointer<EmbeddedImage> EmbeddedImagePtr;
59 QList<EmbeddedImagePtr> embeddedImages;
66 QDataStream &operator<< ( QDataStream &stream,
const SignaturePrivate::EmbeddedImagePtr &img )
68 return stream << img->image << img->name;
71 QDataStream &operator>> ( QDataStream &stream, SignaturePrivate::EmbeddedImagePtr &img )
73 return stream >> img->image >> img->name;
79 typedef QHash<const Signature*,SignaturePrivate*> SigPrivateHash;
80 Q_GLOBAL_STATIC(SigPrivateHash, d_func)
82 static SignaturePrivate* d( const
Signature *sig )
84 SignaturePrivate *ret = d_func()->value( sig, 0 );
86 ret =
new SignaturePrivate;
87 d_func()->insert( sig, ret );
92 static void delete_d(
const Signature* sig )
94 SignaturePrivate *ret = d_func()->value( sig, 0 );
96 d_func()->remove( sig );
101 mInlinedHtml( false )
107 mInlinedHtml( false )
112 mType( isExecutable ? FromCommand : FromFile ),
113 mInlinedHtml( false )
119 mInlinedHtml = that.mInlinedHtml;
122 d(
this )->enabled = d( &that )->enabled;
123 d(
this )->saveLocation = d( &that )->saveLocation;
124 d(
this )->embeddedImages = d( &that )->embeddedImages;
160 return textFromFile( ok );
162 return textFromCommand( ok );
164 kFatal(5325) <<
"Signature::type() returned unknown value!";
168 QString Signature::textFromCommand(
bool *ok )
const
170 assert( mType == FromCommand );
173 if ( mUrl.isEmpty() ) {
182 proc.setOutputChannelMode( KProcess::SeparateChannels );
183 proc.setShellCommand( mUrl );
184 int rc = proc.execute();
191 QString wmsg = i18n(
"<qt>Failed to execute signature script<p><b>%1</b>:</p>"
192 "<p>%2</p></qt>", mUrl, QString( proc.readAllStandardError() ) );
193 KMessageBox::error( 0, wmsg );
203 QByteArray output = proc.readAllStandardOutput();
206 return QString::fromLocal8Bit( output.data(), output.size() );
209 QString Signature::textFromFile(
bool *ok )
const
211 assert( mType == FromFile );
214 if ( !KUrl( mUrl ).isLocalFile() &&
215 !( QFileInfo( mUrl ).isRelative() &&
216 QFileInfo( mUrl ).exists() ) ) {
217 kDebug(5325) <<
"Signature::textFromFile:"
218 <<
"non-local URLs are unsupported";
230 const QByteArray ba = KPIMUtils::kFileToByteArray( mUrl,
false );
231 return QString::fromLocal8Bit( ba.data(), ba.size() );
236 QString signature =
rawText( ok );
237 if ( ok && (*ok) ==
false )
240 if ( signature.isEmpty() ) {
244 const bool htmlSig = (
isInlinedHtml() && mType == Inlined );
245 QString newline = htmlSig ?
"<br>" :
"\n";
246 if ( htmlSig && signature.startsWith( QLatin1String(
"<p" ) ) ) {
250 if ( signature.startsWith( QString::fromLatin1(
"-- " ) + newline )
251 || ( signature.indexOf( newline + QString::fromLatin1(
"-- " ) +
252 newline ) != -1 ) ) {
257 return QString::fromLatin1(
"-- " ) + newline + signature;
264 mType = isExecutable ? FromCommand : FromFile;
269 mInlinedHtml = isHtml;
278 static const char sigTypeKey[] =
"Signature Type";
279 static const char sigTypeInlineValue[] =
"inline";
280 static const char sigTypeFileValue[] =
"file";
281 static const char sigTypeCommandValue[] =
"command";
282 static const char sigTypeDisabledValue[] =
"disabled";
283 static const char sigTextKey[] =
"Inline Signature";
284 static const char sigFileKey[] =
"Signature File";
285 static const char sigCommandKey[] =
"Signature Command";
286 static const char sigTypeInlinedHtmlKey[] =
"Inlined Html";
287 static const char sigImageLocation[] =
"Image Location";
288 static const char sigEnabled[] =
"Signature Enabled";
291 static QStringList findImageNames(
const QString &htmlCode )
296 KPIMTextEdit::TextEdit edit;
297 edit.setHtml( htmlCode );
298 foreach(
const KPIMTextEdit::ImageWithNamePtr &image, edit.imagesWithName() ) {
304 void Signature::cleanupImages()
const
308 foreach(
const SignaturePrivate::EmbeddedImagePtr &imageInList, d(
this )->embeddedImages ) {
310 foreach(
const QString &imageInHtml, findImageNames( mText ) ) {
311 if ( imageInHtml == imageInList->name ) {
317 d(
this )->embeddedImages.removeAll( imageInList );
322 if ( !d(
this )->saveLocation.isEmpty() ) {
323 QDir dir( d(
this )->saveLocation );
324 foreach(
const QString &fileName, dir.entryList( QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks ) ) {
325 if ( fileName.toLower().endsWith( QLatin1String(
".png" ) ) ) {
326 kDebug() <<
"Deleting old image" << dir.path() + fileName;
327 dir.remove( fileName );
333 void Signature::saveImages()
const
335 if (
isInlinedHtml() && !d(
this )->saveLocation.isEmpty() ) {
336 foreach(
const SignaturePrivate::EmbeddedImagePtr &image, d(
this )->embeddedImages ) {
337 QString location = d(
this )->saveLocation +
'/' + image->name;
338 if ( !image->image.save( location,
"PNG" ) ) {
339 kWarning() <<
"Failed to save image" << location;
345 void Signature::readConfig(
const KConfigGroup &config )
347 QString sigType = config.readEntry( sigTypeKey );
348 if ( sigType == sigTypeInlineValue ) {
350 mInlinedHtml = config.readEntry( sigTypeInlinedHtmlKey,
false );
351 }
else if ( sigType == sigTypeFileValue ) {
353 mUrl = config.readPathEntry( sigFileKey, QString() );
354 }
else if ( sigType == sigTypeCommandValue ) {
356 mUrl = config.readPathEntry( sigCommandKey, QString() );
357 }
else if ( sigType == sigTypeDisabledValue ) {
358 d(
this)->enabled =
false;
361 d(
this)->enabled = config.readEntry(sigEnabled,
true);
363 mText = config.readEntry( sigTextKey );
364 d(
this )->saveLocation = config.readEntry( sigImageLocation );
366 if (
isInlinedHtml() && !d(
this )->saveLocation.isEmpty() ) {
367 QDir dir( d(
this )->saveLocation );
368 foreach(
const QString &fileName, dir.entryList( QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks ) ) {
369 if ( fileName.toLower().endsWith( QLatin1String(
".png" ) ) ) {
371 if ( image.load( dir.path() +
'/' + fileName ) ) {
375 kWarning() <<
"Unable to load image" << dir.path() +
'/' + fileName;
382 void Signature::writeConfig( KConfigGroup &config )
const
386 config.writeEntry( sigTypeKey, sigTypeInlineValue );
387 config.writeEntry( sigTypeInlinedHtmlKey, mInlinedHtml );
390 config.writeEntry( sigTypeKey, sigTypeFileValue );
391 config.writePathEntry( sigFileKey, mUrl );
394 config.writeEntry( sigTypeKey, sigTypeCommandValue );
395 config.writePathEntry( sigCommandKey, mUrl );
400 config.writeEntry( sigTextKey, mText );
401 config.writeEntry( sigImageLocation, d(
this )->saveLocation );
402 config.writeEntry( sigEnabled, d(
this )->enabled );
408 static bool isCursorAtEndOfLine(
const QTextCursor &cursor )
410 QTextCursor testCursor = cursor;
411 testCursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor );
412 return !testCursor.hasSelection();
415 static void insertSignatureHelper(
const QString &signature,
416 KRichTextEdit *textEdit,
421 if ( !signature.isEmpty() ) {
425 bool isModified = textEdit->document()->isModified();
428 QTextCursor cursor = textEdit->textCursor();
429 QTextCursor oldCursor = cursor;
430 cursor.beginEditBlock();
433 cursor.movePosition( QTextCursor::End );
435 cursor.movePosition( QTextCursor::Start );
437 cursor.movePosition( QTextCursor::StartOfLine );
438 textEdit->setTextCursor( cursor );
444 lineSep = QLatin1String(
"<br>" );
446 lineSep = QLatin1Char(
'\n' );
450 bool hackForCursorsAtEnd =
false;
451 int oldCursorPos = -1;
454 if ( oldCursor.position() == textEdit->toPlainText().length() ) {
455 hackForCursorsAtEnd =
true;
456 oldCursorPos = oldCursor.position();
459 textEdit->insertHtml( lineSep + signature );
461 textEdit->insertPlainText( lineSep + signature );
465 if ( isCursorAtEndOfLine( cursor ) )
466 textEdit->insertHtml( signature );
468 textEdit->insertHtml( signature + lineSep );
470 if ( isCursorAtEndOfLine( cursor ) )
471 textEdit->insertPlainText( signature );
473 textEdit->insertPlainText( signature + lineSep );
477 cursor.endEditBlock();
484 if ( hackForCursorsAtEnd )
485 oldCursor.setPosition( oldCursorPos );
487 textEdit->setTextCursor( oldCursor );
488 textEdit->ensureCursorVisible();
490 textEdit->document()->setModified( isModified );
493 textEdit->enableRichTextMode();
501 if(!isEnabledSignature()) {
509 insertSignatureHelper( signature, textEdit, placement,
511 type() == KPIMIdentities::Signature::Inlined ),
516 KPIMTextEdit::TextEdit *textEdit )
const
518 insertSignatureText(placement,addedText, textEdit,
false);
522 KPIMTextEdit::TextEdit *textEdit,
bool forceDisplay )
const
524 insertSignatureText(placement,addedText, textEdit, forceDisplay);
527 void Signature::insertSignatureText(Placement placement, AddedText addedText, KPIMTextEdit::TextEdit *textEdit,
bool forceDisplay)
const
530 if(!isEnabledSignature()) {
539 insertSignatureHelper( signature, textEdit, placement,
541 type() == KPIMIdentities::Signature::Inlined ),
546 foreach(
const SignaturePrivate::EmbeddedImagePtr &image, d(
this )->embeddedImages ) {
547 textEdit->loadImage( image->image, image->name, image->name );
556 insertSignatureHelper( signature, textEdit, placement, isHtml,
true );
561 QDataStream &KPIMIdentities::operator<<
564 return stream << static_cast<quint8>( sig.mType ) << sig.mUrl << sig.mText
565 << d( &sig )->saveLocation << d( &sig )->embeddedImages<<d( &sig )->enabled;
568 QDataStream &KPIMIdentities::operator>>
572 stream >> s >> sig.mUrl >> sig.mText >> d( &sig )->saveLocation >> d( &sig )->embeddedImages >>d( &sig )->enabled;
579 if ( mType != other.mType ) {
583 if( d(
this )->enabled != d( &other )->enabled )
586 if ( mType == Inlined && mInlinedHtml ) {
587 if ( d(
this )->saveLocation != d( &other )->saveLocation )
589 if ( d(
this )->embeddedImages != d( &other )->embeddedImages )
595 return mText == other.mText;
598 return mUrl == other.mUrl;
611 QTextDocument helper;
612 QTextCursor helperCursor( &helper );
613 helperCursor.insertHtml( sigText );
614 sigText = helper.toPlainText();
621 Q_ASSERT( !( d(
this )->saveLocation.isEmpty() ) );
622 SignaturePrivate::EmbeddedImagePtr image(
new SignaturePrivate::EmbeddedImage() );
623 image->image = imageData;
624 image->name = imageName;
625 d(
this )->embeddedImages.append( image );
630 d(
this )->saveLocation = path;
635 QString Signature::text()
const
640 QString Signature::url()
const
658 void Signature::setType( Type type )
666 d(
this )->enabled = enabled;
669 bool Signature::isEnabledSignature()
const
671 return d(
this )->enabled;