22 #include "signature.h"
25 #include <klocalizedstring.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;
134 if (
this == &that ) {
161 return textFromFile( ok );
163 return textFromCommand( ok );
165 kFatal( 5325 ) <<
"Signature::type() returned unknown value!";
169 QString Signature::textFromCommand(
bool *ok )
const
171 assert( mType == FromCommand );
174 if ( mUrl.isEmpty() ) {
183 proc.setOutputChannelMode( KProcess::SeparateChannels );
184 proc.setShellCommand( mUrl );
185 int rc = proc.execute();
192 QString wmsg = i18n(
"<qt>Failed to execute signature script<p><b>%1</b>:</p>"
193 "<p>%2</p></qt>", mUrl, QLatin1String( proc.readAllStandardError() ) );
194 KMessageBox::error( 0, wmsg );
204 QByteArray output = proc.readAllStandardOutput();
207 return QString::fromLocal8Bit( output.data(), output.size() );
210 QString Signature::textFromFile(
bool *ok )
const
212 assert( mType == FromFile );
215 if ( !KUrl( mUrl ).isLocalFile() &&
216 !( QFileInfo( mUrl ).isRelative() &&
217 QFileInfo( mUrl ).exists() ) ) {
218 kDebug( 5325 ) <<
"Signature::textFromFile:"
219 <<
"non-local URLs are unsupported";
231 const QByteArray ba = KPIMUtils::kFileToByteArray( mUrl,
false );
232 return QString::fromLocal8Bit( ba.data(), ba.size() );
237 QString signature =
rawText( ok );
238 if ( ok && ( *ok ) ==
false ) {
242 if ( signature.isEmpty() ) {
246 const bool htmlSig = (
isInlinedHtml() && mType == Inlined );
247 QString newline = htmlSig ? QLatin1String(
"<br>") : QLatin1String(
"\n");
248 if ( htmlSig && signature.startsWith( QLatin1String(
"<p" ) ) ) {
252 if ( signature.startsWith( QString::fromLatin1(
"-- " ) + newline ) ||
253 ( signature.indexOf( newline + QString::fromLatin1(
"-- " ) + newline ) != -1 ) ) {
258 return QString::fromLatin1(
"-- " ) + newline + signature;
265 mType = isExecutable ? FromCommand : FromFile;
270 mInlinedHtml = isHtml;
279 static const char sigTypeKey[] =
"Signature Type";
280 static const char sigTypeInlineValue[] =
"inline";
281 static const char sigTypeFileValue[] =
"file";
282 static const char sigTypeCommandValue[] =
"command";
283 static const char sigTypeDisabledValue[] =
"disabled";
284 static const char sigTextKey[] =
"Inline Signature";
285 static const char sigFileKey[] =
"Signature File";
286 static const char sigCommandKey[] =
"Signature Command";
287 static const char sigTypeInlinedHtmlKey[] =
"Inlined Html";
288 static const char sigImageLocation[] =
"Image Location";
289 static const char sigEnabled[] =
"Signature Enabled";
292 static QStringList findImageNames(
const QString &htmlCode )
297 KPIMTextEdit::TextEdit edit;
298 edit.setHtml( htmlCode );
299 foreach (
const KPIMTextEdit::ImageWithNamePtr &image, edit.imagesWithName() ) {
305 void Signature::cleanupImages()
const
309 foreach (
const SignaturePrivate::EmbeddedImagePtr &imageInList, d(
this )->embeddedImages ) {
311 foreach (
const QString &imageInHtml, findImageNames( mText ) ) {
312 if ( imageInHtml == imageInList->name ) {
318 d(
this )->embeddedImages.removeAll( imageInList );
324 if ( !d(
this )->saveLocation.isEmpty() ) {
325 QDir dir( d(
this )->saveLocation );
326 foreach (
const QString &fileName, dir.entryList( QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks ) ) {
327 if ( fileName.toLower().endsWith( QLatin1String(
".png" ) ) ) {
328 kDebug() <<
"Deleting old image" << dir.path() + fileName;
329 dir.remove( fileName );
335 void Signature::saveImages()
const
337 if (
isInlinedHtml() && !d(
this )->saveLocation.isEmpty() ) {
338 foreach (
const SignaturePrivate::EmbeddedImagePtr &image, d(
this )->embeddedImages ) {
339 QString location = d(
this )->saveLocation + QLatin1Char(
'/') + image->name;
340 if ( !image->image.save( location,
"PNG" ) ) {
341 kWarning() <<
"Failed to save image" << location;
347 void Signature::readConfig(
const KConfigGroup &config )
349 QString sigType = config.readEntry( sigTypeKey );
350 if ( sigType == QLatin1String(sigTypeInlineValue) ) {
352 mInlinedHtml = config.readEntry( sigTypeInlinedHtmlKey,
false );
353 }
else if ( sigType == QLatin1String(sigTypeFileValue) ) {
355 mUrl = config.readPathEntry( sigFileKey, QString() );
356 }
else if ( sigType == QLatin1String(sigTypeCommandValue) ) {
358 mUrl = config.readPathEntry( sigCommandKey, QString() );
359 }
else if ( sigType == QLatin1String(sigTypeDisabledValue) ) {
360 d(
this )->enabled =
false;
362 if ( mType != Disabled ) {
363 d(
this )->enabled = config.readEntry( sigEnabled,
true );
366 mText = config.readEntry( sigTextKey );
367 d(
this )->saveLocation = config.readEntry( sigImageLocation );
369 if (
isInlinedHtml() && !d(
this )->saveLocation.isEmpty() ) {
370 QDir dir( d(
this )->saveLocation );
371 foreach (
const QString &fileName, dir.entryList( QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks ) ) {
372 if ( fileName.toLower().endsWith( QLatin1String(
".png" ) ) ) {
374 if ( image.load( dir.path() + QLatin1Char(
'/') + fileName ) ) {
378 kWarning() <<
"Unable to load image" << dir.path() + QLatin1Char(
'/') + fileName;
385 void Signature::writeConfig( KConfigGroup &config )
const
389 config.writeEntry( sigTypeKey, sigTypeInlineValue );
390 config.writeEntry( sigTypeInlinedHtmlKey, mInlinedHtml );
393 config.writeEntry( sigTypeKey, sigTypeFileValue );
394 config.writePathEntry( sigFileKey, mUrl );
397 config.writeEntry( sigTypeKey, sigTypeCommandValue );
398 config.writePathEntry( sigCommandKey, mUrl );
403 config.writeEntry( sigTextKey, mText );
404 config.writeEntry( sigImageLocation, d(
this )->saveLocation );
405 config.writeEntry( sigEnabled, d(
this )->enabled );
411 static bool isCursorAtEndOfLine(
const QTextCursor &cursor )
413 QTextCursor testCursor = cursor;
414 testCursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor );
415 return !testCursor.hasSelection();
418 static void insertSignatureHelper(
const QString &signature,
419 KRichTextEdit *textEdit,
424 if ( !signature.isEmpty() ) {
428 bool isModified = textEdit->document()->isModified();
431 QTextCursor cursor = textEdit->textCursor();
432 QTextCursor oldCursor = cursor;
433 cursor.beginEditBlock();
436 cursor.movePosition( QTextCursor::End );
438 cursor.movePosition( QTextCursor::Start );
440 cursor.movePosition( QTextCursor::StartOfLine );
442 textEdit->setTextCursor( cursor );
448 lineSep = QLatin1String(
"<br>" );
450 lineSep = QLatin1Char(
'\n' );
455 bool hackForCursorsAtEnd =
false;
456 int oldCursorPos = -1;
459 if ( oldCursor.position() == textEdit->toPlainText().length() ) {
460 hackForCursorsAtEnd =
true;
461 oldCursorPos = oldCursor.position();
464 textEdit->insertHtml( lineSep + signature );
466 textEdit->insertPlainText( lineSep + signature );
470 if ( isCursorAtEndOfLine( cursor ) ) {
471 textEdit->insertHtml( signature );
473 textEdit->insertHtml( signature + lineSep );
476 if ( isCursorAtEndOfLine( cursor ) ) {
477 textEdit->insertPlainText( signature );
479 textEdit->insertPlainText( signature + lineSep );
484 cursor.endEditBlock();
491 if ( hackForCursorsAtEnd ) {
492 oldCursor.setPosition( oldCursorPos );
495 textEdit->setTextCursor( oldCursor );
496 textEdit->ensureCursorVisible();
498 textEdit->document()->setModified( isModified );
501 textEdit->enableRichTextMode();
509 if ( !isEnabledSignature() ) {
513 if ( addSeparator ) {
518 insertSignatureHelper( signature, textEdit, placement,
520 type() == KPIMIdentities::Signature::Inlined ),
525 KPIMTextEdit::TextEdit *textEdit )
const
527 insertSignatureText( placement, addedText, textEdit,
false );
531 KPIMTextEdit::TextEdit *textEdit,
bool forceDisplay )
const
533 insertSignatureText( placement, addedText, textEdit, forceDisplay );
536 void Signature::insertSignatureText(Placement placement, AddedText addedText, KPIMTextEdit::TextEdit *textEdit,
bool forceDisplay)
const
538 if ( !forceDisplay ) {
539 if ( !isEnabledSignature() ) {
549 insertSignatureHelper( signature, textEdit, placement,
551 type() == KPIMIdentities::Signature::Inlined ),
556 foreach (
const SignaturePrivate::EmbeddedImagePtr &image, d(
this )->embeddedImages ) {
557 textEdit->loadImage( image->image, image->name, image->name );
566 insertSignatureHelper( signature, textEdit, placement, isHtml,
true );
571 QDataStream &KPIMIdentities::operator<<
574 return stream << static_cast<quint8>( sig.mType ) << sig.mUrl << sig.mText
575 << d( &sig )->saveLocation << d( &sig )->embeddedImages << d( &sig )->enabled;
578 QDataStream &KPIMIdentities::operator>>
582 stream >> s >> sig.mUrl >> sig.mText >> d( &sig )->saveLocation >> d( &sig )->embeddedImages >>d( &sig )->enabled;
589 if ( mType != other.mType ) {
593 if ( d(
this )->enabled != d( &other )->enabled ) {
597 if ( mType == Inlined && mInlinedHtml ) {
598 if ( d(
this )->saveLocation != d( &other )->saveLocation ) {
601 if ( d(
this )->embeddedImages != d( &other )->embeddedImages ) {
608 return mText == other.mText;
611 return mUrl == other.mUrl;
624 QTextDocument helper;
625 QTextCursor helperCursor( &helper );
626 helperCursor.insertHtml( sigText );
627 sigText = helper.toPlainText();
634 Q_ASSERT( !( d(
this )->saveLocation.isEmpty() ) );
635 SignaturePrivate::EmbeddedImagePtr image(
new SignaturePrivate::EmbeddedImage() );
636 image->image = imageData;
637 image->name = imageName;
638 d(
this )->embeddedImages.append( image );
643 d(
this )->saveLocation = path;
648 QString Signature::text()
const
653 QString Signature::url()
const
671 void Signature::setType( Type type )
679 d(
this )->enabled = enabled;
682 bool Signature::isEnabledSignature()
const
684 return d(
this )->enabled;
The signature is placed at the current cursor position.
QFlags< AddedTextFlag > AddedText
Describes which additional parts should be added to the signature.
Add a newline character in front or after the signature, depending on the placement.
The signature is placed at the start of the textedit.
void KPIMIDENTITIES_DEPRECATED insertIntoTextEdit(KRichTextEdit *textEdit, Placement placement=End, bool addSeparator=true)
void setText(const QString &text)
Set the signature text and mark this signature as being of "inline text" type.
Signature()
Constructor for disabled signature.
void setImageLocation(const QString &path)
Sets the location where the copies of the signature images will be stored.
QString rawText(bool *ok=0) const
void setEnabledSignature(bool enabled)
setEnabledSignature
bool isInlinedHtml() const
void setInlinedHtml(bool isHtml)
Sets the inlined signature to text or html.
Signature & operator=(const Signature &that)
Assignment operator.
Abstraction of a signature (aka "footer").
The signature is placed at the end of the textedit.
static void KPIMIDENTITIES_DEPRECATED insertPlainSignatureIntoTextEdit(const QString &signature, KRichTextEdit *textEdit, Placement placement=End, bool isHtml=false)
Inserts this given signature into the given text edit.
The separator '– ' will be added in front of the signature.
Type
Type of signature (ie.
QString toPlainText() const
Returns the text of the signature.
QString withSeparator(bool *ok=0) const
bool operator==(const Signature &other) const
Used for comparison.
void setUrl(const QString &url, bool isExecutable=false)
Set the signature URL and mark this signature as being of "from file" resp.
void addImage(const QImage &image, const QString &imageName)
Adds the given image to the signature.
Placement
Describes the placement of the signature text when it is to be inserted into a text edit...