ATLAS Offline Software
Loading...
Searching...
No Matches
AscObjSelectionManager.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5
7// //
8// Implementation of class AscObjSelectionManager //
9// //
10// Author: Thomas H. Kittelmann (Thomas.Kittelmann@cern.ch) //
11// Initial version: April 2008 //
12// //
14
21#include "VP1Base/VP1Msg.h"
22#include <Inventor/nodes/SoSeparator.h>
23#include <Inventor/SoPath.h>
24#include <QApplication>
25#include<map>
26
27//____________________________________________________________________
29public:
31 : theclass(tc),
32 eventRoot(root),
33 system(sys),
34 controller(c),
36 {
37 eventRoot->ref();
39 sel_assocobjs_click->setName("sel_assocobjs_click");
42 sel_assocobjs_click->policy = SoCooperativeSelection::SINGLE;
43 sys->registerSelectionNode(sel_assocobjs_click);
44
46 sel_assocobjs->setName("sel_assocobjs");
47 sel_assocobjs->ref();
49 sel_assocobjs_click->policy = SoCooperativeSelection::SINGLE;
50 sys->registerSelectionNode(sel_assocobjs);
51
53 root->addChild(sel_assocobjs);
54 }
55 Imp(const Imp &) = delete;
56 Imp & operator=(const Imp &) = delete;
58 {
59 system->unregisterSelectionNode(sel_assocobjs_click);
60 sel_assocobjs_click->unref();
61 sel_assocobjs->unref();
62 eventRoot->unref();
63 }
64
66 SoSeparator* eventRoot;
72
73 std::map<SoSeparator*,AssociatedObjectHandleBase*> ascobjs_simpleToHandle;
74 std::map<SoSeparator*,AssociatedObjectHandleBase*> ascobjs_detailedToHandle;
75
76// bool ascObjHandleFixSelectionPath(AssociatedObjectHandleBase*,SoPath*);
78 AssociatedObjectHandleBase* ascObjHandle(const SoSeparator*);
79 QList<AssociatedObjectHandleBase*> selAscObjHandles;
80
82 static bool shiftIsDown() { return Qt::ShiftModifier & QApplication::keyboardModifiers(); }
83
84};
85
86
87
88//____________________________________________________________________
90 : QObject(sys), VP1HelperClassBase(sys,"AscObjSelectionManager"), m_d(new Imp(this,event_root,sys,controller))
91{
92 connect(controller,SIGNAL(assocObjDetailLevelChanged(TrackCommonFlags::DETAILLEVEL)),this,SLOT(ascObjDetailLevelChanged()));
94}
95
96//____________________________________________________________________
98{
99 //fixme: clear maps and emit signals!
100}
101
102//____________________________________________________________________
104{
105 //Fixme: sanity check that maps are cleared.
106 delete m_d;
107}
108
109//____________________________________________________________________
111{
112 if (m==SINGLE) return "SINGLE";
113 else if (m==TOGGLE) return "TOGGLE";
114 else if (m==SHIFT) return "SHIFT";
115 else return "UNKNOWN(ERROR)";
116}
117
118//____________________________________________________________________
123
124//____________________________________________________________________
126{
127 if (m_d->mode==m)
128 return;
129 message("Mode changed to "+toString(m));
130 m_d->mode=m;
131}
132
133
134//____________________________________________________________________
136{
137 return m_d->sel_assocobjs_click;
138}
139//____________________________________________________________________
140void AscObjSelectionManager::registerAscObj(SoSeparator*simple,SoSeparator *detailed,AssociatedObjectHandleBase*handle)
141{
142 if (VP1Msg::verbose()) {
143 if (!simple||!detailed||!handle) {
144 message("registerAscObj ERROR: Received null pointer!");
145 return;
146 }
147 std::map<SoSeparator*,AssociatedObjectHandleBase*>::iterator it, itE;
148 itE = m_d->ascobjs_simpleToHandle.end();
149 for (it=m_d->ascobjs_simpleToHandle.begin();it!=itE;++it) {
150 if (it->first==simple||it->second==handle)
151 message("registerAscObj ERROR: Simple separator/handle already registered!");
152 }
153 itE = m_d->ascobjs_detailedToHandle.end();
154 for (it=m_d->ascobjs_detailedToHandle.begin();it!=itE;++it) {
155 if (it->first==detailed||it->second==handle)
156 message("registerAscObj ERROR: Detailed separator/handle already registered!");
157 }
158 }
159 m_d->ascobjs_simpleToHandle[simple]=handle;
160 m_d->ascobjs_detailedToHandle[detailed]=handle;
161}
162
163//____________________________________________________________________
164void AscObjSelectionManager::unregisterAscObj(SoSeparator*simple,SoSeparator *detailed)
165{
166 if (VP1Msg::verbose()) {
167 if (!simple||!detailed) {
168 message("unregisterAscObj ERROR: Received null pointer!");
169 return;
170 }
171 }
172 std::map<SoSeparator*,AssociatedObjectHandleBase*>::iterator itSimple = m_d->ascobjs_simpleToHandle.find(simple);
173 if (itSimple==m_d->ascobjs_simpleToHandle.end()) {
174 message("unregisterAscObj ERROR: Not previously registered simple sep!");
175 } else {
176 m_d->ascobjs_simpleToHandle.erase(itSimple);
177 }
178 std::map<SoSeparator*,AssociatedObjectHandleBase*>::iterator itDetailed = m_d->ascobjs_detailedToHandle.find(detailed);
179 if (itDetailed==m_d->ascobjs_detailedToHandle.end()) {
180 message("unregisterAscObj ERROR: Not previously registered detailed sep!");
181 } else {
182 m_d->ascobjs_detailedToHandle.erase(itDetailed);
183 }
184}
185
186//____________________________________________________________________
188{
189 const int n(path?path->getLength():0);
190 AssociatedObjectHandleBase * handle(nullptr);
191 for (int i = 0; i < n; ++i) {
192 if (path->getNodeFromTail(i)->getTypeId()==SoSeparator::getClassTypeId()) {
193 handle = ascObjHandle(static_cast<SoSeparator*>(path->getNodeFromTail(i)));
194 if (handle)
195 return handle;
196 }
197 }
198 return nullptr;
199}
200
201//____________________________________________________________________
203{
204 std::map<SoSeparator*,AssociatedObjectHandleBase*>::const_iterator
205 it(ascobjs_simpleToHandle.find(const_cast<SoSeparator*>(s)));
206 if (it!=ascobjs_simpleToHandle.end())
207 return it->second;
208 it = ascobjs_detailedToHandle.find(const_cast<SoSeparator*>(s));
209 return it==ascobjs_detailedToHandle.end() ? 0 : it->second;
210}
211
212//____________________________________________________________________
214{
215 const bool isSimpleMode = controller->assocObjDetailLevel()==TrackCommonFlags::SIMPLE;
216 sel_assocobjs->deselectAll();
218 SoPath * path = new SoPath(sel_assocobjs);
219 path->ref();
221 (isSimpleMode?handle->shapeSimple():handle->shapeDetailed()))) {
222 theclass->message("updateSelectionVisuals ERROR: Failed to relocate picked node.");
223 path->unref();
224 continue;
225 }
226 sel_assocobjs->select(path);
227 path->unref();
228 }
229}
230
231
232//____________________________________________________________________
234{
235 messageVerbose("handleUserSelectedSingleNode");
236 pickedHandle = nullptr;
237 if (sel==m_d->sel_assocobjs) {
238 messageVerbose(" => ignore selections for m_d->sel_assocobjs");
239 return true;//We simply ignore those
240 }
241 if (sel!=m_d->sel_assocobjs_click) {
242 messageVerbose(" => We don't handle this selection.");
243 return false;
244 }
245
246 AssociatedObjectHandleBase* handle = m_d->ascObjHandle(pickedPath);
247 m_d->sel_assocobjs_click->deselectAll();
248 if (!handle) {
249 message("ERROR: Unknown associated object.");
250 return true;
251 }
252 messageVerbose(" => Found handle. Mode is "+toString(m_d->mode)+", and number of previously selected handles is "+str(m_d->selAscObjHandles.count()));
253 pickedHandle = handle;
254 pretendUserClicked(handle);//we are not really pretending in this case of course...
255 return true;
256}
257
258//____________________________________________________________________
260{
261 assert(handle);
262 if (!handle)
263 return;
264 const bool alreadyselected = m_d->selAscObjHandles.contains(handle);
265 std::sort(m_d->selAscObjHandles.begin(), m_d->selAscObjHandles.end());
266 QList<AssociatedObjectHandleBase*> selHandlesBefore = m_d->selAscObjHandles;
267
268 if (m_d->mode==SINGLE) {
269 if (m_d->selAscObjHandles.isEmpty()) {
270 //Add handle to selection.
271 m_d->selAscObjHandles << handle;
272 if (m_d->controller->printInfoOnSingleSelection())
273 m_d->system->message(handle->clicked());
274 } else {
275 //Clear selection.
276 m_d->selAscObjHandles.clear();
277 //Add if not already selected:
278 if (!alreadyselected) {
279 m_d->selAscObjHandles << handle;
280 if (m_d->controller->printInfoOnSingleSelection())
281 m_d->system->message(handle->clicked());
282 }
283 }
284 } else if (m_d->mode==SHIFT) {
285 if (Imp::shiftIsDown()) {
286 if (alreadyselected)
287 m_d->selAscObjHandles.removeAll(handle);
288 else
289 m_d->selAscObjHandles << handle;
290 } else {
291 m_d->selAscObjHandles.clear();
292 if (!alreadyselected)
293 m_d->selAscObjHandles << handle;
294 }
295 } else if (m_d->mode==TOGGLE) {
296 if (alreadyselected) {
297 m_d->selAscObjHandles.removeAll(handle);
298 } else {
299 m_d->selAscObjHandles << handle;
300 }
301 } else {
302 message("ERROR: Should not happen!");
303 deselectAll();
304 return;
305 }
306 std::sort(m_d->selAscObjHandles.begin(), m_d->selAscObjHandles.end());
307
308 if (selHandlesBefore!=m_d->selAscObjHandles) {
309 m_d->updateSelectionVisuals();
310 currentSelectionChanged(m_d->selAscObjHandles);
311 }
312}
313
314
315//____________________________________________________________________
317{
318 if (m_d->mode==TOGGLE)
319 return;
320 if (m_d->mode==SHIFT&&Imp::shiftIsDown())
321 return;
322 deselectAll();
323}
324
325//____________________________________________________________________
327{
328 if (m_d->selAscObjHandles.isEmpty())
329 return;
330 m_d->selAscObjHandles.clear();
331 currentSelectionChanged(m_d->selAscObjHandles);
332 m_d->updateSelectionVisuals();
333}
334
335//____________________________________________________________________
336void AscObjSelectionManager::ensureDeselected(const QList<AssociatedObjectHandleBase*>& handles)
337{
338 if (handles.isEmpty())
339 return;
340 QList<AssociatedObjectHandleBase*> selHandlesBefore = m_d->selAscObjHandles;
341 for (AssociatedObjectHandleBase*handle : handles)
342 m_d->selAscObjHandles.removeAll(handle);
343 if (selHandlesBefore!=m_d->selAscObjHandles) {
344 m_d->updateSelectionVisuals();
345 currentSelectionChanged(m_d->selAscObjHandles);
346 }
347}
348
349//____________________________________________________________________
350void AscObjSelectionManager::ensureSelected(const QList<AssociatedObjectHandleBase*>& handles)
351{
352 if (handles.isEmpty())
353 return;
354 if (m_d->mode==SINGLE) {
355 //Single selections
356 if (handles.count()>1)
357 message("WARNING: ensureSelected called with more than one handle in SINGLE mode. Ignoring all but the first.");
358 if (m_d->selAscObjHandles.contains(handles.at(0)))
359 return;
360 m_d->selAscObjHandles.clear();
361 m_d->selAscObjHandles << handles.at(0);
362 currentSelectionChanged(m_d->selAscObjHandles);
363 m_d->updateSelectionVisuals();
364 } else {
365 //Multi selections allowed
366 QList<AssociatedObjectHandleBase*> selHandlesBefore = m_d->selAscObjHandles;
367 for (AssociatedObjectHandleBase*handle : handles) {
368 if (!m_d->selAscObjHandles.contains(handle))
369 m_d->selAscObjHandles << handle;
370 }
371 std::sort(m_d->selAscObjHandles.begin(), m_d->selAscObjHandles.end());
372 if (selHandlesBefore!=m_d->selAscObjHandles) {
373 m_d->updateSelectionVisuals();
374 currentSelectionChanged(m_d->selAscObjHandles);
375 }
376 }
377
378}
379
380//____________________________________________________________________
382{
383 messageVerbose("Signal received in ascObjDetailLevelChanged slot");
384 if (m_d->selAscObjHandles.isEmpty()) {
385 m_d->sel_assocobjs->deselectAll();
386 return;
387 }
388 const SoPathList * pathlist = m_d->sel_assocobjs->getList();
389 if (!pathlist||pathlist->getLength()!=m_d->selAscObjHandles.count())
390 return;
391
392 const bool isSimpleMode = (m_d->controller->assocObjDetailLevel()==TrackCommonFlags::SIMPLE);
393 int i(0);
394 for (AssociatedObjectHandleBase* handle : m_d->selAscObjHandles) {
395 SoPath * path = (*pathlist)[i++];
396 if (!path)
397 continue;
398 if (!VP1QtInventorUtils::changePathTail(path,m_d->sel_assocobjs,
399 (isSimpleMode?handle->shapeSimple():handle->shapeDetailed()))) {
400 message("Warning: Failed to relocate picked node.");
401 deselectAll();
402 return;
403 }
404 }
405}
406
407//____________________________________________________________________
408const QList<AssociatedObjectHandleBase*>& AscObjSelectionManager::currentSelection() const
409{
410 return m_d->selAscObjHandles;
411}
412
414{
415 return m_d->eventRoot;
416}
static Double_t tc
QList< AssociatedObjectHandleBase * > selAscObjHandles
Imp(AscObjSelectionManager *tc, SoSeparator *root, IVP13DSystem *sys, TrackSystemController *c)
AssociatedObjectHandleBase * ascObjHandle(const SoPath *)
Imp(const Imp &)=delete
std::map< SoSeparator *, AssociatedObjectHandleBase * > ascobjs_detailedToHandle
SoCooperativeSelection * sel_assocobjs
SoCooperativeSelection * sel_assocobjs_click
Imp & operator=(const Imp &)=delete
AscObjSelectionManager * theclass
std::map< SoSeparator *, AssociatedObjectHandleBase * > ascobjs_simpleToHandle
void unregisterAscObj(SoSeparator *simple, SoSeparator *detailed)
void pretendUserClicked(AssociatedObjectHandleBase *)
void ensureSelected(const QList< AssociatedObjectHandleBase * > &)
bool handleUserSelectedSingleNode(SoCooperativeSelection *, SoNode *, SoPath *, AssociatedObjectHandleBase *&)
void currentSelectionChanged(const QList< AssociatedObjectHandleBase * > &)
void registerAscObj(SoSeparator *simple, SoSeparator *detailed, AssociatedObjectHandleBase *)
SoSeparator * getAscObjAttachSep() const
AscObjSelectionManager(SoSeparator *eventRoot, IVP13DSystem *, TrackSystemController *)
const QList< AssociatedObjectHandleBase * > & currentSelection() const
void ensureDeselected(const QList< AssociatedObjectHandleBase * > &)
virtual QStringList clicked()=0
VP1HelperClassBase(IVP1System *sys=0, QString helpername="")
void messageVerbose(const QString &) const
void message(const QString &) const
static bool verbose()
Definition VP1Msg.h:31
static bool changePathTail(SoPath *path, SoNode *commonBranchPoint, SoNode *newtail)
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.