You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
327 lines
10 KiB
327 lines
10 KiB
/** |
|
* kmcomposereditor.cpp |
|
* |
|
* Copyright (C) 2007, 2008 Laurent Montel <montel@kde.org> |
|
* |
|
* 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, write to the Free Software |
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
* 02110-1301 USA |
|
*/ |
|
|
|
#include "kmcomposereditor.h" |
|
#include "kmcomposewin.h" |
|
#include "kemailquotinghighter.h" |
|
#include "kmcommands.h" |
|
#include "kmmsgdict.h" |
|
#include "kmfolder.h" |
|
#include "maillistdrag.h" |
|
|
|
#include <kmime/kmime_codecs.h> |
|
|
|
#include <KAction> |
|
#include <KActionCollection> |
|
#include <KFileDialog> |
|
#include <klocale.h> |
|
#include <kmenu.h> |
|
#include <kmessagebox.h> |
|
#include <KPushButton> |
|
|
|
#include <QBuffer> |
|
#include <QClipboard> |
|
#include <QDropEvent> |
|
#include <QFileInfo> |
|
|
|
KMComposerEditor::KMComposerEditor( KMComposeWin *win,QWidget *parent) |
|
:KMeditor(parent),m_composerWin(win) |
|
{ |
|
} |
|
|
|
KMComposerEditor::~KMComposerEditor() |
|
{ |
|
} |
|
|
|
void KMComposerEditor::createActions( KActionCollection *actionCollection ) |
|
{ |
|
KMeditor::createActions( actionCollection ); |
|
|
|
actionAddImage = new KAction( KIcon( "insert-image" ), i18n("Add Image"), this ); |
|
actionCollection->addAction( "add_image", actionAddImage ); |
|
connect( actionAddImage, SIGNAL(triggered(bool) ), SLOT( slotAddImage() ) ); |
|
|
|
mPasteQuotation = new KAction( i18n("Pa&ste as Quotation"), this ); |
|
actionCollection->addAction("paste_quoted", mPasteQuotation ); |
|
connect( mPasteQuotation, SIGNAL(triggered(bool) ), this, SLOT( slotPasteAsQuotation()) ); |
|
|
|
mAddQuoteChars = new KAction( i18n("Add &Quote Characters"), this ); |
|
actionCollection->addAction( "tools_quote", mAddQuoteChars ); |
|
connect( mAddQuoteChars, SIGNAL(triggered(bool) ), this, SLOT(slotAddQuotes()) ); |
|
|
|
mRemQuoteChars = new KAction( i18n("Re&move Quote Characters"), this ); |
|
actionCollection->addAction( "tools_unquote", mRemQuoteChars ); |
|
connect (mRemQuoteChars, SIGNAL(triggered(bool) ), this, SLOT(slotRemoveQuotes()) ); |
|
} |
|
|
|
void KMComposerEditor::changeHighlighterColors(KPIM::KEMailQuotingHighlighter * highlighter) |
|
{ |
|
// defaults from kmreaderwin.cpp. FIXME: centralize somewhere. |
|
QColor color1( 0x00, 0x80, 0x00 ); |
|
QColor color2( 0x00, 0x70, 0x00 ); |
|
QColor color3( 0x00, 0x60, 0x00 ); |
|
QColor misspelled = Qt::red; |
|
|
|
if ( !GlobalSettings::self()->useDefaultColors() ) { |
|
KConfigGroup readerConfig( KMKernel::config(), "Reader" ); |
|
color3 = readerConfig.readEntry( "QuotedText3", color3 ); |
|
color2 = readerConfig.readEntry( "QuotedText2", color2 ); |
|
color1 = readerConfig.readEntry( "QuotedText1", color1 ); |
|
misspelled = readerConfig.readEntry( "MisspelledColor", misspelled ); |
|
} |
|
|
|
highlighter->setQuoteColor( Qt::black /* ignored anyway */, |
|
color3, color2, color1, misspelled ); |
|
} |
|
|
|
QString KMComposerEditor::smartQuote( const QString & msg ) |
|
{ |
|
return m_composerWin->smartQuote( msg ); |
|
} |
|
|
|
QString KMComposerEditor::quotePrefixName() const |
|
{ |
|
if ( !m_quotePrefix.simplified().isEmpty() ) |
|
return m_quotePrefix; |
|
else |
|
return ">"; |
|
} |
|
|
|
void KMComposerEditor::setQuotePrefixName( const QString "ePrefix ) |
|
{ |
|
m_quotePrefix = quotePrefix; |
|
} |
|
|
|
void KMComposerEditor::replaceUnknownChars( const QTextCodec *codec ) |
|
{ |
|
QTextCursor cursor( document() ); |
|
cursor.beginEditBlock(); |
|
while ( !cursor.atEnd() ) { |
|
cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor ); |
|
QChar cur = cursor.selectedText().at( 0 ); |
|
if ( !codec->canEncode( cur ) ) { |
|
cursor.insertText( "?" ); |
|
} |
|
else { |
|
cursor.clearSelection(); |
|
} |
|
} |
|
cursor.endEditBlock(); |
|
} |
|
|
|
void KMComposerEditor::dropEvent( QDropEvent *e ) |
|
{ |
|
const QMimeData *md = e->mimeData(); |
|
if ( !md ) |
|
return; |
|
|
|
// If this is a list of mails, attach those mails as forwards. |
|
if ( KPIM::MailList::canDecode( md ) ) { |
|
e->accept(); |
|
// Decode the list of serial numbers stored as the drag data |
|
QByteArray serNums = KPIM::MailList::serialsFromMimeData( md ); |
|
QBuffer serNumBuffer( &serNums ); |
|
serNumBuffer.open( QIODevice::ReadOnly ); |
|
QDataStream serNumStream( &serNumBuffer ); |
|
quint32 serNum; |
|
KMFolder *folder = 0; |
|
int idx; |
|
QList<KMMsgBase*> messageList; |
|
while ( !serNumStream.atEnd() ) { |
|
KMMsgBase *msgBase = 0; |
|
serNumStream >> serNum; |
|
KMMsgDict::instance()->getLocation( serNum, &folder, &idx ); |
|
if ( folder ) { |
|
msgBase = folder->getMsgBase( idx ); |
|
} |
|
if ( msgBase ) { |
|
messageList.append( msgBase ); |
|
} |
|
} |
|
serNumBuffer.close(); |
|
uint identity = folder ? folder->identity() : 0; |
|
KMCommand *command = new KMForwardAttachedCommand( m_composerWin, messageList, |
|
identity, m_composerWin ); |
|
command->start(); |
|
return; |
|
} |
|
|
|
// If this is a PNG image, paste it. |
|
if ( md->hasFormat( "image/png" ) ) { |
|
if ( canInsertFromMimeData( md ) ) { |
|
insertFromMimeData( md ); |
|
return; |
|
} |
|
} |
|
|
|
// If this is a URL list, add those files as attachments |
|
KUrl::List urlList = KUrl::List::fromMimeData( md ); |
|
if ( !urlList.isEmpty() ) { |
|
e->accept(); |
|
foreach( const KUrl &url, urlList ) { |
|
m_composerWin->addAttach( url ); |
|
} |
|
return; |
|
} |
|
|
|
// If this is normal text, paste the text |
|
if ( md->hasText() ) { |
|
KMeditor::dropEvent( e ); |
|
e->accept(); |
|
return; |
|
} |
|
|
|
kDebug() << "Unable to add dropped object"; |
|
return KMeditor::dropEvent( e ); |
|
} |
|
|
|
void KMComposerEditor::paste() |
|
{ |
|
const QMimeData *md = QApplication::clipboard()->mimeData(); |
|
if ( md && canInsertFromMimeData( md ) ) |
|
insertFromMimeData( md ); |
|
} |
|
|
|
bool KMComposerEditor::canInsertFromMimeData( const QMimeData *source ) const |
|
{ |
|
if ( source->hasFormat( "text/x-kmail-textsnippet" ) ) |
|
return true; |
|
if ( textMode() == KRichTextEdit::Rich && source->hasImage() ) |
|
return true; |
|
return KMeditor::canInsertFromMimeData( source ); |
|
} |
|
|
|
void KMComposerEditor::insertFromMimeData( const QMimeData *source ) |
|
{ |
|
if ( source->hasFormat( "text/x-kmail-textsnippet" ) ) |
|
emit insertSnippet(); |
|
if ( textMode() == KRichTextEdit::Rich && source->hasImage() ) |
|
{ |
|
QImage image = qvariant_cast<QImage>( source->imageData() ); |
|
QFileInfo fi( source->text() ); |
|
QString imageName = fi.baseName().isEmpty() ? "image" : fi.baseName(); |
|
addImageHelper( imageName, image ); |
|
return; |
|
} |
|
KMeditor::insertFromMimeData( source ); |
|
} |
|
|
|
void KMComposerEditor::addImage( const KUrl &url ) |
|
{ |
|
QImage image; |
|
if ( !image.load( url.path() ) ) { |
|
KMessageBox::error( this, |
|
i18nc( "@info", "Unable to load image <filename>%1</filename>.", url.path() ) ); |
|
return; |
|
} |
|
QFileInfo fi( url.path() ); |
|
QString imageName = fi.baseName().isEmpty() ? "image.png" : fi.baseName() + ".png"; |
|
addImageHelper( imageName, image ); |
|
} |
|
|
|
void KMComposerEditor::addImageHelper( const QString &imageName, const QImage &image ) |
|
{ |
|
QString imageNameToAdd = imageName; |
|
QTextDocument *document = this->document(); |
|
|
|
// determine the imageNameToAdd |
|
int imageNumber = 1; |
|
while ( mImageNames.contains( imageNameToAdd ) ) { |
|
QVariant qv = document->resource( QTextDocument::ImageResource, QUrl( imageNameToAdd ) ); |
|
if ( qv == image ) { |
|
// use the same name |
|
break; |
|
} |
|
imageNameToAdd = imageName + QString::number( imageNumber++ ); |
|
} |
|
|
|
if ( !mImageNames.contains( imageNameToAdd ) ) { |
|
document->addResource( QTextDocument::ImageResource, QUrl( imageNameToAdd ), image ); |
|
mImageNames << imageNameToAdd; |
|
} |
|
textCursor().insertImage( imageNameToAdd ); |
|
enableRichTextMode(); |
|
} |
|
|
|
QList<KMail::EmbeddedImage*> KMComposerEditor::embeddedImages() const |
|
{ |
|
QList<KMail::EmbeddedImage*> retImages; |
|
QStringList seenImageNames; |
|
QList<QTextImageFormat> imageFormats = embeddedImageFormats(); |
|
foreach( const QTextImageFormat &imageFormat, imageFormats ) { |
|
if ( !seenImageNames.contains( imageFormat.name() ) ) { |
|
QVariant data = document()->resource( QTextDocument::ImageResource, QUrl( imageFormat.name() ) ); |
|
QImage image = qvariant_cast<QImage>( data ); |
|
QBuffer buffer; |
|
buffer.open( QIODevice::WriteOnly ); |
|
image.save( &buffer, "PNG" ); |
|
|
|
qsrand( QDateTime::currentDateTime().toTime_t() + qHash( imageFormat.name() ) ); |
|
KMail::EmbeddedImage *embeddedImage = new KMail::EmbeddedImage(); |
|
retImages.append( embeddedImage ); |
|
embeddedImage->image = KMime::Codec::codecForName( "base64" )->encode( buffer.buffer() ); |
|
embeddedImage->imageName = imageFormat.name(); |
|
embeddedImage->contentID = QString( "%1" ).arg( qrand() ); |
|
seenImageNames.append( imageFormat.name() ); |
|
} |
|
} |
|
return retImages; |
|
} |
|
|
|
QList<QTextImageFormat> KMComposerEditor::embeddedImageFormats() const |
|
{ |
|
QTextDocument *doc = document(); |
|
QList<QTextImageFormat> retList; |
|
|
|
QTextBlock currentBlock = doc->begin(); |
|
while ( currentBlock.isValid() ) { |
|
QTextBlock::iterator it; |
|
for ( it = currentBlock.begin(); !it.atEnd(); ++it ) { |
|
QTextFragment fragment = it.fragment(); |
|
if ( fragment.isValid() ) { |
|
QTextImageFormat imageFormat = fragment.charFormat().toImageFormat(); |
|
if ( imageFormat.isValid() ) { |
|
retList.append( imageFormat ); |
|
} |
|
} |
|
} |
|
currentBlock = currentBlock.next(); |
|
} |
|
return retList; |
|
} |
|
|
|
void KMComposerEditor::slotAddImage() |
|
{ |
|
KFileDialog fdlg( QString(), QString(), this ); |
|
fdlg.setOperationMode( KFileDialog::Other ); |
|
fdlg.setCaption( i18n("Add Image") ); |
|
fdlg.okButton()->setGuiItem( KGuiItem( i18n("&Add"), "document-open") ); |
|
fdlg.setMode( KFile::Files ); |
|
if ( fdlg.exec() != KDialog::Accepted ) |
|
return; |
|
|
|
const KUrl::List files = fdlg.selectedUrls(); |
|
foreach ( const KUrl& url, files ) { |
|
addImage( url ); |
|
} |
|
} |
|
|
|
#include "kmcomposereditor.moc"
|
|
|