Salome HOME
getting nb of intersections (non-gui) + add of profiles of stream to tree
[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 <HYDROGUI_DataObject.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     bool aRuleChanged = false;
125     myPrevRules = myRules;
126
127     int aColumn = theIndex.column();
128
129     if ( aColumn == 0 || aColumn == 2 ) {
130       Handle(HYDROData_Entity) anObject;
131       QString anObjName = theValue.toString();
132       foreach ( const Handle(HYDROData_Entity) anObj, myObjects ) {
133         if ( anObj->GetName() == anObjName ) {
134           anObject = anObj;
135           break;
136         }
137       }
138       if ( !anObject.IsNull() ) {
139         HYDROData_CustomRule anEditedRule = myRules[aRow];
140         
141         QString anEntryNew = HYDROGUI_DataObject::dataObjectEntry( anObject );
142         if ( aColumn == 0 ) {
143           QString anEntryOld = HYDROGUI_DataObject::dataObjectEntry( anEditedRule.Object1 );
144           if ( anEntryOld != anEntryNew )
145             aRuleChanged = true;
146           anEditedRule.Object1 = anObject;
147         } else {
148           QString anEntryOld = HYDROGUI_DataObject::dataObjectEntry( anEditedRule.Object2 );
149           if ( anEntryOld != anEntryNew )
150             aRuleChanged = true;
151           anEditedRule.Object2 = anObject;
152         }
153         
154         if ( !isUsed( anEditedRule.Object1, anEditedRule.Object2 ) ) {
155           myRules[aRow] = anEditedRule;
156           aRes = true;
157         } else {
158           aRuleChanged = false;
159           emit showError( tr("ALREADY_EXISTS") );
160         }
161       }
162     } else if ( aColumn == 1 ) {
163       HYDROData_PriorityType aNewPriority = (HYDROData_PriorityType)theValue.toInt();
164       if ( myRules[aRow].Priority != aNewPriority )
165         aRuleChanged = true;
166       myRules[aRow].Priority = aNewPriority;
167     } else if ( aColumn == 3 ) {
168       HYDROData_Zone::MergeType aNewMergeType = (HYDROData_Zone::MergeType)theValue.toInt();
169       if ( myRules[aRow].MergeType != aNewMergeType )
170         aRuleChanged = true;
171       myRules[aRow].MergeType = aNewMergeType;
172     }
173
174     if ( aRuleChanged )
175       emit ruleChanged();
176   }
177
178   return aRes;
179 }
180
181 /**
182  */
183 int HYDROGUI_PriorityTableModel::rowCount( const QModelIndex &theParent ) const
184 {
185   return myRules.count();
186 }
187
188 /**
189  */
190 int HYDROGUI_PriorityTableModel::columnCount( const QModelIndex &theParent ) const
191 {
192   return myColumnCount;
193 }
194
195 /**
196   Set rules.
197   @param theRules the list of rules
198 */
199 void HYDROGUI_PriorityTableModel::setRules( const HYDROData_ListOfRules& theRules )
200 {
201   beginResetModel();
202   myPrevRules = myRules;
203   myRules = theRules;
204   endResetModel();
205 }
206
207 /**
208   Get rules.
209   @return the list of rules
210 */
211 HYDROData_ListOfRules HYDROGUI_PriorityTableModel::getRules() const
212 {
213   return myRules;
214 }
215
216 /**
217 */
218 QVariant HYDROGUI_PriorityTableModel::headerData( int theSection,
219                                                   Qt::Orientation theOrientation,
220                                                   int theRole ) const
221 {
222   QVariant aData;
223
224   if ( theRole != Qt::DisplayRole ) {
225     return aData;
226   }
227
228   if ( theOrientation == Qt::Horizontal ) {
229     switch( theSection )
230     {
231     case 0:
232       aData = tr( "OBJECT1" );
233       break;
234     case 1:
235       aData = tr( "PRIORITY" );
236       break;
237     case 2:
238       aData = tr( "OBJECT2" );
239       break;
240     case 3:
241       {
242         if ( getObjectsKind() != KIND_LAND_COVER_MAP )
243           aData = tr( "BATHYMETRY" );
244       }
245       break;
246     };
247   } else if ( theOrientation == Qt::Vertical ) {
248     aData = theSection + 1;
249   }
250
251   return aData;
252 }
253
254 /**
255   Set objects which could be used for rules definition.
256   @param theObjects the ordered list of objects
257  */
258 void HYDROGUI_PriorityTableModel::setObjects( const QList<Handle(HYDROData_Entity)>& theObjects )
259 {
260   myObjects = theObjects;
261     
262   myPrevRules = myRules;
263
264   beginResetModel();
265
266   // Remove rules which use objects which are no longer available
267   QStringList aNames = getAvailableObjectNames();
268   QMutableListIterator<HYDROData_CustomRule> anIter( myRules );
269   while ( anIter.hasNext() ) {
270     HYDROData_CustomRule aRule = anIter.next();
271      if ( !aNames.contains( aRule.Object1->GetName() ) || 
272           !aNames.contains( aRule.Object2->GetName() ) ) {
273       anIter.remove();
274     }
275   }
276
277   endResetModel();
278 }
279
280 /**
281  Create new rule.
282  @return true if a rule has been created successfully
283  */
284 bool HYDROGUI_PriorityTableModel::createNewRule() 
285 {
286   if ( !canCreateNewRule() ) {
287     return false;
288   }
289   
290   // Existing pairs of object indexes
291   QStringList aNames = getAvailableObjectNames();
292   QList< QPair<int, int> > aRules;
293   foreach( const HYDROData_CustomRule& aRule, getRules() ) {
294     int anIndex1 = aNames.indexOf( aRule.Object1->GetName() );
295     int anIndex2 = aNames.indexOf( aRule.Object2->GetName() );
296     if ( anIndex1 >= 0 && anIndex2 >= 0 ) {
297       aRules << QPair<int, int>( anIndex1, anIndex2 );
298       aRules << QPair<int, int>( anIndex2, anIndex1 );
299     }
300   }
301     
302   // Try to find:
303   // 1. the new pair of objects 
304   // 2. the priority type corresponding to the objects order
305   Handle(HYDROData_Entity) anObject1, anObject2;
306   HYDROData_PriorityType aPriorityType = GREATER;
307
308   int aNbObjects = myObjects.count();
309   for ( int anIndex1 = 0; anIndex1 < aNbObjects; anIndex1++ ) {
310     bool isFound = false;
311
312     for ( int anIndex2 = 0; anIndex2 < aNbObjects; anIndex2++ ) {
313       if ( anIndex1 == anIndex2 ) {
314         continue;
315       }
316
317       if ( !aRules.contains( QPair<int, int>( anIndex1, anIndex2 ) ) ) {
318         anObject1 = myObjects.at( anIndex1 );
319         anObject2 = myObjects.at( anIndex2 );
320         if ( anIndex1 > anIndex2 ) {
321           aPriorityType = LESS;
322         }
323         isFound = true;
324         break;
325       }
326     }
327
328     if ( isFound ) {
329       break;
330     }
331   }
332
333   // Create a new rule
334   bool isCreated = false;
335
336   if ( !anObject1.IsNull() && !anObject2.IsNull() ) {
337     HYDROData_CustomRule aNewRule;
338     aNewRule.Object1 = anObject1;
339     aNewRule.Object2 = anObject2;
340     aNewRule.Priority = aPriorityType;
341     aNewRule.MergeType = HYDROData_Zone::Merge_ZMIN;
342
343     myPrevRules = myRules;
344
345     beginResetModel();
346     myRules << aNewRule;
347     endResetModel();
348
349     isCreated = true;
350   }
351
352   return isCreated;
353 }
354
355 /**
356  Check if a new rule can be created.
357  @return true if a new rule could be created
358  */
359 bool HYDROGUI_PriorityTableModel::canCreateNewRule() const
360 {
361   int aNbObjects = myObjects.count();
362
363   return ( myRules.count() < (aNbObjects - 1)*aNbObjects/2 );
364 }
365
366 /**
367  */
368 bool HYDROGUI_PriorityTableModel::removeRows ( int theRow, int theCount, const QModelIndex & theParent )
369 {
370   if ( myRules.isEmpty() || theRow < 0 || theRow >= myRules.count() ) {
371     return false;
372   }
373
374   int aLastRow = theRow + theCount - 1;
375   if ( aLastRow > myRules.count() ) {
376     aLastRow = myRules.count() - 1;
377   }
378
379   myPrevRules = myRules;
380
381   beginRemoveRows( theParent, theRow, aLastRow );
382
383   // Remove the corresponding rules
384   for ( int i = 1; i <= theCount; i++ ) {
385     myRules.removeAt( theRow );
386   }
387
388   endRemoveRows();
389
390   return true;
391 }
392
393 /**
394  Remove all data from the model.
395  @return true if at least one row is removed
396  */
397 bool HYDROGUI_PriorityTableModel::removeAll()
398 {
399   return removeRows( 0, rowCount() );
400 }
401
402 /**
403  Get available pairs for the given object.
404  @param theObject the object
405  @return the list of object names
406  */
407 QStringList HYDROGUI_PriorityTableModel::getAvailablePairs(  const Handle(HYDROData_Entity)& theObject ) const
408 {
409   QStringList aNames;
410
411   if ( !theObject.IsNull() ) {
412     aNames = getAvailableObjectNames();
413     aNames.removeAll( theObject->GetName() );
414   }
415
416   return aNames;
417 }
418
419 /**
420  Remove the rows.
421  @params theRows the list of rows to remove
422  @return true if at least one row is removed
423  */
424 bool HYDROGUI_PriorityTableModel::removeRows ( const QList<int> theRows )
425 {
426   QList<int> aSortedRows = theRows;
427   qSort( aSortedRows );
428
429   int aRowToRemove = -1;
430   int aNbRemoved = 0;
431   foreach ( int aRow, aSortedRows ) {
432     aRowToRemove = aRow - aNbRemoved;
433     if ( removeRow( aRowToRemove ) ) {
434       aNbRemoved++;
435     }
436   }
437
438   return ( aNbRemoved > 0 );
439 }
440
441 /**
442  Get priority string representation.
443  @param thePriority the priority
444  */
445 QString HYDROGUI_PriorityTableModel::priorityToString( const int thePriority ) const
446 {
447   switch( thePriority )
448   {
449   case LESS:
450     return tr( "LESS" );
451   case GREATER:
452     return tr( "GREATER" );
453   default:
454     return QString();
455   };
456 }
457
458 /**
459  Get merge type string representation.
460  @param theMergeType the merge type
461  */
462 QString HYDROGUI_PriorityTableModel::mergeTypeToString( const int theMergeType ) const
463 {
464   switch( theMergeType )
465   {
466   case HYDROData_Zone::Merge_Object:
467     return tr( "PRIORITY" );
468   case HYDROData_Zone::Merge_ZMIN:
469     return tr( "ZMIN" );
470   case HYDROData_Zone::Merge_ZMAX:
471     return tr( "ZMAX" );
472   default:
473     return QString();
474   };
475 }
476
477 /**
478   Check if the given pair of objects is already used.
479   @return true if the pair is used
480  */
481 bool HYDROGUI_PriorityTableModel::isUsed( const Handle(HYDROData_Entity)& theObj1, 
482                                           const Handle(HYDROData_Entity)& theObj2 ) const
483 {
484   bool isUsed = false;
485
486   foreach ( const HYDROData_CustomRule& aRule, myRules ) {
487     if ( ( aRule.Object1->GetName() == theObj1->GetName() && 
488            aRule.Object2->GetName() == theObj2->GetName() ) ||
489          ( aRule.Object1->GetName() == theObj2->GetName() && 
490            aRule.Object2->GetName() == theObj1->GetName() ) ) {
491       isUsed = true;
492       break;
493     }
494   }       
495
496   return isUsed;
497 }
498
499 /**
500   Get available object names.
501   @return the list of object names
502  */
503 QStringList HYDROGUI_PriorityTableModel::getAvailableObjectNames() const
504 {
505   QStringList aNames;
506
507   foreach ( const Handle(HYDROData_Entity) anObj, myObjects ) {
508     if ( !anObj.IsNull() ) {
509       aNames << anObj->GetName();
510     }
511   }
512
513   return aNames;
514 }
515
516 /**
517   Set number of columns in the table.
518   @param theColumnCount the number of columns
519  */
520 void HYDROGUI_PriorityTableModel::setColumnCount( int theColumnCount )
521 {
522   myColumnCount = theColumnCount;
523 }
524
525 /**
526  Undo last change in the list of priority rules.
527  */
528 void HYDROGUI_PriorityTableModel::undoLastChange()
529 {
530   beginResetModel();
531   myRules = myPrevRules;
532   endResetModel();
533   reset();
534 }
535
536 /**
537   Get type of objects for which rules are defined assuming,
538   that all objects in the list have the same type.
539   @return the type of objects
540  */
541 const ObjectKind HYDROGUI_PriorityTableModel::getObjectsKind() const
542 {
543   if ( myObjects.isEmpty() )
544     return KIND_UNKNOWN;
545   
546   return myObjects.at( 0 )->GetKind();
547 }