1 // Created on: 2017-06-16
2 // Created by: Natalia ERMOLAEVA
3 // Copyright (c) 2017 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15 
16 #include <inspector/TreeModel_ModelBase.hxx>
17 
18 #include <inspector/TreeModel_ItemBase.hxx>
19 #include <inspector/TreeModel_ItemProperties.hxx>
20 #include <inspector/TreeModel_Tools.hxx>
21 #include <inspector/TreeModel_VisibilityState.hxx>
22 
23 #include <Standard_Transient.hxx>
24 
25 #include <Standard_WarningsDisable.hxx>
26 #include <QIcon>
27 #include <Standard_WarningsRestore.hxx>
28 
29 const int COLUMN_NAME_WIDTH = 260;
30 const int COLUMN_SIZE_WIDTH = 30;
31 
32 // =======================================================================
33 // function : Constructor
34 // purpose :
35 // =======================================================================
TreeModel_ModelBase(QObject * theParent)36 TreeModel_ModelBase::TreeModel_ModelBase (QObject* theParent)
37 : QAbstractItemModel (theParent), m_pUseVisibilityColumn (false),
38   myVisibilityState (0)
39 {
40   myVisibleIcon = QIcon (":/icons/item_visible.png");
41   myInvisibleIcon = QIcon (":/icons/item_invisible.png");
42 }
43 
44 // =======================================================================
45 // function :  InitColumns
46 // purpose :
47 // =======================================================================
InitColumns()48 void TreeModel_ModelBase::InitColumns()
49 {
50   setHeaderItem (TreeModel_ColumnType_Name,       TreeModel_HeaderSection ("Name", COLUMN_NAME_WIDTH));
51   setHeaderItem (TreeModel_ColumnType_Visibility, TreeModel_HeaderSection ("Visibility", TreeModel_ModelBase::ColumnVisibilityWidth()));
52   setHeaderItem (TreeModel_ColumnType_Row,        TreeModel_HeaderSection ("Row", COLUMN_SIZE_WIDTH));
53 }
54 
55 // =======================================================================
56 // function :  GetItemByIndex
57 // purpose :
58 // =======================================================================
GetItemByIndex(const QModelIndex & theIndex)59 TreeModel_ItemBasePtr TreeModel_ModelBase::GetItemByIndex (const QModelIndex& theIndex)
60 {
61   TreeModel_ItemBase* anItem = (TreeModel_ItemBase*)theIndex.internalPointer();
62   return TreeModel_ItemBasePtr (anItem);
63 }
64 
65 // =======================================================================
66 // function :  reset
67 // purpose :
68 // =======================================================================
Reset()69 void TreeModel_ModelBase::Reset()
70 {
71   for (int aColId = 0, aNbColumns = columnCount(); aColId < aNbColumns; aColId++)
72   {
73     TreeModel_ItemBasePtr aRootItem = RootItem (aColId);
74     if (aRootItem)
75       aRootItem->Reset();
76   }
77 }
78 
79 // =======================================================================
80 // function :  index
81 // purpose :
82 // =======================================================================
index(int theRow,int theColumn,const QModelIndex & theParent) const83 QModelIndex TreeModel_ModelBase::index (int theRow, int theColumn, const QModelIndex& theParent) const
84 {
85   if (!hasIndex (theRow, theColumn, theParent))
86     return QModelIndex();
87 
88   // to create index on the root item
89   if (!theParent.isValid())
90     return createIndex (theRow, theColumn, getIndexValue (RootItem (theColumn)));
91 
92   TreeModel_ItemBasePtr aParentItem;
93   if (!theParent.isValid())
94     aParentItem = RootItem (theColumn);
95   else
96     aParentItem = GetItemByIndex (theParent);
97 
98   TreeModel_ItemBasePtr aChildItem = aParentItem->Child (theRow, theColumn);
99   return aChildItem ? createIndex (theRow, theColumn, getIndexValue (aChildItem)) : QModelIndex();
100 }
101 
102 // =======================================================================
103 // function :  data
104 // purpose :
105 // =======================================================================
data(const QModelIndex & theIndex,int theRole) const106 QVariant TreeModel_ModelBase::data (const QModelIndex& theIndex, int theRole) const
107 {
108   if (!theIndex.isValid())
109     return QVariant ("undefined");
110 
111   if (IsUseVisibilityColumn() && theIndex.column() == TreeModel_ColumnType_Visibility)
112   {
113     if (theRole != Qt::DecorationRole)
114       return QVariant();
115 
116     TreeModel_ItemBasePtr anItem = GetItemByIndex (theIndex);
117     if (!anItem->data (theIndex, theRole).isNull()) // value is already in cache
118       return anItem->data (theIndex, theRole);
119 
120     if (!anItem->IsInitialized())
121       anItem->Init();
122 
123     if (!myVisibilityState || !myVisibilityState->CanBeVisible (theIndex))
124       return QVariant();
125 
126     QVariant aValue = myVisibilityState->IsVisible (theIndex) ? myVisibleIcon : myInvisibleIcon;
127     anItem->SetCustomData (aValue, theRole);
128     return aValue;
129   }
130 
131   TreeModel_ItemBasePtr anItem = GetItemByIndex (theIndex);
132   QVariant anItemData = anItem->data (theIndex, theRole);
133 
134   if (anItemData.isNull() && theRole == Qt::BackgroundRole && myHighlightedIndices.contains (theIndex))
135     anItemData = TreeModel_Tools::LightHighlightColor();
136 
137   return anItemData;
138 }
139 
140 // =======================================================================
141 // function :  parent
142 // purpose :
143 // =======================================================================
parent(const QModelIndex & theIndex) const144 QModelIndex TreeModel_ModelBase::parent (const QModelIndex& theIndex) const
145 {
146   if (!theIndex.isValid())
147     return QModelIndex();
148 
149   TreeModel_ItemBasePtr aChildItem = GetItemByIndex (theIndex);
150   TreeModel_ItemBasePtr aParentItem = aChildItem ? aChildItem->Parent() : TreeModel_ItemBasePtr();
151 
152   if (!aParentItem)
153     return QModelIndex();
154 
155   return createIndex (aParentItem->Row(), aParentItem->Column(), getIndexValue (aParentItem));
156 }
157 
158 // =======================================================================
159 // function :  flags
160 // purpose :
161 // =======================================================================
flags(const QModelIndex & theIndex) const162 Qt::ItemFlags TreeModel_ModelBase::flags (const QModelIndex& theIndex) const
163 {
164   if (!theIndex.isValid())
165   {
166     return Qt::ItemFlags();
167   }
168   return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
169 }
170 
171 // =======================================================================
172 // function : headerData
173 // purpose :
174 // =======================================================================
headerData(int theSection,Qt::Orientation theOrientation,int theRole) const175 QVariant TreeModel_ModelBase::headerData (int theSection, Qt::Orientation theOrientation, int theRole) const
176 {
177   if (theOrientation != Qt::Horizontal || theRole != Qt::DisplayRole)
178     return QVariant();
179 
180   if (IsUseVisibilityColumn() && theSection == TreeModel_ColumnType_Visibility)
181     return QVariant();
182 
183   return myHeaderValues[theSection].GetName();
184 }
185 
186 // =======================================================================
187 // function :  rowCount
188 // purpose :
189 // =======================================================================
rowCount(const QModelIndex & theParent) const190 int TreeModel_ModelBase::rowCount (const QModelIndex& theParent) const
191 {
192   // to create index on the root item
193   if (!theParent.isValid())
194     return 1;
195 
196   TreeModel_ItemBasePtr aParentItem;
197   if (!theParent.isValid())
198     aParentItem = RootItem (0);
199   else
200     aParentItem = GetItemByIndex (theParent);
201 
202   if (!aParentItem)
203     return 0;
204 
205   return aParentItem ? aParentItem->rowCount() : 0;
206 }
207 
208 // =======================================================================
209 // function : EmitLayoutChanged
210 // purpose :
211 // =======================================================================
EmitLayoutChanged()212 void TreeModel_ModelBase::EmitLayoutChanged()
213 {
214   emit layoutChanged();
215 }
216 
217 // =======================================================================
218 // function : EmitLayoutChanged
219 // purpose :
220 // =======================================================================
EmitDataChanged(const QModelIndex & theTopLeft,const QModelIndex & theBottomRight,const QVector<int> & theRoles,const bool isResetItem)221 void TreeModel_ModelBase::EmitDataChanged (const QModelIndex& theTopLeft, const QModelIndex& theBottomRight,
222                                            const QVector<int>& theRoles,
223                                            const bool isResetItem)
224 {
225   TreeModel_ItemBasePtr anItemBase = TreeModel_ModelBase::GetItemByIndex (theTopLeft);
226   if (anItemBase && isResetItem)
227     anItemBase->Reset();
228 
229 #if QT_VERSION < 0x050000
230   (void)theRoles;
231   emit dataChanged (theTopLeft, theBottomRight);
232 #else
233   emit dataChanged (theTopLeft, theBottomRight, theRoles);
234 #endif
235 }
236 
237 // =======================================================================
238 // function : Selected
239 // purpose :
240 // =======================================================================
Selected(const QModelIndexList & theIndices,const int theCellId,const Qt::Orientation theOrientation)241 QModelIndexList TreeModel_ModelBase::Selected (const QModelIndexList& theIndices, const int theCellId,
242                                                const Qt::Orientation theOrientation)
243 {
244   QModelIndexList aSelected;
245   for (QModelIndexList::const_iterator anIndicesIt = theIndices.begin(); anIndicesIt != theIndices.end(); anIndicesIt++)
246   {
247     QModelIndex anIndex = *anIndicesIt;
248     if ((theOrientation == Qt::Horizontal && anIndex.column() == theCellId) ||
249         (theOrientation == Qt::Vertical && anIndex.row() == theCellId))
250       aSelected.append (anIndex);
251   }
252   return aSelected;
253 }
254 
255 // =======================================================================
256 // function : SingleSelected
257 // purpose :
258 // =======================================================================
SingleSelected(const QModelIndexList & theIndices,const int theCellId,const Qt::Orientation theOrientation)259 QModelIndex TreeModel_ModelBase::SingleSelected (const QModelIndexList& theIndices, const int theCellId,
260                                                  const Qt::Orientation theOrientation)
261 {
262   QModelIndexList aSelected = Selected (theIndices, theCellId, theOrientation);
263   return aSelected.size() == 1 ? aSelected.first() : QModelIndex();
264 }
265 
266 // =======================================================================
267 // function :  SelectedItems
268 // purpose :
269 // =======================================================================
SelectedItems(const QModelIndexList & theIndices)270 QList<TreeModel_ItemBasePtr> TreeModel_ModelBase::SelectedItems (const QModelIndexList& theIndices)
271 {
272   QList<TreeModel_ItemBasePtr> anItems;
273 
274   for (QModelIndexList::const_iterator anIndicesIt = theIndices.begin(); anIndicesIt != theIndices.end(); anIndicesIt++)
275   {
276     TreeModel_ItemBasePtr anItem = TreeModel_ModelBase::GetItemByIndex (*anIndicesIt);
277     if (!anItem || anItems.contains (anItem))
278       continue;
279     anItems.append (anItem);
280   }
281   return anItems;
282 }
283 
284 // =======================================================================
285 // function : SubItemsPresentations
286 // purpose :
287 // =======================================================================
SubItemsPresentations(const QModelIndexList & theIndices,NCollection_List<Handle (Standard_Transient)> & thePresentations)288 void TreeModel_ModelBase::SubItemsPresentations (const QModelIndexList& theIndices,
289                                                  NCollection_List<Handle(Standard_Transient)>& thePresentations)
290 {
291   QList<TreeModel_ItemBasePtr> anItems;
292 
293   for (QModelIndexList::const_iterator anIndicesIt = theIndices.begin(); anIndicesIt != theIndices.end(); anIndicesIt++)
294   {
295     TreeModel_ItemBasePtr anItem = TreeModel_ModelBase::GetItemByIndex (*anIndicesIt);
296     if (!anItem || anItems.contains (anItem))
297       continue;
298     subItemsPresentations (anItem, thePresentations);
299   }
300 }
301 
302 // =======================================================================
303 // function : subItemPresentations
304 // purpose :
305 // =======================================================================
subItemsPresentations(const TreeModel_ItemBasePtr & theItem,NCollection_List<Handle (Standard_Transient)> & thePresentations)306 void TreeModel_ModelBase::subItemsPresentations (const TreeModel_ItemBasePtr& theItem,
307                                                  NCollection_List<Handle(Standard_Transient)>& thePresentations)
308 {
309   theItem->Presentations (thePresentations);
310 
311   QList<TreeModel_ItemBasePtr> anItems;
312   for (int aRowId = 0; aRowId < theItem->rowCount(); aRowId++)
313   {
314     subItemsPresentations (theItem->Child (aRowId, theItem->Column()), thePresentations);
315   }
316 }
317 
318 // =======================================================================
319 // function : createRoot
320 // purpose :
321 // =======================================================================
createRoot(const int theColumnId)322 void TreeModel_ModelBase::createRoot (const int theColumnId)
323 {
324   myRootItems.insert (theColumnId, createRootItem (theColumnId));
325 }
326 
327 // =======================================================================
328 // function : setHeaderItem
329 // purpose :
330 // =======================================================================
setHeaderItem(const int theColumnId,const TreeModel_HeaderSection & theSection)331 void TreeModel_ModelBase::setHeaderItem (const int theColumnId, const TreeModel_HeaderSection& theSection)
332 {
333   if (theSection.IsEmpty())
334   {
335     // remove section
336     myHeaderValues.remove (theColumnId);
337     myRootItems.remove (theColumnId);
338   }
339 
340   myHeaderValues[theColumnId] = theSection;
341   createRoot (theColumnId);
342 }
343 
344 // =======================================================================
345 // function :  getIndexValue
346 // purpose :
347 // =======================================================================
getIndexValue(const TreeModel_ItemBasePtr & theItem)348 void* TreeModel_ModelBase::getIndexValue (const TreeModel_ItemBasePtr& theItem)
349 {
350   return theItem.data();
351 }
352