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.
 
 
 

458 lines
12 KiB

/*
* This file is part of KMail.
* Copyright (c) 2009 Constantin Berzan <exit3219@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "attachmentmodel.h"
#include <boost/shared_ptr.hpp>
#include <QMimeData>
#include <QUrl>
#include <KDebug>
#include <KGlobal>
#include <KLocale>
#include <KTempDir>
#include <kmime/kmime_util.h>
#include <akonadi/item.h>
#include "foldercollection.h"
#include "kmcommands.h"
#include <kpimutils/kfileio.h>
using namespace KMail;
using namespace KPIM;
static Qt::CheckState boolToCheckState( bool checked ) // local
{
if( checked ) {
return Qt::Checked;
} else {
return Qt::Unchecked;
}
}
class KMail::AttachmentModel::Private
{
public:
Private( AttachmentModel *qq );
~Private();
AttachmentModel *const q;
AttachmentPart::List parts;
bool modified;
bool encryptEnabled;
bool signEnabled;
bool encryptSelected;
bool signSelected;
QList<KTempDir*> tempDirs;
};
AttachmentModel::Private::Private( AttachmentModel *qq )
: q( qq )
, modified( false )
, encryptEnabled( false )
, signEnabled( false )
, encryptSelected( false )
, signSelected( false )
{
}
AttachmentModel::Private::~Private()
{
// There should be an automatic way to manage the lifetime of these...
qDeleteAll( tempDirs );
}
AttachmentModel::AttachmentModel( QObject *parent )
: QAbstractItemModel( parent )
, d( new Private( this ) )
{
}
AttachmentModel::~AttachmentModel()
{
delete d;
}
bool AttachmentModel::dropMimeData( const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent )
{
Q_UNUSED( row );
Q_UNUSED( column );
Q_UNUSED( parent );
kDebug() << "data has formats" << data->formats() << "urls" << data->urls() << "action" << action;
if( action == Qt::IgnoreAction ) {
return true;
//} else if( action != Qt::CopyAction ) {
// return false;
}
// The dropped data is a list of URLs.
KUrl::List urls = KUrl::List::fromMimeData( data );
if( !urls.isEmpty() ) {
Akonadi::Item::List items;
foreach ( const KUrl &url, urls ) {
Akonadi::Item item = Akonadi::Item::fromUrl( url );
if ( item.isValid() ) {
items << item;
}
}
if ( items.isEmpty() )
emit attachUrlsRequested( urls );
else {
emit attachItemsRequester( items );
}
return true;
} else {
return false;
}
}
QMimeData *AttachmentModel::mimeData( const QModelIndexList &indexes ) const
{
kDebug();
QList<QUrl> urls;
foreach( const QModelIndex &index, indexes ) {
if( index.column() != 0 ) {
// Avoid processing the same attachment more than once, since the entire
// row is selected.
kWarning() << "column != 0. Possibly duplicate rows passed to mimeData().";
continue;
}
const AttachmentPart::Ptr part = d->parts[ index.row() ];
QString attachmentName = part->fileName();
if( attachmentName.isEmpty() ) {
attachmentName = part->name();
}
if( attachmentName.isEmpty() ) {
attachmentName = i18n( "unnamed attachment" );
}
KTempDir *tempDir = new KTempDir; // Will remove the directory on destruction.
d->tempDirs.append( tempDir );
const QString fileName = tempDir->name() + attachmentName;
KPIMUtils::kByteArrayToFile( part->data(),
fileName,
false, false, false );
QUrl url;
url.setScheme( "file" );
url.setPath( fileName );
kDebug() << url;
urls.append( url );
}
QMimeData *mimeData = new QMimeData;
mimeData->setUrls( urls );
return mimeData;
}
QStringList AttachmentModel::mimeTypes() const
{
QStringList types;
types << QString::fromLatin1( "text/uri-list" );
return types;
}
Qt::DropActions AttachmentModel::supportedDropActions() const
{
return Qt::CopyAction | Qt::MoveAction;
}
bool AttachmentModel::isModified() const
{
return d->modified; // TODO actually set modified=true sometime...
}
void AttachmentModel::setModified( bool modified )
{
d->modified = modified;
}
bool AttachmentModel::isEncryptEnabled() const
{
return d->encryptEnabled;
}
void AttachmentModel::setEncryptEnabled( bool enabled )
{
d->encryptEnabled = enabled;
emit encryptEnabled( enabled );
}
bool AttachmentModel::isSignEnabled() const
{
return d->signEnabled;
}
void AttachmentModel::setSignEnabled( bool enabled )
{
d->signEnabled = enabled;
emit signEnabled( enabled );
}
bool AttachmentModel::isEncryptSelected() const
{
return d->encryptSelected;
}
void AttachmentModel::setEncryptSelected( bool selected )
{
d->encryptSelected = selected;
foreach( AttachmentPart::Ptr part, d->parts ) {
part->setEncrypted( selected );
}
emit dataChanged( index( 0, EncryptColumn ), index( rowCount() - 1, EncryptColumn ) );
}
bool AttachmentModel::isSignSelected() const
{
return d->signSelected;
}
void AttachmentModel::setSignSelected( bool selected )
{
d->signSelected = selected;
foreach( AttachmentPart::Ptr part, d->parts ) {
part->setSigned( selected );
}
emit dataChanged( index( 0, SignColumn ), index( rowCount() - 1, SignColumn ) );
}
QVariant AttachmentModel::data( const QModelIndex &index, int role ) const
{
if( !index.isValid() ) {
return QVariant();
}
AttachmentPart::Ptr part = d->parts[ index.row() ];
if( role == Qt::DisplayRole ) {
switch( index.column() ) {
case NameColumn:
return QVariant::fromValue( part->fileName() );
case SizeColumn:
return QVariant::fromValue( KGlobal::locale()->formatByteSize( part->size() ) );
case EncodingColumn:
return QVariant::fromValue( KMime::nameForEncoding( part->encoding() ) );
case MimeTypeColumn:
return QVariant::fromValue( part->mimeType() );
default:
return QVariant();
};
} else if( role == Qt::CheckStateRole ) {
switch( index.column() ) {
case CompressColumn:
return QVariant::fromValue( int( boolToCheckState( part->isCompressed() ) ) );
case EncryptColumn:
return QVariant::fromValue( int( boolToCheckState( part->isEncrypted() ) ) );
case SignColumn:
return QVariant::fromValue( int( boolToCheckState( part->isSigned() ) ) );
default:
return QVariant();
}
} else if( role == AttachmentPartRole ) {
if( index.column() == 0 ) {
return QVariant::fromValue( part );
} else {
kWarning() << "AttachmentPartRole and column != 0.";
return QVariant();
}
} else {
return QVariant();
}
}
bool AttachmentModel::setData( const QModelIndex &index, const QVariant &value, int role )
{
bool emitDataChanged = true;
AttachmentPart::Ptr part = d->parts[ index.row() ];
if( role == Qt::CheckStateRole ) {
switch( index.column() ) {
case CompressColumn:
{
bool toZip = value.toBool();
if( toZip != part->isCompressed() ) {
emit attachmentCompressRequested( part, toZip );
emitDataChanged = false; // Will emit when the part is updated.
}
break;
}
case EncryptColumn:
part->setEncrypted( value.toBool() );
break;
case SignColumn:
part->setSigned( value.toBool() );
break;
default:
break; // Do nothing.
};
} else {
return false;
}
if( emitDataChanged ) {
emit dataChanged( index, index );
}
return true;
}
bool AttachmentModel::addAttachment( AttachmentPart::Ptr part )
{
Q_ASSERT( !d->parts.contains( part ) );
beginInsertRows( QModelIndex(), rowCount(), rowCount() );
d->parts.append( part );
endInsertRows();
return true;
}
bool AttachmentModel::updateAttachment( AttachmentPart::Ptr part )
{
int idx = d->parts.indexOf( part );
if( idx == -1 ) {
kWarning() << "Tried to update non-existent part.";
return false;
}
// Emit dataChanged() for the whole row.
emit dataChanged( index( idx, 0 ), index( idx, LastColumn - 1 ) );
return true;
}
bool AttachmentModel::replaceAttachment( AttachmentPart::Ptr oldPart, AttachmentPart::Ptr newPart )
{
Q_ASSERT( oldPart != newPart );
int idx = d->parts.indexOf( oldPart );
if( idx == -1 ) {
kWarning() << "Tried to replace non-existent part.";
return false;
}
d->parts[ idx ] = newPart;
// Emit dataChanged() for the whole row.
emit dataChanged( index( idx, 0 ), index( idx, LastColumn - 1 ) );
return true;
}
bool AttachmentModel::removeAttachment( AttachmentPart::Ptr part )
{
int idx = d->parts.indexOf( part );
if( idx < 0 ) {
kWarning() << "Attachment not found.";
return false;
}
beginRemoveRows( QModelIndex(), idx, idx );
d->parts.removeAt( idx );
endRemoveRows();
emit attachmentRemoved( part );
return true;
}
AttachmentPart::List AttachmentModel::attachments() const
{
return d->parts;
}
Qt::ItemFlags AttachmentModel::flags( const QModelIndex &index ) const
{
Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
if( !index.isValid() ) {
return Qt::ItemIsDropEnabled | defaultFlags;
}
if( index.column() == CompressColumn ||
index.column() == EncryptColumn ||
index.column() == SignColumn ) {
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable | defaultFlags;
} else {
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
}
}
QVariant AttachmentModel::headerData( int section, Qt::Orientation orientation, int role ) const
{
if( orientation != Qt::Horizontal || role != Qt::DisplayRole ) {
return QVariant();
}
switch( section ) {
case NameColumn:
return i18nc( "@title column attachment name.", "Name" );
case SizeColumn:
return i18nc( "@title column attachment size.", "Size" );
case EncodingColumn:
return i18nc( "@title column attachment encoding.", "Encoding" );
case MimeTypeColumn:
return i18nc( "@title column attachment type.", "Type" );
case CompressColumn:
return i18nc( "@title column attachment compression checkbox.", "Compress" );
case EncryptColumn:
return i18nc( "@title column attachment encryption checkbox.", "Encrypt" );
case SignColumn:
return i18nc( "@title column attachment signed checkbox.", "Sign" );
default:
kWarning() << "Bad column" << section;
return QVariant();
};
}
QModelIndex AttachmentModel::index( int row, int column, const QModelIndex &parent ) const
{
if( !hasIndex( row, column, parent ) ) {
return QModelIndex();
}
Q_ASSERT( row >= 0 && row < rowCount() );
if( parent.isValid() ) {
kWarning() << "Called with weird parent.";
return QModelIndex();
}
return createIndex( row, column );
}
QModelIndex AttachmentModel::parent( const QModelIndex &index ) const
{
Q_UNUSED( index );
return QModelIndex(); // No parent.
}
int AttachmentModel::rowCount( const QModelIndex &parent ) const
{
if( parent.isValid() ) {
return 0; // Items have no children.
}
Q_UNUSED( parent );
return d->parts.count();
}
int AttachmentModel::columnCount( const QModelIndex &parent ) const
{
Q_UNUSED( parent );
return LastColumn;
}
#include "attachmentmodel.moc"