[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    KDE/kdepim/akonadi/libakonadi
From:       Volker Krause <volker.krause () rwth-aachen ! de>
Date:       2006-09-17 9:47:03
Message-ID: 1158486423.404119.6844.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 585474 by vkrause:

Add DND support to the collection model.
It's now possible to drag eg. a message from KDE3's Kontact into Akonadi.


 M  +100 -5    collectionmodel.cpp  
 M  +27 -0     collectionmodel.h  
 M  +25 -2     collectionview.cpp  
 M  +11 -0     collectionview.h  
 M  +1 -1      tests/collectionbrowser.cpp  
 M  +4 -1      tests/messagebrowser.cpp  


--- trunk/KDE/kdepim/akonadi/libakonadi/collectionmodel.cpp #585473:585474
@@ -23,6 +23,7 @@
 #include "collectionlistjob.h"
 #include "collectionmodel.h"
 #include "collectionrenamejob.h"
+#include "itemappendjob.h"
 #include "jobqueue.h"
 #include "monitor.h"
 
@@ -33,6 +34,7 @@
 
 #include <QDebug>
 #include <QHash>
+#include <QMimeData>
 #include <QPixmap>
 #include <QQueue>
 
@@ -49,6 +51,18 @@
     QString editOldName;
     Monitor* monitor;
     JobQueue *queue;
+    QStringList mimeTypes;
+
+    void updateSupportedMimeTypes( Collection *col )
+    {
+      QList<QByteArray> l = col->contentTypes();
+      for ( QList<QByteArray>::ConstIterator it = l.constBegin(); it != \
l.constEnd(); ++it ) { +        if ( (*it) == Collection::collectionMimeType() )
+          continue;
+        if ( !mimeTypes.contains( QString::fromLatin1( *it ) ) )
+          mimeTypes << QString::fromLatin1( *it );
+      }
+    }
 };
 
 PIM::CollectionModel::CollectionModel( QObject * parent ) :
@@ -262,6 +276,8 @@
       foreach ( CollectionAttribute* attr, csjob->attributes() )
         col->addAttribute( attr );
 
+      d->updateSupportedMimeTypes( col );
+
       QModelIndex startIndex = indexForPath( path );
       QModelIndex endIndex = indexForPath( path, columnCount( parent( startIndex ) ) \
- 1 );  emit dataChanged( startIndex, endIndex );
@@ -312,6 +328,8 @@
         d->childCollections[ col->parent() ].append( col->path() );
       }
 
