]> SALOME platform Git repositories - modules/gui.git/commitdiff
Salome HOME
Support of drag-and-drop
authorsln <sln@opencascade.com>
Thu, 7 Jul 2011 09:25:06 +0000 (09:25 +0000)
committersln <sln@opencascade.com>
Thu, 7 Jul 2011 09:25:06 +0000 (09:25 +0000)
src/SUIT/SUIT_DataBrowser.cxx
src/SUIT/SUIT_DataBrowser.h
src/SUIT/SUIT_DataObject.cxx
src/SUIT/SUIT_DataObject.h
src/SUIT/SUIT_TreeModel.cxx
src/SUIT/SUIT_TreeModel.h

index aa099cb90c7188b9d5cd9e5c3937f176b3254772..0a7ab032b657750da2e06ff19efd2ab56edeecf4 100644 (file)
@@ -25,6 +25,9 @@
 #include <QtxTreeView.h>
 
 #include <QShortcut>
+#include <QEvent>
+#include <QEvent>
+#include <QDropEvent>
 
 /*!
   \class SUIT_DataBrowser
@@ -317,6 +320,8 @@ void SUIT_DataBrowser::init( SUIT_DataObject* root )
 {
   SUIT_ProxyModel* m = new SUIT_ProxyModel( root, this );
   connect( m, SIGNAL( modelUpdated() ), this, SLOT( onModelUpdated() ) );
+  connect( m, SIGNAL( drop( const QList<SUIT_DataObject*>& , SUIT_DataObject* ) ), 
+           this, SIGNAL( drop( const QList<SUIT_DataObject*>& , SUIT_DataObject* ) ) );
   
   setModel( m );
   setItemDelegate( qobject_cast<SUIT_ProxyModel*>( model() )->delegate() );
@@ -330,6 +335,9 @@ void SUIT_DataBrowser::init( SUIT_DataObject* root )
           this,       SLOT( onExpanded( const QModelIndex& ) ) );
   myShortcut = new QShortcut( Qt::Key_F5, this, SIGNAL( requestUpdate() ), SIGNAL( requestUpdate() ) );
 
+  treeView()->installEventFilter( this );
+  treeView()->viewport()->installEventFilter( this );
+
   myAutoSizeFirstColumn = true;
   myAutoSizeColumns = false;
   myResizeOnExpandItem = false;
@@ -418,3 +426,62 @@ void SUIT_DataBrowser::onExpanded( const QModelIndex& index )
   }
 }
 
+/*!
+  \brief Activate drag-and-drop in object browser
+*/
+void SUIT_DataBrowser::setDragEnabled( const bool enabled )
+{
+  QTreeView* tree = treeView();
+
+  tree->setDragEnabled( enabled );
+
+  if ( enabled )
+  {
+    tree->setDragDropMode( QAbstractItemView::InternalMove );
+    tree->viewport()->setAcceptDrops( true );
+    tree->setDropIndicatorShown( true );
+
+  }
+}
+
+/*!
+  \brief Check whether drag-and-drop is activated.
+*/
+bool SUIT_DataBrowser::dragEnabled() const
+{
+  return treeView()->dragEnabled();
+}
+
+/*!
+  \brief Catch drag events, analyze mimeData, analyze underlying object and call 
+  SUIT_TreeModel::setDropAccepted() with corresponding flag
+*/
+bool SUIT_DataBrowser::eventFilter( QObject* obj, QEvent* e )
+{
+  QEvent::Type type = e->type();
+  QtxTreeView* tree = treeView();
+
+  if ( obj == tree->viewport() )
+  {
+    if ( type == QEvent::DragEnter || type == QEvent::DragMove )
+    {
+      SUIT_DataObject* destObj = 0;
+
+      QDropEvent* dropEvent = (QDropEvent*)e;
+      QModelIndex ind = tree->indexAt( dropEvent->pos() );
+      SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
+      if ( m && ind.isValid() ) 
+      {
+        destObj = m->object( ind );
+        if ( destObj )
+        {
+          QList<SUIT_DataObject*> srcList;
+          m->getObjects( dropEvent->mimeData(), srcList );
+          m->setDropAccepted( destObj->isDropAccepted( srcList ) );
+        }
+      }
+    }
+  }
+
+  return OB_Browser::eventFilter( obj, e );
+}
index d9d0e4cafcf88a558565c06a003e9778bb5c05b1..52054ca3bb7b94302d59db44d7e558db036b7ee4 100644 (file)
@@ -27,6 +27,7 @@
 #include "SUIT_PopupClient.h"
 #include "SUIT_DataObject.h"
 #include <OB_Browser.h>
