ATLAS Offline Software
Loading...
Searching...
No Matches
VolumeTreeModel.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 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 //HGTD
124 // Calorimeters
127 //Toroids
131 // Structure
135 // Muon chambers
143 // Beam Pipe
145 // FWD detectors
149 // Cavern
151 }
152}
153
154//____________________________________________________________________
156{
157 //This is where we delete all SectionInfo/SubSystem pointers (and thus also all VolumeHandles):
158 std::map<VP1GeoFlags::SubSystemFlag,Imp::SubSystem*>::iterator it, itE = m_d->flag2subsystems.end();
159 for (it = m_d->flag2subsystems.begin();it!=itE;++it)
160 disableSubSystem(it->first);
161 for (it = m_d->flag2subsystems.begin();it!=itE;++it)
162 delete it->second;
163 for (Imp::SectionInfo* section : m_d->allSections)
164 delete section;
165}
166
167//____________________________________________________________________
172
173//____________________________________________________________________
175 const VolumeHandle::VolumeHandleList& roothandles )
176{
177 //NB: This method does not need to be super-fast, thus we do a lot
178 //of not-so-fast iterations over maps/lists rather than keep extra
179 //maps/lists around.
180
181 //Check whether we added this subsystem already:
182 bool found(false);
183 for(Imp::SectionInfo* section : m_d->allSections) {
184 for(Imp::SubSystem* subsys : (section->enabledSubSystems+section->disabledSubSystems)) {
185 if (subsys->subsysflag==flag) {
186 found=true;
187 break;
188 }
189 }
190 }
191
192 if (found) {
193 std::cout<<"VolumeTreeModel::addSubSystem Error: System has already been added!"<<std::endl;
194 return;
195 }
196
197 //Determine section flag:
198 Imp::SECTION sectionflag;
200 std::cout<<"VolumeTreeModel::addSubSystem Error: Unknown system flag! Please update the code!"<<std::endl;
201 sectionflag=Imp::UNKNOWN;
202 } else {
203 sectionflag=Imp::subsysflag2section[flag];
204 }
205
206 //Find the section belonging to the system (create a new one if
207 //needed - i.e. if this is the first subsystem in a given section):
209 found = false;
210 for(Imp::SectionInfo* sec : m_d->allSections) {
211 if (sec->sectionflag==sectionflag) {
212 //std::cout << "added section: " << sec->sectionflag << std::endl;
213 section = sec;
214 break;
215 }
216 }
217
218 if (!section) {
219 section = new Imp::SectionInfo(sectionflag);
220 //section->sectionflag = sectionflag;
221 if (Imp::section2string.find(sectionflag)==Imp::section2string.end())
222 section->name = "Unknown Section Flag";
223 else
224 section->name = Imp::section2string[sectionflag];
225 m_d->allSections<<section;
226 //We dont add it to m_d->activeSections since the subsystem (and
227 //thus the section since it has no other subsystems) is considered
228 //disabled until enabled by a call to enableSubSystem().
229 }
230
231 //Create SubSystem instance for this subsystem and give it the roothandles:
232 Imp::SubSystem * subsys = new Imp::SubSystem(section,flag);
233 //subsys->section = section;
234 //subsys->subsysflag = flag;
236 subsys->name = "Unknown subsystem flag";
237 else
238 subsys->name = Imp::subsysflag2string[flag];
239 subsys->volhandlelist = roothandles;
240
241 //Add the subsystem pointer to the relevant maps:
242 section->disabledSubSystems << subsys;
243 m_d->flag2subsystems[flag]=subsys;
244}
245
246//____________________________________________________________________
248{
249 beginResetModel(); // see: http://doc.qt.io/qt-5/qabstractitemmodel-obsolete.html
250
251 //Check the subsystem was added previously:
252 if (m_d->flag2subsystems.find(flag)==m_d->flag2subsystems.end()) {
253 std::cout<<"VolumeTreeModel::enableSubSystem Error: System never added!"<<std::endl;
254 return;
255 }
256 Imp::SubSystem * subsys = m_d->flag2subsystems[flag];
257 //Find the appropriate section:
259 for(Imp::SectionInfo* sec : m_d->allSections) {
260 if (sec->enabledSubSystems.contains(subsys)) {
261 //It is already enabled
262 assert(!sec->disabledSubSystems.contains(subsys));
263 return;
264 }
265 if (sec->disabledSubSystems.contains(subsys)) {
266 assert(!sec->enabledSubSystems.contains(subsys));
267 section=sec;
268 break;
269 }
270 }
271 assert(section);
272 if (!section) {
273 std::cout<<"VolumeTreeModel::enableSubSystem Error: Did not find section of subsystem!."<<std::endl;
274 return;
275 }
276 //Move the subsystem from the disabled to the enabled list:
277 section->enabledSubSystems << subsys;//Fixme: Ordering.
278 section->disabledSubSystems.removeAll(subsys);
279 //If the newly added subsystem is the only enabled subsystem, the section needs to be enabled as well:
280 if (section->enabledSubSystems.count()==1) {
281 assert(!m_d->activeSections.contains(section));
282 m_d->activeSections << section;//Fixme: Ordering.
283 }
284 //Put volume handle pointers into quick subsystem access map:
285 for (VolumeHandle* volhandle : subsys->volhandlelist ) {
286 m_d->volhandle2subsystem[volhandle] = subsys;
287 }
288
289 endResetModel();
290
291}
292
293//____________________________________________________________________
295{
296 beginResetModel(); // see: http://doc.qt.io/qt-5/qabstractitemmodel-obsolete.html
297
298 //If it was not even added previously we can just return:
299 if (m_d->flag2subsystems.find(flag)==m_d->flag2subsystems.end())
300 return;
301
302 Imp::SubSystem * subsys = m_d->flag2subsystems[flag];
303 //Find the appropriate section:
305 for(Imp::SectionInfo* sec : m_d->allSections) {
306 if (sec->disabledSubSystems.contains(subsys)) {
307 //It is already disabled
308 assert(!sec->enabledSubSystems.contains(subsys));
309 return;
310 }
311 if (sec->enabledSubSystems.contains(subsys)) {
312 assert(!sec->disabledSubSystems.contains(subsys));
313 section=sec;
314 break;
315 }
316 }
317 assert(section);
318 if (!section) {
319 std::cout<<"VolumeTreeModel::disableSubSystem Error: Did not find section of subsystem!."<<std::endl;
320 return;
321 }
322
323 //Move the subsystem from the enabled to the disabled list:
324 section->disabledSubSystems << subsys;
325 section->enabledSubSystems.removeAll(subsys);
326 //If the newly disabled subsystem was the only enabled subsystem, the section needs to be disabled as well:
327 if (section->enabledSubSystems.count()==0) {
328 assert(m_d->activeSections.contains(section));
329 m_d->activeSections.removeAll(section);
330 }
331
332 //Remove volume handle pointers from quick subsystem access map:
333 for (VolumeHandle* volhandle : subsys->volhandlelist ) {
334 Q_ASSERT(m_d->volhandle2subsystem.find(volhandle)!=m_d->volhandle2subsystem.end());
335 m_d->volhandle2subsystem.erase(m_d->volhandle2subsystem.find(volhandle));
336 }
337
338 endResetModel();
339// reset();//Fixme: use proper insert rows/colums/etc. instead!
340}
341
342//____________________________________________________________________
343void VolumeTreeModel::getRootHandles(std::vector<std::pair<VolumeHandle::VolumeHandleListItr,VolumeHandle::VolumeHandleListItr> >& out) const
344{
345 out.clear();
346 out.reserve(m_d->flag2subsystems.size());
347 std::map<VP1GeoFlags::SubSystemFlag,Imp::SubSystem*>::iterator it, itE = m_d->flag2subsystems.end();
348 for (it = m_d->flag2subsystems.begin();it!=itE;++it)
349 out.push_back(std::pair<VolumeHandle::VolumeHandleListItr,VolumeHandle::VolumeHandleListItr>
350 (it->second->volhandlelist.begin(),it->second->volhandlelist.end()));
351
352}
353
354//____________________________________________________________________
355QModelIndex VolumeTreeModel::index(int row, int column, const QModelIndex &parent) const
356{
357 //Check that row and column are in allowed ranges (positive and within row/column count of parent):
358 if (!hasIndex(row, column, parent))
359 return QModelIndex();
360
361 if (!parent.isValid()) {
362 //We must return the index of a section label:
363 Q_ASSERT(row<m_d->activeSections.count());
364 return createIndex(row, column, m_d->activeSections.at(row));
365 }
366
367 VolumeHandle * parentHandle = Imp::handlePointer(parent);
368
369 if (Imp::isRegularVolumeHandle(parentHandle)) {
370 if (!parentHandle->childrenAreInitialised())
371 parentHandle->initialiseChildren();//Fixme: It seems that it is occasionally necessary to do this. Why?? Why not fetchMore??
372 VolumeHandle * childHandle = parentHandle->child(row);
373 Q_ASSERT(childHandle);
374 return createIndex(row, column, childHandle);
375 }
376
377 if (Imp::isSubSystemPointer(parentHandle)) {
378 //Return index of top-level volume:
379 Q_ASSERT(unsigned(row)<Imp::subSystemPointer(parentHandle)->volhandlelist.size());
380 return createIndex(row, column, Imp::subSystemPointer(parentHandle)->volhandlelist.at(row));
381 }
382
383 //Must be SectionInfo:
384 Q_ASSERT(Imp::isSectionInfoPointer(parentHandle));
385 Q_ASSERT(row<Imp::sectionInfoPointer(parentHandle)->enabledSubSystems.count());
386 return createIndex(row, column, Imp::sectionInfoPointer(parentHandle)->enabledSubSystems.at(row));
387}
388
389//____________________________________________________________________
390QModelIndex VolumeTreeModel::parent(const QModelIndex& index) const
391{
392 if (!index.isValid())
393 return QModelIndex();
394
395 //See if we have a volumeHandle as index:
396 VolumeHandle *childHandle = Imp::handlePointer(index);
397
398 if (Imp::isRegularVolumeHandle(childHandle)) {
399 VolumeHandle *parentHandle = childHandle->parent();
400 if (parentHandle)
401 return createIndex(parentHandle->childNumber(), 0, parentHandle);
402
403 //childHandle has 0 parent pointer => parent must be a subsystem label:
404 Q_ASSERT(m_d->volhandle2subsystem.find(childHandle)!=m_d->volhandle2subsystem.end());
405 Imp::SubSystem * subsys = m_d->volhandle2subsystem[childHandle];
406 Q_ASSERT(subsys);
407 Q_ASSERT(subsys->section->enabledSubSystems.contains(subsys));
408 return createIndex(subsys->section->enabledSubSystems.indexOf(subsys), 0, subsys);
409 }
410
411
412 if (Imp::isSubSystemPointer(childHandle)) {
413 //Index is a SubSystem => parent must be a section label:
414 Q_ASSERT(m_d->activeSections.contains(Imp::subSystemPointer(childHandle)->section));
415 return createIndex(m_d->activeSections.indexOf(Imp::subSystemPointer(childHandle)->section), 0, Imp::subSystemPointer(childHandle)->section);
416 }
417
418 //Must be SectionInfo => parent is root (i.e. invalid):
419 Q_ASSERT(Imp::isSectionInfoPointer(childHandle));
420 return QModelIndex();
421}
422
423//____________________________________________________________________
424int VolumeTreeModel::rowCount(const QModelIndex& parent) const
425{
426 if (parent.column() > 0)
427 return 0;
428
429 if (!parent.isValid())
430 return m_d->activeSections.size();//Number of active sections
431
432 VolumeHandle * parentHandle = Imp::handlePointer(parent);
433
434 if (Imp::isRegularVolumeHandle(parentHandle)) {
435 return parentHandle->nChildren();
436 }
437
438 if (Imp::isSubSystemPointer(parentHandle)) {
439 return Imp::subSystemPointer(parentHandle)->volhandlelist.size();
440 }
441
442 //Must be SectionInfo pointer:
443 Q_ASSERT(Imp::isSectionInfoPointer(parentHandle));
444 return Imp::sectionInfoPointer(parentHandle)->enabledSubSystems.count();
445}
446
447//____________________________________________________________________
448QVariant VolumeTreeModel::data(const QModelIndex& index, int role) const
449{
450 if ((role!=Qt::DisplayRole&&role!=Qt::ForegroundRole)||!index.isValid())
451 return QVariant();
452
453 VolumeHandle *volumeHandle = Imp::handlePointer(index);
454 if (Imp::isRegularVolumeHandle(volumeHandle)) {
455 if (role==Qt::ForegroundRole) {
456 if (volumeHandle->isAttached())
457 return QVariant();
458 else
459 return QColor::fromRgbF( 0.5, 0.5, 0.5 );
460 }
461 //DisplayRole:
462 if (volumeHandle->nChildren()>1)
463 return volumeHandle->getName()+" ["+QString::number(volumeHandle->nChildren())+"]";
464 else
465 return volumeHandle->getName();
466 }
467
468 if (role==Qt::ForegroundRole)
469 return QVariant();
470
471 if (Imp::isSubSystemPointer(volumeHandle))
472 return Imp::subSystemPointer(volumeHandle)->name;
473
474 Q_ASSERT(Imp::isSectionInfoPointer(volumeHandle));
475 return Imp::sectionInfoPointer(volumeHandle)->name;
476}
477
478
479//____________________________________________________________________
480Qt::ItemFlags VolumeTreeModel::flags(const QModelIndex &index) const
481{
482 if (!index.isValid())
483 return Qt::ItemFlags();
484
486 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
487 else
488 return Qt::ItemIsEnabled;
489}
490
491//____________________________________________________________________
492QVariant VolumeTreeModel::headerData(int /*section*/, Qt::Orientation /*orientation*/,int /*role*/) const
493{
494 return QVariant();
495}
496
497//____________________________________________________________________
498bool VolumeTreeModel::canFetchMore( const QModelIndex & parent ) const
499{
500 if (!parent.isValid())
501 return false;
502
503 VolumeHandle * parentHandle = Imp::handlePointer(parent);
504
505 if (Imp::isRegularVolumeHandle(parentHandle)&&!parentHandle->childrenAreInitialised())
506 return true;
507
508 return false;
509}
510
511//____________________________________________________________________
512void VolumeTreeModel::fetchMore( const QModelIndex & parent )
513{
514 if (!parent.isValid())
515 return;//should probably never happen
516
517 VolumeHandle* parentHandle = Imp::handlePointer(parent);
518
519 if (Imp::isRegularVolumeHandle(parentHandle)&&!parentHandle->childrenAreInitialised()) {
520 // beginInsertRows(parent,0,int(parentHandle->nChildren())-1);
521 parentHandle->initialiseChildren();
522 layoutChanged();//fixme??
523 // endInsertRows();
524 return;
525 }
526}
527
528//____________________________________________________________________
529bool VolumeTreeModel::hasChildren ( const QModelIndex & parent ) const
530{
531 return rowCount(parent)>0;//Our rowCount is relatively fast (no looping to count).
532}
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:140
Definition index.py:1