+      d->updateSupportedMimeTypes( col );
+
       // start a status job for every collection to get message counts, etc.
       if ( col->type() != Collection::VirtualParent ) {
         CollectionStatusJob* csjob = new CollectionStatusJob( col->path(), d->queue \
); @@ -350,12 +368,24 @@
 
 Qt::ItemFlags PIM::CollectionModel::flags( const QModelIndex & index ) const
 {
-  if ( index.column() == 0 ) {
-    Collection *col = static_cast<Collection*>( index.internalPointer() );
-    if ( col->type() != Collection::VirtualParent && d->currentEdit == Private::None \
                )
-      return QAbstractItemModel::flags( index ) | Qt::ItemIsEditable;
+  Qt::ItemFlags flags = QAbstractItemModel::flags( index );
+
+  Collection *col = 0;
+  if ( index.isValid() ) {
+    col = static_cast<Collection*>( index.internalPointer() );
+    Q_ASSERT( col );
   }
-  return QAbstractItemModel::flags( index );
+
+  if ( col ) {
+    if ( col->type() != Collection::VirtualParent )  {
+      if ( d->currentEdit == Private::None && index.column() == 0 )
+        flags = flags | Qt::ItemIsEditable;
+      if ( col->type() != Collection::Virtual )
+        flags = flags | Qt::ItemIsDropEnabled;
+    }
+  }
+
+  return flags;
 }
 
 void PIM::CollectionModel::editDone( PIM::Job * job )
@@ -436,4 +466,69 @@
   return QByteArray();
 }
 
+Qt::DropActions PIM::CollectionModel::supportedDropActions() const
+{
+  return Qt::CopyAction; // | Qt::MoveAction;
+}
+
+QStringList PIM::CollectionModel::mimeTypes() const
+{
+  return d->mimeTypes;
+}
+
+bool PIM::CollectionModel::supportsContentType(const QModelIndex & index, const \
QStringList & contentTypes) +{
+  if ( !index.isValid() )
+    return false;
+  Collection *col = static_cast<Collection*>( index.internalPointer() );
+  Q_ASSERT( col );
+  QList<QByteArray> ct = col->contentTypes();
+  foreach ( QByteArray a, ct ) {
+    if ( contentTypes.contains( QString::fromLatin1( a ) ) )
+      return true;
+  }
+  return false;
+}
+
+bool PIM::CollectionModel::dropMimeData(const QMimeData * data, Qt::DropAction \
action, int row, int column, const QModelIndex & parent) +{
+  if ( !(action & supportedDropActions()) )
+    return false;
+
+  // handle drops onto items as well as drops between items
+  QModelIndex idx;
+  if ( row >= 0 && column >= 0 )
+    idx = index( row, column, parent );
+  else
+    idx = parent;
+
+  if ( !idx.isValid() )
+    return false;
+
+  // find a type the target collection supports
+  foreach ( QString type, data->formats() ) {
+    if ( !supportsContentType( idx, QStringList( type ) ) )
+      continue;
+    QByteArray path = pathForIndex( idx );
+    QByteArray item = data->data( type );
+    // HACK for some unknown reason the data is sometimes 0-terminated...
+    if ( !item.isEmpty() && item.at( item.size() - 1 ) == 0 )
+      item.resize( item.size() - 1 );
+    ItemAppendJob *job = new ItemAppendJob( path, item, type.toLatin1(), d->queue );
+    d->queue->addJob( job );
+    return true;
+  }
+
+  return false;
+}
+
+void PIM::CollectionModel::appendDone(PIM::Job * job)
+{
+  if ( job->error() ) {
+    kWarning() << "Append failed: " << job->errorText() << endl;
+    // TODO: error handling
+  }
+  job->deleteLater();
+}
+
 #include "collectionmodel.moc"
--- trunk/KDE/kdepim/akonadi/libakonadi/collectionmodel.h #585473:585474
@@ -94,6 +94,21 @@
     Qt::ItemFlags flags( const QModelIndex &index ) const;
 
     /**
+      Reimplemented.
+    */
+    virtual Qt::DropActions supportedDropActions() const;
+
+    /**
+      Reimplemented.
+    */
+    virtual QStringList mimeTypes() const;
+
+    /**
+      Reimplemented.
+    */
+    virtual bool dropMimeData( const QMimeData *data, Qt::DropAction action, int \
row, int column, const QModelIndex &parent ); +
+    /**
       Add a new collection to the model and try to save it into the backend.
       @param parent The parent model index.
       @param name The name of the new collection.
@@ -113,6 +128,13 @@
     */
     QByteArray pathForIndex( const QModelIndex &index ) const;
 
+    /**
+      Returns wether the specified collection supports <em>any</em> of the given \
mime-types. +      @param index The model index.
+      @param contentTypes The content types to check.
+    */
+    bool supportsContentType( const QModelIndex &index, const QStringList \
&contentTypes ); +
   private:
     /**
       Helper function to generate a model index for a given collection reference.
@@ -152,6 +174,11 @@
     */
     void editDone( PIM::Job *job );
 
+    /**
+      Connected to item append jobs used for DND.
+    */
+    void appendDone( PIM::Job *job );
+
   private:
     class Private;
     Private *d;
--- trunk/KDE/kdepim/akonadi/libakonadi/collectionview.cpp #585473:585474
@@ -23,6 +23,7 @@
 #include <klocale.h>
 
 #include <QDebug>
+#include <QDragMoveEvent>
 #include <QHeaderView>
 #include <QInputDialog>
 #include <QSortFilterProxyModel>
@@ -49,6 +50,9 @@
 
   setSortingEnabled( true );
   setEditTriggers( QAbstractItemView::EditKeyPressed );
+  setAcceptDrops( true );
+  setDropIndicatorShown( true );
+  setDragDropMode( DropOnly );
 
   // temporary for testing
   connect( this, SIGNAL(doubleClicked(QModelIndex)), \
SLOT(createCollection(QModelIndex)) ); @@ -70,13 +74,32 @@
 
 void PIM::CollectionView::createCollection( const QModelIndex & parent )
 {
-  if ( !d->model->canCreateCollection( parent ) )
+  QModelIndex index =sourceIndex( parent );
+  if ( !d->model->canCreateCollection( index ) )
     return;
   QString name = QInputDialog::getText( this, i18n("New Folder"), i18n("Name") );
   if ( name.isEmpty() )
     return;
-  if ( !d->model->createCollection( parent, name ) )
+  if ( !d->model->createCollection( index, name ) )
     qWarning() << "Collection creation failed immediately!";
 }
 
+void PIM::CollectionView::dragMoveEvent(QDragMoveEvent * event)
+{
+  QModelIndex index = sourceIndex( indexAt( event->pos() ) );
+  QStringList mimeTypes = event->mimeData()->formats();
+  if ( !d->model->supportsContentType( index, mimeTypes ) ) {
+    event->setDropAction( Qt::IgnoreAction );
+    return;
+  }
+  QTreeView::dragMoveEvent( event );
+}
+
+QModelIndex PIM::CollectionView::sourceIndex(const QModelIndex & index)
+{
+  if ( index.model() == d->filterModel )
+    return d->filterModel->mapToSource( index );
+  return index;
+}
+
 #include "collectionview.moc"
--- trunk/KDE/kdepim/akonadi/libakonadi/collectionview.h #585473:585474
@@ -23,6 +23,8 @@
 #include <QTreeView>
 #include <kdepim_export.h>
 
+class QDragMoveEvent;
+
 namespace PIM {
 
 /**
@@ -56,6 +58,15 @@
     */
     void createCollection( const QModelIndex &index );
 
+  protected:
+    virtual void dragMoveEvent( QDragMoveEvent *event );
+
+    /**
+      Translates a QModelIndex from the sort proxy model into a QModelIndex
+      from the CollectionModel if necessary.
+    */
+    QModelIndex sourceIndex( const QModelIndex &index );
+
   private:
     class Private;
     Private *d;
--- trunk/KDE/kdepim/akonadi/libakonadi/tests/collectionbrowser.cpp #585473:585474
@@ -42,7 +42,7 @@
 
 void PIM::CollectionBrowser::slotItemActivated( const QModelIndex & index )
 {
-  QByteArray path = model->pathForIndex( index );
+  QByteArray path = model->pathForIndex( sourceIndex( index ) );
   if ( path.isNull() )
     return;
   MessageBrowser *mb = new MessageBrowser( path );
--- trunk/KDE/kdepim/akonadi/libakonadi/tests/messagebrowser.cpp #585473:585474
@@ -49,10 +49,13 @@
 
 void PIM::MessageBrowser::slotFetchDone( PIM::Job * job )
 {
+  MessageFetchJob *fetch = static_cast<MessageFetchJob*>( job );
   if ( job->error() ) {
     qWarning() << "Message fetch failed: " << job->errorText();
+  } else if ( fetch->messages().isEmpty() ) {
+    qWarning() << "No message found!";
   } else {
-    Message *msg = static_cast<MessageFetchJob*>( job )->messages().first();
+    Message *msg = fetch->messages().first();
     QTextEdit *te = new QTextEdit();
     te->setReadOnly( true );
     te->setPlainText( msg->mime()->encodedContent() );


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic