Salome HOME
refs #568: use ordered list view with selection synchronized with object browser...
[modules/hydro.git] / src / HYDROGUI / HYDROGUI_PriorityTableModel.cxx
index c0e1dacbfd2ea5b4edd6256e413c944c9371b5b5..6e2e46cd14efa289ff6f55974fd52cf78f5d89bd 100644 (file)
@@ -1,12 +1,8 @@
-// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
-//
-// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
-// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
-//
+// Copyright (C) 2014-2015  EDF-R&D
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 // License as published by the Free Software Foundation; either
-// version 2.1 of the License.
+// version 2.1 of the License, or (at your option) any later version.
 //
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 #include "HYDROGUI_PriorityTableModel.h"
 
+#include <HYDROData_LandCover.h>
 
 /**
   Constructor.
   @param theParent the parent object
 */
 HYDROGUI_PriorityTableModel::HYDROGUI_PriorityTableModel( QObject* theParent )
- : QAbstractTableModel( theParent )
+ : QAbstractTableModel( theParent ),
+   myColumnCount( 4 )
 {
 }
 
@@ -85,7 +83,13 @@ QVariant HYDROGUI_PriorityTableModel::data( const QModelIndex &theIndex, int the
     }
   } else if ( theRole ==  Qt::UserRole ) {
     if ( aColumn == 0 || aColumn == 2 ) {
-      aVariant = getAvailableObjects();
+      QStringList aNames;
+      HYDROData_CustomRule aRule = myRules.at( aRow );
+      Handle(HYDROData_Entity) aUsedObject = aColumn == 0 ? aRule.Object2 : aRule.Object1;
+      if ( !aUsedObject.IsNull() ) {
+        aNames = getAvailablePairs( aUsedObject );
+      }
+      aVariant = aNames;
     } else if ( aColumn == 1 ) {
       QMap<QString, QVariant> aMap;
       aMap.insert( priorityToString( LESS ), LESS );
@@ -120,22 +124,29 @@ bool HYDROGUI_PriorityTableModel::setData( const QModelIndex & theIndex, const Q
     int aColumn = theIndex.column();
 
     if ( aColumn == 0 || aColumn == 2 ) {
-      Handle(HYDROData_Object) anObject;
+      Handle(HYDROData_Entity) anObject;
       QString anObjName = theValue.toString();
-      foreach ( const Handle(HYDROData_Object) anObj, myObjects ) {
+      foreach ( const Handle(HYDROData_Entity) anObj, myObjects ) {
         if ( anObj->GetName() == anObjName ) {
           anObject = anObj;
           break;
         }
       }
       if ( !anObject.IsNull() ) {
+        HYDROData_CustomRule anEditedRule = myRules[aRow];
+        
         if ( aColumn == 0 ) {
-          myRules[aRow].Object1 = anObject;
+          anEditedRule.Object1 = anObject;
         } else {
-          myRules[aRow].Object2 = anObject;
+          anEditedRule.Object2 = anObject;
+        }
+        
+        if ( !isUsed( anEditedRule.Object1, anEditedRule.Object2 ) ) {
+          myRules[aRow] = anEditedRule;
+          aRes = true;
+        } else {
+          emit showError( tr("ALREADY_EXISTS") );
         }
-
-        aRes = true;
       }
     } else if ( aColumn == 1 ) {
       myRules[aRow].Priority = (HYDROData_PriorityType)theValue.toInt();
@@ -158,7 +169,7 @@ int HYDROGUI_PriorityTableModel::rowCount( const QModelIndex &theParent ) const
  */
 int HYDROGUI_PriorityTableModel::columnCount( const QModelIndex &theParent ) const
 {
-  return 4;
+  return myColumnCount;
 }
 
 /**
@@ -167,9 +178,9 @@ int HYDROGUI_PriorityTableModel::columnCount( const QModelIndex &theParent ) con
 */
 void HYDROGUI_PriorityTableModel::setRules( const HYDROData_ListOfRules& theRules )
 {
+  beginResetModel();
   myRules = theRules;
-
-  reset();
+  endResetModel();
 }
 
 /**
@@ -206,7 +217,10 @@ QVariant HYDROGUI_PriorityTableModel::headerData( int theSection,
       aData = tr( "OBJECT2" );
       break;
     case 3:
-      aData = tr( "BATHYMETRY" );
+      {
+        if ( getObjectsKind() != KIND_LAND_COVER )
+          aData = tr( "BATHYMETRY" );
+      }
       break;
     };
   } else if ( theOrientation == Qt::Vertical ) {
@@ -217,74 +231,159 @@ QVariant HYDROGUI_PriorityTableModel::headerData( int theSection,
 }
 
 /**
-  Set objects which could be used for rules.
-  @param theObjects the list of objects
+  Set objects which could be used for rules definition.
+  @param theObjects the ordered list of objects
  */
-void HYDROGUI_PriorityTableModel::setObjects( const QList<Handle(HYDROData_Object)>& theObjects )
+void HYDROGUI_PriorityTableModel::setObjects( const QList<Handle(HYDROData_Entity)>& theObjects )
 {
   myObjects = theObjects;
+    
+  beginResetModel();
 
+  // Remove rules which use objects which are no longer available
+  QStringList aNames = getAvailableObjectNames();
   QMutableListIterator<HYDROData_CustomRule> anIter( myRules );
   while ( anIter.hasNext() ) {
     HYDROData_CustomRule aRule = anIter.next();
-     if ( !myObjects.contains( aRule.Object1 ) || 
-          !myObjects.contains( aRule.Object2 ) ) {
+     if ( !aNames.contains( aRule.Object1->GetName() ) || 
+          !aNames.contains( aRule.Object2->GetName() ) ) {
       anIter.remove();
     }
   }
 
-  reset();
+  endResetModel();
 }
 
 /**
- Create new rule. 
+ Create new rule.
+ @return true if a rule has been created successfully
  */
-void HYDROGUI_PriorityTableModel::createNewRule() 
+bool HYDROGUI_PriorityTableModel::createNewRule() 
 {
-  if ( myObjects.count() < 2 ) {
-    return;
+  if ( !canCreateNewRule() ) {
+    return false;
+  }
+  
+  // Existing pairs of object indexes
+  QStringList aNames = getAvailableObjectNames();
+  QList< QPair<int, int> > aRules;
+  foreach( const HYDROData_CustomRule& aRule, getRules() ) {
+    int anIndex1 = aNames.indexOf( aRule.Object1->GetName() );
+    int anIndex2 = aNames.indexOf( aRule.Object2->GetName() );
+    if ( anIndex1 >= 0 && anIndex2 >= 0 ) {
+      aRules << QPair<int, int>( anIndex1, anIndex2 );
+      aRules << QPair<int, int>( anIndex2, anIndex1 );
+    }
+  }
+    
+  // Try to find:
+  // 1. the new pair of objects 
+  // 2. the priority type corresponding to the objects order
+  Handle(HYDROData_Entity) anObject1, anObject2;
+  HYDROData_PriorityType aPriorityType = GREATER;
+
+  int aNbObjects = myObjects.count();
+  for ( int anIndex1 = 0; anIndex1 < aNbObjects; anIndex1++ ) {
+    bool isFound = false;
+
+    for ( int anIndex2 = 0; anIndex2 < aNbObjects; anIndex2++ ) {
+      if ( anIndex1 == anIndex2 ) {
+        continue;
+      }
+
+      if ( !aRules.contains( QPair<int, int>( anIndex1, anIndex2 ) ) ) {
+        anObject1 = myObjects.at( anIndex1 );
+        anObject2 = myObjects.at( anIndex2 );
+        if ( anIndex1 > anIndex2 ) {
+          aPriorityType = LESS;
+        }
+        isFound = true;
+        break;
+      }
+    }
+
+    if ( isFound ) {
+      break;
+    }
+  }
+
+  // Create a new rule
+  bool isCreated = false;
+
+  if ( !anObject1.IsNull() && !anObject2.IsNull() ) {
+    HYDROData_CustomRule aNewRule;
+    aNewRule.Object1 = anObject1;
+    aNewRule.Object2 = anObject2;
+    aNewRule.Priority = aPriorityType;
+    aNewRule.MergeType = HYDROData_Zone::Merge_ZMIN;
+
+    beginResetModel();
+    myRules << aNewRule;
+    endResetModel();
+
+    isCreated = true;
   }
 
-  HYDROData_CustomRule aNewRule;
-  aNewRule.Object1 = myObjects.at(0);
-  aNewRule.Object2 = myObjects.at(1);
-  aNewRule.Priority = LESS;
-  aNewRule.MergeType = HYDROData_Zone::Merge_ZMIN;
+  return isCreated;
+}
 
-  myRules << aNewRule;
+/**
+ Check if a new rule can be created.
+ @return true if a new rule could be created
+ */
+bool HYDROGUI_PriorityTableModel::canCreateNewRule() const
+{
+  int aNbObjects = myObjects.count();
 
-  reset();
+  return ( myRules.count() < (aNbObjects - 1)*aNbObjects/2 );
 }
 
 /**
  */
 bool HYDROGUI_PriorityTableModel::removeRows ( int theRow, int theCount, const QModelIndex & theParent )
 {
-  bool aRes = false;
+  if ( myRules.isEmpty() || theRow < 0 || theRow >= myRules.count() ) {
+    return false;
+  }
 
-  if ( theRow + theCount <= myRules.count() ) {
-    for ( int i = 1; i <= theCount; i++ ) {
-      myRules.removeAt( theRow );
-    }
-    aRes = true;
-    reset();
+  int aLastRow = theRow + theCount - 1;
+  if ( aLastRow > myRules.count() ) {
+    aLastRow = myRules.count() - 1;
+  }
+
+  beginRemoveRows( theParent, theRow, aLastRow );
+
+  // Remove the corresponding rules
+  for ( int i = 1; i <= theCount; i++ ) {
+    myRules.removeAt( theRow );
   }
 
+  endRemoveRows();
+
   return true;
 }
 
 /**
- Get available objects.
+ Remove all data from the model.
+ @return true if at least one row is removed
+ */
+bool HYDROGUI_PriorityTableModel::removeAll()
+{
+  return removeRows( 0, rowCount() );
+}
+
+/**
+ Get available pairs for the given object.
+ @param theObject the object
  @return the list of object names
  */
-QStringList HYDROGUI_PriorityTableModel::getAvailableObjects() const
+QStringList HYDROGUI_PriorityTableModel::getAvailablePairs(  const Handle(HYDROData_Entity)& theObject ) const
 {
   QStringList aNames;
 
-  foreach ( const Handle(HYDROData_Object) anObj, myObjects ) {
-    if ( !anObj.IsNull() ) {
-      aNames << anObj->GetName();
-    }
+  if ( !theObject.IsNull() ) {
+    aNames = getAvailableObjectNames();
+    aNames.removeAll( theObject->GetName() );
   }
 
   return aNames;
@@ -293,8 +392,9 @@ QStringList HYDROGUI_PriorityTableModel::getAvailableObjects() const
 /**
  Remove the rows.
  @params theRows the list of rows to remove
+ @return true if at least one row is removed
  */
-void HYDROGUI_PriorityTableModel::removeRows ( const QList<int> theRows )
+bool HYDROGUI_PriorityTableModel::removeRows ( const QList<int> theRows )
 {
   QList<int> aSortedRows = theRows;
   qSort( aSortedRows );
@@ -307,6 +407,8 @@ void HYDROGUI_PriorityTableModel::removeRows ( const QList<int> theRows )
       aNbRemoved++;
     }
   }
+
+  return ( aNbRemoved > 0 );
 }
 
 /**
@@ -344,3 +446,64 @@ QString HYDROGUI_PriorityTableModel::mergeTypeToString( const int theMergeType )
     return QString();
   };
 }
+
+/**
+  Check if the given pair of objects is already used.
+  @return true if the pair is used
+ */
+bool HYDROGUI_PriorityTableModel::isUsed( const Handle(HYDROData_Entity)& theObj1, 
+                                          const Handle(HYDROData_Entity)& theObj2 ) const
+{
+  bool isUsed = false;
+
+  foreach ( const HYDROData_CustomRule& aRule, myRules ) {
+    if ( ( aRule.Object1->GetName() == theObj1->GetName() && 
+           aRule.Object2->GetName() == theObj2->GetName() ) ||
+         ( aRule.Object1->GetName() == theObj2->GetName() && 
+           aRule.Object2->GetName() == theObj1->GetName() ) ) {
+      isUsed = true;
+      break;
+    }
+  }       
+
+  return isUsed;
+}
+
+/**
+  Get available object names.
+  @return the list of object names
+ */
+QStringList HYDROGUI_PriorityTableModel::getAvailableObjectNames() const
+{
+  QStringList aNames;
+
+  foreach ( const Handle(HYDROData_Entity) anObj, myObjects ) {
+    if ( !anObj.IsNull() ) {
+      aNames << anObj->GetName();
+    }
+  }
+
+  return aNames;
+}
+
+/**
+  Set number of columns in the table.
+  @param theColumnCount the number of columns
+ */
+void HYDROGUI_PriorityTableModel::setColumnCount( int theColumnCount )
+{
+  myColumnCount = theColumnCount;
+}
+
+/**
+  Get type of objects for which rules are defined assuming,
+  that all objects in the list have the same type.
+  @return the type of objects
+ */
+const ObjectKind HYDROGUI_PriorityTableModel::getObjectsKind() const
+{
+  if ( myObjects.isEmpty() )
+    return KIND_UNKNOWN;
+  
+  return myObjects.at( 0 )->GetKind();
+}