+#include <QAbstractItemView>
 
 class QShortcut;
 
@@ -66,23 +67,28 @@ public:
 
   void             ensureItemVisible( const SUIT_DataObject* );
 
+  void             setDragEnabled( const bool enabled );
+  bool             dragEnabled() const;
+
 protected:
   virtual void     contextMenuEvent( QContextMenuEvent* );
+  virtual bool     eventFilter( QObject*, QEvent* );
 
 private:
   void             init( SUIT_DataObject* );
-
+  
 signals:
   void             requestUpdate();
   void             clicked( SUIT_DataObject* );
   void             doubleClicked( SUIT_DataObject* );
+  void             drop( const QList<SUIT_DataObject*>& , SUIT_DataObject* );
 
 private slots:
   void             onModelUpdated();
   void             onClicked( const QModelIndex& );
   void             onDblClicked( const QModelIndex& );
   void             onExpanded( const QModelIndex& );
-
+  
 private:
   QShortcut*       myShortcut;
 
index 98b323b3a74cf179bd8fa7a6e4afd548b0653050..bb64cafa42846d37ff866b29a27176b984b42e16 100755 (executable)
@@ -542,7 +542,7 @@ bool SUIT_DataObject::isDragable() const
           to this object
 */
 
-bool SUIT_DataObject::isDropAccepted( SUIT_DataObject* /*obj*/ )
+bool SUIT_DataObject::isDropAccepted( const QList<SUIT_DataObject*>& /*list*/ )
 {
   return false;
 }
index 2ea48adb7463e8e41297b51c6e84753b89ea942e..c849c801884afb1ac3cb59b3c55470fcfd9de288 100755 (executable)
@@ -104,8 +104,8 @@ public:
   virtual int                 alignment( const int = NameId ) const;
 
   virtual bool                isDragable() const;
-  virtual bool                isDropAccepted( SUIT_DataObject* obj );
-
+  virtual bool                isDropAccepted( const QList<SUIT_DataObject*>& );
+  
   virtual bool                isEnabled() const;
   virtual bool                isSelectable() const;
   virtual bool                isCheckable( const int = NameId ) const;
index 716a7dd2adfdd7e670759874e0f87b3709de9bcd..b5ea72803cb61acd27d0674a9a576b0960bbfc35 100755 (executable)
 
 #include <QApplication>
 #include <QHash>
+#include <QMimeData>
+#include <QSet>
+
+static const QString SUIT_DATAOBJECT_MIME_TYPE = "suit_dataobject.ptr";
 
 SUIT_AbstractModel::SUIT_AbstractModel()
 {
@@ -439,7 +443,8 @@ SUIT_TreeModel::SUIT_TreeModel( QObject* parent )
   myRoot( 0 ),
   myRootItem( 0 ),
   myAutoDeleteTree( false ),
-  myAutoUpdate( true )
+  myAutoUpdate( true ),
+  myDropAccepted( false )
 {
   initialize();
 }
@@ -822,6 +827,10 @@ Qt::ItemFlags SUIT_TreeModel::flags( const QModelIndex& index ) const
     // data object is checkable
     if ( obj->isCheckable( index.column() ) )
       f = f | Qt::ItemIsUserCheckable;
+
+    // sln: is moveable
+    if ( obj->isDragable() )
+      f = f | Qt::ItemIsDragEnabled;
   }
   return f;
 }
@@ -1301,6 +1310,9 @@ SUIT_ProxyModel::SUIT_ProxyModel( QObject* parent )
 {
   SUIT_TreeModel* model = new SUIT_TreeModel( this );
   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
+  connect( model, SIGNAL( drop( const QList<SUIT_DataObject*>& , SUIT_DataObject* ) ),
+           this,  SIGNAL( drop( const QList<SUIT_DataObject*>& , SUIT_DataObject* ) ) );
+
   setSourceModel( model );
 }
 
