Salome HOME
Renaming, add selector for selection synchronization.
[modules/hydro.git] / src / HYDROGUI / HYDROGUI_ListModel.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "HYDROGUI_ListModel.h"
24
25 #include "HYDROGUI_DataObject.h"
26
27 #include <SUIT_Session.h>
28 #include <SUIT_ResourceMgr.h>
29
30 #include <QMimeData>
31
32 const QString OBJ_LIST_MIME_TYPE = "application/hydro.objects.list";
33
34
35 /**
36   Constructor.
37   @param theParent the parent object
38 */
39 HYDROGUI_ListModel::HYDROGUI_ListModel( QObject* theParent )
40  : QAbstractListModel( theParent )
41 {
42   // Get resource manager
43   SUIT_ResourceMgr* aResMgr = 0;
44   SUIT_Session* aSession = SUIT_Session::session();
45   if ( aSession ) {
46     aResMgr = SUIT_Session::session()->resourceMgr();
47   }
48
49   // Define eye icon and empty icon
50   myEmpty = QPixmap( 16, 16 );
51   myEmpty.fill( Qt::white );
52   if ( aResMgr ) {
53     myEye = aResMgr->loadPixmap( "HYDRO", tr( "EYE_ICO" ) );
54   } else {
55     myEye = QPixmap( 16, 16 );
56     myEye.fill( Qt::black );
57   }
58
59   // Set the supported drag actions for the items in the model
60   setSupportedDragActions( Qt::MoveAction | Qt::CopyAction );
61 }
62
63 /**
64   Destructor.
65 */
66 HYDROGUI_ListModel::~HYDROGUI_ListModel()
67 {
68 }
69
70 /**
71 */
72 QVariant HYDROGUI_ListModel::data( const QModelIndex &theIndex, int theRole ) const
73 {
74   QVariant aVariant;
75
76   int aRow = theIndex.row();
77   int aColumn = theIndex.column();
78
79   switch( theRole )
80   {
81   case Qt::DisplayRole:
82     {
83       if( aColumn==0 && aRow >=0 && aRow < myObjects.count() )
84         return myObjects.at( aRow ).first->GetName();
85       else
86         return QVariant();
87     }
88     break;
89
90   case Qt::DecorationRole:
91     {
92       if( aColumn==0 && aRow >=0 && aRow < myObjects.count() )
93       {
94         bool isVisible = isObjectVisible( aRow );
95         if( isVisible )
96           return myEye;
97         else
98           return myEmpty;
99       }
100       return QVariant();
101     }
102     break;
103
104   case HYDROGUI_VisibleRole:
105     {
106       bool isVisible = isObjectVisible( aRow );
107       return QVariant( isVisible ).toString();
108     }
109     break;
110   case HYDROGUI_EntryRole:
111     {
112       if( aColumn==0 && aRow >=0 && aRow < myObjects.count() ) {
113         aVariant = HYDROGUI_DataObject::dataObjectEntry( myObjects.at( aRow ).first );
114       }
115     }
116     break;
117   }
118
119   return aVariant;
120 }
121
122 /**
123 */
124 int HYDROGUI_ListModel::rowCount( const QModelIndex &theParent ) const
125 {
126   return myObjects.count();
127 }
128
129 /**
130   Set objects list.
131   @param theObjects the list of pairs (object; object visibility)
132 */
133 void HYDROGUI_ListModel::setObjects( const Object2VisibleList& theObjects )
134 {
135   myObjects = theObjects;
136
137   reset();
138 }
139
140 /**
141   Get objects list.
142   @return the list of objects ordered according to the model
143 */
144 HYDROGUI_ListModel::ObjectList HYDROGUI_ListModel::getObjects() const
145 {
146   ObjectList anObjects;
147
148   foreach( const Object2Visible& anItem, myObjects ) {
149     anObjects << anItem.first;
150   }
151
152   return anObjects;
153 }
154
155 /**
156   Check if the object is visible.
157   @param theIndex the object index
158   @return true if the object is visible, false - otherwise
159 */
160 bool HYDROGUI_ListModel::isObjectVisible( int theIndex ) const
161 {
162   bool isVisible = false;
163
164   if ( theIndex >= 0 && theIndex < myObjects.count() ) {
165     isVisible = myObjects.at( theIndex ).second;
166   }
167
168   return isVisible;
169 }
170
171 /**
172 */
173 QVariant HYDROGUI_ListModel::headerData( int theSection,
174                                             Qt::Orientation theOrientation,
175                                             int theRole ) const
176 {
177   if( theOrientation==Qt::Horizontal && theRole==Qt::DisplayRole )
178   {
179     switch( theSection )
180     {
181     case 0:
182       return tr( "VISIBLE" );
183     case 1:
184       return tr( "OBJECT_NAME" );
185     };
186   }
187   return QVariant();
188 }
189
190 /**
191 */
192 Qt::ItemFlags HYDROGUI_ListModel::flags( const QModelIndex& theIndex ) const
193 {
194   Qt::ItemFlags aDefaultFlags = QAbstractListModel::flags( theIndex );
195   if( theIndex.isValid() )
196     return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | aDefaultFlags;
197   else
198     return Qt::ItemIsDropEnabled | aDefaultFlags;
199 }
200
201 /**
202 */
203 QMimeData* HYDROGUI_ListModel::mimeData( const QModelIndexList& theIndexes ) const
204 {
205   QMimeData* aMimeData = new QMimeData();
206   QByteArray anEncodedData;
207   QDataStream aStream( &anEncodedData, QIODevice::WriteOnly );
208
209   QList<int> anIdsList = getIds( theIndexes );
210   foreach( int anId, anIdsList )
211     aStream << anId;
212
213   aMimeData->setData( OBJ_LIST_MIME_TYPE, anEncodedData );
214   return aMimeData;
215 }
216
217 /**
218 */
219 QStringList HYDROGUI_ListModel::mimeTypes() const
220 {
221   QStringList aTypes;
222   aTypes << OBJ_LIST_MIME_TYPE;
223   return aTypes;
224 }
225
226 /**
227 */
228 bool HYDROGUI_ListModel::dropMimeData( const QMimeData* theData, Qt::DropAction theAction,
229                                           int theRow, int theColumn, const QModelIndex& theParent )
230 {
231   if( theAction == Qt::IgnoreAction)
232     return true;
233
234   if( !theData->hasFormat( OBJ_LIST_MIME_TYPE ))
235     return false;
236
237   if( theColumn > 0 )
238     return false;
239
240   int aDropItemId = theParent.row();
241
242   QByteArray anEncodedData = theData->data( OBJ_LIST_MIME_TYPE );
243   QDataStream aStream( &anEncodedData, QIODevice::ReadOnly );
244   QList<int> anIdsList;
245   while( !aStream.atEnd() )
246   {
247     int anId;
248     aStream >> anId;
249     anIdsList << anId;
250   }
251   qSort( anIdsList ); // TODO should be moved?
252   move( anIdsList, DragAndDrop, false, aDropItemId ); //TODO set visibility?
253   return true;
254 }
255
256 /**
257 */
258 Qt::DropActions HYDROGUI_ListModel::supportedDropActions() const
259 {
260   return Qt::MoveAction | Qt::CopyAction;
261 }
262
263 /**
264   Get list of ids by the list model indexes.
265   @param theIsToSort defines if the list of ids should be sorted in ascending order
266   @return the list of ids
267 */
268 QList<int> HYDROGUI_ListModel::getIds( const QModelIndexList& theIndexes, bool theIsToSort ) const
269 {
270   QList<int> anIds;
271   foreach( const QModelIndex& anIndex, theIndexes ) {
272     anIds << anIndex.row();
273   }
274
275   if ( theIsToSort ) {
276     qSort( anIds );
277   }
278
279   return anIds;
280 }
281
282 /**
283   Move the item.
284   @param theItem the item id to move
285   @param theType the move operation type
286   @param theIsVisibleOnly indicates if do move relating to the visible objects only
287   @param theDropItem the drop item id ( used for drag and drop obly )
288   @return true in case of success
289 */
290 bool HYDROGUI_ListModel::move( const int theItem, const OpType theType,
291                                   bool theIsVisibleOnly, const int theDropItem )
292 {
293   bool aRes = false;
294   if ( theItem < 0 || theItem >= myObjects.count() ) {
295     return aRes;
296   }
297
298   int aDestinationIndex = -1;
299   bool isInsertBefore = false;
300
301   switch ( theType ) {
302     case Up:
303       isInsertBefore = true;
304       if ( theItem > 0 ) {
305         aDestinationIndex = theItem - 1;
306         if ( theIsVisibleOnly ) {
307           while ( aDestinationIndex >= 0 && !isObjectVisible( aDestinationIndex ) ) {
308             aDestinationIndex--;
309           }
310         }
311       }
312       break;
313     case Down:
314       if ( theItem < myObjects.count() - 1 ) {
315         aDestinationIndex = theItem + 1;
316         if ( theIsVisibleOnly ) {
317           while ( aDestinationIndex < myObjects.count() && !isObjectVisible( aDestinationIndex ) ) {
318             aDestinationIndex++;
319           }
320         }
321       }
322       break;
323     case Top:
324       isInsertBefore = true;
325       if ( theItem > 0 ) {
326         aDestinationIndex = 0;
327       }
328       break;
329     case Bottom:
330       if ( theItem < myObjects.count() - 1 ) {
331         aDestinationIndex = myObjects.count() - 1;
332       }
333       break;
334     case DragAndDrop:
335       if ( theItem > theDropItem ) {
336         isInsertBefore = true;
337         aDestinationIndex = theDropItem;
338       } else {
339         aDestinationIndex = theDropItem - 1;
340       }
341       break;
342   }
343
344   if ( aDestinationIndex >= 0 && aDestinationIndex < myObjects.count() ) {
345     int aDestinationRow = isInsertBefore ? aDestinationIndex : aDestinationIndex + 1;
346     if ( beginMoveRows( QModelIndex(), theItem, theItem, QModelIndex(), aDestinationRow ) ) {
347       myObjects.move( theItem, aDestinationIndex );
348       endMoveRows();
349       aRes = true;
350     }
351   }
352         
353   return aRes;
354 }
355
356 /**
357   Move the items.
358   @param theItems the list of item ids to move
359   @param theType the move operation type
360   @param theIsVisibleOnly indicates if do move relating to the visible objects only
361   @param theDropItem the drop item id ( used for drag and drop obly )
362   @return true in case of success
363 */
364 bool HYDROGUI_ListModel::move( const QList<int>& theItems, const OpType theType, 
365                                   bool theIsVisibleOnly, const int theDropItem )
366 {
367   bool aRes = true;
368
369   QListIterator<int> anIt( theItems );
370   int aDragShift = 0;
371
372   switch ( theType ) {
373     case Top:
374     case Down:
375       // reverse order
376       anIt.toBack();
377       while ( anIt.hasPrevious() ) {
378         int anId = anIt.previous();
379         if ( theType == Top ) {
380           anId += aDragShift;
381           aDragShift++;
382         }
383         if ( !move( anId, theType, theIsVisibleOnly, theDropItem ) ) {
384           aRes = false;
385           break;
386         }
387       }
388       break;
389     case Bottom:
390     case Up:
391       // direct order
392       while ( anIt.hasNext() ) {
393         int anId = anIt.next();
394         if ( theType == Bottom ) {
395           anId -= aDragShift;
396           aDragShift++;
397         }
398         if ( !move( anId, theType, theIsVisibleOnly, theDropItem ) ) {
399           aRes = false;
400           break;
401         }
402       }
403       break;
404     case DragAndDrop:
405       // direct order
406       aRes = isDragAndDropAllowed( theItems, theDropItem );
407       if ( aRes ) {
408         int aDropShift = 0;
409         int aDropItem = theDropItem;
410         while ( anIt.hasNext() ) {
411           int anId = anIt.next();
412           aDropItem = theDropItem + aDropShift;
413           if ( anId > aDropItem ) {
414             aDragShift = 0;
415             aDropShift++;
416           } else {
417             anId -= aDragShift;
418             if ( ( aDropItem - anId ) != 1 ) {
419               aDragShift++;
420             }
421           }
422           move( anId, theType, theIsVisibleOnly, aDropItem );
423         }
424       }
425       break;
426     default:
427       aRes = false;
428   }
429   
430   return aRes;
431 }
432
433 /**
434   Check if drag and drop operation allowed.
435   @param theItems the list of dragged item ids
436   @param theDropItem the drop item id
437   @return true if drag and drop allowed
438 */
439 bool HYDROGUI_ListModel::isDragAndDropAllowed( const QList<int>& theItems, 
440                                                   const int theDropItem ) const
441 {
442   bool isAllowed = false;
443
444   if ( theDropItem >= 0 && theDropItem < myObjects.count() &&
445        !theItems.empty() && theItems.count() < myObjects.count() &&
446        !theItems.contains( theDropItem )) {
447     isAllowed = true;
448   }
449
450   return isAllowed;
451 }