Salome HOME
refs #567: add "POLYLINES" partition and modified icon for Land Cover object.
[modules/hydro.git] / src / HYDROGUI / HYDROGUI_PriorityTableModel.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_PriorityTableModel.h"
20
21 #include <HYDROData_LandCover.h>
22
23 /**
24   Constructor.
25   @param theParent the parent object
26 */
27 HYDROGUI_PriorityTableModel::HYDROGUI_PriorityTableModel( QObject* theParent )
28  : QAbstractTableModel( theParent ),
29    myColumnCount( 4 )
30 {
31 }
32
33 /**
34   Destructor.
35 */
36 HYDROGUI_PriorityTableModel::~HYDROGUI_PriorityTableModel()
37 {
38 }
39
40 /**
41  */
42 Qt::ItemFlags   HYDROGUI_PriorityTableModel::flags( const QModelIndex & theIndex ) const
43 {
44   return Qt::ItemIsSelectable   | Qt::ItemIsEditable | Qt::ItemIsEnabled;
45 }
46
47 /**
48  */
49 QVariant HYDROGUI_PriorityTableModel::data( const QModelIndex &theIndex, int theRole ) const
50 {
51   QVariant aVariant;
52
53   int aRow = theIndex.row();
54   int aColumn = theIndex.column();
55
56   if ( !theIndex.isValid() || aRow > myRules.size() ) {
57     return aVariant;
58   }
59   
60   if ( theRole == Qt::DisplayRole ) {
61     HYDROData_CustomRule aRule = myRules.at(aRow);
62
63     if ( aColumn == 0 ) {
64       aVariant = aRule.Object1->GetName();
65     } else if ( aColumn == 1 ) {
66       aVariant = priorityToString( aRule.Priority );
67     } else if ( aColumn == 2 ) {
68       aVariant = aRule.Object2->GetName();
69     } else if ( aColumn == 3 ) {
70       aVariant = mergeTypeToString( aRule.MergeType );
71     }
72   } else if ( theRole == Qt::EditRole ) {
73     HYDROData_CustomRule aRule = myRules.at(aRow);
74
75     if ( aColumn == 0 ) {
76       aVariant = aRule.Object1->GetName();
77     } else if ( aColumn == 1 ) {
78       aVariant = aRule.Priority;
79     } else if ( aColumn == 2 ) {
80       aVariant = aRule.Object2->GetName();
81     } else if ( aColumn == 3 ) {
82       aVariant = aRule.MergeType;
83     }
84   } else if ( theRole ==  Qt::UserRole ) {
85     if ( aColumn == 0 || aColumn == 2 ) {
86       QStringList aNames;
87       HYDROData_CustomRule aRule = myRules.at( aRow );
88       Handle(HYDROData_Entity) aUsedObject = aColumn == 0 ? aRule.Object2 : aRule.Object1;
89       if ( !aUsedObject.IsNull() ) {
90         aNames = getAvailablePairs( aUsedObject );
91       }
92       aVariant = aNames;
93     } else if ( aColumn == 1 ) {
94       QMap<QString, QVariant> aMap;
95       aMap.insert( priorityToString( LESS ), LESS );
96       aMap.insert( priorityToString( GREATER ), GREATER );
97       aVariant = QVariant( aMap );
98     } else if ( aColumn == 3 ) {
99       QMap<QString, QVariant> aMap;
100       aMap.insert( mergeTypeToString( HYDROData_Zone::Merge_Object ), HYDROData_Zone::Merge_Object );
101       aMap.insert( mergeTypeToString( HYDROData_Zone::Merge_ZMIN ), HYDROData_Zone::Merge_ZMIN );
102       aMap.insert( mergeTypeToString( HYDROData_Zone::Merge_ZMAX ), HYDROData_Zone::Merge_ZMAX );
103       aVariant = QVariant( aMap );
104     } 
105   } else if ( theRole == Qt::TextAlignmentRole ) {
106     aVariant = Qt::AlignCenter;
107   }
108
109   return aVariant;
110 }
111
112 /**
113  */
114 bool HYDROGUI_PriorityTableModel::setData( const QModelIndex & theIndex, const QVariant & theValue, int theRole )
115 {
116   int aRow = theIndex.row();
117   if ( !theIndex.isValid() || aRow > myRules.size() ) {
118     return false;
119   }
120
121   bool aRes = false;
122
123   if ( theRole ==  Qt::EditRole ) {
124     int aColumn = theIndex.column();
125
126     if ( aColumn == 0 || aColumn == 2 ) {
127       Handle(HYDROData_Entity) anObject;
128       QString anObjName = theValue.toString();
129       foreach ( const Handle(HYDROData_Entity) anObj, myObjects ) {
130         if ( anObj->GetName() == anObjName ) {
131           anObject = anObj;
132           break;
133         }
134       }
135       if ( !anObject.IsNull() ) {
136         HYDROData_CustomRule anEditedRule = myRules[aRow];
137         
138         if ( aColumn == 0 ) {
139           anEditedRule.Object1 = anObject;
140         } else {
141           anEditedRule.Object2 = anObject;
142         }
143         
144         if ( !isUsed( anEditedRule.Object1, anEditedRule.Object2 ) ) {
145           myRules[aRow] = anEditedRule;
146           aRes = true;
147         } else {
148           emit showError( tr("ALREADY_EXISTS") );
149         }
150       }
151     } else if ( aColumn == 1 ) {
152       myRules[aRow].Priority = (HYDROData_PriorityType)theValue.toInt();
153     } else if ( aColumn == 3 ) {
154       myRules[aRow].MergeType = (HYDROData_Zone::MergeType)theValue.toInt();;
155     }
156   }
157
158   return aRes;
159 }
160
161 /**
162  */
163 int HYDROGUI_PriorityTableModel::rowCount( const QModelIndex &theParent ) const
164 {
165   return myRules.count();
166 }
167
168 /**
169  */
170 int HYDROGUI_PriorityTableModel::columnCount( const QModelIndex &theParent ) const
171 {
172   return myColumnCount;
173 }
174
175 /**
176   Set rules.
177   @param theRules the list of rules
178 */
179 void HYDROGUI_PriorityTableModel::setRules( const HYDROData_ListOfRules& theRules )
180 {
181   beginResetModel();
182   myRules = theRules;
183   endResetModel();
184 }
185
186 /**
187   Get rules.
188   @return the list of rules
189 */
190 HYDROData_ListOfRules HYDROGUI_PriorityTableModel::getRules() const
191 {
192   return myRules;
193 }
194
195 /**
196 */
197 QVariant HYDROGUI_PriorityTableModel::headerData( int theSection,
198                                                   Qt::Orientation theOrientation,
199                                                   int theRole ) const
200 {
201   QVariant aData;
202
203   if ( theRole != Qt::DisplayRole ) {
204     return aData;
205   }
206
207   if ( theOrientation == Qt::Horizontal ) {
208     switch( theSection )
209     {
210     case 0:
211       aData = tr( "OBJECT1" );
212       break;
213     case 1:
214       aData = tr( "PRIORITY" );
215       break;
216     case 2:
217       aData = tr( "OBJECT2" );
218       break;
219     case 3:
220       {
221         if ( getObjectsKind() != KIND_LAND_COVER )
222           aData = tr( "BATHYMETRY" );
223       }
224       break;
225     };
226   } else if ( theOrientation == Qt::Vertical ) {
227     aData = theSection + 1;
228   }
229
230   return aData;
231 }
232
233 /**
234   Set objects which could be used for rules definition.
235   @param theObjects the ordered list of objects
236  */
237 void HYDROGUI_PriorityTableModel::setObjects( const QList<Handle(HYDROData_Entity)>& theObjects )
238 {
239   myObjects = theObjects;
240     
241   beginResetModel();
242
243   // Remove rules which use objects which are no longer available
244   QStringList aNames = getAvailableObjectNames();
245   QMutableListIterator<HYDROData_CustomRule> anIter( myRules );
246   while ( anIter.hasNext() ) {
247     HYDROData_CustomRule aRule = anIter.next();
248      if ( !aNames.contains( aRule.Object1->GetName() ) || 
249           !aNames.contains( aRule.Object2->GetName() ) ) {
250       anIter.remove();
251     }
252   }
253
254   endResetModel();
255 }
256
257 /**
258  Create new rule.
259  @return true if a rule has been created successfully
260  */
261 bool HYDROGUI_PriorityTableModel::createNewRule() 
262 {
263   if ( !canCreateNewRule() ) {
264     return false;
265   }
266   
267   // Existing pairs of object indexes
268   QStringList aNames = getAvailableObjectNames();
269   QList< QPair<int, int> > aRules;
270   foreach( const HYDROData_CustomRule& aRule, getRules() ) {
271     int anIndex1 = aNames.indexOf( aRule.Object1->GetName() );
272     int anIndex2 = aNames.indexOf( aRule.Object2->GetName() );
273     if ( anIndex1 >= 0 && anIndex2 >= 0 ) {
274       aRules << QPair<int, int>( anIndex1, anIndex2 );
275       aRules << QPair<int, int>( anIndex2, anIndex1 );
276     }
277   }
278     
279   // Try to find:
280   // 1. the new pair of objects 
281   // 2. the priority type corresponding to the objects order
282   Handle(HYDROData_Entity) anObject1, anObject2;
283   HYDROData_PriorityType aPriorityType = GREATER;
284
285   int aNbObjects = myObjects.count();
286   for ( int anIndex1 = 0; anIndex1 < aNbObjects; anIndex1++ ) {
287     bool isFound = false;
288
289     for ( int anIndex2 = 0; anIndex2 < aNbObjects; anIndex2++ ) {
290       if ( anIndex1 == anIndex2 ) {
291         continue;
292       }
293
294       if ( !aRules.contains( QPair<int, int>( anIndex1, anIndex2 ) ) ) {
295         anObject1 = myObjects.at( anIndex1 );
296         anObject2 = myObjects.at( anIndex2 );
297         if ( anIndex1 > anIndex2 ) {
298           aPriorityType = LESS;
299         }
300         isFound = true;
301         break;
302       }
303     }
304
305     if ( isFound ) {
306       break;
307     }
308   }
309
310   // Create a new rule
311   bool isCreated = false;
312
313   if ( !anObject1.IsNull() && !anObject2.IsNull() ) {
314     HYDROData_CustomRule aNewRule;
315     aNewRule.Object1 = anObject1;
316     aNewRule.Object2 = anObject2;
317     aNewRule.Priority = aPriorityType;
318     aNewRule.MergeType = HYDROData_Zone::Merge_ZMIN;
319
320     beginResetModel();
321     myRules << aNewRule;
322     endResetModel();
323
324     isCreated = true;
325   }
326
327   return isCreated;
328 }
329
330 /**
331  Check if a new rule can be created.
332  @return true if a new rule could be created
333  */
334 bool HYDROGUI_PriorityTableModel::canCreateNewRule() const
335 {
336   int aNbObjects = myObjects.count();
337
338   return ( myRules.count() < (aNbObjects - 1)*aNbObjects/2 );
339 }
340
341 /**
342  */
343 bool HYDROGUI_PriorityTableModel::removeRows ( int theRow, int theCount, const QModelIndex & theParent )
344 {
345   if ( myRules.isEmpty() || theRow < 0 || theRow >= myRules.count() ) {
346     return false;
347   }
348
349   int aLastRow = theRow + theCount - 1;
350   if ( aLastRow > myRules.count() ) {
351     aLastRow = myRules.count() - 1;
352   }
353
354   beginRemoveRows( theParent, theRow, aLastRow );
355
356   // Remove the corresponding rules
357   for ( int i = 1; i <= theCount; i++ ) {
358     myRules.removeAt( theRow );
359   }
360
361   endRemoveRows();
362
363   return true;
364 }
365
366 /**
367  Remove all data from the model.
368  @return true if at least one row is removed
369  */
370 bool HYDROGUI_PriorityTableModel::removeAll()
371 {
372   return removeRows( 0, rowCount() );
373 }
374
375 /**
376  Get available pairs for the given object.
377  @param theObject the object
378  @return the list of object names
379  */
380 QStringList HYDROGUI_PriorityTableModel::getAvailablePairs(  const Handle(HYDROData_Entity)& theObject ) const
381 {
382   QStringList aNames;
383
384   if ( !theObject.IsNull() ) {
385     aNames = getAvailableObjectNames();
386     aNames.removeAll( theObject->GetName() );
387   }
388
389   return aNames;
390 }
391
392 /**
393  Remove the rows.
394  @params theRows the list of rows to remove
395  @return true if at least one row is removed
396  */
397 bool HYDROGUI_PriorityTableModel::removeRows ( const QList<int> theRows )
398 {
399   QList<int> aSortedRows = theRows;
400   qSort( aSortedRows );
401
402   int aRowToRemove = -1;
403   int aNbRemoved = 0;
404   foreach ( int aRow, aSortedRows ) {
405     aRowToRemove = aRow - aNbRemoved;
406     if ( removeRow( aRowToRemove ) ) {
407       aNbRemoved++;
408     }
409   }
410
411   return ( aNbRemoved > 0 );
412 }
413
414 /**
415  Get priority string representation.
416  @param thePriority the priority
417  */
418 QString HYDROGUI_PriorityTableModel::priorityToString( const int thePriority ) const
419 {
420   switch( thePriority )
421   {
422   case LESS:
423     return tr( "LESS" );
424   case GREATER:
425     return tr( "GREATER" );
426   default:
427     return QString();
428   };
429 }
430
431 /**
432  Get merge type string representation.
433  @param theMergeType the merge type
434  */
435 QString HYDROGUI_PriorityTableModel::mergeTypeToString( const int theMergeType ) const
436 {
437   switch( theMergeType )
438   {
439   case HYDROData_Zone::Merge_Object:
440     return tr( "PRIORITY" );
441   case HYDROData_Zone::Merge_ZMIN:
442     return tr( "ZMIN" );
443   case HYDROData_Zone::Merge_ZMAX:
444     return tr( "ZMAX" );
445   default:
446     return QString();
447   };
448 }
449
450 /**
451   Check if the given pair of objects is already used.
452   @return true if the pair is used
453  */
454 bool HYDROGUI_PriorityTableModel::isUsed( const Handle(HYDROData_Entity)& theObj1, 
455                                           const Handle(HYDROData_Entity)& theObj2 ) const
456 {
457   bool isUsed = false;
458
459   foreach ( const HYDROData_CustomRule& aRule, myRules ) {
460     if ( ( aRule.Object1->GetName() == theObj1->GetName() && 
461            aRule.Object2->GetName() == theObj2->GetName() ) ||
462          ( aRule.Object1->GetName() == theObj2->GetName() && 
463            aRule.Object2->GetName() == theObj1->GetName() ) ) {
464       isUsed = true;
465       break;
466     }
467   }       
468
469   return isUsed;
470 }
471
472 /**
473   Get available object names.
474   @return the list of object names
475  */
476 QStringList HYDROGUI_PriorityTableModel::getAvailableObjectNames() const
477 {
478   QStringList aNames;
479
480   foreach ( const Handle(HYDROData_Entity) anObj, myObjects ) {
481     if ( !anObj.IsNull() ) {
482       aNames << anObj->GetName();
483     }
484   }
485
486   return aNames;
487 }
488
489 /**
490   Set number of columns in the table.
491   @param theColumnCount the number of columns
492  */
493 void HYDROGUI_PriorityTableModel::setColumnCount( int theColumnCount )
494 {
495   myColumnCount = theColumnCount;
496 }
497
498 /**
499   Get type of objects for which rules are defined assuming,
500   that all objects in the list have the same type.
501   @return the type of objects
502  */
503 const ObjectKind HYDROGUI_PriorityTableModel::getObjectsKind() const
504 {
505   if ( myObjects.isEmpty() )
506     return KIND_UNKNOWN;
507   
508   return myObjects.at( 0 )->GetKind();
509 }