@@ -1314,7 +1326,10 @@ SUIT_ProxyModel::SUIT_ProxyModel( SUIT_DataObject* root, QObject* parent )
   mySortingEnabled( true )
 {
   SUIT_TreeModel* model = new SUIT_TreeModel( root, this );
+  model->setSupportedDragActions( Qt::MoveAction );
   connect( model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
+  connect( model, SIGNAL( drop( const QList<SUIT_DataObject*>& , SUIT_DataObject* ) ),
+           this,  SIGNAL( drop( const QList<SUIT_DataObject*>& , SUIT_DataObject* ) ) );
   setSourceModel( model );
 }
 
@@ -1328,6 +1343,8 @@ SUIT_ProxyModel::SUIT_ProxyModel( SUIT_AbstractModel* model, QObject* parent )
   mySortingEnabled( true )
 {
   connect( *model, SIGNAL( modelUpdated() ), this, SIGNAL( modelUpdated() ) );
+  connect( *model, SIGNAL( drop( const QList<SUIT_DataObject*>& , SUIT_DataObject* ) ),
+           this,  SIGNAL( drop( const QList<SUIT_DataObject*>& , SUIT_DataObject* ) ) );
   setSourceModel( *model );
 }
 
@@ -1614,10 +1631,30 @@ Qtx::Appropriate SUIT_ProxyModel::appropriate( const QString& name ) const
   return treeModel() ? treeModel()->appropriate( name ) : Qtx::Shown;
 }
 
+/*!
+  \brief Retrieve objects from mime data
 
+  \param data - mime data
+  \param lst - out list of objects
+  \return TRUE if operation has been completed successfully; FALSE otherwise
+*/
+bool SUIT_ProxyModel::getObjects( const QMimeData* data, QList<SUIT_DataObject*>& lst ) const
+{
+  SUIT_TreeModel* tm = dynamic_cast<SUIT_TreeModel*>( treeModel() );
+  return tm ? tm->getObjects( data, lst ) : false;
+}
 
+/*!
+  \brief Specify whether drop is acceptable
 
-
+  \param on - TRUE if drop is acceptable; FALSE otherwise
+*/
+void SUIT_ProxyModel::setDropAccepted( const bool on )
+{
+  SUIT_TreeModel* tm = dynamic_cast<SUIT_TreeModel*>( treeModel() );
+  if ( tm )
+    tm->setDropAccepted( on );
+}
 
 /*!
   \class SUIT_ItemDelegate
@@ -1673,3 +1710,164 @@ void SUIT_ItemDelegate::paint( QPainter* painter,
   }
   QItemDelegate::paint( painter, opt, index );
 }
+
+// ++++++++++++ TREE MODEL ++++++++++++
+
+/*!
+  \brief to do Gets supported drag and drop actions. Current implementation returns Qt::MoveAction only
+
+  \return Qt::MoveAction
+*/
+Qt::DropActions SUIT_TreeModel::supportedDropActions() const
+{
+  return Qt::MoveAction;
+}
+
+/*!
+  \brief Gets supported mime types
+
+  \return "suit_dataobject.ptr"
+*/
+QStringList SUIT_TreeModel::mimeTypes() const
+{
+  QStringList types;
+  if ( myDropAccepted )
+    types << SUIT_DATAOBJECT_MIME_TYPE;
+  return types;
+}
+
+/*!
+  \brief Create mime data for given objects
+
+  \param indexes - list of model indexes of objects for drag operation
+  \return mime data
+*/
+QMimeData* SUIT_TreeModel::mimeData( const QModelIndexList& indexes ) const
+{
+  QMimeData* mimeData = new QMimeData();
+  QByteArray encodedData;
+
+  QDataStream stream( &encodedData, QIODevice::WriteOnly );
+
+  bool is64 = ( sizeof( void* ) == 64 );
+
+  QSet<SUIT_DataObject*> anAdded;
+  foreach( QModelIndex index, indexes ) 
+  {
+    if ( !index.isValid() ) 
+      continue;
+
+    SUIT_DataObject* dataObj = object( index );
+    if ( dataObj && !anAdded.contains( dataObj ) )
+    {
+      if ( !dataObj->isDragable() )
+      {
+        delete mimeData;
+        return 0;      
+      }
+        
+      if ( is64 )
+        stream << (quint64)dataObj;
+      else
+        stream << (quint32)dataObj;
+      anAdded.insert( dataObj );
+    }
+  }
+
+  mimeData->setData( SUIT_DATAOBJECT_MIME_TYPE , encodedData );
+  
+  return mimeData;
+}
+
+/*!
+  \brief Drop objects coded in mime data under parent object reimplemented from the base class
+
+  \return TRUE if operation has been completed successfully; FALSE otherwise
+*/
+bool SUIT_TreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action, 
+                                   int row, int column, const QModelIndex& parent )
+{
+  QList<SUIT_DataObject*> resList;
+  SUIT_DataObject* targetObj = 0;
+
+  try
+  {
+    targetObj = object( parent );
+    if ( targetObj )
+      getObjects( data, resList );
+  }
+  catch (...)
+  {
+    resList.clear();
+  }
+
+  if ( resList.count() > 0 && targetObj )
+  {
+    emit drop( resList, targetObj );
+    return true;
+  }
+  else 
+    return false;
+}
+
+/*!
+  \brief Retrieve objects from mime data
+
+  \param data - mime data
+  \param lst - out list of objects
+  \return TRUE if operation has been completed successfully; FALSE otherwise
+*/
+bool SUIT_TreeModel::getObjects( const QMimeData* data, QList<SUIT_DataObject*>& outList ) const
+{
+  outList.clear();
+
+  QByteArray encodedData = data->data( SUIT_DATAOBJECT_MIME_TYPE );
+  QDataStream stream( &encodedData, QIODevice::ReadOnly );
+
+  bool is64 = ( sizeof( void* ) == 64 );
+
+  while( !stream.atEnd() ) 
+  {
+    SUIT_DataObject* dataObj = 0;
+
+    if ( is64 )
+    {
+      quint64 buff;
+      stream >> buff;
+      dataObj = (SUIT_DataObject*)buff;
+    }
+    else
+    {
+      quint32 buff;
+      stream >> buff;
+      dataObj = (SUIT_DataObject*)buff;
+    }
+
+    if ( dataObj )
+      outList.append( dataObj );
+  }  
+
+  return outList.count() > 0;
+}
+
+/*!
+  \brief Specify whether drop is acceptable
+
+  Purpose of this method is to enable drop operation for some items and disable
+  it for other items. QT does not provide corresponding interface. Drop operation 
+  can be enabled or disabled by means of mimeTypes() method only. If out of 
+  mimeTypes() contains type of mime data used for drag and drop, operation is 
+  enabled; disabled otherwise. SUIT_DataBrowser catches drag events, analyzes 
+  mimeData, analyzes underlying object and calls setDropAccepted() with 
+  corresponding flag
+
+  \param on - TRUE if drop is acceptable; FALSE otherwise
+*/
+void SUIT_TreeModel::setDropAccepted( const bool on )
+{
+  myDropAccepted = on;
+}
+
+
+
+
index 5ccdf8455ca96c6d41d3e26a385efda87fa61c41..9d1d7a0cb61325ccb08ae19d5e65dc02d581cafa 100755 (executable)
@@ -143,12 +143,22 @@ public:
 
   QAbstractItemDelegate* delegate() const;
 
