Salome HOME
refs #430: incorrect coordinates in dump polyline
[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::transparent );
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, true );
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   // TODO: to disable drop between items use: int aDropItemId = theParent.row();
241   int aDropItemId = theParent.isValid() ? theParent.row() : theRow;
242
243   QByteArray anEncodedData = theData->data( OBJ_LIST_MIME_TYPE );
244   QDataStream aStream( &anEncodedData, QIODevice::ReadOnly );
245   QList<int> anIdsList;
246   while( !aStream.atEnd() )
247   {
248     int anId;
249     aStream >> anId;
250     anIdsList << anId;
251   }
252
253   move( anIdsList, DragAndDrop, false, aDropItemId ); //TODO set visibility?
254   return true;
255 }
256
257 /**
258 */
259 Qt::DropActions HYDROGUI_ListModel::supportedDropActions() const
260 {
261   return Qt::MoveAction | Qt::CopyAction;
262 }
263
264 /**
265   Get list of ids by the list model indexes.
266   @param theIsToSort defines if the list of ids should be sorted in ascending order
267   @return the list of ids
268 */
269 QList<int> HYDROGUI_ListModel::getIds( const QModelIndexList& theIndexes, 
270                                        bool theIsToSort ) const
271 {
272   QList<int> anIds;
273   foreach( const QModelIndex& anIndex, theIndexes ) {
274     anIds << anIndex.row();
275   }
276
277   if ( theIsToSort ) {
278     qSort( anIds );
279   }
280
281   return anIds;
282 }
283
284 /**
285   Move the item.
286   @param theItem the item id to move
287   @param theType the move operation type
288   @param theIsVisibleOnly indicates if do move relating to the visible objects only
289   @param theDropItem the drop item id ( used for drag and drop obly )
290   @return true in case of success
291 */
292 bool HYDROGUI_ListModel::move( const int theItem, const OpType theType,
293                                bool theIsVisibleOnly, const int theDropItem )
294 {
295   bool aRes = false;
296   if ( theItem < 0 || theItem >= myObjects.count() ) {
297     return aRes;
298   }
299
300   int aDestinationIndex = -1;
301   bool isInsertBefore = false;
302
303   switch ( theType ) {
304     case Up:
305       isInsertBefore = true;
306       if ( theItem > 0 ) {
307         aDestinationIndex = theItem - 1;
308         if ( theIsVisibleOnly ) {
309           while ( aDestinationIndex >= 0 && !isObjectVisible( aDestinationIndex ) ) {
310             aDestinationIndex--;
311           }
312         }
313       }
314       break;
315     case Down:
316       if ( theItem < myObjects.count() - 1 ) {
317         aDestinationIndex = theItem + 1;
318         if ( theIsVisibleOnly ) {
319           while ( aDestinationIndex < myObjects.count() && !isObjectVisible( aDestinationIndex ) ) {
320             aDestinationIndex++;
321           }
322         }
323       }
324       break;
325     case Top:
326       isInsertBefore = true;
327       if ( theItem > 0 ) {
328         aDestinationIndex = 0;
329       }
330       break;
331     case Bottom:
332       if ( theItem < myObjects.count() - 1 ) {
333         aDestinationIndex = myObjects.count() - 1;
334       }
335       break;
336     case DragAndDrop:
337       if ( theItem > theDropItem ) {
338         isInsertBefore = true;
339         aDestinationIndex = theDropItem;
340       } else {
341         aDestinationIndex = theDropItem - 1;
342       }
343       break;
344   }
345
346   if ( aDestinationIndex >= 0 && aDestinationIndex < myObjects.count() ) {
347     int aDestinationRow = isInsertBefore ? aDestinationIndex : aDestinationIndex + 1;
348     if ( beginMoveRows( QModelIndex(), theItem, theItem, QModelIndex(), aDestinationRow ) ) {
349       myObjects.move( theItem, aDestinationIndex );
350       endMoveRows();
351       aRes = true;
352     }
353   }
354         
355   return aRes;
356 }
357
358 /**
359   Move the items.
360   @param theItems the list of item ids to move
361   @param theType the move operation type
362   @param theIsVisibleOnly indicates if do move relating to the visible objects only
363   @param theDropItem the drop item id ( used for drag and drop obly )
364   @return true in case of success
365 */
366 bool HYDROGUI_ListModel::move( const QList<int>& theItems, const OpType theType, 
367                                bool theIsVisibleOnly, const int theDropItem )
368 {
369   bool aRes = true;
370
371   QListIterator<int> anIt( theItems );
372   int aDragShift = 0;
373
374   switch ( theType ) {
375     case Top:
376     case Down:
377       // reverse order
378       anIt.toBack();
379       while ( anIt.hasPrevious() ) {
380         int anId = anIt.previous();
381         if ( theType == Top ) {
382           anId += aDragShift;
383           aDragShift++;
384         }
385         if ( !move( anId, theType, theIsVisibleOnly, theDropItem ) ) {
386           aRes = false;
387           break;
388         }
389       }
390       break;
391     case Bottom:
392     case Up:
393       // direct order
394       while ( anIt.hasNext() ) {
395         int anId = anIt.next();
396         if ( theType == Bottom ) {
397           anId -= aDragShift;
398           aDragShift++;
399         }
400         if ( !move( anId, theType, theIsVisibleOnly, theDropItem ) ) {
401           aRes = false;
402           break;
403         }
404       }
405       break;
406     case DragAndDrop:
407       // direct order
408       aRes = isDragAndDropAllowed( theItems, theDropItem );
409       if ( aRes ) {
410         int aDropShift = 0;
411         int aDropItem = theDropItem;
412         while ( anIt.hasNext() ) {
413           int anId = anIt.next();
414           aDropItem = theDropItem + aDropShift;
415           if ( anId > aDropItem ) {
416             aDragShift = 0;
417             aDropShift++;
418           } else {
419             anId -= aDragShift;
420             if ( ( aDropItem - anId ) != 1 ) {
421               aDragShift++;
422             }
423           }
424           move( anId, theType, theIsVisibleOnly, aDropItem );
425         }
426       }
427       break;
428     default:
429       aRes = false;
430   }
431   
432   return aRes;
433 }
434
435 /**
436   Check if drag and drop operation allowed.
437   @param theItems the list of dragged item ids
438   @param theDropItem the drop item id
439   @return true if drag and drop allowed
440 */
441 bool HYDROGUI_ListModel::isDragAndDropAllowed( const QList<int>& theItems, 
442                                                const int theDropItem ) const
443 {
444   bool isAllowed = false;
445
446   if ( theDropItem >= 0 && 
447        // TODO: to disable drop between items use: theDropItem < myObjects.count()
448        theDropItem <= myObjects.count() &&
449        !theItems.empty() && theItems.count() < myObjects.count() &&
450        !theItems.contains( theDropItem )) {
451     isAllowed = true;
452   }
453
454   return isAllowed;
455 }