ATLAS Offline Software
Loading...
Searching...
No Matches
VolumeTreeModel.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
6#include <QColor>
7#include <cassert>
8#include <iostream>
9#include <utility>
10
12//NB: Since the QModelIndices uses void pointers, the VolumeHandle,
13//SectionInfo and SubSystem classes must derive from the same
14//base class before we know which class we can cast to.
15//
16//In order to not add any unnecessary overhead to VolumeHandle (which
17//has a copy of the entire GeoModel tree), we let SectionInfo and
18//SubSystem both inherit from VolumeHandle, and we use the
19//m_childNumber field (which is always non-negative for actual
20//VolumeHandles) of VolumeHandle to indicate the type:
21//
22// -2: SectionInfo
23// -1: SubSystem
24// 0+: Regular VolumeHandle
25//
26// This is taken care of by the constructors of the two derived
27// classes, and four helper methods below makes the conversions a
28// breeze (even though its a bit hackish behind the scenes)
30
31//____________________________________________________________________
33public:
34 //Static definitions of sections and which subsystems goes in which sections:
36 static std::map<SECTION,QString> section2string;
37 static std::map<VP1GeoFlags::SubSystemFlag,SECTION> subsysflag2section;
38 static std::map<VP1GeoFlags::SubSystemFlag,QString> subsysflag2string;
40
41 //Class for the dynamic information of a given subsystem:
42 class SectionInfo;
43 class SubSystem: public VolumeHandle {
44 public:
46 : VolumeHandle(0,0, GeoPVConstLink(), -1),
47 section(si), subsysflag(sf) {}
50 for (volItr = volhandlelist.begin();volItr!=volItrE;++volItr)
51 delete (*volItr);//This is where volume handles are deleted
52 }
53 //
57 QString name;
58 };
59 //lists/maps for the added subsystems:
60 std::map<VP1GeoFlags::SubSystemFlag,SubSystem*> flag2subsystems;
61 //Map to quickly find subsystem from volumehandle. Only contains volumehandles from enabled subsystems:
62 std::map<VolumeHandle*,SubSystem*> volhandle2subsystem;
63
64 //Class for the dynamic information about sections and their daughter subsystems:
65 class SectionInfo: public VolumeHandle {
66 public:
67 SectionInfo(SECTION sf): VolumeHandle(0,0, GeoPVConstLink(), -2),sectionflag(sf) {}
68 //
70 QList<SubSystem*> enabledSubSystems;
71 QList<SubSystem*> disabledSubSystems;
72 QString name;
73 };
74 //Lists of these sections:
75 QList<SectionInfo*> allSections;
76 QList<SectionInfo*> activeSections;
77
78 //Convenience methods for dealing with the void pointers from the QModelIndices:
79 static VolumeHandle* handlePointer(const QModelIndex& idx) { return static_cast<VolumeHandle*>(idx.internalPointer()); }
80 static bool isSectionInfoPointer(VolumeHandle* handle) { return handle->childNumber()==-2; }
81 static bool isSubSystemPointer(VolumeHandle* handle) { return handle->childNumber()==-1; }
82 static bool isRegularVolumeHandle(VolumeHandle* handle) { return handle->childNumber()>=0; }
83 static SectionInfo * sectionInfoPointer (VolumeHandle* handle) { return handle->childNumber()==-2 ? static_cast<SectionInfo*>(handle) : 0; }
84 static SubSystem * subSystemPointer (VolumeHandle* handle) { return handle->childNumber()==-1 ? static_cast<SubSystem*>(handle) : 0; }
87
88};
89
90//Static variables:
91std::map<VolumeTreeModel::Imp::SECTION,QString> VolumeTreeModel::Imp::section2string;
92std::map<VP1GeoFlags::SubSystemFlag,VolumeTreeModel::Imp::SECTION> VolumeTreeModel::Imp::subsysflag2section;
93std::map<VP1GeoFlags::SubSystemFlag,QString> VolumeTreeModel::Imp::subsysflag2string;
94
95//____________________________________________________________________
97{
98 Imp::subsysflag2section[subsysflag] = section;
99 Imp::subsysflag2string[subsysflag] = std::move(subsysname);
100}
101
102//____________________________________________________________________
104 : QAbstractItemModel(parent), m_d(new Imp())
105{
108 Imp::section2string[Imp::INDET] = "Inner Detector";
109 Imp::section2string[Imp::CALO] = "Calorimeters";
110 Imp::section2string[Imp::MUON] = "Muon Spectrometer";
111 Imp::section2string[Imp::MISC] = "Miscellaneous";
112 }
115 // Inner Detector
122 // Calorimeters
125 //Toroids
129 // Structure
133 // Muon chambers
141 // Beam Pipe
143 // FWD detectors
147 // Cavern
149 }
150}
151
152//____________________________________________________________________
154{
155 //This is where we delete all SectionInfo/SubSystem pointers (and thus also all VolumeHandles):
156 std::map<VP1GeoFlags::SubSystemFlag,Imp::SubSystem*>::iterator it, itE = m_d->flag2subsystems.end();
157 for (it = m_d->flag2subsystems.begin();it!=itE;++it)
158 disableSubSystem(it->first);
159 for (it = m_d->flag2subsystems.begin();it!=itE;++it)
160 delete it->second;
161 for (Imp::SectionInfo* section : m_d->allSections)
162 delete section;
163}
164
165//____________________________________________________________________
170
171//____________________________________________________________________
173 const VolumeHandle::VolumeHandleList& roothandles )
174{
175 //NB: This method does not need to be super-fast, thus we do a lot
176 //of not-so-fast iterations over maps/lists rather than keep extra
177 //maps/lists around.
178
179 //Check whether we added this subsystem already:
180 bool found(false);
181 for(Imp::SectionInfo* section : m_d->allSections) {
182 for(Imp::SubSystem* subsys : (section->enabledSubSystems+section->disabledSubSystems)) {
183 if (subsys->subsysflag==flag) {
184 found=true;
185 break;
186 }
187 }
188 }
189
190 if (found) {
191 std::cout<<"VolumeTreeModel::addSubSystem Error: System has already been added!"<<std::endl;
192 return;
193 }
194
195 //Determine section flag:
196 Imp::SECTION sectionflag;
198 std::cout<<"VolumeTreeModel::addSubSystem Error: Unknown system flag! Please update the code!"<<std::endl;
199 sectionflag=Imp::UNKNOWN;
200 } else {
201 sectionflag=Imp::subsysflag2section[flag];
202 }
203
204 //Find the section belonging to the system (create a new one if
205 //needed - i.e. if this is the first subsystem in a given section):
207 found = false;
208 for(Imp::SectionInfo* sec : m_d->allSections) {
209 if (sec->sectionflag==sectionflag) {
210 //std::cout << "added section: " << sec->sectionflag << std::endl;
211 section = sec;
212 break;
213 }
214 }
215
216 if (!section) {
217 section = new Imp::SectionInfo(sectionflag);
218 //section->sectionflag = sectionflag;
219 if (Imp::section2string.find(sectionflag)==Imp::section2string.end())
220 section->name = "Unknown Section Flag";
221 else
222 section->name = Imp::section2string[sectionflag];
223 m_d->allSections<<section;
224 //We dont add it to m_d->activeSections since the subsystem (and
225 //thus the section since it has no other subsystems) is considered
226 //disabled until enabled by a call to enableSubSystem().
227 }
228
229 //Create SubSystem instance for this subsystem and give it the roothandles:
230 Imp::SubSystem * subsys = new Imp::SubSystem(section,flag);
231 //subsys->section = section;
232 //subsys->subsysflag = flag;
234 subsys->name = "Unknown subsystem flag";
235 else
236 subsys->name = Imp::subsysflag2string[flag];
237 subsys->volhandlelist = roothandles;
238
239 //Add the subsystem pointer to the relevant maps:
240 section->disabledSubSystems << subsys;
241 m_d->flag2subsystems[flag]=subsys;
242}
243
244//____________________________________________________________________
246{
247 beginResetModel(); // see: http://doc.qt.io/qt-5/qabstractitemmodel-obsolete.html
248
249 //Check the subsystem was added previously:
250 if (m_d->flag2subsystems.find(flag)==m_d->flag2subsystems.end()) {
251 std::cout<<"VolumeTreeModel::enableSubSystem Error: System never added!"<<std::endl;
252 return;
253 }
254 Imp::SubSystem * subsys = m_d->flag2subsystems[flag];
255 //Find the appropriate section:
257 for(Imp::SectionInfo* sec : m_d->allSections) {
258 if (sec->enabledSubSystems.contains(subsys)) {
259 //It is already enabled
260 assert(!sec->disabledSubSystems.contains(subsys));
261 return;
262 }
263 if (sec->disabledSubSystems.contains(subsys)) {
264 assert(!sec->enabledSubSystems.contains(subsys));
265 section=sec;
266 break;
267 }
268 }
269 assert(section);
270 if (!section) {
271 std::cout<<"VolumeTreeModel::enableSubSystem Error: Did not find section of subsystem!."<<std::endl;
272 return;
273 }
274 //Move the subsystem from the disabled to the enabled list:
275 section->enabledSubSystems << subsys;//Fixme: Ordering.
276 section->disabledSubSystems.removeAll(subsys);
277 //If the newly added subsystem is the only enabled subsystem, the section needs to be enabled as well:
278 if (section->enabledSubSystems.count()==1) {
279 assert(!m_d->activeSections.contains(section));
280 m_d->activeSections << section;//Fixme: Ordering.
281 }
282 //Put volume handle pointers into quick subsystem access map:
283 for (VolumeHandle* volhandle : subsys->volhandlelist ) {
284 m_d->volhandle2subsystem[volhandle] = subsys;
285 }
286
287 endResetModel();
288
289}
290
291//____________________________________________________________________
293{
294 beginResetModel(); // see: http://doc.qt.io/qt-5/qabstractitemmodel-obsolete.html
295
296 //If it was not even added previously we can just return:
297 if (m_d->flag2subsystems.find(flag)==m_d->flag2subsystems.end())
298 return;
299
300 Imp::SubSystem * subsys = m_d->flag2subsystems[flag];
301 //Find the appropriate section:
303 for(Imp::SectionInfo* sec : m_d->allSections) {
304 if (sec->disabledSubSystems.contains(subsys)) {
305 //It is already disabled
306 assert(!sec->enabledSubSystems.contains(subsys));
307 return;
308 }
309 if (sec->enabledSubSystems.contains(subsys)) {
310 assert(!sec->disabledSubSystems.contains(subsys));
311 section=sec;
312 break;
313 }
314 }
315 assert(section);
316 if (!section) {
317 std::cout<<"VolumeTreeModel::disableSubSystem Error: Did not find section of subsystem!."<<std::endl;
318 return;
319 }
320
321 //Move the subsystem from the enabled to the disabled list:
322 section->disabledSubSystems << subsys;
323 section->enabledSubSystems.removeAll(subsys);
324 //If the newly disabled subsystem was the only enabled subsystem, the section needs to be disabled as well:
325 if (section->enabledSubSystems.count()==0) {
326 assert(m_d->activeSections.contains(section));
327 m_d->activeSections.removeAll(section);
328 }
329
330 //Remove volume handle pointers from quick subsystem access map:
331 for (VolumeHandle* volhandle : subsys->volhandlelist ) {
332 Q_ASSERT(m_d->volhandle2subsystem.find(volhandle)!=m_d->volhandle2subsystem.end());
333 m_d->volhandle2subsystem.erase(m_d->volhandle2subsystem.find(volhandle));
334 }
335
336 endResetModel();
337// reset();//Fixme: use proper insert rows/colums/etc. instead!
338}
339
340//____________________________________________________________________
341void VolumeTreeModel::getRootHandles(std::vector<std::pair<VolumeHandle::VolumeHandleListItr,VolumeHandle::VolumeHandleListItr> >& out) const
342{
343 out.clear();
344 out.reserve(m_d->flag2subsystems.size());
345 std::map<VP1GeoFlags::SubSystemFlag,Imp::SubSystem*>::iterator it, itE = m_d->flag2subsystems.end();
346 for (it = m_d->flag2subsystems.begin();it!=itE;++it)
347 out.push_back(std::pair<VolumeHandle::VolumeHandleListItr,VolumeHandle::VolumeHandleListItr>
348 (it->second->volhandlelist.begin(),it->second->volhandlelist.end()));
349
350}
351
352//____________________________________________________________________
353QModelIndex VolumeTreeModel::index(int row, int column, const QModelIndex &parent) const
354{
355 //Check that row and column are in allowed ranges (positive and within row/column count of parent):
356 if (!hasIndex(row, column, parent))
357 return QModelIndex();
358
359 if (!parent.isValid()) {
360 //We must return the index of a section label:
361 Q_ASSERT(row<m_d->activeSections.count());
362 return createIndex(row, column, m_d->activeSections.at(row));
363 }
364
365 VolumeHandle * parentHandle = Imp::handlePointer(parent);
366
367 if (Imp::isRegularVolumeHandle(parentHandle)) {
368 if (!parentHandle->childrenAreInitialised())
369 parentHandle->initialiseChildren();//Fixme: It seems that it is occasionally necessary to do this. Why?? Why not fetchMore??
370 VolumeHandle * childHandle = parentHandle->child(row);
371 Q_ASSERT(childHandle);
372 return createIndex(row, column, childHandle);
373 }
374
375 if (Imp::isSubSystemPointer(parentHandle)) {
376 //Return index of top-level volume:
377 Q_ASSERT(unsigned(row)<Imp::subSystemPointer(parentHandle)->volhandlelist.size());
378 return createIndex(row, column, Imp::subSystemPointer(parentHandle)->volhandlelist.at(row));
379 }
380
381 //Must be SectionInfo:
382 Q_ASSERT(Imp::isSectionInfoPointer(parentHandle));
383 Q_ASSERT(row<Imp::sectionInfoPointer(parentHandle)->enabledSubSystems.count());
384 return createIndex(row, column, Imp::sectionInfoPointer(parentHandle)->enabledSubSystems.at(row));
385}
386
387//____________________________________________________________________
388QModelIndex VolumeTreeModel::parent(const QModelIndex& index) const
389{
390 if (!index.isValid())
391 return QModelIndex();
392
393 //See if we have a volumeHandle as index:
394 VolumeHandle *childHandle = Imp::handlePointer(index);
395
396 if (Imp::isRegularVolumeHandle(childHandle)) {
397 VolumeHandle *parentHandle = childHandle->parent();
398 if (parentHandle)
399 return createIndex(parentHandle->childNumber(), 0, parentHandle);
400
401 //childHandle has 0 parent pointer => parent must be a subsystem label:
402 Q_ASSERT(m_d->volhandle2subsystem.find(childHandle)!=m_d->volhandle2subsystem.end());
403 Imp::SubSystem * subsys = m_d->volhandle2subsystem[childHandle];
404 Q_ASSERT(subsys);
405 Q_ASSERT(subsys->section->enabledSubSystems.contains(subsys));
406 return createIndex(subsys->section->enabledSubSystems.indexOf(subsys), 0, subsys);
407 }
408
409
410 if (Imp::isSubSystemPointer(childHandle)) {
411 //Index is a SubSystem => parent must be a section label:
412 Q_ASSERT(m_d->activeSections.contains(Imp::subSystemPointer(childHandle)->section));
413 return createIndex(m_d->activeSections.indexOf(Imp::subSystemPointer(childHandle)->section), 0, Imp::subSystemPointer(childHandle)->section);
414 }
415
416 //Must be SectionInfo => parent is root (i.e. invalid):
417 Q_ASSERT(Imp::isSectionInfoPointer(childHandle));
418 return QModelIndex();
419}
420
421//____________________________________________________________________
422int VolumeTreeModel::rowCount(const QModelIndex& parent) const
423{
424 if (parent.column() > 0)
425 return 0;
426
427 if (!parent.isValid())
428 return m_d->activeSections.size();//Number of active sections
429
430 VolumeHandle * parentHandle = Imp::handlePointer(parent);
431
432 if (Imp::isRegularVolumeHandle(parentHandle)) {
433 return parentHandle->nChildren();
434 }
435
436 if (Imp::isSubSystemPointer(parentHandle)) {
437 return Imp::subSystemPointer(parentHandle)->volhandlelist.size();
438 }
439
440 //Must be SectionInfo pointer:
441 Q_ASSERT(Imp::isSectionInfoPointer(parentHandle));
442 return Imp::sectionInfoPointer(parentHandle)->enabledSubSystems.count();
443}
444
445//____________________________________________________________________
446QVariant VolumeTreeModel::data(const QModelIndex& index, int role) const
447{
448 if ((role!=Qt::DisplayRole&&role!=Qt::ForegroundRole)||!index.isValid())
449 return QVariant();
450
451 VolumeHandle *volumeHandle = Imp::handlePointer(index);
452 if (Imp::isRegularVolumeHandle(volumeHandle)) {
453 if (role==Qt::ForegroundRole) {
454 if (volumeHandle->isAttached())
455 return QVariant();
456 else
457 return QColor::fromRgbF( 0.5, 0.5, 0.5 );
458 }
459 //DisplayRole:
460 if (volumeHandle->nChildren()>1)
461 return volumeHandle->getName()+" ["+QString::number(volumeHandle->nChildren())+"]";
462 else
463 return volumeHandle->getName();
464 }
465
466 if (role==Qt::ForegroundRole)
467 return QVariant();
468
469 if (Imp::isSubSystemPointer(volumeHandle))
470 return Imp::subSystemPointer(volumeHandle)->name;
471
472 Q_ASSERT(Imp::isSectionInfoPointer(volumeHandle));
473 return Imp::sectionInfoPointer(volumeHandle)->name;
474}
475
476
477//____________________________________________________________________
478Qt::ItemFlags VolumeTreeModel::flags(const QModelIndex &index) const
479{
480 if (!index.isValid())
481 return Qt::ItemFlags();
482
484 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
485 else
486 return Qt::ItemIsEnabled;
487}
488
489//____________________________________________________________________
490QVariant VolumeTreeModel::headerData(int /*section*/, Qt::Orientation /*orientation*/,int /*role*/) const
491{
492 return QVariant();
493}
494
495//____________________________________________________________________
496bool VolumeTreeModel::canFetchMore( const QModelIndex & parent ) const
497{
498 if (!parent.isValid())
499 return false;
500
501 VolumeHandle * parentHandle = Imp::handlePointer(parent);
502
503 if (Imp::isRegularVolumeHandle(parentHandle)&&!parentHandle->childrenAreInitialised())
504 return true;
505
506 return false;
507}
508
509//____________________________________________________________________
510void VolumeTreeModel::fetchMore( const QModelIndex & parent )
511{
512 if (!parent.isValid())
513 return;//should probably never happen
514
515 VolumeHandle* parentHandle = Imp::handlePointer(parent);
516
517 if (Imp::isRegularVolumeHandle(parentHandle)&&!parentHandle->childrenAreInitialised()) {
518 // beginInsertRows(parent,0,int(parentHandle->nChildren())-1);
519 parentHandle->initialiseChildren();
520 layoutChanged();//fixme??
521 // endInsertRows();
522 return;
523 }
524}
525
526//____________________________________________________________________
527bool VolumeTreeModel::hasChildren ( const QModelIndex & parent ) const
528{
529 return rowCount(parent)>0;//Our rowCount is relatively fast (no looping to count).
530}
void section(const std::string &sec)
static const Attributes_t empty
@ MuonEndcapStationTGC
Definition VP1GeoFlags.h:47
@ MuonEndcapStationNSW
Definition VP1GeoFlags.h:65
@ MuonBarrelStationInner
Definition VP1GeoFlags.h:42
@ MuonBarrelStationMiddle
Definition VP1GeoFlags.h:44
@ MuonBarrelStationOuter
Definition VP1GeoFlags.h:45
@ MuonEndcapStationCSC
Definition VP1GeoFlags.h:46
@ MuonEndcapStationMDT
Definition VP1GeoFlags.h:49
VolumeHandle(VolumeHandleSharedData *, VolumeHandle *parent, const GeoPVConstLink &, int childNumber, const MuonChamberState &mcs=NONMUONCHAMBER, const SbMatrix &accumTrans=SbMatrix())
bool childrenAreInitialised() const
void initialiseChildren()
QString getName() const
bool isAttached() const
std::vector< VolumeHandle * > VolumeHandleList
VolumeHandleList::iterator VolumeHandleListItr
VolumeHandle * parent()
int childNumber() const
VolumeHandle * child(int index) const
unsigned nChildren() const
QList< SubSystem * > disabledSubSystems
SubSystem(SectionInfo *si, VP1GeoFlags::SubSystemFlag sf)
VolumeHandle::VolumeHandleList volhandlelist
VP1GeoFlags::SubSystemFlag subsysflag
static VolumeHandle * handlePointer(const QModelIndex &idx)
static void defineSubSystem(VP1GeoFlags::SubSystemFlag, QString, SECTION)
static std::map< VP1GeoFlags::SubSystemFlag, QString > subsysflag2string
std::map< VP1GeoFlags::SubSystemFlag, SubSystem * > flag2subsystems
static std::map< SECTION, QString > section2string
static std::map< VP1GeoFlags::SubSystemFlag, SECTION > subsysflag2section
static bool isRegularVolumeHandle(VolumeHandle *handle)
static SubSystem * subSystemPointer(VolumeHandle *handle)
static bool isSectionInfoPointer(VolumeHandle *handle)
static SectionInfo * sectionInfoPointer(VolumeHandle *handle)
QList< SectionInfo * > activeSections
QList< SectionInfo * > allSections
std::map< VolumeHandle *, SubSystem * > volhandle2subsystem
static bool isSubSystemPointer(VolumeHandle *handle)
QVariant data(const QModelIndex &, int) const
int rowCount(const QModelIndex &) const
void enableSubSystem(VP1GeoFlags::SubSystemFlag flag)
VolumeTreeModel(QObject *parent=0)
Qt::ItemFlags flags(const QModelIndex &index) const
QModelIndex index(int, int, const QModelIndex &) const
void disableSubSystem(VP1GeoFlags::SubSystemFlag flag)
void fetchMore(const QModelIndex &parent)
void addSubSystem(VP1GeoFlags::SubSystemFlag flag, const VolumeHandle::VolumeHandleList &roothandles)
QVariant headerData(int section, Qt::Orientation orientation, int role) const
bool canFetchMore(const QModelIndex &parent) const
QModelIndex parent(const QModelIndex &) const
void getRootHandles(std::vector< std::pair< VolumeHandle::VolumeHandleListItr, VolumeHandle::VolumeHandleListItr > > &) const
bool hasChildren(const QModelIndex &parent=QModelIndex()) const
std::string find(const std::string &s)
return a remapped string
Definition hcg.cxx:138
Definition index.py:1