Salome HOME
a9bb8b61b76b7264fdf3545d059621e23bafafdb
[modules/shaper.git] / src / XGUI / XGUI_DocumentDataModel.cpp
1 #include "XGUI_DocumentDataModel.h"
2 #include "XGUI_PartDataModel.h"
3
4 #include <ModelAPI_PluginManager.h>
5 #include <ModelAPI_Iterator.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
14 #include <QIcon>
15 #include <QString>
16
17
18 XGUI_DocumentDataModel::XGUI_DocumentDataModel(QObject* theParent)
19   : QAbstractItemModel(theParent)
20 {
21   // Find Document object
22   boost::shared_ptr<ModelAPI_PluginManager> aMgr = ModelAPI_PluginManager::get();
23   myDocument = aMgr->currentDocument();
24
25   // Register in event loop
26   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
27   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
28   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
29
30   // Create a top part of data tree model
31   myModel = new XGUI_TopDataModel(myDocument, this);
32 }
33
34
35 XGUI_DocumentDataModel::~XGUI_DocumentDataModel()
36 {
37   clearModelIndexes();
38 }
39
40
41 void XGUI_DocumentDataModel::processEvent(const Events_Message* theMessage)
42 {
43   // Created object event *******************
44   if (QString(theMessage->eventID().eventText()) == EVENT_FEATURE_CREATED) {
45     const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
46     boost::shared_ptr<ModelAPI_Feature> aFeature = aUpdMsg->feature();
47     boost::shared_ptr<ModelAPI_Document> aDoc = aFeature->document();
48
49     if (aDoc == myDocument) {  // If root objects
50       if (aFeature->getGroup().compare(PARTS_GROUP) == 0) { // Update only Parts group
51         // Add a new part
52         int aStart = myPartModels.size() + 1;
53         XGUI_PartDataModel* aModel = new XGUI_PartDataModel(myDocument, this);
54         aModel->setPartId(myPartModels.count());
55         myPartModels.append(aModel);
56         insertRows(partFolderNode(), aStart, aStart);
57       } else { // Update top groups (other except parts
58         QModelIndex aIndex = myModel->findParent(aFeature);
59         int aStart = myModel->rowCount(aIndex) - 1;
60         aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
61         insertRows(aIndex, aStart, aStart);
62       }
63     } else { // if sub-objects of first level nodes
64       XGUI_PartModel* aPartModel = 0;
65       QList<XGUI_PartModel*>::const_iterator aIt;
66       for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
67         if ((*aIt)->hasDocument(aDoc)) {
68           aPartModel = (*aIt);
69           break;
70         }
71       }
72       if (aPartModel) {
73         QModelIndex aIndex = aPartModel->findParent(aFeature);
74         int aStart = aPartModel->rowCount(aIndex) - 1;
75         aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
76         insertRows(aIndex, aStart, aStart);
77       }
78     }
79
80   // Deleted object event ***********************
81   } else if (QString(theMessage->eventID().eventText()) == EVENT_FEATURE_DELETED) {
82     const Model_FeatureDeletedMessage* aUpdMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
83     boost::shared_ptr<ModelAPI_Document> aDoc = aUpdMsg->document();
84
85     if (aDoc == myDocument) {  // If root objects
86       if (aUpdMsg->group().compare(PARTS_GROUP) == 0) { // Updsate only Parts group
87         int aStart = myPartModels.size();
88         beginRemoveRows(partFolderNode(), aStart, aStart);
89         removeSubModel(myPartModels.size() - 1);
90         endRemoveRows();
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         beginRemoveRows(aIndex, aStart, aStart);
96         endRemoveRows();
97       }
98     } else {
99       XGUI_PartModel* aPartModel = 0;
100       QList<XGUI_PartModel*>::const_iterator aIt;
101       for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
102         if ((*aIt)->hasDocument(aDoc)) {
103           aPartModel = (*aIt);
104           break;
105         }
106       }
107       if (aPartModel) {
108         QModelIndex aIndex = aPartModel->findGroup(aUpdMsg->group());
109         int aStart = aPartModel->rowCount(aIndex);
110         aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
111         beginRemoveRows(aIndex, aStart, aStart);
112         endRemoveRows();
113       }
114     }
115
116   // Deleted object event ***********************
117   } else if (QString(theMessage->eventID().eventText()) == EVENT_FEATURE_UPDATED) {
118     const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
119     boost::shared_ptr<ModelAPI_Feature> aFeature = aUpdMsg->feature();
120     boost::shared_ptr<ModelAPI_Document> aDoc = aFeature->document();
121     
122     QModelIndex aIndex;
123     emit dataChanged(aIndex, aIndex);
124
125   // Reset whole tree **************************
126   } else {  
127     beginResetModel();
128     int aNbParts = myDocument->featuresIterator(PARTS_GROUP)->numIterationsLeft();
129     if (myPartModels.size() != aNbParts) { // resize internal models
130       while (myPartModels.size() > aNbParts) {
131         delete myPartModels.last();
132         myPartModels.removeLast();
133       }
134       while (myPartModels.size() < aNbParts) {
135         myPartModels.append(new XGUI_PartDataModel(myDocument, this));
136       }
137       for (int i = 0; i < myPartModels.size(); i++)
138         myPartModels.at(i)->setPartId(i);
139     }
140     clearModelIndexes();
141     endResetModel();
142   }
143 }
144
145 QVariant XGUI_DocumentDataModel::data(const QModelIndex& theIndex, int theRole) const
146 {
147   if (!theIndex.isValid())
148     return QVariant();
149   if (theIndex.internalId() == 0){
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   }
161   QModelIndex aParent = theIndex.parent();
162   if (aParent.isValid() && (aParent.internalId() == 0)) {
163     return myPartModels.at(theIndex.row())->data(QModelIndex(), theRole);
164   }
165   return toSourceModelIndex(theIndex).data(theRole);
166 }
167
168
169 QVariant XGUI_DocumentDataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
170 {
171   return QVariant();
172 }
173
174 int XGUI_DocumentDataModel::rowCount(const QModelIndex& theParent) const
175 {
176   if (!theParent.isValid()) {
177     int aVal = myModel->rowCount(theParent) + myPartModels.size();
178     return myModel->rowCount(theParent) + 1;//myPartModels.size();
179   }
180   if (theParent.internalId() == 0) {
181     return myPartModels.size();
182   }
183   QModelIndex aParent = toSourceModelIndex(theParent);
184   if (!isSubModel(aParent.model())) 
185     return 0;
186
187   return aParent.model()->rowCount(aParent);
188 }
189
190 int XGUI_DocumentDataModel::columnCount(const QModelIndex& theParent) const
191 {
192   return 1;
193 }
194
195 QModelIndex XGUI_DocumentDataModel::index(int theRow, int theColumn, const QModelIndex& theParent) const
196 {
197   QModelIndex aIndex;
198   if (!theParent.isValid()) {
199     int aOffs = myModel->rowCount();
200     if (theRow < aOffs) {
201       aIndex = myModel->index(theRow, theColumn, theParent);
202       aIndex = createIndex(theRow, theColumn, (void*)getModelIndex(aIndex));
203     } else {
204       // Create Parts node
205       aIndex = partFolderNode();
206     }
207   } else {
208     if (theParent.internalId() == 0) {
209       aIndex = myPartModels.at(theRow)->index(0, theColumn, QModelIndex());
210     } else {
211       QModelIndex* aParent = (QModelIndex*)theParent.internalPointer();
212       aIndex = aParent->model()->index(theRow, theColumn, (*aParent));
213     }
214     aIndex = createIndex(theRow, theColumn, (void*)getModelIndex(aIndex));
215   }
216   return aIndex;
217 }
218
219
220 QModelIndex XGUI_DocumentDataModel::parent(const QModelIndex& theIndex) const
221 {
222   if (theIndex.internalId() == 0)
223     return QModelIndex();
224
225   QModelIndex aIndex = toSourceModelIndex(theIndex);
226   const QAbstractItemModel* aModel = aIndex.model();
227   if (!isSubModel(aModel)) 
228     return QModelIndex();
229
230   if (isPartSubModel(aModel)) {
231     if (!aModel->parent(aIndex).isValid()) {
232       return partFolderNode();
233     }
234   }
235
236   aIndex = aModel->parent(aIndex);
237   if (aIndex.isValid())
238     return createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
239   return aIndex;
240 }
241
242
243 bool XGUI_DocumentDataModel::hasChildren(const QModelIndex& theParent) const
244 {
245   if (!theParent.isValid())
246     return true;
247   return rowCount(theParent) > 0;
248 }
249
250
251 QModelIndex XGUI_DocumentDataModel::toSourceModelIndex(const QModelIndex& theProxy) const
252 {
253   QModelIndex* aIndexPtr = static_cast<QModelIndex*>(theProxy.internalPointer());
254   return (*aIndexPtr);
255 }
256
257
258 QModelIndex* XGUI_DocumentDataModel::findModelIndex(const QModelIndex& theIndex) const
259 {
260   QList<QModelIndex*>::const_iterator aIt;
261   for (aIt = myIndexes.constBegin(); aIt != myIndexes.constEnd(); ++aIt) {
262     QModelIndex* aIndex = (*aIt);
263     if ((*aIndex) == theIndex)
264       return aIndex;
265   }
266   return 0;
267 }
268
269 QModelIndex* XGUI_DocumentDataModel::getModelIndex(const QModelIndex& theIndex) const
270 {
271   QModelIndex* aIndexPtr = findModelIndex(theIndex);
272   if (!aIndexPtr) {
273     aIndexPtr = new QModelIndex(theIndex);
274     XGUI_DocumentDataModel* that = (XGUI_DocumentDataModel*) this;
275     that->myIndexes.append(aIndexPtr);
276   }
277   return aIndexPtr;
278 }
279
280 void XGUI_DocumentDataModel::clearModelIndexes()
281 {
282   QList<QModelIndex*>::const_iterator aIt;
283   for (aIt = myIndexes.constBegin(); aIt != myIndexes.constEnd(); ++aIt) 
284     delete (*aIt);
285   myIndexes.clear();
286 }
287
288 FeaturePtr XGUI_DocumentDataModel::feature(const QModelIndex& theIndex) const
289 {
290   if (theIndex.internalId() == 0)
291     return FeaturePtr();
292
293   QModelIndex aIndex = toSourceModelIndex(theIndex);
294   if (!isSubModel(aIndex.model())) 
295     return FeaturePtr();
296
297   const XGUI_FeaturesModel* aModel = dynamic_cast<const XGUI_FeaturesModel*>(aIndex.model());
298   return aModel->feature(aIndex);
299 }
300
301 void XGUI_DocumentDataModel::insertRows(const QModelIndex& theParent, int theStart, int theEnd)
302 {
303   beginInsertRows(theParent, theStart, theEnd);
304   endInsertRows();
305   if (theStart == 0) // Update parent if this is a first child in order to update node decoration
306     emit dataChanged(theParent, theParent);
307 }
308
309 void XGUI_DocumentDataModel::removeSubModel(int theModelId)
310 {
311   XGUI_PartModel* aModel = myPartModels.at(theModelId);
312   QIntList aToRemove;
313   for (int i = 0; i < myIndexes.size(); i++) {
314     if (myIndexes.at(i)->model() == aModel)
315       aToRemove.append(i);
316   }
317   int aId;
318   while(aToRemove.size() > 0) {
319     aId = aToRemove.last();
320     delete myIndexes.at(aId);
321     myIndexes.removeAt(aId);
322     aToRemove.removeLast();
323   }
324   delete aModel;
325   myPartModels.removeAt(theModelId);
326 }
327
328 bool XGUI_DocumentDataModel::isSubModel(const QAbstractItemModel* theModel) const
329 {
330   if (theModel == myModel)
331     return true;
332   return isPartSubModel(theModel);
333 }
334
335 bool XGUI_DocumentDataModel::isPartSubModel(const QAbstractItemModel* theModel) const
336 {
337   return myPartModels.contains((XGUI_PartModel*)theModel);
338 }
339
340 QModelIndex XGUI_DocumentDataModel::partFolderNode() const
341 {
342   int aPos = myModel->rowCount(QModelIndex());
343   return createIndex(aPos, columnCount() - 1, 0);
344 }