+  // sln: tree model
+  virtual Qt::DropActions  supportedDropActions() const;
+  virtual QStringList      mimeTypes() const;
+  virtual QMimeData*        mimeData( const QModelIndexList& indexes ) const;
+  virtual bool             dropMimeData( const QMimeData* data, Qt::DropAction action, 
+                             int row, int column, const QModelIndex& parent );
+  bool                     getObjects( const QMimeData* data, QList<SUIT_DataObject*>& ) const;
+  void                     setDropAccepted( const bool );
+  
 public slots:
   virtual void           updateTree( const QModelIndex& );
   virtual void           updateTree( SUIT_DataObject* = 0 );
 
 signals:
   void modelUpdated();
+  void drop( const QList<SUIT_DataObject*>& , SUIT_DataObject* );
 
 private:
   void                   initialize();
@@ -171,10 +181,9 @@ private:
   typedef struct
   {
     QString myName;
-       QMap<int,int> myIds;
-       QPixmap myIcon;
-       Qtx::Appropriate myAppropriate;
-
+         QMap<int,int> myIds;
+         QPixmap myIcon;
+         Qtx::Appropriate myAppropriate;
   } ColumnInfo;
   
   SUIT_DataObject*    myRoot;
@@ -182,6 +191,7 @@ private:
   ItemMap             myItems;
   bool                myAutoDeleteTree;
   bool                myAutoUpdate;
+  bool                myDropAccepted;
   QVector<ColumnInfo> myColumns;
 
   friend class SUIT_TreeModel::TreeSync;
@@ -222,6 +232,9 @@ public:
 
   QAbstractItemDelegate* delegate() const;
 
+  bool                     getObjects( const QMimeData* data, QList<SUIT_DataObject*>& ) const;
+  void                     setDropAccepted( const bool );
+
 public slots:
   virtual void           updateTree( const QModelIndex& );
   virtual void           updateTree( SUIT_DataObject* = 0 );
@@ -229,6 +242,7 @@ public slots:
 
 signals:
   void modelUpdated();
+  void drop( const QList<SUIT_DataObject*>& , SUIT_DataObject* );
 
 protected:
   SUIT_AbstractModel*    treeModel() const;