Salome HOME
Useful methods for sketch operations managements
[modules/shaper.git] / src / XGUI / XGUI_DocumentDataModel.cpp
1 #include "XGUI_DocumentDataModel.h"
2 #include "XGUI_PartDataModel.h"
3 #include "XGUI_Workshop.h"
4
5 #include <ModelAPI_PluginManager.h>
6 #include <ModelAPI_Document.h>
7 #include <ModelAPI_Feature.h>
8 #include <ModelAPI_Data.h>
9 #include <Model_Events.h>
10
11 #include <Events_Loop.h>
12
13 #include <Config_FeatureMessage.h>
14
15 #include <QIcon>
16 #include <QString>
17
18
19 XGUI_DocumentDataModel::XGUI_DocumentDataModel(QObject* theParent)
20   : QAbstractItemModel(theParent), myActivePart(0)
21 {
22   // Find Document object
23   boost::shared_ptr<ModelAPI_PluginManager> aMgr = ModelAPI_PluginManager::get();
24   myDocument = aMgr->currentDocument();
25
26   // Register in event loop
27   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
28   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
29   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
30
31   // Create a top part of data tree model
32   myModel = new XGUI_TopDataModel(myDocument, this);
33 }
34
35
36 XGUI_DocumentDataModel::~XGUI_DocumentDataModel()
37 {
38   clearModelIndexes();
39 }
40
41
42 void XGUI_DocumentDataModel::processEvent(const Events_Message* theMessage)
43 {
44   // Created object event *******************
45   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED)) {
46     const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
47     boost::shared_ptr<ModelAPI_Feature> aFeature = aUpdMsg->feature();
48     boost::shared_ptr<ModelAPI_Document> aDoc = aFeature->document();
49
50     if (aDoc == myDocument) {  // If root objects
51       if (aFeature->getGroup().compare(PARTS_GROUP) == 0) { // Update only Parts group
52         // Add a new part
53         int aStart = myPartModels.size() + 1;
54         XGUI_PartDataModel* aModel = new XGUI_PartDataModel(myDocument, this);
55         aModel->setPartId(myPartModels.count());
56         myPartModels.append(aModel);
57         insertRow(aStart, partFolderNode());
58       } else { // Update top groups (other except parts
59         QModelIndex aIndex = myModel->findParent(aFeature);
60         int aStart = myModel->rowCount(aIndex) - 1;
61         aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
62         insertRow(aStart, aIndex);
63       }
64     } else { // if sub-objects of first level nodes
65       XGUI_PartModel* aPartModel = 0;
66       QList<XGUI_PartModel*>::const_iterator aIt;
67       for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
68         if ((*aIt)->hasDocument(aDoc)) {
69           aPartModel = (*aIt);
70           break;
71         }
72       }
73       if (aPartModel) {
74         QModelIndex aIndex = aPartModel->findParent(aFeature);
75         int aStart = aPartModel->rowCount(aIndex) - 1;
76         aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
77         insertRow(aStart, aIndex);
78       }
79     }
80
81   // Deleted object event ***********************
82   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED)) {
83     const Model_FeatureDeletedMessage* aUpdMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
84     boost::shared_ptr<ModelAPI_Document> aDoc = aUpdMsg->document();
85
86     if (aDoc == myDocument) {  // If root objects
87       if (aUpdMsg->group().compare(PARTS_GROUP) == 0) { // Updsate only Parts group
88         int aStart = myPartModels.size();
89         removeSubModel(myPartModels.size() - 1);
90         removeRow(aStart - 1, partFolderNode());
91       } else { // Update top groups (other except parts
92         QModelIndex aIndex = myModel->findGroup(aUpdMsg->group());
93         int aStart = myModel->rowCount(aIndex);
94         aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
95         removeRow(aStart - 1, aIndex);
96       }
97     } else {
98       XGUI_PartModel* aPartModel = 0;
99       QList<XGUI_PartModel*>::const_iterator aIt;
100       for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
101         if ((*aIt)->hasDocument(aDoc)) {
102           aPartModel = (*aIt);
103           break;
104         }
105       }
106       if (aPartModel) {
107         QModelIndex aIndex = aPartModel->findGroup(aUpdMsg->group());
108         int aStart = aPartModel->rowCount(aIndex);
109         aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
110         removeRow(aStart - 1, aIndex);
111       }
112     }
113
114   // Deleted object event ***********************
115   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED)) {
116     //const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
117     //boost::shared_ptr<ModelAPI_Feature> aFeature = aUpdMsg->feature();
118     //boost::shared_ptr<ModelAPI_Document> aDoc = aFeature->document();
119     
120     // TODO: Identify the necessary index by the modified feature
121     QModelIndex aIndex;
122     emit dataChanged(aIndex, aIndex);
123
124   // Reset whole tree **************************
125   } else {  
126     beginResetModel();
127     int aNbParts = myDocument->size(PARTS_GROUP);
128     if (myPartModels.size() != aNbParts) { // resize internal models
129       while (myPartModels.size() > aNbParts) {
130         delete myPartModels.last();
131         myPartModels.removeLast();
132       }
133       while (myPartModels.size() < aNbParts) {
134         myPartModels.append(new XGUI_PartDataModel(myDocument, this));
135       }
136       for (int i = 0; i < myPartModels.size(); i++)
137         myPartModels.at(i)->setPartId(i);
138     }
139     clearModelIndexes();
140     endResetModel();
141   }
142 }
143
144 QVariant XGUI_DocumentDataModel::data(const QModelIndex& theIndex, int theRole) const
145 {
146   if (!theIndex.isValid())
147     return QVariant();
148   switch (theIndex.internalId()) {
149   case PartsFolder:
150     switch (theRole) {
151     case Qt::DisplayRole:
152       return tr("Parts") + QString(" (%1)").arg(rowCount(theIndex));
153     case Qt::DecorationRole:
154       return QIcon(":pictures/constr_folder.png");
155     case Qt::ToolTipRole:
156       return tr("Parts folder");
157     default:
158       return QVariant();
159     }
160     break;
161   case HistoryNode:
162     {
163       int aOffset = historyOffset();
164       FeaturePtr aFeature = myDocument->feature(FEATURES_GROUP, theIndex.row() - aOffset);
165       if (!aFeature)
166         return QVariant();
167       switch (theRole) {
168       case Qt::DisplayRole:
169         if (aFeature)
170           return aFeature->data()->getName().c_str();
171         else 
172           return QVariant();
173       case Qt::DecorationRole:
174         return QIcon(XGUI_Workshop::featureIcon(aFeature->getKind()));
175       case Qt::ToolTipRole:
176         return tr("Feature object");
177       default:
178         return QVariant();
179       }
180     }
181     break;
182   }
183   QModelIndex aParent = theIndex.parent();
184   if (aParent.isValid() && (aParent.internalId() == PartsFolder)) {
185     return myPartModels.at(theIndex.row())->data(QModelIndex(), theRole);
186   }
187   return toSourceModelIndex(theIndex)->data(theRole);
188 }
189
190
191 QVariant XGUI_DocumentDataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
192 {
193   return QVariant();
194 }
195
196 int XGUI_DocumentDataModel::rowCount(const QModelIndex& theParent) const
197 {
198   if (!theParent.isValid()) {
199     // Size of external models
200     int aVal = historyOffset();
201     // Plus history size
202     aVal += myDocument->size(FEATURES_GROUP);
203     return aVal;
204   }
205   if (theParent.internalId() == PartsFolder) {
206     return myPartModels.size();
207   }
208   if (theParent.internalId() == HistoryNode) {
209     return 0;
210   }
211   QModelIndex* aParent = toSourceModelIndex(theParent);
212   const QAbstractItemModel* aModel = aParent->model();
213   if (!isSubModel(aModel)) 
214     return 0;
215
216   if (isPartSubModel(aModel)) {
217     if (aModel != myActivePart)
218       return 0;
219   }
220   return aModel->rowCount(*aParent);
221 }
222
223 int XGUI_DocumentDataModel::columnCount(const QModelIndex& theParent) const
224 {
225   return 1;
226 }
227
228 QModelIndex XGUI_DocumentDataModel::index(int theRow, int theColumn, const QModelIndex& theParent) const
229 {
230   QModelIndex aIndex;
231   if (!theParent.isValid()) {
232     int aOffs = myModel->rowCount();
233     if (theRow < aOffs) {
234       aIndex = myModel->index(theRow, theColumn, theParent);
235       aIndex = createIndex(theRow, theColumn, (void*)getModelIndex(aIndex));
236     } else {
237       if (theRow == aOffs)  // Create Parts node
238         aIndex = partFolderNode();
239       else // create history node
240         aIndex = createIndex(theRow, theColumn, HistoryNode);
241     }
242   } else {
243     if (theParent.internalId() == PartsFolder) {
244       aIndex = myPartModels.at(theRow)->index(0, theColumn, QModelIndex());
245     } else {
246       QModelIndex* aParent = (QModelIndex*)theParent.internalPointer();
247       aIndex = aParent->model()->index(theRow, theColumn, (*aParent));
248     }
249     aIndex = createIndex(theRow, theColumn, (void*)getModelIndex(aIndex));
250   }
251   return aIndex;
252 }
253
254
255 QModelIndex XGUI_DocumentDataModel::parent(const QModelIndex& theIndex) const
256 {
257   if ((theIndex.internalId() == PartsFolder) || (theIndex.internalId() == HistoryNode))
258     return QModelIndex();
259
260   QModelIndex* aIndex = toSourceModelIndex(theIndex);
261   const QAbstractItemModel* aModel = aIndex->model();
262   if (!isSubModel(aModel)) 
263     return QModelIndex();
264
265   if (isPartSubModel(aModel)) {
266     if (!aModel->parent(*aIndex).isValid()) {
267       return partFolderNode();
268     }
269   }
270
271   QModelIndex aIndex1 = aModel->parent(*aIndex);
272   if (aIndex1.isValid())
273     return createIndex(aIndex1.row(), aIndex1.column(), (void*)getModelIndex(aIndex1));
274   return aIndex1;
275 }
276
277
278 bool XGUI_DocumentDataModel::hasChildren(const QModelIndex& theParent) const
279 {
280   if (!theParent.isValid())
281     return true;
282   return rowCount(theParent) > 0;
283 }
284
285
286 QModelIndex* XGUI_DocumentDataModel::toSourceModelIndex(const QModelIndex& theProxy) const
287 {
288   QModelIndex* aIndexPtr = static_cast<QModelIndex*>(theProxy.internalPointer());
289   return aIndexPtr;
290 }
291
292
293 QModelIndex* XGUI_DocumentDataModel::findModelIndex(const QModelIndex& theIndex) const
294 {
295   QList<QModelIndex*>::const_iterator aIt;
296   for (aIt = myIndexes.constBegin(); aIt != myIndexes.constEnd(); ++aIt) {
297     QModelIndex* aIndex = (*aIt);
298     if ((*aIndex) == theIndex)
299       return aIndex;
300   }
301   return 0;
302 }
303
304 QModelIndex* XGUI_DocumentDataModel::getModelIndex(const QModelIndex& theIndex) const
305 {
306   QModelIndex* aIndexPtr = findModelIndex(theIndex);
307   if (!aIndexPtr) {
308     aIndexPtr = new QModelIndex(theIndex);
309     XGUI_DocumentDataModel* that = (XGUI_DocumentDataModel*) this;
310     that->myIndexes.append(aIndexPtr);
311   }
312   return aIndexPtr;
313 }
314
315 void XGUI_DocumentDataModel::clearModelIndexes()
316 {
317   QList<QModelIndex*>::const_iterator aIt;
318   for (aIt = myIndexes.constBegin(); aIt != myIndexes.constEnd(); ++aIt) 
319     delete (*aIt);
320   myIndexes.clear();
321 }
322
323 FeaturePtr XGUI_DocumentDataModel::feature(const QModelIndex& theIndex) const
324 {
325   if (theIndex.internalId() == PartsFolder)
326     return FeaturePtr();
327   if (theIndex.internalId() == HistoryNode) {
328       int aOffset = historyOffset();
329       return myDocument->feature(FEATURES_GROUP, theIndex.row() - aOffset);
330   }
331   QModelIndex* aIndex = toSourceModelIndex(theIndex);
332   if (!isSubModel(aIndex->model())) 
333     return FeaturePtr();
334
335   const XGUI_FeaturesModel* aModel = dynamic_cast<const XGUI_FeaturesModel*>(aIndex->model());
336   return aModel->feature(*aIndex);
337 }
338
339 bool XGUI_DocumentDataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
340 {
341   beginInsertRows(theParent, theRow, theRow + theCount - 1);
342   //endInsertRows();
343
344   // Update history
345   QModelIndex aRoot;
346   int aRow = rowCount(aRoot);
347   beginInsertRows(aRoot, aRow, aRow);
348   endInsertRows();
349
350   return true;
351 }
352
353 bool XGUI_DocumentDataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
354 {
355   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
356   endRemoveRows();
357   return true;
358 }
359
360
361 void XGUI_DocumentDataModel::removeSubModel(int theModelId)
362 {
363   XGUI_PartModel* aModel = myPartModels.at(theModelId);
364   QIntList aToRemove;
365   for (int i = 0; i < myIndexes.size(); i++) {
366     if (myIndexes.at(i)->model() == aModel)
367       aToRemove.append(i);
368   }
369   int aId;
370   while(aToRemove.size() > 0) {
371     aId = aToRemove.last();
372     delete myIndexes.at(aId);
373     myIndexes.removeAt(aId);
374     aToRemove.removeLast();
375   }
376   delete aModel;
377   myPartModels.removeAt(theModelId);
378 }
379
380 bool XGUI_DocumentDataModel::isSubModel(const QAbstractItemModel* theModel) const
381 {
382   if (theModel == myModel)
383     return true;
384   return isPartSubModel(theModel);
385 }
386
387 bool XGUI_DocumentDataModel::isPartSubModel(const QAbstractItemModel* theModel) const
388 {
389   return myPartModels.contains((XGUI_PartModel*)theModel);
390 }
391
392 QModelIndex XGUI_DocumentDataModel::partFolderNode() const
393 {
394   int aPos = myModel->rowCount(QModelIndex());
395   return createIndex(aPos, columnCount() - 1, PartsFolder);
396 }
397
398 int XGUI_DocumentDataModel::historyOffset() const
399 {
400   // Nb of rows of top model + Parts folder
401   return myModel->rowCount(QModelIndex()) + 1;
402 }
403
404 bool XGUI_DocumentDataModel::activatedIndex(const QModelIndex& theIndex)
405 {
406   if ((theIndex.internalId() == PartsFolder) || (theIndex.internalId() == HistoryNode))
407     return false;
408
409   QModelIndex* aIndex = toSourceModelIndex(theIndex);
410   if (!aIndex)
411     return false;
412
413   const QAbstractItemModel* aModel = aIndex->model();
414
415   if (isPartSubModel(aModel)) {
416     // if this is root node (Part item index)
417     if (!aIndex->parent().isValid()) {
418       beginResetModel();
419       myActivePart = (myActivePart == aModel)? 0 : (XGUI_PartModel*)aModel;
420       endResetModel();
421       return true;
422     }
423   }
424   return false;
425 }
426
427 FeaturePtr XGUI_DocumentDataModel::activePart() const
428 {
429   if (myActivePart) 
430     return myActivePart->part();
431   return FeaturePtr();
432 }