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