ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4OpenGLQtViewer.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4OpenGLQtViewer.cc
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 //
27 //
28 //
29 // G4OpenGLQtViewer : Class to provide Qt specific
30 // functionality for OpenGL in GEANT4
31 //
32 // 27/06/2003 : G.Barrand : implementation (at last !).
33 // 30/06/2014 : M.Kelsey : Change QPixmap objects to pointers
34 
35 #ifdef G4VIS_BUILD_OPENGLQT_DRIVER
36 
37 #include "G4LogicalVolumeStore.hh"
38 #include "G4PhysicalVolumeStore.hh"
40 #include "G4PhysicalVolumeModel.hh"
41 #include "G4Text.hh"
42 #include "G4UnitsTable.hh"
44 #include "G4Threading.hh"
45 
46 #include "G4OpenGLQtViewer.hh"
47 #include "G4OpenGLSceneHandler.hh"
49 #include "G4OpenGLQtMovieDialog.hh"
50 #include "G4Qt.hh"
51 #include "G4UIQt.hh"
52 #include "G4UImanager.hh"
53 #include "G4UIcommandTree.hh"
54 
56 
57 #include <typeinfo>
58 #include <mutex>
59 
60 #include <qlayout.h>
61 #include <qlabel.h>
62 #include <qdialog.h>
63 #include <qpushbutton.h>
64 #include <qprocess.h>
65 #include <qdesktopwidget.h>
66 
67 #include <qmenu.h>
68 #include <qimagewriter.h>
69 
70 #include <qtextedit.h>
71 #include <qtreewidget.h>
72 #include <qapplication.h>
73 #include <qmessagebox.h>
74 #include <qfiledialog.h>
75 #include <qprinter.h>
76 #include <qdatetime.h>
77 #include <qpainter.h>
78 #include <qgl.h> // include <qglwidget.h>
79 #include <qdialog.h>
80 #include <qcolordialog.h>
81 #include <qevent.h> //include <qcontextmenuevent.h>
82 #include <qobject.h>
83 #include <qgroupbox.h>
84 #include <qcombobox.h>
85 #include <qlineedit.h>
86 #if QT_VERSION < 0x050600
87 #include <qsignalmapper.h>
88 #else
89 #include <qscreen.h>
90 #endif
91 #include <qmainwindow.h>
92 #include <qtablewidget.h>
93 #include <qheaderview.h>
94 #include <qscrollarea.h>
95 #include <qsplitter.h>
96 #include <qcheckbox.h>
97 #include <qcursor.h>
98 #include <qthread.h>
99 
100 namespace
101 {
102  G4Mutex mWaitForVisSubThreadQtOpenGLContextMoved = G4MUTEX_INITIALIZER;
103  G4Mutex mWaitForVisSubThreadQtOpenGLContextInitialized = G4MUTEX_INITIALIZER;
104  // avoid unused variable warning
105 #ifdef G4MULTITHREADED
106  G4Condition c1_VisSubThreadQtOpenGLContextInitialized = G4CONDITION_INITIALIZER;
107  G4Condition c2_VisSubThreadQtOpenGLContextMoved = G4CONDITION_INITIALIZER;
108 #endif
109 }
110 
112 void G4OpenGLQtViewer::CreateMainWindow (
113  QGLWidget* glWidget
114  ,const QString& name
115 )
116 
117 
118 {
119 
120  if(fGLWidget) return; //Done.
121 
122  fGLWidget = glWidget ;
123  // fGLWidget->makeCurrent();
124 
125  G4Qt* interactorManager = G4Qt::getInstance ();
126 
127  ResizeWindow(fVP.GetWindowSizeHintX(),fVP.GetWindowSizeHintY());
128 
129  // FIXME L.Garnier 9/11/09 Has to be check !!!
130  // Qt UI with Qt Vis
131  // Qt UI with X Vis
132  // X UI with Qt Vis
133  // X UI with X Vis
134  // Ne marche pas avec un UIBatch !! (ecran blanc)
135 
136  // return false if G4UIQt was not launch
137 
139  if (UI == NULL) return;
140 
141  if (! static_cast<G4UIQt*> (UI->GetG4UIWindow())) {
142  // NO UI, should be batch mode
143  fBatchMode = true;
144  return;
145  }
146  fUiQt = static_cast<G4UIQt*> (UI->GetG4UIWindow());
147 
148  bool isTabbedView = false;
149  if ( fUiQt) {
150  if (!fBatchMode) {
151  if (!interactorManager->IsExternalApp()) {
152  // INIT size
153  fWinSize_x = fVP.GetWindowSizeHintX();
154  fWinSize_y = fVP.GetWindowSizeHintY();
155 
156  isTabbedView = fUiQt->AddTabWidget((QWidget*)fGLWidget,name);
157  QObject::connect(fUiQt->GetViewerTabWidget(),
158  SIGNAL(currentChanged(int)),
159  this,
160  SLOT(currentTabActivated(int)));
161 
162 
163  }
164  createSceneTreeWidget();
165  // activate them
166  }
167  }
168 
169  if (!isTabbedView) { // we have to do a dialog
170 
171  QWidget *glDialogWidget = getParentWidget();
172  if (glDialogWidget == NULL) {
173  return;
174  }
175  glWidget->setParent(glDialogWidget);
176  QHBoxLayout *mainLayout = new QHBoxLayout();
177 
178  mainLayout->setMargin(0);
179  mainLayout->setSpacing(0);
180  mainLayout->addWidget(fGLWidget);
181  if (fGLWidget->inherits("QMainWindow")) {
182  fGLWidget->setWindowTitle( name);
183  }
184  glDialogWidget->setLayout(mainLayout);
185 
186 
187  //useful for MACOSX, we have to compt the menuBar height
188 #if QT_VERSION >= 0x050a00
189  G4int offset = QApplication::desktop()->height()
190  - QGuiApplication::screenAt(QPoint(20,20))->availableGeometry().height();
191 #else
192  G4int offset = QApplication::desktop()->height()
193  - QApplication::desktop()->availableGeometry().height();
194 #endif
195 
196  G4int YPos= fVP.GetWindowAbsoluteLocationHintY(QApplication::desktop()->height());
197  if (fVP.GetWindowAbsoluteLocationHintY(QApplication::desktop()->height())< offset) {
198  YPos = offset;
199  }
200  glDialogWidget->resize(getWinWidth(), getWinHeight());
201  glDialogWidget->move(fVP.GetWindowAbsoluteLocationHintX(QApplication::desktop()->width()),YPos);
202  glDialogWidget->show();
203  }
204 
205  if(!fGLWidget) return;
206 
207  if (!fContextMenu)
208  createPopupMenu();
209 
210 }
211 
212 
214 G4OpenGLQtViewer::G4OpenGLQtViewer (
215  G4OpenGLSceneHandler& scene
216 )
217  :G4VViewer (scene, -1)
218  ,G4OpenGLViewer (scene)
219  ,fGLWidget(NULL)
220  ,fRecordFrameNumber(0)
221  ,fMouseOnSceneTree(false)
222  ,fContextMenu(0)
223  ,fLastPickPoint(-1,-1)
224  ,fDeltaDepth(0.01)
225  ,fDeltaZoom(0.05)
226  ,fHoldKeyEvent(false)
227  ,fHoldMoveEvent(false)
228  ,fHoldRotateEvent(false)
229  ,fAutoMove(false)
230  ,fEncoderPath("")
231  ,fTempFolderPath("")
232  ,fMovieTempFolderPath("")
233  ,fSaveFileName("")
234  ,fParameterFileName("ppmtompeg_encode_parameter_file.par")
235  ,fMovieParametersDialog(NULL)
236  ,fRecordingStep(WAIT)
237  ,fProcess(NULL)
238  ,fNbMaxFramesPerSec(100)
239  ,fNbMaxAnglePerSec(360)
240  ,fLaunchSpinDelay(100)
241  ,fUISceneTreeWidget(NULL)
242  ,fUIViewerPropertiesWidget(NULL)
243  ,fUIPickInfosWidget(NULL)
244  ,fNoKeyPress(true)
245  ,fAltKeyPress(false)
246  ,fControlKeyPress(false)
247  ,fShiftKeyPress(false)
248  ,fBatchMode(false)
249  ,fCheckSceneTreeComponentSignalLock(false)
250  ,fViewerPropertiesTableWidgetIsInit(false)
251  ,fSceneTreeComponentTreeWidget(NULL)
252  ,fSceneTreeWidget(NULL)
253  ,fPVRootNodeCreate(false)
254  ,fFilterOutput(NULL)
255  ,fNbRotation(0)
256  ,fTimeRotation(0)
257  ,fTouchableVolumes("Touchables")
258  ,fShortcutsDialog(NULL)
259  ,fViewerPropertiesTableWidget(NULL)
260  ,fPickInfosWidget(NULL)
261  ,fPickInfosScrollArea(NULL)
262  ,fTreeWidgetInfosIgnoredCommands(0)
263  ,fSceneTreeDepthSlider(NULL)
264  ,fSceneTreeDepth(1)
265  ,fModelShortNameItem(NULL)
266  ,fMaxPOindexInserted(-1)
267  ,fUiQt(NULL)
268 #if QT_VERSION < 0x050600
269  ,fSignalMapperMouse(NULL)
270  ,fSignalMapperSurface(NULL)
271  ,fSignalMapperPicking(NULL)
272 #endif
273  ,fTreeIconOpen(NULL)
274  ,fTreeIconClosed(NULL)
275  ,fLastExportSliderValue(80)
276  ,fLastHighlightColor(G4Color(0,0,0,0))
277  ,fLastHighlightName(0)
278  ,fIsDeleting(false)
279 {
280  lWaitForVisSubThreadQtOpenGLContextInitialized
281  = new G4AutoLock(mWaitForVisSubThreadQtOpenGLContextInitialized,
282  std::defer_lock);
283  lWaitForVisSubThreadQtOpenGLContextMoved
284  = new G4AutoLock(mWaitForVisSubThreadQtOpenGLContextMoved,
285  std::defer_lock);
286 
287  // launch Qt if not
288  if (QCoreApplication::instance () == NULL) {
289  fBatchMode = true;
290  }
291  G4Qt::getInstance ();
292 
293  fLastPos3 = QPoint(-1,-1);
294  fLastPos2 = QPoint(-1,-1);
295  fLastPos1 = QPoint(-1,-1);
296 
297  initMovieParameters();
298 
299  fLastEventTime = new QTime();
300 #if QT_VERSION < 0x050600
301  fSignalMapperMouse = new QSignalMapper(this);
302  fSignalMapperSurface = new QSignalMapper(this);
303 #endif
304  // Set default path and format
305  fFileSavePath = QDir::currentPath();
306 
307  // add available export format
308  QList<QByteArray> formats = QImageWriter::supportedImageFormats ();
309  for (int i = 0; i < formats.size(); ++i) {
310  addExportImageFormat(formats.at(i).data());
311  }
312 
313  const char * const icon1[]={
314  /* columns rows colors chars-per-pixel */
315  "20 20 34 1",
316  " c None",
317  ". c #7C7C7C7C7C7C",
318  "X c #7D7D7D7D7D7D",
319  "o c #828282828282",
320  "O c #838383838383",
321  "+ c #848484848484",
322  "@ c #858585858585",
323  "# c #878787878787",
324  "$ c #888888888888",
325  "% c #8B8B8B8B8B8B",
326  "& c #8C8C8C8C8C8C",
327  "* c #8F8F8F8F8F8F",
328  "= c #909090909090",
329  "- c #919191919191",
330  "; c #999999999999",
331  ": c #9D9D9D9D9D9D",
332  "> c #A2A2A2A2A2A2",
333  ", c #A3A3A3A3A3A3",
334  "< c #A5A5A5A5A5A5",
335  "1 c #A6A6A6A6A6A6",
336  "2 c #B3B3B3B3B3B3",
337  "3 c #B6B6B6B6B6B6",
338  "4 c #C2C2C2C2C2C2",
339  "5 c #C6C6C6C6C6C6",
340  "6 c #CACACACACACA",
341  "7 c #CFCFCFCFCFCF",
342  "8 c #D0D0D0D0D0D0",
343  "9 c #D4D4D4D4D4D4",
344  "0 c #D7D7D7D7D7D7",
345  "q c #DEDEDEDEDEDE",
346  "w c #E0E0E0E0E0E0",
347  "e c #E7E7E7E7E7E7",
348  "r c #F4F4F4F4F4F4",
349  "t c #F7F7F7F7F7F7",
350  " ",
351  " ",
352  " ",
353  " ",
354  " ",
355  " ",
356  " =========> ",
357  " 7&X+++Oo<e ",
358  " 2o+@@+-8 ",
359  " w;.#@+3 ",
360  " 4$o@:q ",
361  " r1X%5 ",
362  " 9*,t ",
363  " 60 ",
364  " ",
365  " ",
366  " ",
367  " ",
368  " ",
369  " "
370  };
371  const char * const icon2[]={
372  "20 20 68 1",
373  " c None",
374  ". c #5F5F10102323",
375  "X c #40405F5F1010",
376  "o c #696963632E2E",
377  "O c #101019194C4C",
378  "+ c #101023237070",
379  "@ c #70702D2D6363",
380  "# c #73732D2D6464",
381  "$ c #79792E2E6767",
382  "% c #19194C4C5353",
383  "& c #2D2D63636161",
384  "* c #2E2E61617070",
385  "= c #6F6F6E6E4343",
386  "- c #707065655F5F",
387  "; c #727279795454",
388  ": c #535341417070",
389  "> c #797954547979",
390  ", c #434361617474",
391  "< c #414170707070",
392  "1 c #686869696363",
393  "2 c #6C6C69696363",
394  "3 c #656567676F6F",
395  "4 c #69696F6F6E6E",
396  "5 c #747465656767",
397  "6 c #757562626C6C",
398  "7 c #70706C6C6969",
399  "8 c #616174746565",
400  "9 c #656573736969",
401  "0 c #616174746969",
402  "q c #707075756262",
403  "w c #797970706565",
404  "e c #636361617474",
405  "r c #67676F6F7272",
406  "t c #727261617070",
407  "y c #616170707070",
408  "u c #6F6F72727979",
409  "i c #67676E6ED1D1",
410  "p c #808080808080",
411  "a c #828282828282",
412  "s c #838383838383",
413  "d c #848484848484",
414  "f c #858585858585",
415  "g c #868686868686",
416  "h c #888888888888",
417  "j c #8A8A8A8A8A8A",
418  "k c #8D8D8D8D8D8D",
419  "l c #8F8F8F8F8F8F",
420  "z c #909090909090",
421  "x c #949494949494",
422  "c c #9C9C9C9C9C9C",
423  "v c #9F9F9F9F9F9F",
424  "b c #A2A2A2A2A2A2",
425  "n c #AEAEAEAEAEAE",
426  "m c #B7B7B7B7B7B7",
427  "M c #C7C7C7C7C7C7",
428  "N c #C9C9C9C9C9C9",
429  "B c #D1D1D1D1D1D1",
430  "V c #D4D4D4D4D4D4",
431  "C c #D9D9D9D9D9D9",
432  "Z c #E0E0E0E0E0E0",
433  "A c #E2E2E2E2E2E2",
434  "S c #EEEEEEEEEEEE",
435  "D c #F0F0F0F0F0F0",
436  "F c #F5F5F5F5F5F5",
437  "G c #F6F6F6F6F6F6",
438  "H c #F9F9F9F9F9F9",
439  "J c #FCFCFCFCFCFC",
440  "K c #FDFDFDFDFDFD",
441  " ",
442  " ",
443  " ",
444  " ",
445  " ",
446  " bC ",
447  " zjnD ",
448  " ldjjMK ",
449  " zdhdjcA ",
450  " zddhdddVK ",
451  " zghdalBH ",
452  " zghamSK ",
453  " lubZH ",
454  " xMF ",
455  " G ",
456  " ",
457  " ",
458  " ",
459  " ",
460  " ",
461 
462  };
463 
464  const char * const search[] = {
465  /* columns rows colors chars-per-pixel */
466  "19 19 8 1",
467  " c #5C5C5C",
468  ". c #7D7D7D",
469  "X c #9B9B9B",
470  "o c #C3C3C3",
471  "O c None",
472  "+ c #000000",
473  "@ c #000000",
474  "# c None",
475  /* pixels */
476  "OOOOOOOOOOOOOOOOOOO",
477  "OOOOOOOOOOOOOOOOOOO",
478  "OOOOOOOo. .oOOOOOO",
479  "OOOOOOX XOOOOO",
480  "OOOOOo XOOX oOOOO",
481  "OOOOO. XOOOOX .OOOO",
482  "OOOOO OOOOOO OOOO",
483  "OOOOO OOOOOO OOOO",
484  "OOOOO. XOOOOo .OOOO",
485  "OOOOOo oOOo oOOOO",
486  "OOOOOOX XOOOO",
487  "OOOOOOOo. . XOOO",
488  "OOOOOOOOOOOOO. XOO",
489  "OOOOOOOOOOOOOO. XOO",
490  "OOOOOOOOOOOOOOOoOOO",
491  "OOOOOOOOOOOOOOOOOOO",
492  "OOOOOOOOOOOOOOOOOOO",
493  "OOOOOOOOOOOOOOOOOOO",
494  "OOOOOOOOOOOOOOOOOOO"
495  };
496 
497  fSearchIcon = new QPixmap(search);
498  fTreeIconOpen = new QPixmap(icon1);
499  fTreeIconClosed = new QPixmap(icon2);
500 
501 }
502 
504 G4OpenGLQtViewer::~G4OpenGLQtViewer (
505 )
506 
507 
508 {
509  fIsDeleting = true;
510 
511  // remove scene tree from layout
512  // Delete all the existing buttons in the layout
513  QLayoutItem *wItem;
514  if (fSceneTreeWidget != NULL) {
515  if (fSceneTreeWidget->layout() != NULL) {
516  while ((wItem = fSceneTreeWidget->layout()->takeAt(0)) != 0) {
517  delete wItem->widget();
518  delete wItem;
519  }
520  }
521  }
522 
523  // Delete the open/close icons
524  delete fTreeIconOpen;
525  delete fTreeIconClosed;
526 
527  G4cout <<removeTempFolder().toStdString().c_str() <<G4endl;
528 
529  delete lWaitForVisSubThreadQtOpenGLContextInitialized;
530  delete lWaitForVisSubThreadQtOpenGLContextMoved;
531 
532 }
533 
534 
535 //
536 // Create a popup menu for the widget. This menu is activated by right-mouse click
537 //
538 void G4OpenGLQtViewer::createPopupMenu() {
539 
540  fContextMenu = new QMenu("All");
541 
542  QMenu *mMouseAction = fContextMenu->addMenu("&Mouse actions");
543 
544 #if QT_VERSION < 0x050600
545  fMouseRotateAction = mMouseAction->addAction("Rotate", fSignalMapperMouse, SLOT(map()));
546  fMouseMoveAction = mMouseAction->addAction("Move", fSignalMapperMouse, SLOT(map()));
547  fMousePickAction = mMouseAction->addAction("Pick", fSignalMapperMouse, SLOT(map()));
548  fMouseZoomOutAction = mMouseAction->addAction("Zoom out", fSignalMapperMouse, SLOT(map()));
549  fMouseZoomInAction = mMouseAction->addAction("Zoom in", fSignalMapperMouse, SLOT(map()));
550 #else
551  fMouseRotateAction = mMouseAction->addAction("Rotate", this, [=](){ this->toggleMouseAction(1); });
552  fMouseMoveAction = mMouseAction->addAction("Move", this, [=](){ this->toggleMouseAction(2); });
553  fMousePickAction = mMouseAction->addAction("Pick", this, [=](){ this->toggleMouseAction(3); });
554  fMouseZoomOutAction = mMouseAction->addAction("Zoom out", this, [=](){ this->toggleMouseAction(4); });
555  fMouseZoomInAction = mMouseAction->addAction("Zoom in", this, [=](){ this->toggleMouseAction(5); });
556 #endif
557  QAction *shortcutsAction = mMouseAction->addAction("Show shortcuts");
558 
559  fMouseRotateAction->setCheckable(true);
560  fMouseMoveAction->setCheckable(true);
561  fMousePickAction->setCheckable(true);
562  fMouseZoomOutAction->setCheckable(true);
563  fMouseZoomInAction->setCheckable(true);
564  shortcutsAction->setCheckable(false);
565 
566 #if QT_VERSION < 0x050600
567  connect(fSignalMapperMouse, SIGNAL(mapped(int)),this, SLOT(toggleMouseAction(int)));
568  fSignalMapperMouse->setMapping(fMouseRotateAction,1);
569  fSignalMapperMouse->setMapping(fMouseMoveAction,2);
570  fSignalMapperMouse->setMapping(fMousePickAction,3);
571  fSignalMapperMouse->setMapping(fMouseZoomOutAction,4);
572  fSignalMapperMouse->setMapping(fMouseZoomInAction,5);
573 #endif
574 
575  QObject::connect(shortcutsAction,
576  SIGNAL(triggered(bool)),
577  this,
578  SLOT(showShortcuts()));
579 
580  // === Style Menu ===
581  QMenu *mStyle = fContextMenu->addMenu("&Style");
582 
583  QMenu *mProjection = mStyle->addMenu("&Projection");
584 
585 #if QT_VERSION < 0x050600
586  fProjectionOrtho = mProjection->addAction("Orthographic", fSignalMapperSurface, SLOT(map()));
587  fProjectionPerspective = mProjection->addAction("Persepective", fSignalMapperSurface, SLOT(map()));
588 
589  // INIT mProjection
590  if (fVP.GetFieldHalfAngle() == 0) {
591  createRadioAction(fProjectionOrtho, fProjectionPerspective,SLOT(toggleProjection(bool)),1);
592  } else {
593  createRadioAction(fProjectionOrtho, fProjectionPerspective,SLOT(toggleProjection(bool)),2);
594  }
595 #else
596  // no more radioAction, not realy useful and could be confusing to use context menu and icon at the same time
597  fProjectionOrtho = mProjection->addAction("Orthographic", this, [=](){ this->toggleProjection(1); });
598  fProjectionPerspective = mProjection->addAction("Persepective", this, [=](){ this->toggleProjection(2); });
599 #endif
600  // === Drawing Menu ===
601  QMenu *mDrawing = mStyle->addMenu("&Drawing");
602 
603 #if QT_VERSION < 0x050600
604  fDrawingWireframe = mDrawing->addAction("Wireframe", fSignalMapperSurface, SLOT(map()));
605 
606  fDrawingLineRemoval = mDrawing->addAction("Hidden line removal", fSignalMapperSurface, SLOT(map()));
607 
608  fDrawingSurfaceRemoval = mDrawing->addAction("Hidden Surface removal", fSignalMapperSurface, SLOT(map()));
609 
610  fDrawingLineSurfaceRemoval = mDrawing->addAction("Hidden line and surface removal", fSignalMapperSurface, SLOT(map()));
611 #endif
612 
613 #if QT_VERSION < 0x050600
614  connect(fSignalMapperSurface, SIGNAL(mapped(int)),this, SLOT(toggleSurfaceAction(int)));
615  fSignalMapperSurface->setMapping(fDrawingWireframe,1);
616  fSignalMapperSurface->setMapping(fDrawingLineRemoval,2);
617  fSignalMapperSurface->setMapping(fDrawingSurfaceRemoval,3);
618  fSignalMapperSurface->setMapping(fDrawingLineSurfaceRemoval,4);
619 #else
620  fDrawingWireframe = mDrawing->addAction("Wireframe", this, [=](){ this->toggleSurfaceAction(1); });
621  fDrawingLineRemoval = mDrawing->addAction("Hidden line removal", this, [=](){ this->toggleSurfaceAction(2); });
622  fDrawingSurfaceRemoval = mDrawing->addAction("Hidden Surface removal", this, [=](){ this->toggleSurfaceAction(3); });
623  fDrawingLineSurfaceRemoval = mDrawing->addAction("Hidden line and surface removal", this, [=](){ this->toggleSurfaceAction(4); });
624 #endif
625 
626  fDrawingWireframe->setCheckable(true);
627  fDrawingLineRemoval->setCheckable(true);
628  fDrawingSurfaceRemoval->setCheckable(true);
629  fDrawingLineSurfaceRemoval->setCheckable(true);
630 
631  // Background Color
632 
633  QAction *backgroundColorChooser ;
634  // === Action Menu ===
635  backgroundColorChooser = mStyle->addAction("Background color");
636  QObject ::connect(backgroundColorChooser,
637  SIGNAL(triggered()),
638  this,
639  SLOT(actionChangeBackgroundColor()));
640 
641  // Text Color
642 
643  QAction *textColorChooser ;
644  // === Action Menu ===
645  textColorChooser = mStyle->addAction("Text color");
646  QObject ::connect(textColorChooser,
647  SIGNAL(triggered()),
648  this,
649  SLOT(actionChangeTextColor()));
650 
651  // Default Color
652 
653  QAction *defaultColorChooser ;
654  // === Action Menu ===
655  defaultColorChooser = mStyle->addAction("Default color");
656  QObject ::connect(defaultColorChooser,
657  SIGNAL(triggered()),
658  this,
659  SLOT(actionChangeDefaultColor()));
660 
661 
662  // === Action Menu ===
663  QMenu *mActions = fContextMenu->addMenu("&Actions");
664  QAction *createEPS = mActions->addAction("Save as ...");
665  QObject ::connect(createEPS,
666  SIGNAL(triggered()),
667  this,
668  SLOT(actionSaveImage()));
669 
670  // === Action Menu ===
671  QAction *movieParameters = mActions->addAction("Save as movie...");
672  QObject ::connect(movieParameters,
673  SIGNAL(triggered()),
674  this,
675  SLOT(actionMovieParameters()));
676 
677 
678 
679 
680  // === Special Menu ===
681  QMenu *mSpecial = fContextMenu->addMenu("S&pecial");
682  QMenu *mTransparency = mSpecial->addMenu("Transparency");
683  QAction *transparencyOn = mTransparency->addAction("On");
684  QAction *transparencyOff = mTransparency->addAction("Off");
685 
686  if (transparency_enabled == false) {
687  createRadioAction(transparencyOn,transparencyOff,SLOT(toggleTransparency(bool)),2);
688  } else if (transparency_enabled == true) {
689  createRadioAction(transparencyOn,transparencyOff,SLOT(toggleTransparency(bool)),1);
690  } else {
691  mSpecial->clear();
692  }
693 
694 
695  QMenu *mAntialiasing = mSpecial->addMenu("Antialiasing");
696  QAction *antialiasingOn = mAntialiasing->addAction("On");
697  QAction *antialiasingOff = mAntialiasing->addAction("Off");
698 
699  if (antialiasing_enabled == false) {
700  createRadioAction(antialiasingOn,antialiasingOff,SLOT(toggleAntialiasing(bool)),2);
701  } else if (antialiasing_enabled == true) {
702  createRadioAction(antialiasingOn,antialiasingOff,SLOT(toggleAntialiasing(bool)),1);
703  } else {
704  mAntialiasing->clear();
705  }
706 
707  QMenu *mHaloing = mSpecial->addMenu("Haloing");
708  QAction *haloingOn = mHaloing->addAction("On");
709  QAction *haloingOff = mHaloing->addAction("Off");
710  if (haloing_enabled == false) {
711  createRadioAction(haloingOn,haloingOff,SLOT(toggleHaloing(bool)),2);
712  } else if (haloing_enabled == true) {
713  createRadioAction(haloingOn,haloingOff,SLOT(toggleHaloing(bool)),1);
714  } else {
715  mHaloing->clear();
716  }
717 
718  QMenu *mAux = mSpecial->addMenu("Auxiliary edges");
719  QAction *auxOn = mAux->addAction("On");
720  QAction *auxOff = mAux->addAction("Off");
721  if (!fVP.IsAuxEdgeVisible()) {
722  createRadioAction(auxOn,auxOff,SLOT(toggleAux(bool)),2);
723  } else {
724  createRadioAction(auxOn,auxOff,SLOT(toggleAux(bool)),1);
725  }
726 
727 
728  QMenu *mHiddenMarkers = mSpecial->addMenu("Hidden markers");
729  QAction *hiddenMarkersOn = mHiddenMarkers->addAction("On");
730  QAction *hiddenMarkersOff = mHiddenMarkers->addAction("Off");
731  if (fVP.IsMarkerNotHidden()) {
732  createRadioAction(hiddenMarkersOn,hiddenMarkersOff,SLOT(toggleHiddenMarkers(bool)),2);
733  } else {
734  createRadioAction(hiddenMarkersOn,hiddenMarkersOff,SLOT(toggleHiddenMarkers(bool)),1);
735  }
736 
737 
738 
739  QMenu *mFullScreen = mSpecial->addMenu("&Full screen");
740  fFullScreenOn = mFullScreen->addAction("On");
741  fFullScreenOff = mFullScreen->addAction("Off");
742  createRadioAction(fFullScreenOn,fFullScreenOff,SLOT(toggleFullScreen(bool)),2);
743 
744  // INIT All
745  updateToolbarAndMouseContextMenu();
746 }
747 
748 void G4OpenGLQtViewer::G4manageContextMenuEvent(QContextMenuEvent *e)
749 {
750  if (!fGLWidget) {
751  G4cerr << "Visualization window not defined, please choose one before" << G4endl;
752  } else {
753 
754  if (!fContextMenu)
755  createPopupMenu();
756 
757  // launch menu
758  if ( fContextMenu ) {
759  fContextMenu->exec( e->globalPos() );
760  // delete fContextMenu;
761  }
762  }
763  e->accept();
764 }
765 
766 
775 void G4OpenGLQtViewer::createRadioAction(QAction *action1,QAction *action2, const std::string& method,unsigned int nCheck) {
776 
777  action1->setCheckable(true);
778  action2->setCheckable(true);
779 
780  if (nCheck ==1)
781  action1->setChecked (true);
782  else
783  action2->setChecked (true);
784 
785  QObject ::connect(action1, SIGNAL(triggered(bool)),action2, SLOT(toggle()));
786  QObject ::connect(action2, SIGNAL(triggered(bool)),action1, SLOT(toggle()));
787 
788  QObject ::connect(action1, SIGNAL(toggled(bool)),this, method.c_str());
789 
790 }
791 
792 
793 
797 void G4OpenGLQtViewer::showShortcuts() {
798  G4String text;
799 
800  text = "========= Mouse Shortcuts =========\n";
801  if (fUiQt != NULL) {
802  if (fUiQt->IsIconRotateSelected()) { // rotate
803  text += "Click and move mouse to rotate volume \n";
804  text += "ALT + Click and move mouse to rotate volume (Toggle View/Theta-Phi Direction) \n";
805  text += "CTRL + Click and move mouse to zoom in/out \n";
806  text += "SHIFT + Click and move mouse to change camera point of view \n";
807  } else if (fUiQt->IsIconMoveSelected()) { //move
808  text += "Move camera point of view with mouse \n";
809  } else if (fUiQt->IsIconPickSelected()) { //pick
810  text += "Click and pick \n";
811  }
812  } else {
813  text += "Click and move mouse to rotate volume \n";
814  text += "ALT + Click and move mouse to rotate volume (Toggle View/Theta-Phi Direction) \n";
815  text += "CTRL + Click and zoom mouse to zoom in/out \n";
816  text += "SHIFT + Click and zoommove camera point of view \n";
817  }
818  text += "========= Move Shortcuts ========= \n";
819  text += "Press left/right arrows to move volume left/right \n";
820  text += "Press up/down arrows to move volume up/down \n";
821  text += "Press '+'/'-' to move volume toward/forward \n";
822  text += "\n";
823  text += "========= Rotation (Theta/Phi) Shortcuts ========= \n";
824  text += "Press SHIFT + left/right arrows to rotate volume left/right \n";
825  text += "Press SHIFT + up/down arrows to rotate volume up/down \n";
826  text += "\n";
827  text += "========= Rotation (View Direction) Shortcuts ========= \n";
828  text += "Press ALT + left/right to rotate volume around vertical direction \n";
829  text += "Press ALT + up/down to rotate volume around horizontal direction \n";
830  text += "\n";
831  text += "========= Zoom View ========= \n";
832  text += "Press CTRL + '+'/'-' to zoom into volume \n";
833  text += "\n";
834  text += "========= Misc ========= \n";
835  text += "Press ALT +/- to slow/speed rotation/move \n";
836  text += "Press H to reset view \n";
837  text += "Press Esc to exit FullScreen \n";
838  text += "\n";
839  text += "========= Video ========= \n";
840  text += "In video mode : \n";
841  text += " Press SPACE to Start/Pause video recording \n";
842  text += " Press RETURN to Stop video recording \n";
843  text += "\n";
844 
845  G4cout << text;
846 
847  if ( fShortcutsDialog == NULL) {
848  fShortcutsDialog = new QDialog();
849  fShortcutsDialogInfos = new QTextEdit() ;
850  QVBoxLayout *mainLayout = new QVBoxLayout;
851  mainLayout->addWidget(fShortcutsDialogInfos);
852  fShortcutsDialog->setLayout(mainLayout);
853  fShortcutsDialog->setWindowTitle(tr("Shortcuts"));
854  }
855 
856  fShortcutsDialogInfos->setPlainText(text.data());
857  fShortcutsDialog->show();
858 }
859 
860 
861 
868 void G4OpenGLQtViewer::toggleMouseAction(int aAction) {
869 
870  if (aAction == 1) {
871  fUiQt->SetIconRotateSelected();
872  } else if (aAction == 2) {
873  fUiQt->SetIconMoveSelected();
874  } else if (aAction == 3) {
875  togglePicking();
876  } else if (aAction == 4) {
877  fUiQt->SetIconZoomOutSelected();
878  } else if (aAction == 5) {
879  fUiQt->SetIconZoomInSelected();
880  }
881 
882  updateQWidget();
883  updateToolbarAndMouseContextMenu();
884 }
885 
886 
897 void G4OpenGLQtViewer::toggleSurfaceAction(int aAction) {
898 
900 
901  if (aAction ==1) {
902  d_style = G4ViewParameters::wireframe;
903 
904  } else if (aAction ==2) {
905  d_style = G4ViewParameters::hlr;
906 
907  } else if (aAction ==3) {
908  d_style = G4ViewParameters::hsr;
909 
910  } else if (aAction ==4) {
911  d_style = G4ViewParameters::hlhsr;
912  }
913  fVP.SetDrawingStyle(d_style);
914 
915  updateToolbarAndMouseContextMenu();
916  updateQWidget();
917 }
918 
919 
930 void G4OpenGLQtViewer::toggleProjection(bool check) {
931 
932  if (check == 1) {
933  fVP.SetOrthogonalProjection ();
934  } else {
935  fVP.SetPerspectiveProjection();
936  }
937  updateToolbarAndMouseContextMenu();
938  updateQWidget();
939 }
940 
941 
946 void G4OpenGLQtViewer::toggleTransparency(bool check) {
947 
948  if (check) {
949  transparency_enabled = true;
950  } else {
951  transparency_enabled = false;
952  }
953  SetNeedKernelVisit (true);
954  updateToolbarAndMouseContextMenu();
955  updateQWidget();
956 }
957 
962 void G4OpenGLQtViewer::toggleAntialiasing(bool check) {
963 
964  if (!check) {
965  antialiasing_enabled = false;
966  glDisable (GL_LINE_SMOOTH);
967  glDisable (GL_POLYGON_SMOOTH);
968  } else {
969  antialiasing_enabled = true;
970  glEnable (GL_LINE_SMOOTH);
971  glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
972  glEnable (GL_POLYGON_SMOOTH);
973  glHint (GL_POLYGON_SMOOTH_HINT, GL_NICEST);
974  }
975 
976  updateToolbarAndMouseContextMenu();
977  updateQWidget();
978 }
979 
984 //FIXME : I SEE NOTHING...
985 void G4OpenGLQtViewer::toggleHaloing(bool check) {
986  if (check) {
987  haloing_enabled = false;
988  } else {
989  haloing_enabled = true;
990  }
991 
992  updateToolbarAndMouseContextMenu();
993  updateQWidget();
994 
995 }
996 
1001 void G4OpenGLQtViewer::toggleAux(bool check) {
1002  if (check) {
1003  fVP.SetAuxEdgeVisible(true);
1004  } else {
1005  fVP.SetAuxEdgeVisible(false);
1006  }
1007  SetNeedKernelVisit (true);
1008  updateToolbarAndMouseContextMenu();
1009  updateQWidget();
1010 }
1011 
1012 
1013 void G4OpenGLQtViewer::togglePicking() {
1014  // FIXME : Not the good way to do, we should handle the multiple cases of Icon/ContextMenu and CheckBox in a better way
1015  if (fUiQt) {
1016  if (!fVP.IsPicking()) {
1017  fUiQt->SetIconPickSelected();
1018  } else {
1019  fUiQt->SetIconRotateSelected();
1020  }
1021  }
1022 
1024  if(UI != NULL) {
1025  if (!fVP.IsPicking()) {
1026  UI->ApplyCommand(std::string("/vis/viewer/set/picking true"));
1027  } else {
1028  UI->ApplyCommand(std::string("/vis/viewer/set/picking false"));
1029  }
1030  }
1031 
1032 }
1033 
1034 
1039 void G4OpenGLQtViewer::toggleHiddenMarkers(bool check) {
1040  if (check) {
1041  fVP.SetMarkerHidden();
1042  } else {
1043  fVP.SetMarkerNotHidden();
1044  }
1045  // SetNeedKernelVisit (true);
1046  updateToolbarAndMouseContextMenu();
1047  updateQWidget();
1048 }
1049 
1053 void G4OpenGLQtViewer::toggleFullScreen(bool check) {
1054  if (check != fGLWidget->isFullScreen()) { //toggle
1055  fGLWidget->setWindowState(fGLWidget->windowState() ^ Qt::WindowFullScreen);
1056  }
1057 }
1058 
1059 
1060 void G4OpenGLQtViewer::savePPMToTemp() {
1061  if (fMovieTempFolderPath == "") {
1062  return;
1063  }
1064  QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
1065  if (! qGLW) {
1066  return;
1067  }
1068  QString fileName ="Test"+QString::number(fRecordFrameNumber)+".ppm";
1069  QString filePath =fMovieTempFolderPath+fileName;
1070 
1071  QImage image;
1072  image = qGLW->grabFrameBuffer();
1073  bool res = false;
1074 
1075  res = image.save(filePath,0);
1076  if (res == false) {
1077  resetRecording();
1078  setRecordingInfos("Can't save tmp file "+filePath);
1079  return;
1080  }
1081 
1082  setRecordingInfos("File "+fileName+" saved");
1083  fRecordFrameNumber++;
1084 }
1085 
1086 
1087 
1088 void G4OpenGLQtViewer::actionSaveImage() {
1089  QString filters;
1090  for (unsigned int i = 0; i < fExportImageFormatVector.size(); ++i) {
1091  filters += QString("*.") + fExportImageFormatVector.at(i).c_str() + ";;";
1092  }
1093 
1094  QString* selectedFormat = new QString(fDefaultExportImageFormat.c_str());
1095  QString qFilename;
1096  qFilename = QFileDialog::getSaveFileName ( fGLWidget,
1097  tr("Save as ..."),
1098  fFileSavePath,
1099  filters,
1100  selectedFormat );
1101 
1102 
1103  std::string name = qFilename.toStdString().c_str();
1104 
1105  // bmp jpg jpeg png ppm xbm xpm
1106  if (name.empty()) {
1107  return;
1108  }
1109 
1110  fFileSavePath = QFileInfo(qFilename).path();
1111 
1112  std::string format = selectedFormat->toLower().toStdString().c_str();
1113 
1114  // set the format to current
1115  fExportImageFormat = format.substr(format.find_last_of(".") + 1);
1116 
1117  std::string filename = name;
1118  std::string extension = "";
1119  if (name.find_last_of(".") != std::string::npos) {
1120  filename = name.substr(0,name.find_last_of(".") + 1);
1121  extension = name.substr(name.find_last_of(".") + 1);
1122  } else {
1123  extension = fExportImageFormat;
1124  }
1125 
1126  filename+= "."+ extension;
1127 
1128  if (!setExportFilename(filename.c_str(),0)) {
1129  return;
1130  }
1131 
1132  G4OpenGLQtExportDialog* exportDialog= new G4OpenGLQtExportDialog(fGLWidget,format.c_str(),fGLWidget->height(),fGLWidget->width());
1133  if( exportDialog->exec()) {
1134 
1135  if ((exportDialog->getWidth() !=fGLWidget->width()) ||
1136  (exportDialog->getHeight() !=fGLWidget->height())) {
1137  setExportSize(exportDialog->getWidth(),exportDialog->getHeight());
1138 
1139  }
1140  if (fExportImageFormat == "eps") {
1141  fVectoredPs = exportDialog->getVectorEPS();
1142  } else if (fExportImageFormat == "ps") {
1143  fVectoredPs = true;
1144  }
1145  fLastExportSliderValue = exportDialog->getSliderValue();
1146 
1147  if (exportImage(filename)) {
1148  // set the default format to current
1149  fDefaultExportImageFormat = format;
1150  }
1151  } else { // cancel selected
1152  return;
1153  }
1154 
1155 }
1156 
1157 
1158 void G4OpenGLQtViewer::actionChangeBackgroundColor() {
1159 
1160  // //I need to revisit the kernel if the background colour changes and
1161  // //hidden line removal is enabled, because hlr drawing utilises the
1162  // //background colour in its drawing...
1163  // // (Note added by JA 13/9/2005) Background now handled in view
1164  // // parameters. A kernel visit is triggered on change of background.
1165 
1166 #if QT_VERSION < 0x040500
1167  bool a;
1168  const QColor color = QColor(QColorDialog::getRgba (QColor(Qt::black).rgba(),&a,fGLWidget));
1169 #else
1170  const QColor color =
1171  QColorDialog::getColor(Qt::black,
1172  fGLWidget,
1173  " Get background color and transparency",
1174  QColorDialog::ShowAlphaChannel);
1175 #endif
1176  if (color.isValid()) {
1177  G4Colour colour(((G4double)color.red())/255,
1178  ((G4double)color.green())/255,
1179  ((G4double)color.blue())/255,
1180  ((G4double)color.alpha())/255);
1181  fVP.SetBackgroundColour(colour);
1182 
1183  updateToolbarAndMouseContextMenu();
1184  updateQWidget();
1185  }
1186 }
1187 
1188 void G4OpenGLQtViewer::actionChangeTextColor() {
1189 
1190 #if QT_VERSION < 0x040500
1191  bool a;
1192  const QColor color = QColor(QColorDialog::getRgba (QColor(Qt::yellow).rgba(),&a,fGLWidget));
1193 #else
1194  const QColor& color =
1195  QColorDialog::getColor(Qt::yellow,
1196  fGLWidget,
1197  " Get text color and transparency",
1198  QColorDialog::ShowAlphaChannel);
1199 #endif
1200  if (color.isValid()) {
1201  G4Colour colour(((G4double)color.red())/255,
1202  ((G4double)color.green())/255,
1203  ((G4double)color.blue())/255,
1204  ((G4double)color.alpha())/255);
1205 
1206  fVP.SetDefaultTextColour(colour);
1207 
1208  updateToolbarAndMouseContextMenu();
1209  updateQWidget();
1210  }
1211 }
1212 
1213 void G4OpenGLQtViewer::actionChangeDefaultColor() {
1214 
1215 #if QT_VERSION < 0x040500
1216  bool a;
1217  const QColor color = QColor(QColorDialog::getRgba (QColor(Qt::white).rgba(),&a,fGLWidget));
1218 #else
1219  const QColor& color =
1220  QColorDialog::getColor(Qt::white,
1221  fGLWidget,
1222  " Get default color and transparency",
1223  QColorDialog::ShowAlphaChannel);
1224 #endif
1225  if (color.isValid()) {
1226  G4Colour colour(((G4double)color.red())/255,
1227  ((G4double)color.green())/255,
1228  ((G4double)color.blue())/255,
1229  ((G4double)color.alpha())/255);
1230 
1231  fVP.SetDefaultColour(colour);
1232 
1233  updateToolbarAndMouseContextMenu();
1234  updateQWidget();
1235  }
1236 }
1237 
1238 
1239 void G4OpenGLQtViewer::actionMovieParameters() {
1240  showMovieParametersDialog();
1241 }
1242 
1243 
1244 void G4OpenGLQtViewer::showMovieParametersDialog() {
1245  if (!fMovieParametersDialog) {
1246  fMovieParametersDialog= new G4OpenGLQtMovieDialog(this,fGLWidget);
1247  displayRecordingStatus();
1248  fMovieParametersDialog->checkEncoderSwParameters();
1249  fMovieParametersDialog->checkSaveFileNameParameters();
1250  fMovieParametersDialog->checkTempFolderParameters();
1251  if (getEncoderPath() == "") {
1252  setRecordingInfos("ppmtompeg is needed to encode in video format. It is available here: http://netpbm.sourceforge.net ");
1253  }
1254  }
1255  fMovieParametersDialog->show();
1256 }
1257 
1258 
1259 
1260 void G4OpenGLQtViewer::FinishView()
1261 {
1262  /* From Apple doc:
1263  CGLFlushDrawable : Copies the back buffer of a double-buffered context to the front buffer.
1264  If the backing store attribute is set to false, the buffers can be exchanged rather than copied
1265  */
1266  glFlush ();
1267 
1268  // L. Garnier 10/2009 : Not necessary and cause problems on mac OS X 10.6
1269  // fGLWidget->swapBuffers ();
1270 }
1271 
1276 void G4OpenGLQtViewer::G4MousePressEvent(QMouseEvent *evnt)
1277 {
1278  if (evnt->button() == Qt::RightButton) {
1279  return;
1280  }
1281  if ((evnt->button() & Qt::LeftButton) && (! (evnt->modifiers() & Qt::ControlModifier ))){
1282  fGLWidget->setMouseTracking(true);
1283  fAutoMove = false; // stop automove
1284  fLastPos1 = evnt->pos();
1285  fLastPos2 = fLastPos1;
1286  fLastPos3 = fLastPos2;
1287  fLastEventTime->start();
1288  if (fUiQt != NULL) {
1289 
1290  if (fUiQt->IsIconZoomInSelected()) { // zoomIn
1291  // Move click point to center of OGL
1292 
1293  float deltaX = ((float)getWinWidth()/2-evnt->pos().x());
1294  float deltaY = ((float)getWinHeight()/2-evnt->pos().y());
1295 
1296  G4double coefTrans = 0;
1297  coefTrans = ((G4double)getSceneNearWidth())/((G4double)getWinWidth());
1298  if (getWinHeight() <getWinWidth()) {
1299  coefTrans = ((G4double)getSceneNearWidth())/((G4double)getWinHeight());
1300  }
1301  fVP.IncrementPan(-deltaX*coefTrans,deltaY*coefTrans,0);
1302  fVP.SetZoomFactor(1.5 * fVP.GetZoomFactor());
1303 
1304  updateQWidget();
1305 
1306  } else if (fUiQt->IsIconZoomOutSelected()) { // zoomOut
1307  // Move click point to center of OGL
1308  moveScene(((float)getWinWidth()/2-evnt->pos().x()),((float)getWinHeight()/2-evnt->pos().y()),0,true);
1309 
1310  fVP.SetZoomFactor(0.75 * fVP.GetZoomFactor());
1311  updateQWidget();
1312 
1313  } else if (fUiQt->IsIconRotateSelected() ) {
1314 
1315  if (fShiftKeyPress) { // move
1316  fGLWidget->setCursor(QCursor(Qt::SizeAllCursor));
1317 
1318  } else { // rotate
1319  fGLWidget->setCursor(QCursor(Qt::ClosedHandCursor));
1320  }
1321  } else if (fUiQt->IsIconMoveSelected()) {
1322  fGLWidget->setCursor(QCursor(Qt::SizeAllCursor));
1323  } else if (fUiQt->IsIconPickSelected()) {
1324  fGLWidget->setCursor(QCursor(Qt::PointingHandCursor));
1325  }
1326  }
1327  }
1328 }
1329 
1332 void G4OpenGLQtViewer::G4MouseReleaseEvent(QMouseEvent *evnt)
1333 {
1334  GLint viewport[4];
1335  glGetIntegerv(GL_VIEWPORT, viewport);
1336 
1337  // factorX == factorY
1338  double factorX = ((double)viewport[2]/fGLWidget->width());
1339  double factorY = ((double)viewport[3]/fGLWidget->height());
1340  fSpinningDelay = fLastEventTime->elapsed();
1341  QPoint delta = (fLastPos3-fLastPos1)*factorX;
1342 
1343  // reset cursor state
1344  fGLWidget->setCursor(QCursor(Qt::ArrowCursor));
1345 
1346  if (fVP.IsPicking()){ // pick
1347  if ((delta.x() != 0) || (delta.y() != 0)) {
1348  return;
1349  }
1350  updatePickInfosWidget(evnt->pos().x()*factorX,evnt->pos().y()*factorY);
1351 
1352  } else if (fSpinningDelay < fLaunchSpinDelay ) {
1353  if ((delta.x() == 0) && (delta.y() == 0)) {
1354  return;
1355  }
1356 
1357  fAutoMove = true;
1358  QTime lastMoveTime;
1359  lastMoveTime.start();
1360  // try to addapt speed move/rotate looking to drawing speed
1361  float correctionFactor = 5;
1362  while (fAutoMove) {
1363  if ( lastMoveTime.elapsed() >= (int)(1000/fNbMaxFramesPerSec)) {
1364  float lTime = 1000/lastMoveTime.elapsed();
1365  if (((((float)delta.x())/correctionFactor)*lTime > fNbMaxAnglePerSec) ||
1366  ((((float)delta.x())/correctionFactor)*lTime < -fNbMaxAnglePerSec) ) {
1367  correctionFactor = (float)delta.x()*(lTime/fNbMaxAnglePerSec);
1368  if (delta.x() <0 ) {
1369  correctionFactor = -correctionFactor;
1370  }
1371  }
1372  if (((((float)delta.y())/correctionFactor)*lTime > fNbMaxAnglePerSec) ||
1373  ((((float)delta.y())/correctionFactor)*lTime < -fNbMaxAnglePerSec) ) {
1374  correctionFactor = (float)delta.y()*(lTime/fNbMaxAnglePerSec);
1375  if (delta.y() <0 ) {
1376  correctionFactor = -correctionFactor;
1377  }
1378  }
1379 
1380  // Check Qt Versions for META Keys
1381 
1382  // Click and move mouse to rotate volume
1383  // ALT + Click and move mouse to rotate volume (View Direction)
1384  // SHIFT + Click and move camera point of view
1385  // CTRL + Click and zoom mouse to zoom in/out
1386 
1387  lastMoveTime.start();
1388 
1389  bool rotate = false;
1390  bool move = false;
1391 
1392  if (fUiQt != NULL) {
1393  if (fUiQt->IsIconRotateSelected()) { // rotate
1394  rotate = true;
1395  } else if (fUiQt->IsIconMoveSelected()) { // move
1396  move = true;
1397  }
1398  } else {
1399  rotate = true;
1400  }
1401  // prevent from closing widget when rotating (cause a crash)
1402  if (fIsDeleting) {
1403  return;
1404  }
1405 
1406  if (rotate) { // rotate
1407  if (fNoKeyPress) {
1408  rotateQtScene(((float)delta.x())/correctionFactor,((float)delta.y())/correctionFactor);
1409  } else if (fAltKeyPress) {
1410  rotateQtSceneToggle(((float)delta.x())/correctionFactor,((float)delta.y())/correctionFactor);
1411  }
1412 
1413  } else if (move) { // move
1414  moveScene(-((float)delta.x())/correctionFactor,-((float)delta.y())/correctionFactor,0,true);
1415  }
1416  }
1417  ((QApplication*)G4Qt::getInstance ())->processEvents();
1418  }
1419  }
1420  fGLWidget->setMouseTracking(false);
1421 
1422 }
1423 
1424 
1425 void G4OpenGLQtViewer::G4MouseDoubleClickEvent()
1426 {
1427  fGLWidget->setMouseTracking(true);
1428 }
1429 
1430 
1438 void G4OpenGLQtViewer::G4MouseMoveEvent(QMouseEvent *evnt)
1439 {
1440 
1441  Qt::MouseButtons mButtons = evnt->buttons();
1442 
1443  updateKeyModifierState(evnt->modifiers());
1444 
1445  if (fAutoMove) {
1446  return;
1447  }
1448 
1449  fLastPos3 = fLastPos2;
1450  fLastPos2 = fLastPos1;
1451  fLastPos1 = QPoint(evnt->x(), evnt->y());
1452 
1453  int deltaX = fLastPos2.x()-fLastPos1.x();
1454  int deltaY = fLastPos2.y()-fLastPos1.y();
1455 
1456  bool move = false;
1457  if (fUiQt != NULL) {
1458  if (fUiQt->IsIconMoveSelected()) { // move
1459  move = true;
1460  }
1461  }
1462  if (!move) { // rotate, pick, zoom...
1463  if (mButtons & Qt::LeftButton) {
1464  if (fNoKeyPress) {
1465  rotateQtScene(((float)deltaX),((float)deltaY));
1466  } else if (fAltKeyPress) {
1467  rotateQtSceneToggle(((float)deltaX),((float)deltaY));
1468  } else if (fShiftKeyPress) {
1469  unsigned int sizeWin;
1470  sizeWin = getWinWidth();
1471  if (getWinHeight() < getWinWidth()) {
1472  sizeWin = getWinHeight();
1473  }
1474 
1475  // L.Garnier : 08/2010 100 is the good value, but don't ask me why !
1476  float factor = ((float)100/(float)sizeWin) ;
1477  moveScene(-(float)deltaX*factor,-(float)deltaY*factor,0,false);
1478  } else if (fControlKeyPress) {
1479  fVP.SetZoomFactor(fVP.GetZoomFactor()*(1+((float)deltaY)));
1480  }
1481  }
1482  } else if (move) { // move
1483  if (mButtons & Qt::LeftButton) {
1484  moveScene(-(float)deltaX,-(float)deltaY,0,true);
1485  }
1486  }
1487 
1488  fLastEventTime->start();
1489 }
1490 
1491 
1499 void G4OpenGLQtViewer::moveScene(float dx,float dy, float dz,bool mouseMove)
1500 {
1501  if (fHoldMoveEvent)
1502  return;
1503  fHoldMoveEvent = true;
1504 
1505  G4double coefTrans = 0;
1506  GLdouble coefDepth = 0;
1507  if(mouseMove) {
1508  coefTrans = ((G4double)getSceneNearWidth())/((G4double)getWinWidth());
1509  if (getWinHeight() <getWinWidth()) {
1510  coefTrans = ((G4double)getSceneNearWidth())/((G4double)getWinHeight());
1511  }
1512  } else {
1513  coefTrans = getSceneNearWidth()*fPan_sens;
1514  coefDepth = getSceneDepth()*fDeltaDepth;
1515  }
1516  fVP.IncrementPan(-dx*coefTrans,dy*coefTrans,dz*coefDepth);
1517 
1518  updateQWidget();
1519  if (fAutoMove)
1520  ((QApplication*)G4Qt::getInstance ())->processEvents();
1521 
1522  fHoldMoveEvent = false;
1523 }
1524 
1525 
1531 void G4OpenGLQtViewer::rotateQtScene(float dx, float dy)
1532 {
1533  if (fHoldRotateEvent)
1534  return;
1535  fHoldRotateEvent = true;
1536 
1537  rotateScene(dx,dy);
1538 
1539  updateQWidget();
1540 
1541  fHoldRotateEvent = false;
1542 }
1543 
1549 void G4OpenGLQtViewer::rotateQtSceneToggle(float dx, float dy)
1550 {
1551  if (fHoldRotateEvent)
1552  return;
1553  fHoldRotateEvent = true;
1554 
1555  rotateSceneToggle(dx,dy);
1556 
1557  updateQWidget();
1558 
1559  fHoldRotateEvent = false;
1560 }
1561 
1562 
1563 
1564 
1565 
1570 void G4OpenGLQtViewer::rescaleImage(
1571  int /* aWidth */
1572 ,int /* aHeight */
1573 ){
1574  // GLfloat* feedback_buffer;
1575  // GLint returned;
1576  // FILE* file;
1577 
1578  // feedback_buffer = new GLfloat[size];
1579  // glFeedbackBuffer (size, GL_3D_COLOR, feedback_buffer);
1580  // glRenderMode (GL_FEEDBACK);
1581 
1582  // DrawView();
1583  // returned = glRenderMode (GL_RENDER);
1584 
1585 }
1586 
1587 
1588 
1589 
1590 void G4OpenGLQtViewer::G4wheelEvent (QWheelEvent * evnt)
1591 {
1592  fVP.SetZoomFactor(fVP.GetZoomFactor()+(fVP.GetZoomFactor()*(evnt->delta())/1200));
1593  updateQWidget();
1594 }
1595 
1596 
1597 void G4OpenGLQtViewer::G4keyPressEvent (QKeyEvent * evnt)
1598 {
1599  if (fHoldKeyEvent)
1600  return;
1601 
1602  fHoldKeyEvent = true;
1603 
1604 
1605  // with no modifiers
1606  updateKeyModifierState(evnt->modifiers());
1607  if ((fNoKeyPress) || (evnt->modifiers() == Qt::KeypadModifier )) {
1608  if (evnt->key() == Qt::Key_Down) { // go down
1609  moveScene(0,1,0,false);
1610  }
1611  else if (evnt->key() == Qt::Key_Up) { // go up
1612  moveScene(0,-1,0,false);
1613  }
1614  if (evnt->key() == Qt::Key_Left) { // go left
1615  moveScene(-1,0,0,false);
1616  }
1617  else if (evnt->key() == Qt::Key_Right) { // go right
1618  moveScene(1,0,0,false);
1619  }
1620  if (evnt->key() == Qt::Key_Minus) { // go backward
1621  moveScene(0,0,1,false);
1622  }
1623  else if (evnt->key() == Qt::Key_Plus) { // go forward
1624  moveScene(0,0,-1,false);
1625  }
1626  // escaped from full screen
1627  if (evnt->key() == Qt::Key_Escape) {
1628  toggleFullScreen(false);
1629  }
1630  }
1631  // several case here : If return is pressed, in every case -> display the movie parameters dialog
1632  // If one parameter is wrong -> put it in red (only save filenam could be wrong..)
1633  // If encoder not found-> does nothing.Only display a message in status box
1634  // If all ok-> generate parameter file
1635  // If ok -> put encoder button enabled
1636 
1637  if ((evnt->key() == Qt::Key_Return) || (evnt->key() == Qt::Key_Enter)){ // end of video
1638  stopVideo();
1639  }
1640  if (evnt->key() == Qt::Key_Space){ // start/pause of video
1641  startPauseVideo();
1642  }
1643 
1644  // H : Return Home view
1645  if (evnt->key() == Qt::Key_H){ // go Home
1646  ResetView();
1647 
1648  updateQWidget();
1649  }
1650 
1651  // Shift Modifier
1652  if (fShiftKeyPress) {
1653  fGLWidget->setCursor(QCursor(Qt::SizeAllCursor));
1654 
1655  if (evnt->key() == Qt::Key_Down) { // rotate phi
1656  rotateQtScene(0,-fRot_sens);
1657  }
1658  else if (evnt->key() == Qt::Key_Up) { // rotate phi
1659  rotateQtScene(0,fRot_sens);
1660  }
1661  if (evnt->key() == Qt::Key_Left) { // rotate theta
1662  rotateQtScene(fRot_sens,0);
1663  }
1664  else if (evnt->key() == Qt::Key_Right) { // rotate theta
1665  rotateQtScene(-fRot_sens,0);
1666  }
1667  if (evnt->key() == Qt::Key_Plus) { // go forward ("Plus" imply
1668  // "Shift" on Mac French keyboard
1669  moveScene(0,0,-1,false);
1670  }
1671 
1672  // Alt Modifier
1673  }
1674  if ((fAltKeyPress)) {
1675  fGLWidget->setCursor(QCursor(Qt::ClosedHandCursor));
1676 
1677  if (evnt->key() == Qt::Key_Down) { // rotate phi
1678  rotateQtSceneToggle(0,-fRot_sens);
1679  }
1680  else if (evnt->key() == Qt::Key_Up) { // rotate phi
1681  rotateQtSceneToggle(0,fRot_sens);
1682  }
1683  if (evnt->key() == Qt::Key_Left) { // rotate theta
1684  rotateQtSceneToggle(fRot_sens,0);
1685  }
1686  else if (evnt->key() == Qt::Key_Right) { // rotate theta
1687  rotateQtSceneToggle(-fRot_sens,0);
1688  }
1689 
1690  // Rotatio +/-
1691  if (evnt->key() == Qt::Key_Plus) {
1692  fRot_sens = fRot_sens/0.7;
1693  G4cout << "Auto-rotation set to : " << fRot_sens << G4endl;
1694  }
1695  else if (evnt->key() == Qt::Key_Minus) {
1696  fRot_sens = fRot_sens*0.7;
1697  G4cout << "Auto-rotation set to : " << fRot_sens << G4endl;
1698  }
1699 
1700  // Control Modifier OR Command on MAC
1701  }
1702  if ((fControlKeyPress)) {
1703  if (evnt->key() == Qt::Key_Plus) {
1704  fVP.SetZoomFactor(fVP.GetZoomFactor()*(1+fDeltaZoom));
1705  updateQWidget();
1706  }
1707  else if (evnt->key() == Qt::Key_Minus) {
1708  fVP.SetZoomFactor(fVP.GetZoomFactor()*(1-fDeltaZoom));
1709  updateQWidget();
1710  }
1711  }
1712 
1713  fHoldKeyEvent = false;
1714 }
1715 
1716 
1717 void G4OpenGLQtViewer::G4keyReleaseEvent (QKeyEvent *)
1718 {
1719  fGLWidget->setCursor(QCursor(Qt::ArrowCursor));
1720 }
1721 
1722 
1723 void G4OpenGLQtViewer::updateKeyModifierState(const Qt::KeyboardModifiers& modifier) {
1724  // Check Qt Versions for META Keys
1725 
1726  fNoKeyPress = true;
1727  fAltKeyPress = false;
1728  fShiftKeyPress = false;
1729  fControlKeyPress = false;
1730 
1731  if (modifier & Qt::AltModifier ) {
1732  fAltKeyPress = true;
1733  fNoKeyPress = false;
1734  }
1735  if (modifier & Qt::ShiftModifier ) {
1736  fShiftKeyPress = true;
1737  fNoKeyPress = false;
1738  }
1739  if (modifier & Qt::ControlModifier ) {
1740  fControlKeyPress = true;
1741  fNoKeyPress = false;
1742  }
1743 }
1744 
1745 
1748 void G4OpenGLQtViewer::stopVideo() {
1749 
1750  // if encoder parameter is wrong, display parameters dialog and return
1751  if (!fMovieParametersDialog) {
1752  showMovieParametersDialog();
1753  }
1754  setRecordingStatus(STOP);
1755 
1756  if (fRecordFrameNumber >0) {
1757  // check parameters if they were modified (Re APPLY them...)
1758  if (!(fMovieParametersDialog->checkEncoderSwParameters())) {
1759  setRecordingStatus(BAD_ENCODER);
1760  } else if (!(fMovieParametersDialog->checkSaveFileNameParameters())) {
1761  setRecordingStatus(BAD_OUTPUT);
1762  }
1763  } else {
1764  resetRecording();
1765  setRecordingInfos("No frame to encode.");
1766  }
1767 }
1768 
1771 void G4OpenGLQtViewer::saveVideo() {
1772 
1773  // if encoder parameter is wrong, display parameters dialog and return
1774  if (!fMovieParametersDialog) {
1775  showMovieParametersDialog();
1776  }
1777 
1778  fMovieParametersDialog->checkEncoderSwParameters();
1779  fMovieParametersDialog->checkSaveFileNameParameters();
1780 
1781  if (fRecordingStep == STOP) {
1782  setRecordingStatus(SAVE);
1783  generateMpegEncoderParameters();
1784  encodeVideo();
1785  }
1786 }
1787 
1788 
1791 void G4OpenGLQtViewer::startPauseVideo() {
1792 
1793  // first time, if temp parameter is wrong, display parameters dialog and return
1794 
1795  if ( fRecordingStep == WAIT) {
1796  if ( fRecordFrameNumber == 0) {
1797  if (getTempFolderPath() == "") { // BAD_OUTPUT
1798  showMovieParametersDialog();
1799  setRecordingInfos("You should specified the temp folder in order to make movie");
1800  return;
1801  } else {
1802  // remove temp folder if it was create
1803  QString tmp = removeTempFolder();
1804  if (tmp !="") {
1805  setRecordingInfos(tmp);
1806  return;
1807  }
1808  tmp = createTempFolder();
1809  if (tmp != "") {
1810  setRecordingInfos("Can't create temp folder."+tmp);
1811  return;
1812  }
1813  }
1814  }
1815  }
1816  if (fRecordingStep == WAIT) {
1817  setRecordingStatus(START);
1818  } else if (fRecordingStep == START) {
1819  setRecordingStatus(PAUSE);
1820  } else if (fRecordingStep == PAUSE) {
1821  setRecordingStatus(CONTINUE);
1822  } else if (fRecordingStep == CONTINUE) {
1823  setRecordingStatus(PAUSE);
1824  }
1825 }
1826 
1827 void G4OpenGLQtViewer::setRecordingStatus(RECORDING_STEP step) {
1828 
1829  fRecordingStep = step;
1830  displayRecordingStatus();
1831 }
1832 
1833 
1834 void G4OpenGLQtViewer::displayRecordingStatus() {
1835 
1836  QString txtStatus = "";
1837  if (fRecordingStep == WAIT) {
1838  txtStatus = "Waiting to start...";
1839  fRecordFrameNumber = 0; // reset the frame number
1840  } else if (fRecordingStep == START) {
1841  txtStatus = "Start Recording...";
1842  } else if (fRecordingStep == PAUSE) {
1843  txtStatus = "Pause Recording...";
1844  } else if (fRecordingStep == CONTINUE) {
1845  txtStatus = "Continue Recording...";
1846  } else if (fRecordingStep == STOP) {
1847  txtStatus = "Stop Recording...";
1848  } else if (fRecordingStep == READY_TO_ENCODE) {
1849  txtStatus = "Ready to Encode...";
1850  } else if (fRecordingStep == ENCODING) {
1851  txtStatus = "Encoding...";
1852  } else if (fRecordingStep == FAILED) {
1853  txtStatus = "Failed to encode...";
1854  } else if ((fRecordingStep == BAD_ENCODER)
1855  || (fRecordingStep == BAD_OUTPUT)
1856  || (fRecordingStep == BAD_TMP)) {
1857  txtStatus = "Correct above errors first";
1858  } else if (fRecordingStep == SUCCESS) {
1859  txtStatus = "File encoded successfully";
1860  } else {
1861  }
1862 
1863  if (fMovieParametersDialog) {
1864  fMovieParametersDialog->setRecordingStatus(txtStatus);
1865  } else {
1866  G4cout << txtStatus.toStdString().c_str() << G4endl;
1867  }
1868  setRecordingInfos("");
1869 }
1870 
1871 
1872 void G4OpenGLQtViewer::setRecordingInfos(const QString& txt) {
1873  if (fMovieParametersDialog) {
1874  fMovieParametersDialog->setRecordingInfos(txt);
1875  } else {
1876  G4cout << txt.toStdString().c_str() << G4endl;
1877  }
1878 }
1879 
1882 void G4OpenGLQtViewer::initMovieParameters() {
1883  //init encoder
1884 
1885  //look for encoderPath
1886  fProcess = new QProcess();
1887 
1888  QObject ::connect(fProcess,SIGNAL(finished ( int)),
1889  this,SLOT(processLookForFinished()));
1890  fProcess->setProcessChannelMode(QProcess::MergedChannels);
1891  fProcess->start ("which ppmtompeg");
1892 
1893 }
1894 
1897 QString G4OpenGLQtViewer::getEncoderPath() {
1898  return fEncoderPath;
1899 }
1900 
1901 
1906 QString G4OpenGLQtViewer::setEncoderPath(QString path) {
1907  if (path == "") {
1908  return "ppmtompeg is needed to encode in video format. It is available here: http://netpbm.sourceforge.net ";
1909  }
1910 
1911  path = QDir::cleanPath(path);
1912  QFileInfo *f = new QFileInfo(path);
1913  if (!f->exists()) {
1914  return "File does not exist";
1915  } else if (f->isDir()) {
1916  return "This is a directory";
1917  } else if (!f->isExecutable()) {
1918  return "File exist but is not executable";
1919  } else if (!f->isFile()) {
1920  return "This is not a file";
1921  }
1922  fEncoderPath = path;
1923 
1924  if (fRecordingStep == BAD_ENCODER) {
1925  setRecordingStatus(STOP);
1926  }
1927  return "";
1928 }
1929 
1930 
1931 bool G4OpenGLQtViewer::isRecording(){
1932  if ((fRecordingStep == START) || (fRecordingStep == CONTINUE)) {
1933  return true;
1934  }
1935  return false;
1936 }
1937 
1938 bool G4OpenGLQtViewer::isPaused(){
1939  if (fRecordingStep == PAUSE) {
1940  return true;
1941  }
1942  return false;
1943 }
1944 
1945 bool G4OpenGLQtViewer::isEncoding(){
1946  if (fRecordingStep == ENCODING) {
1947  return true;
1948  }
1949  return false;
1950 }
1951 
1952 bool G4OpenGLQtViewer::isWaiting(){
1953  if (fRecordingStep == WAIT) {
1954  return true;
1955  }
1956  return false;
1957 }
1958 
1959 bool G4OpenGLQtViewer::isStopped(){
1960  if (fRecordingStep == STOP) {
1961  return true;
1962  }
1963  return false;
1964 }
1965 
1966 bool G4OpenGLQtViewer::isFailed(){
1967  if (fRecordingStep == FAILED) {
1968  return true;
1969  }
1970  return false;
1971 }
1972 
1973 bool G4OpenGLQtViewer::isSuccess(){
1974  if (fRecordingStep == SUCCESS) {
1975  return true;
1976  }
1977  return false;
1978 }
1979 
1980 bool G4OpenGLQtViewer::isBadEncoder(){
1981  if (fRecordingStep == BAD_ENCODER) {
1982  return true;
1983  }
1984  return false;
1985 }
1986 bool G4OpenGLQtViewer::isBadTmp(){
1987  if (fRecordingStep == BAD_TMP) {
1988  return true;
1989  }
1990  return false;
1991 }
1992 bool G4OpenGLQtViewer::isBadOutput(){
1993  if (fRecordingStep == BAD_OUTPUT) {
1994  return true;
1995  }
1996  return false;
1997 }
1998 
1999 void G4OpenGLQtViewer::setBadEncoder(){
2000  fRecordingStep = BAD_ENCODER;
2001  displayRecordingStatus();
2002 }
2003 void G4OpenGLQtViewer::setBadTmp(){
2004  fRecordingStep = BAD_TMP;
2005  displayRecordingStatus();
2006 }
2007 void G4OpenGLQtViewer::setBadOutput(){
2008  fRecordingStep = BAD_OUTPUT;
2009  displayRecordingStatus();
2010 }
2011 
2012 void G4OpenGLQtViewer::setWaiting(){
2013  fRecordingStep = WAIT;
2014  displayRecordingStatus();
2015 }
2016 
2017 
2018 bool G4OpenGLQtViewer::isReadyToEncode(){
2019  if (fRecordingStep == READY_TO_ENCODE) {
2020  return true;
2021  }
2022  return false;
2023 }
2024 
2025 void G4OpenGLQtViewer::resetRecording() {
2026  setRecordingStatus(WAIT);
2027 }
2028 
2033 QString G4OpenGLQtViewer::setTempFolderPath(QString path) {
2034 
2035  if (path == "") {
2036  return "Path does not exist";
2037  }
2038  path = QDir::cleanPath(path);
2039  QFileInfo *d = new QFileInfo(path);
2040  if (!d->exists()) {
2041  return "Path does not exist";
2042  } else if (!d->isDir()) {
2043  return "This is not a directory";
2044  } else if (!d->isReadable()) {
2045  return path +" is read protected";
2046  } else if (!d->isWritable()) {
2047  return path +" is write protected";
2048  }
2049 
2050  if (fRecordingStep == BAD_TMP) {
2051  setRecordingStatus(WAIT);
2052  }
2053  fTempFolderPath = path;
2054  return "";
2055 }
2056 
2059 QString G4OpenGLQtViewer::getTempFolderPath() {
2060  return fTempFolderPath;
2061 }
2062 
2067 QString G4OpenGLQtViewer::setSaveFileName(QString path) {
2068 
2069  if (path == "") {
2070  return "Path does not exist";
2071  }
2072 
2073  QFileInfo *file = new QFileInfo(path);
2074  QDir dir = file->dir();
2075  path = QDir::cleanPath(path);
2076  if (file->exists()) {
2077  return "File already exist, please choose a new one";
2078  } else if (!dir.exists()) {
2079  return "Dir does not exist";
2080  } else if (!dir.isReadable()) {
2081  return path +" is read protected";
2082  }
2083 
2084  if (fRecordingStep == BAD_OUTPUT) {
2085  setRecordingStatus(STOP);
2086  }
2087  fSaveFileName = path;
2088  return "";
2089 }
2090 
2093 QString G4OpenGLQtViewer::getSaveFileName() {
2094  return fSaveFileName ;
2095 }
2096 
2101 QString G4OpenGLQtViewer::createTempFolder() {
2102  fMovieTempFolderPath = "";
2103  //check
2104  QString tmp = setTempFolderPath(fTempFolderPath);
2105  if (tmp != "") {
2106  return tmp;
2107  }
2108  QString sep = QString(QDir::separator());
2109  QString path = sep+"QtMovie_"+QDateTime::currentDateTime ().toString("dd-MM-yyyy_hh-mm-ss")+sep;
2110  QDir *d = new QDir(QDir::cleanPath(fTempFolderPath));
2111  // check if it is already present
2112  if (d->exists(path)) {
2113  return "Folder "+path+" already exists.Please remove it first";
2114  }
2115  if (d->mkdir(fTempFolderPath+path)) {
2116  fMovieTempFolderPath = fTempFolderPath+path;
2117  return "";
2118  }
2119  return "Can't create "+fTempFolderPath+path;
2120 }
2121 
2124 QString G4OpenGLQtViewer::removeTempFolder() {
2125  // remove files in Qt_temp folder
2126  if (fMovieTempFolderPath == "") {
2127  return "";
2128  }
2129  QDir *d = new QDir(QDir::cleanPath(fMovieTempFolderPath));
2130  if (!d->exists()) {
2131  return ""; // already remove
2132  }
2133 
2134  d->setFilter( QDir::Files );
2135  QStringList subDirList = d->entryList();
2136  int res = true;
2137  QString error = "";
2138  for (QStringList::ConstIterator it = subDirList.begin() ;(it != subDirList.end()) ; it++) {
2139  const QString currentFile = *it;
2140  if (!d->remove(currentFile)) {
2141  res = false;
2142  QString file = fMovieTempFolderPath+currentFile;
2143  error +="Removing file failed : "+file;
2144  } else {
2145  }
2146  }
2147  if (res) {
2148  if (d->rmdir(fMovieTempFolderPath)) {
2149  fMovieTempFolderPath = "";
2150  return "";
2151  } else {
2152  return "Dir "+fMovieTempFolderPath+" should be empty, but could not remove it";
2153  }
2154 
2155  }
2156  return "Could not remove "+fMovieTempFolderPath+" because of the following errors :"+error;
2157 }
2158 
2166 bool G4OpenGLQtViewer::exportImage(std::string name, int width, int height) {
2167 
2168  QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
2169  if (! qGLW) {
2170  return false;
2171  }
2172  // If there is already an extention
2173  bool increaseFileNumber = true;
2174  // if
2175  if (name.size() != name.substr(name.find_last_of(".") + 1).size()) {
2176  increaseFileNumber = false;
2177  }
2178  if (! setExportFilename(name,increaseFileNumber)) {
2179  return false;
2180  }
2181  if ((width !=-1) && (height != -1)) {
2182  setExportSize(width, height);
2183  }
2184  // first, try to do it with generic function
2185  if (G4OpenGLViewer::exportImage(name, width, height)) {
2186  return true;
2187 
2188  // Then try Qt saving functions
2189  } else {
2190  QImage image;
2191  image = qGLW->grabFrameBuffer();
2192 
2193  bool res = image.save(QString(getRealPrintFilename().c_str()),0,fLastExportSliderValue);
2194 
2195  if (!res) {
2196  G4cerr << "Error saving file... " << getRealPrintFilename().c_str() << G4endl;
2197  return false;
2198  } else {
2199  G4cout << "File " << getRealPrintFilename().c_str() << " size: " << fGLWidget->width() << "x" << fGLWidget->height() << " has been saved " << G4endl;
2200  fExportFilenameIndex++;
2201  }
2202  }
2203  return true;
2204 }
2205 
2206 bool G4OpenGLQtViewer::generateMpegEncoderParameters () {
2207 
2208  // save the parameter file
2209  FILE* fp;
2210  fp = fopen (QString(fMovieTempFolderPath+fParameterFileName).toStdString().c_str(), "w");
2211 
2212  if (fp == NULL) {
2213  setRecordingInfos("Generation of parameter file failed");
2214  return false;
2215  }
2216 
2217  fprintf (fp,"# Pattern affects speed, quality and compression. See the User's Guide\n");
2218  fprintf (fp,"# for more info.\n");
2219  fprintf (fp,"\n");
2220  fprintf (fp,"PATTERN I\n");
2221  fprintf (fp,"OUTPUT %s\n",getSaveFileName().toStdString().c_str());
2222  fprintf (fp,"\n");
2223  fprintf (fp,"# You must specify the type of the input files. The choices are:\n");
2224  fprintf (fp,"# YUV, PPM, JMOVIE, Y, JPEG, PNM\n");
2225  fprintf (fp,"# (must be upper case)\n");
2226  fprintf (fp,"#\n");
2227  fprintf (fp,"BASE_FILE_FORMAT PPM\n");
2228  fprintf (fp,"\n");
2229  fprintf (fp,"\n");
2230  fprintf (fp,"# If you are using YUV, there are different supported file formats.\n");
2231  fprintf (fp,"# EYUV or UCB are the same as previous versions of this encoder.\n");
2232  fprintf (fp,"# (All the Y's, then U's then V's, in 4:2:0 subsampling.)\n");
2233  fprintf (fp,"# Other formats, such as Abekas, Phillips, or a general format are\n");
2234  fprintf (fp,"# permissible, the general format is a string of Y's, U's, and V's\n");
2235  fprintf (fp,"# to specify the file order.\n");
2236  fprintf (fp,"\n");
2237  fprintf (fp,"INPUT_FORMAT UCB\n");
2238  fprintf (fp,"\n");
2239  fprintf (fp,"# the conversion statement\n");
2240  fprintf (fp,"#\n");
2241  fprintf (fp,"# Each occurrence of '*' will be replaced by the input file\n");
2242  fprintf (fp,"#\n");
2243  fprintf (fp,"# e.g., if you have a bunch of GIF files, then this might be:\n");
2244  fprintf (fp,"# INPUT_CONVERT giftoppm *\n");
2245  fprintf (fp,"#\n");
2246  fprintf (fp,"# e.g., if you have a bunch of files like a.Y a.U a.V, etc., then:\n");
2247  fprintf (fp,"# INPUT_CONVERT cat *.Y *.U *.V\n");
2248  fprintf (fp,"#\n");
2249  fprintf (fp,"# e.g., if you are grabbing from laser disc you might have something like\n");
2250  fprintf (fp,"# INPUT_CONVERT goto frame *; grabppm\n");
2251  fprintf (fp,"# 'INPUT_CONVERT *' means the files are already in the base file format\n");
2252  fprintf (fp,"#\n");
2253  fprintf (fp,"INPUT_CONVERT * \n");
2254  fprintf (fp,"\n");
2255  fprintf (fp,"# number of frames in a GOP.\n");
2256  fprintf (fp,"#\n");
2257  fprintf (fp,"# since each GOP must have at least one I-frame, the encoder will find the\n");
2258  fprintf (fp,"# the first I-frame after GOP_SIZE frames to start the next GOP\n");
2259  fprintf (fp,"#\n");
2260  fprintf (fp,"# later, will add more flexible GOP signalling\n");
2261  fprintf (fp,"#\n");
2262  fprintf (fp,"GOP_SIZE 1\n");
2263  fprintf (fp,"\n");
2264  fprintf (fp,"# number of slices in a frame\n");
2265  fprintf (fp,"#\n");
2266  fprintf (fp,"# 1 is a good number. another possibility is the number of macroblock rows\n");
2267  fprintf (fp,"# (which is the height divided by 16)\n");
2268  fprintf (fp,"#\n");
2269  fprintf (fp,"SLICES_PER_FRAME 1\n");
2270  fprintf (fp,"PIXEL HALF");
2271  fprintf (fp,"\n");
2272  fprintf (fp,"# directory to get all input files from (makes this file easier to read)\n");
2273  fprintf (fp,"INPUT_DIR %s\n",fMovieTempFolderPath.toStdString().c_str());
2274  fprintf (fp,"\n");
2275  fprintf (fp,"# There are a bunch of ways to specify the input files.\n");
2276  fprintf (fp,"# from a simple one-per-line listing, to the following \n");
2277  fprintf (fp,"# way of numbering them. See the manual for more information.\n");
2278  fprintf (fp,"INPUT\n");
2279  fprintf (fp,"# '*' is replaced by the numbers 01, 02, 03, 04\n");
2280  fprintf (fp,"# if I instead do [01-11], it would be 01, 02, ..., 09, 10, 11\n");
2281  fprintf (fp,"# if I instead do [1-11], it would be 1, 2, 3, ..., 9, 10, 11\n");
2282  fprintf (fp,"# if I instead do [1-11+3], it would be 1, 4, 7, 10\n");
2283  fprintf (fp,"# the program assumes none of your input files has a name ending in ']'\n");
2284  fprintf (fp,"# if you do, too bad!!!\n");
2285  fprintf (fp,"#\n");
2286  fprintf (fp,"#\n");
2287  fprintf (fp,"Test*.ppm [0-%d]\n",fRecordFrameNumber-1);
2288  fprintf (fp,"# can have more files here if you want...there is no limit on the number\n");
2289  fprintf (fp,"# of files\n");
2290  fprintf (fp,"END_INPUT\n");
2291  fprintf (fp,"\n");
2292  fprintf (fp,"\n");
2293  fprintf (fp,"\n");
2294  fprintf (fp,"# Many of the remaining options have to do with the motion search and qscale\n");
2295  fprintf (fp,"\n");
2296  fprintf (fp,"# FULL or HALF -- must be upper case\n");
2297  fprintf (fp,"# Should be FULL for computer generated images\n");
2298  fprintf (fp,"PIXEL FULL\n");
2299  fprintf (fp,"\n");
2300  fprintf (fp,"# means +/- this many pixels for both P and B frame searches\n");
2301  fprintf (fp,"# specify two numbers if you wish to serc different ranges in the two.\n");
2302  fprintf (fp,"RANGE 10\n");
2303  fprintf (fp,"\n");
2304  fprintf (fp,"# The two search algorithm parameters below mostly affect speed,\n");
2305  fprintf (fp,"# with some affect on compression and almost none on quality.\n");
2306  fprintf (fp,"\n");
2307  fprintf (fp,"# this must be one of {EXHAUSTIVE, SUBSAMPLE, LOGARITHMIC}\n");
2308  fprintf (fp,"PSEARCH_ALG LOGARITHMIC\n");
2309  fprintf (fp,"\n");
2310  fprintf (fp,"# this must be one of {SIMPLE, CROSS2, EXHAUSTIVE}\n");
2311  fprintf (fp,"#\n");
2312  fprintf (fp,"# note that EXHAUSTIVE is really, really, really slow\n");
2313  fprintf (fp,"#\n");
2314  fprintf (fp,"BSEARCH_ALG SIMPLE\n");
2315  fprintf (fp,"\n");
2316  fprintf (fp,"#\n");
2317  fprintf (fp,"# these specify the q-scale for I, P, and B frames\n");
2318  fprintf (fp,"# (values must be between 1 and 31)\n");
2319  fprintf (fp,"# These are the Qscale values for the entire frame in variable bit-rate\n");
2320  fprintf (fp,"# mode, and starting points (but not important) for constant bit rate\n");
2321  fprintf (fp,"#\n");
2322  fprintf (fp,"\n");
2323  fprintf (fp,"# Qscale (Quantization scale) affects quality and compression,\n");
2324  fprintf (fp,"# but has very little effect on speed.\n");
2325  fprintf (fp,"\n");
2326  fprintf (fp,"IQSCALE 4\n");
2327  fprintf (fp,"PQSCALE 5\n");
2328  fprintf (fp,"BQSCALE 12\n");
2329  fprintf (fp,"\n");
2330  fprintf (fp,"# this must be ORIGINAL or DECODED\n");
2331  fprintf (fp,"REFERENCE_FRAME ORIGINAL\n");
2332  fprintf (fp,"\n");
2333  fprintf (fp,"# for parallel parameters see parallel.param in the exmaples subdirectory\n");
2334  fprintf (fp,"\n");
2335  fprintf (fp,"# if you want constant bit-rate mode, specify it as follows (number is bits/sec):\n");
2336  fprintf (fp,"#BIT_RATE 1000000\n");
2337  fprintf (fp,"\n");
2338  fprintf (fp,"# To specify the buffer size (327680 is default, measused in bits, for 16bit words)\n");
2339  fprintf (fp,"BUFFER_SIZE 327680\n");
2340  fprintf (fp,"\n");
2341  fprintf (fp,"# The frame rate is the number of frames/second (legal values:\n");
2342  fprintf (fp,"# 23.976, 24, 25, 29.97, 30, 50 ,59.94, 60\n");
2343  fprintf (fp,"FRAME_RATE 30\n");
2344  fprintf (fp,"\n");
2345  fprintf (fp,"# There are many more options, see the users manual for examples....\n");
2346  fprintf (fp,"# ASPECT_RATIO, USER_DATA, GAMMA, IQTABLE, etc.\n");
2347  fprintf (fp,"\n");
2348  fprintf (fp,"\n");
2349  fclose (fp);
2350 
2351  setRecordingInfos("Parameter file "+fParameterFileName+" generated in "+fMovieTempFolderPath);
2352  setRecordingStatus(READY_TO_ENCODE);
2353  return true;
2354 }
2355 
2356 void G4OpenGLQtViewer::encodeVideo()
2357 {
2358  if ((getEncoderPath() != "") && (getSaveFileName() != "")) {
2359  setRecordingStatus(ENCODING);
2360 
2361  fProcess = new QProcess();
2362 #if QT_VERSION > 0x040100
2363  QObject ::connect(fProcess,SIGNAL(finished ( int,QProcess::ExitStatus)),
2364  this,SLOT(processEncodeFinished()));
2365  QObject ::connect(fProcess,SIGNAL(readyReadStandardOutput ()),
2366  this,SLOT(processEncodeStdout()));
2367 #else
2368  QObject ::connect(fProcess,SIGNAL(finished ( int)),
2369  this,SLOT(processEncodeFinished()));
2370  QObject ::connect(fProcess,SIGNAL(readyReadStandardOutput ()),
2371  this,SLOT(processEncodeStdout()));
2372 #endif
2373 #if QT_VERSION < 0x050a00
2374  fProcess->setReadChannelMode(QProcess::MergedChannels);
2375 #else
2376  fProcess->setProcessChannelMode(QProcess::MergedChannels);
2377 #endif
2378  fProcess->start (fEncoderPath, QStringList(fMovieTempFolderPath+fParameterFileName));
2379  }
2380 }
2381 
2382 
2383 // FIXME : does not work on Qt3
2384 void G4OpenGLQtViewer::processEncodeStdout()
2385 {
2386  QString tmp = fProcess->readAllStandardOutput ().data();
2387  int start = tmp.lastIndexOf("ESTIMATED TIME");
2388  tmp = tmp.mid(start,tmp.indexOf("\n",start)-start);
2389  setRecordingInfos(tmp);
2390 }
2391 
2392 
2393 void G4OpenGLQtViewer::processEncodeFinished()
2394 {
2395 
2396  QString txt = "";
2397  txt = getProcessErrorMsg();
2398  if (txt == "") {
2399  setRecordingStatus(SUCCESS);
2400  } else {
2401  setRecordingStatus(FAILED);
2402  }
2403  // setRecordingInfos(txt+removeTempFolder());
2404 }
2405 
2406 
2407 void G4OpenGLQtViewer::processLookForFinished()
2408 {
2409 
2410  QString txt = getProcessErrorMsg();
2411  if (txt != "") {
2412  fEncoderPath = "";
2413  } else {
2414  fEncoderPath = QString(fProcess->readAllStandardOutput ().data()).trimmed();
2415  // if not found, return "not found"
2416  if (fEncoderPath.contains(" ")) {
2417  fEncoderPath = "";
2418  } else if (!fEncoderPath.contains("ppmtompeg")) {
2419  fEncoderPath = "";
2420  }
2421  setEncoderPath(fEncoderPath);
2422  }
2423  // init temp folder
2424  setTempFolderPath(QDir::temp ().absolutePath ());
2425 }
2426 
2427 
2428 QString G4OpenGLQtViewer::getProcessErrorMsg()
2429 {
2430  QString txt = "";
2431  if (fProcess->exitCode() != 0) {
2432  switch (fProcess->error()) {
2433  case QProcess::FailedToStart:
2434  txt = "The process failed to start. Either the invoked program is missing, or you may have insufficient permissions to invoke the program.\n";
2435  break;
2436  case QProcess::Crashed:
2437  txt = "The process crashed some time after starting successfully.\n";
2438  break;
2439  case QProcess::Timedout:
2440  txt = "The last waitFor...() function timed out. The state of QProcess is unchanged, and you can try calling waitFor...() again.\n";
2441  break;
2442  case QProcess::WriteError:
2443  txt = "An error occurred when attempting to write to the process. For example, the process may not be running, or it may have closed its input channel.\n";
2444  break;
2445  case QProcess::ReadError:
2446  txt = "An error occurred when attempting to read from the process. For example, the process may not be running.\n";
2447  break;
2448  case QProcess::UnknownError:
2449  txt = "An unknown error occurred. This is the default return value of error().\n";
2450  break;
2451  }
2452  }
2453  return txt;
2454 }
2455 
2456 
2457 
2458 
2459 QWidget *G4OpenGLQtViewer::getParentWidget()
2460 {
2461  // launch Qt if not
2462  G4Qt* interactorManager = G4Qt::getInstance ();
2463  // G4UImanager* UI =
2464  // G4UImanager::GetUIpointer();
2465 
2466  bool found = false;
2467  QDialog* dialog = NULL;
2468  // create window
2469  if (((QApplication*)interactorManager->GetMainInteractor())) {
2470  // look for the main window
2471  QWidgetList wl = QApplication::allWidgets();
2472  QWidget *widget = NULL;
2473  for (int i=0; i < wl.size(); i++) {
2474  widget = wl.at(i);
2475  if ((found== false) && (widget->inherits("QMainWindow"))) {
2476  dialog = new QDialog(widget,Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
2477  found = true;
2478  }
2479  }
2480 
2481  if (found==false) {
2482  dialog = new QDialog();
2483  }
2484  } else {
2485  dialog= new QDialog();
2486  }
2487  if (found) {
2488  return dialog;
2489  } else {
2490  return NULL;
2491  }
2492 }
2493 
2494 
2495 void G4OpenGLQtViewer::createSceneTreeWidget() {
2496  fUISceneTreeWidget = fUiQt->GetSceneTreeWidget();
2497 
2498  if (!fUISceneTreeWidget) {
2499  return;
2500  }
2501 
2502  // do not remove previous widgets, hide them!
2503  QLayoutItem * wItem;
2504  bool found = false;
2505  if (fUISceneTreeWidget->layout()->count() ) {
2506  for(int idx = 0; idx < fUISceneTreeWidget->layout()->count(); idx++){
2507  wItem = fUISceneTreeWidget->layout()->itemAt(idx);
2508  if (fSceneTreeWidget) {
2509  if(dynamic_cast<QWidget *>(wItem->widget())) {
2510  if (wItem->widget()->windowTitle() == fSceneTreeWidget->windowTitle()) {
2511  wItem->widget()->show();
2512  found = true;
2513  } else {
2514  wItem->widget()->hide();
2515  }
2516  }
2517  } else {
2518  wItem->widget()->hide();
2519  }
2520  }
2521  }
2522 
2523  if (!found) {
2524  // initialize scene tree / viewer properties / picking
2525  fSceneTreeWidget = new QWidget();
2526  QVBoxLayout* layoutSceneTree = new QVBoxLayout();
2527  fSceneTreeWidget->setStyleSheet ("padding: 0px ");
2528 
2529  fSceneTreeWidget->setLayout(layoutSceneTree);
2530  fSceneTreeWidget->layout()->setContentsMargins(5,5,5,5);
2531  fSceneTreeWidget->setWindowTitle(QString(GetName().data()));
2532 
2533  if (fUISceneTreeWidget != NULL) {
2534  fUISceneTreeWidget->layout()->addWidget(fSceneTreeWidget);
2535  }
2536 
2537  // not available for Immediate mode
2538  if (dynamic_cast<G4OpenGLStoredQtViewer*> (this)) {
2539  createSceneTreeComponent();
2540  }
2541  }
2542 }
2543 
2544 
2545 void G4OpenGLQtViewer::createSceneTreeComponent(){
2546 
2547  QLayout* vLayout = fSceneTreeWidget->layout();
2548 
2549  // Search line
2550  QWidget* coutButtonWidget = new QWidget();
2551  QHBoxLayout* layoutCoutTBButtons = new QHBoxLayout();
2552 
2553  fFilterOutput = new QLineEdit();
2554  fFilterOutput->setToolTip("Filter output by...");
2555  fFilterOutput->setStyleSheet ("padding: 0px ");
2556 
2557  QPixmap* searchIcon = fUiQt->getSearchIcon();
2558 #if QT_VERSION > 0x050100
2559  fFilterOutput->addAction(*searchIcon,QLineEdit::TrailingPosition);
2560  fFilterOutput->setStyleSheet ("border-radius:7px;");
2561 #else
2562  QPushButton *coutTBFilterButton = new QPushButton();
2563  coutTBFilterButton->setIcon(*searchIcon);
2564  coutTBFilterButton->setStyleSheet ("padding-left: 0px; border:0px;");
2565  fFilterOutput->setStyleSheet ("padding-right: 0px;");
2566 #endif
2567  layoutCoutTBButtons->addWidget(fFilterOutput);
2568 
2569 #if QT_VERSION <= 0x050100
2570  layoutCoutTBButtons->addWidget(coutTBFilterButton);
2571 #endif
2572 
2573  coutButtonWidget->setLayout(layoutCoutTBButtons);
2574  vLayout->addWidget(coutButtonWidget);
2575 
2576  // reduce margins
2577  vLayout->setContentsMargins(0,0,0,0);
2578 
2579 
2580  fSceneTreeComponentTreeWidget = new QTreeWidget();
2581  fSceneTreeComponentTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
2582  fSceneTreeComponentTreeWidget->setHeaderLabel ("Scene tree : "+QString(GetName().data()));
2583  fSceneTreeComponentTreeWidget->setColumnHidden (1,true); // copy number
2584  fSceneTreeComponentTreeWidget->setColumnHidden (2,true); // PO index
2585  fSceneTreeComponentTreeWidget->setColumnHidden (3,true); // Informations
2586  // data(0) : POindex
2587  // data(1) : copy number
2588  // data(2) : g4color
2589 
2590  vLayout->addWidget(fSceneTreeComponentTreeWidget);
2591 
2592  connect(fSceneTreeComponentTreeWidget,SIGNAL(itemChanged(QTreeWidgetItem*, int)),SLOT(sceneTreeComponentItemChanged(QTreeWidgetItem*, int)));
2593  connect(fSceneTreeComponentTreeWidget,SIGNAL(itemSelectionChanged ()),SLOT(sceneTreeComponentSelected()));
2594  connect(fSceneTreeComponentTreeWidget,SIGNAL(itemDoubleClicked ( QTreeWidgetItem*, int)),SLOT(changeColorAndTransparency( QTreeWidgetItem*, int)));
2595 
2596 
2597  // Depth slider
2598  QWidget *helpWidget = new QWidget();
2599  QHBoxLayout *helpLayout = new QHBoxLayout();
2600 
2601  QWidget* depthWidget = new QWidget();
2602  QWidget *showBox = new QWidget(depthWidget);
2603  QHBoxLayout *showBoxLayout = new QHBoxLayout();
2604 
2605  // reduce margins
2606  showBoxLayout->setContentsMargins(5,5,5,5);
2607 
2608  QLabel *zero = new QLabel();
2609  zero->setText("Show all");
2610  QLabel *one = new QLabel();
2611  one->setText("Hide all");
2612  fSceneTreeDepthSlider = new QSlider ( Qt::Horizontal);
2613  fSceneTreeDepthSlider->setMaximum (1000);
2614  fSceneTreeDepthSlider->setMinimum (0);
2615  fSceneTreeDepthSlider->setTickPosition(QSlider::TicksAbove);
2616  // set a minimum size
2617  fSceneTreeDepthSlider->setMinimumWidth (40);
2618 
2619  showBoxLayout->addWidget(zero);
2620  showBoxLayout->addWidget(fSceneTreeDepthSlider);
2621  showBoxLayout->addWidget(one);
2622 
2623  showBox->setLayout(showBoxLayout);
2624 
2625  helpLayout->addWidget(showBox);
2626  helpWidget->setLayout(helpLayout);
2627  helpLayout->setContentsMargins(0,0,0,0);
2628 
2629  vLayout->addWidget(helpWidget);
2630 
2631  connect( fSceneTreeDepthSlider, SIGNAL( valueChanged(int) ), this, SLOT( changeDepthInSceneTree(int) ) );
2632  connect( fFilterOutput, SIGNAL( textEdited ( const QString &) ), this, SLOT(changeSearchSelection()));
2633  fTreeItemModels.clear();
2634 
2635  fPVRootNodeCreate = false;
2636 
2637  fMaxPOindexInserted = -1;
2638 
2639 
2640 }
2641 
2642 
2643 void G4OpenGLQtViewer::createViewerPropertiesWidget() {
2644 
2645  // Get the pointer to the Viewer Properties widget
2646  fUIViewerPropertiesWidget = fUiQt->GetViewerPropertiesWidget();
2647 
2648  if (!fUIViewerPropertiesWidget) {
2649  return;
2650  }
2651 
2652  // remove previous widgets
2653  QLayoutItem * wItem;
2654  if (fUIViewerPropertiesWidget->layout()->count()) {
2655  while ((wItem = fUIViewerPropertiesWidget->layout()->takeAt(0)) != 0) {
2656  delete wItem->widget();
2657  delete wItem;
2658  }
2659  }
2660 
2661  // add properties
2662  QGroupBox *groupBox = new QGroupBox();
2663  groupBox->setTitle(GetName().data());
2664  QVBoxLayout *vbox = new QVBoxLayout;
2665 
2666  // add properties content
2667  fViewerPropertiesTableWidget = new QTableWidget();
2668 
2669  QSizePolicy vPolicy = fViewerPropertiesTableWidget->sizePolicy();
2670  vPolicy.setVerticalStretch(4);
2671 
2672  vbox->addWidget(fViewerPropertiesTableWidget);
2673  groupBox->setLayout(vbox);
2674  fUIViewerPropertiesWidget->layout()->addWidget(groupBox);
2675 
2676  connect(fViewerPropertiesTableWidget, SIGNAL(itemChanged(QTableWidgetItem*)),this, SLOT(tableWidgetViewerSetItemChanged(QTableWidgetItem *)));
2677 
2678  updateViewerPropertiesTableWidget();
2679 
2680  QDialog* dial = static_cast<QDialog*> (fUIViewerPropertiesWidget->parent());
2681  if (dial) {
2682  // change name
2683  dial->setWindowTitle(QString("Viewer properties - ")+GetName());
2684  }
2685 }
2686 
2687 
2688 void G4OpenGLQtViewer::createPickInfosWidget(){
2689 
2690  // Get the pointer to the Pick infos widget
2691  fUIPickInfosWidget = fUiQt->GetPickInfosWidget();
2692 
2693  if (!fUIPickInfosWidget) {
2694  return;
2695  }
2696 
2697  // remove previous widgets
2698  QLayoutItem * wItem;
2699  if (fUIPickInfosWidget->layout()->count()) {
2700  while ((wItem = fUIPickInfosWidget->layout()->takeAt(0)) != 0) {
2701  delete wItem->widget();
2702  delete wItem;
2703  }
2704  }
2705 
2706  QGroupBox *groupBox = new QGroupBox("");
2707  QVBoxLayout *vbox = new QVBoxLayout;
2708 
2709  // add picking infos
2710  QWidget *pickingInfoWidget = new QWidget();
2711  QHBoxLayout *pickingInfoLayout = new QHBoxLayout();
2712 
2713  pickingInfoWidget->setStyleSheet ("padding-left: 0px; border:0px;");
2714  pickingInfoWidget->setLayout(pickingInfoLayout);
2715 
2716  vbox->addWidget(pickingInfoWidget);
2717  // add picking content
2718 
2719  fPickInfosScrollArea = new QScrollArea();
2720  fPickInfosScrollArea->setWidgetResizable(true);
2721 
2722 
2723  fPickInfosWidget = new QWidget();
2724  fPickInfosWidget->setStyleSheet ("padding: 0px ");
2725 
2726  QVBoxLayout* vLayout = new QVBoxLayout();
2727  fPickInfosWidget->setLayout (vLayout);
2728  fPickInfosScrollArea->setWidget(fPickInfosWidget);
2729 
2730  QSizePolicy vPolicy = fPickInfosWidget->sizePolicy();
2731  vPolicy.setVerticalStretch(4);
2732  vbox->addWidget(fPickInfosScrollArea);
2733  pickingInfoLayout->setContentsMargins(0,0,0,0);
2734  vLayout->setContentsMargins(0,0,0,0);
2735  vbox->setContentsMargins(1,1,1,1);
2736 
2737  groupBox->setLayout(vbox);
2738  fUIPickInfosWidget->layout()->addWidget(groupBox);
2739 
2740  updatePickInfosWidget(fLastPickPoint.x(),fLastPickPoint.y());
2741 }
2742 
2743 
2744 // set the component to check/unchecked, also go into its child
2745 // and set the same status to all his childs
2746 void G4OpenGLQtViewer::setCheckComponent(QTreeWidgetItem* item,bool check)
2747 {
2748  if (item) {
2749 
2750  const PVPath& fullPath = fTreeItemModels[item->data(0,Qt::UserRole).toInt()];
2751  // If a physical volume
2752  if (fullPath.size() > 0) {
2753  SetTouchable(fullPath);
2754  TouchableSetVisibility(fullPath, check);
2755  fMouseOnSceneTree = true;
2756  }
2757  }
2758 
2759  if (item != NULL) {
2760  if (check) {
2761  item->setCheckState(0,Qt::Checked);
2762  } else {
2763  item->setCheckState(0,Qt::Unchecked);
2764  }
2765  updatePositivePoIndexSceneTreeWidgetQuickMap(item->data(0,Qt::UserRole).toInt(),item);
2766  int nChildCount = item->childCount();
2767  for (int i = 0; i < nChildCount; i++) {
2768  setCheckComponent(item->child(i),check);
2769  }
2770  }
2771 }
2772 
2773 
2774 void G4OpenGLQtViewer::DrawText(const G4Text& g4text)
2775 {
2776  QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
2777  if (! qGLW) {
2778  return;
2779  }
2780  if (isGl2psWriting()) {
2781 
2782  G4OpenGLViewer::DrawText(g4text);
2783 
2784  } else {
2785 
2786  if (!fGLWidget) return;
2787 
2788 #ifdef G4MULTITHREADED
2790 #endif
2791 
2793  G4double size = fSceneHandler.GetMarkerSize(g4text,sizeType);
2794 
2795  QFont font = QFont();
2796  font.setPointSizeF(size);
2797 
2798  const G4Colour& c = fSceneHandler.GetTextColour(g4text);
2799  glColor4d(c.GetRed(),c.GetGreen(),c.GetBlue(),c.GetAlpha());
2800 
2801  G4Point3D position = g4text.GetPosition();
2802 
2803  const G4String& textString = g4text.GetText();
2804  const char* textCString = textString.c_str();
2805 
2806  glRasterPos3d(position.x(),position.y(),position.z());
2807 
2808  // Calculate move for centre and right adjustment
2809  QFontMetrics* f = new QFontMetrics (font);
2810 #if QT_VERSION > 0x050110
2811  G4double span = f->boundingRect(textCString[0]).width();
2812 #else
2813  G4double span = f->width(textCString);
2814 #endif
2815  G4double xmove = 0., ymove = 0.;
2816  switch (g4text.GetLayout()) {
2817  case G4Text::left: break;
2818  case G4Text::centre: xmove -= span / 2.; break;
2819  case G4Text::right: xmove -= span;
2820  }
2821 
2822  //Add offsets
2823  xmove += g4text.GetXOffset();
2824  ymove += g4text.GetYOffset();
2825 
2826  qGLW->renderText
2827  ((position.x()+(2*xmove)/getWinWidth()),
2828  (position.y()+(2*ymove)/getWinHeight()),
2829  position.z(),
2830  textCString,
2831  font);
2832 
2833  }
2834 }
2835 
2836 
2837 void G4OpenGLQtViewer::ResetView () {
2838  G4OpenGLViewer::ResetView();
2839  fDeltaDepth = 0.01;
2840  fDeltaZoom = 0.05;
2841 }
2842 
2843 
2844 
2845 
2846 void G4OpenGLQtViewer::addPVSceneTreeElement(const G4String& model, G4PhysicalVolumeModel* pPVModel, int currentPOIndex) {
2847 
2848  const QString& modelShortName = getModelShortName(model);
2849 
2850  if (modelShortName == "") {
2851  return ;
2852  }
2853  // try to init it
2854  if (fSceneTreeComponentTreeWidget == NULL) {
2855  createSceneTreeComponent();
2856  }
2857 
2858  // if no UI
2859  if (fSceneTreeComponentTreeWidget == NULL) {
2860  return;
2861  }
2862 
2863  fSceneTreeComponentTreeWidget->blockSignals(true);
2864 
2865  // Create the "volume" node if not
2866  // if (fSceneTreeComponentTreeWidget->topLevelItemCount () == 0) {
2867  if (!fPVRootNodeCreate) {
2868  const G4Colour& color = fSceneHandler.GetColour();
2869 
2870  fModelShortNameItem = createTreeWidgetItem(pPVModel->GetFullPVPath(),
2871  modelShortName,
2872  0, // currentPVCopyNb
2873  -1, // currentPVPOIndex
2874  "",
2875  Qt::Checked,
2876  NULL,
2877  color);
2878  fPVRootNodeCreate = true;
2879  }
2880 
2881  bool added = parseAndInsertInSceneTree(fModelShortNameItem,pPVModel,0,modelShortName,0,currentPOIndex);
2882  if (!added) {
2883  }
2884 
2885  fSceneTreeComponentTreeWidget->blockSignals(false);
2886 
2887 }
2888 
2889 
2894 QTreeWidgetItem* G4OpenGLQtViewer::createTreeWidgetItem(
2895  const PVPath& fullPath
2896  ,const QString& name
2897  ,int copyNb
2898  ,int POIndex
2899  ,const QString& logicalName
2900  ,Qt::CheckState state
2901  ,QTreeWidgetItem * parentTreeNode
2902  ,const G4Colour& color
2903 ) {
2904 
2905  // Set depth
2906  if (fullPath.size() > fSceneTreeDepth) {
2907  fSceneTreeDepth = fullPath.size();
2908  // Change slider value
2909  if (fSceneTreeDepthSlider) {
2910  fSceneTreeDepthSlider->setTickInterval(1000/(fSceneTreeDepth+1));
2911  }
2912  }
2913  QTreeWidgetItem * newItem = NULL;
2914  if (parentTreeNode == NULL) {
2915  newItem = new QTreeWidgetItem();
2916  fSceneTreeComponentTreeWidget->addTopLevelItem(newItem);
2917  } else {
2918  newItem = new QTreeWidgetItem(parentTreeNode);
2919  fSceneTreeComponentTreeWidget->addTopLevelItem(parentTreeNode);
2920  }
2921 
2922 
2923  newItem->setText(0,name);
2924  newItem->setData(1,Qt::UserRole,copyNb);
2925  newItem->setText(2,QString::number(POIndex));
2926  newItem->setData(0, Qt::UserRole, POIndex);
2927  newItem->setText(3,logicalName);
2928  newItem->setFlags(newItem->flags()|Qt::ItemIsUserCheckable);
2929  newItem->setCheckState(0,state);
2930  newItem->setExpanded(true);
2931  updatePositivePoIndexSceneTreeWidgetQuickMap(POIndex,newItem);
2932 
2933  changeQColorForTreeWidgetItem(newItem,QColor((int)(color.GetRed()*255),
2934  (int)(color.GetGreen()*255),
2935  (int)(color.GetBlue()*255),
2936  (int)(color.GetAlpha()*255)));
2937 
2938  // If invisible
2939  if ((state == Qt::Unchecked) && (POIndex == -1)) {
2940  newItem->setForeground (0, QBrush( Qt::gray) );
2941 
2942  // Set a tootip
2943  newItem->setToolTip (0,QString(
2944  "This node exists in the geometry but has not been\n")+
2945  "drawn, perhaps because it has been set invisible. It \n"+
2946  "cannot be made visible with a click on the button.\n"+
2947  "To see it, change the visibility, for example, with \n"+
2948  "/vis/geometry/set/visibility " + logicalName + " 0 true\n"+
2949  "and rebuild the view with /vis/viewer/rebuild.\n"+
2950  "Click here will only show/hide all child components");
2951  } else {
2952  // Set a tootip
2953  newItem->setToolTip (0,QString("double-click to change the color"));
2954  }
2955 
2956  // special case: if alpha=0, it is a totally transparent objet,
2957  // then, do not redraw it
2958  if (color.GetAlpha() == 0) {
2959  state = Qt::Unchecked;
2960  newItem->setCheckState(0,state);
2961  updatePositivePoIndexSceneTreeWidgetQuickMap(POIndex,newItem);
2962  }
2963 
2964  fTreeItemModels.insert(std::pair <int, PVPath > (POIndex,fullPath) );
2965 
2966  // Check last status of this item and change if necessary
2967  // open/close/hidden/visible/selected
2968  changeOpenCloseVisibleHiddenSelectedColorSceneTreeElement(newItem);
2969  return newItem;
2970 }
2971 
2972 
2973 //
2974 // Recursive function.
2975 // Try to insert the given item :
2976 // - If not present and last item of the path: insert it and mark it CHECK
2977 // - If not present and NOT last item of the path: insert it and mark it UNCHECKED
2978 // - If already present and name/PO/Transformation identical, then it is a transparent
2979 // object : Change the PO number and transparency
2980 // - If already present and PO different, then it is an unvisible item : Have to
2981 // set it visible
2982 // - else : Create a new element
2983 // @return true if inserted, false if already present
2984 //
2985 bool G4OpenGLQtViewer::parseAndInsertInSceneTree(
2986  QTreeWidgetItem * parentItem
2987  ,G4PhysicalVolumeModel* pPVModel
2988  ,unsigned int fullPathIndex
2989  ,const QString& parentRoot
2990  ,unsigned int currentIndexInTreeSceneHandler
2991  ,int currentPVPOIndex
2992 ) {
2993 
2994  if (parentItem == NULL) {
2995  return false;
2996  }
2997 
2998  const PVPath& fullPath = pPVModel->GetFullPVPath();
2999 
3000  std::ostringstream oss;
3001  oss << fullPath.at(fullPathIndex).GetCopyNo();
3002  std::string currentPVName = G4String(fullPath.at(fullPathIndex).GetPhysicalVolume()->GetName()+" ["+oss.str()+"]").data();
3003 
3004  int currentPVCopyNb = fullPath.at(fullPathIndex).GetCopyNo();
3005 
3006  const G4Colour& color = fSceneHandler.GetColour();
3007 
3008  // look in all children in order to get if their is already a
3009  // child corresponding:
3010  // - if so, go into this child
3011  // - if not : create it as invisible
3012 
3013  // Realy quick check if the POindex is already there
3014  QTreeWidgetItem* subItem = NULL;
3015  QList<QTreeWidgetItem *> parentItemList;
3016 
3017 
3018  // first of all, very quick check if it was not the same as last one
3019 
3020  // Check only if it is a transparent object
3021  // If it is the last item and it is not transparent -> nothing to look for,
3022  // simply add it.
3023  if ((currentIndexInTreeSceneHandler == (fullPath.size()-1)) && ((color.GetAlpha() == 1.))) {
3024  } else {
3025  QString lookForString = QString(currentPVName.c_str());
3026  for (int i = 0;i < parentItem->childCount(); i++ ) {
3027  if (parentItem->child(i)->text(0) == lookForString) {
3028  parentItemList.push_back(parentItem->child(i));
3029  }
3030  }
3031  }
3032 
3033  for (int i = 0; i < parentItemList.size(); ++i) {
3034  const std::string& parentItemName = parentItemList.at(i)->text(0).toStdString();
3035  int parentItemCopyNb = parentItemList.at(i)->data(1,Qt::UserRole).toInt();
3036  int parentItemPOIndex = parentItemList.at(i)->data(0,Qt::UserRole).toInt();
3037 
3038  // if already inside
3039  // -> return true
3040  // special case, do not have to deal with hierarchy except for PhysicalVolume
3041 
3042 
3043  /* Physical Volume AND copy number equal AND name equal */
3044  if (((parentRoot == fTouchableVolumes) && (currentPVCopyNb == parentItemCopyNb)
3045  && (currentPVName == parentItemName)) ||
3046  /* NOT a Physical Volume AND copy number equal */
3047  ((parentRoot != fTouchableVolumes) && (currentPVCopyNb == parentItemCopyNb)
3048  /*AND name equal AND PO index equal*/
3049  && (currentPVName == parentItemName) && (currentPVPOIndex == parentItemPOIndex) )) {
3050 
3051  // then check for the Transform3D
3052  bool sameTransform = true;
3053  if (parentItemPOIndex >= 0) {
3054  const PVPath& fullPathTmp = fTreeItemModels[parentItemPOIndex];
3055  if (fullPathTmp.size() > 0) {
3056  if (fullPathTmp.at(fullPathTmp.size()-1).GetTransform () == pPVModel->GetTransformation ()) {
3057  sameTransform = true;
3058  } else {
3059  sameTransform = false;
3060  }
3061  }
3062  }
3063 
3064  // Same transformation, then try to change the PO index
3065  if (sameTransform == true) {
3066  // already exist in the tree, is it a transparent object ?
3067  // If so, then have to change the PO index ONLY if it is the last
3068  // and then change the state ONLY if POIndex has change
3069  // If not, then go deaper
3070 
3071  // last element
3072  if (currentIndexInTreeSceneHandler == (fullPath.size()-1)) {
3073 
3074  parentItemList.at(i)->setText(2,QString::number(currentPVPOIndex));
3075  parentItemList.at(i)->setData(0, Qt::UserRole,currentPVPOIndex);
3076 
3077  fTreeItemModels.insert(std::pair <int, PVPath >(currentPVPOIndex,fullPath) );
3078 
3079  // Then remove tooltip and special font
3080  QFont f = QFont();
3081  parentItemList.at(i)->setFont (0,f);
3082 
3083  // set foreground
3084  parentItemList.at(i)->setForeground (0,QBrush());
3085 
3086  // Set a tootip
3087  parentItemList.at(i)->setToolTip (0,"");
3088 
3089  changeQColorForTreeWidgetItem(parentItemList.at(i),QColor((int)(color.GetRed()*255),
3090  (int)(color.GetGreen()*255),
3091  (int)(color.GetBlue()*255),
3092  (int)(color.GetAlpha()*255)));
3093 
3094  // set check only if there is something to display
3095  if (color.GetAlpha() > 0) {
3096  parentItemList.at(i)->setCheckState(0,Qt::Checked);
3097  updatePositivePoIndexSceneTreeWidgetQuickMap(currentPVPOIndex,parentItemList.at(i));
3098  }
3099  return false;
3100  } else {
3101  subItem = parentItemList.at(i);
3102  }
3103 
3104  // Exists but not the end of path, then forget get it
3105  } else if (currentIndexInTreeSceneHandler < (fullPath.size()-1)) {
3106  subItem = parentItemList.at(i);
3107  }
3108  }
3109 
3110  } // end for
3111 
3112  // if it the last, then add it and set it checked
3113  if (currentIndexInTreeSceneHandler == (fullPath.size()-1)) {
3114  /* subItem =*/ createTreeWidgetItem(fullPath,
3115  QString(currentPVName.c_str()),
3116  currentPVCopyNb,
3117  currentPVPOIndex,
3118  QString(fullPath.at(fullPathIndex).GetPhysicalVolume()->GetLogicalVolume()->GetName().data()),
3119  Qt::Checked,
3120  parentItem,
3121  color);
3122 
3123  if (currentPVPOIndex > fMaxPOindexInserted) {
3124  fMaxPOindexInserted = currentPVPOIndex;
3125  }
3126 
3127  } else {
3128 
3129  // if no child found, then this child is create and marked as invisible, then go inside
3130  if (subItem == NULL) {
3131 
3132  if (currentIndexInTreeSceneHandler < (fullPath.size()-1)) {
3133  subItem = createTreeWidgetItem(fullPath,
3134  QString(currentPVName.c_str()),
3135  currentPVCopyNb,
3136  -1,
3137  QString(fullPath.at(fullPathIndex).GetPhysicalVolume()->GetLogicalVolume()->GetName().data()),
3138  Qt::Unchecked,
3139  parentItem,
3140  color);
3141  }
3142  }
3143 
3144  return parseAndInsertInSceneTree(subItem,pPVModel,fullPathIndex+1,parentRoot,currentIndexInTreeSceneHandler+1,currentPVPOIndex);
3145  }
3146  return true;
3147 }
3148 
3149 
3150 void G4OpenGLQtViewer::changeOpenCloseVisibleHiddenSelectedColorSceneTreeElement(
3151  QTreeWidgetItem* subItem
3152 )
3153 {
3154  // Check if object with the same POIndex is the same in old tree
3155  QTreeWidgetItem* oldItem = NULL;
3156 
3157  QTreeWidgetItem* foundItem = getOldTreeWidgetItem(subItem->data(0,Qt::UserRole).toInt());
3158 
3159  if (foundItem != NULL) {
3160  if (isSameSceneTreeElement(foundItem,subItem)) {
3161  oldItem = foundItem;
3162  }
3163  }
3164  if (foundItem == NULL) { // PO should have change, parse all
3165 
3166  // POindex > 0
3167  std::map <int, QTreeWidgetItem*>::const_iterator i;
3168  i = fOldPositivePoIndexSceneTreeWidgetQuickMap.begin();
3169  while (i != fOldPositivePoIndexSceneTreeWidgetQuickMap.end()) {
3170  if (isSameSceneTreeElement(i->second,subItem)) {
3171  oldItem = i->second;
3172  i = fOldPositivePoIndexSceneTreeWidgetQuickMap.end();
3173  } else {
3174  i++;
3175  }
3176  }
3177  // POindex == 0 ?
3178  if (oldItem == NULL) {
3179  unsigned int a = 0;
3180  while (a < fOldNullPoIndexSceneTreeWidgetQuickVector.size()) {
3181  if (isSameSceneTreeElement(fOldNullPoIndexSceneTreeWidgetQuickVector[a],subItem)) {
3182  oldItem = fOldNullPoIndexSceneTreeWidgetQuickVector[a];
3183  a = fOldNullPoIndexSceneTreeWidgetQuickVector.size();
3184  } else {
3185  a++;
3186  }
3187  }
3188  }
3189  }
3190 
3191  // if found : retore old state
3192  if (oldItem != NULL) {
3193  subItem->setFlags(oldItem->flags()); // flags
3194  subItem->setCheckState(0,oldItem->checkState(0)); // check state
3195  subItem->setSelected(oldItem->isSelected()); // selected
3196  subItem->setExpanded(oldItem->isExpanded ()); // expand
3197 
3198  // change color
3199  // when we call this function, the color in the item is the one of vis Attr
3200 
3201  std::map <int, QTreeWidgetItem* >::iterator it;
3202 
3203  // getOldPO
3204  int oldPOIndex = oldItem->data(0,Qt::UserRole).toInt();
3205  it = fOldPositivePoIndexSceneTreeWidgetQuickMap.find(oldPOIndex);
3206  QColor color;
3207 
3208  // get old Vis Attr Color
3209  std::map <int, QColor >::iterator itVis;
3210  itVis = fOldVisAttrColorMap.find(oldPOIndex);
3211 
3212  QColor oldVisAttrColor;
3213  const QColor& newVisAttrColor = subItem->data(2,Qt::UserRole).value<QColor>();
3214 
3215  bool visAttrChange = false;
3216  // if old vis attr color found
3217  if (itVis != fOldVisAttrColorMap.end()) {
3218  oldVisAttrColor = itVis->second;
3219  if (oldVisAttrColor != newVisAttrColor) {
3220  visAttrChange = true;
3221  }
3222  } else {
3223  visAttrChange = true;
3224  }
3225 
3226  if (visAttrChange) {
3227  fOldVisAttrColorMap.insert(std::pair <int, QColor > (subItem->data(0,Qt::UserRole).toInt(),newVisAttrColor) );
3228 
3229  } else { // if no changes, get old PO value
3230  // if old PO found
3231  if (it != fOldPositivePoIndexSceneTreeWidgetQuickMap.end()) {
3232  color = (it->second)->data(2,Qt::UserRole).value<QColor>();
3233  } else {
3234  color = oldItem->data(2,Qt::UserRole).value<QColor>();
3235  }
3236  changeQColorForTreeWidgetItem(subItem,color);
3237  }
3238  }
3239 
3240  return;
3241 }
3242 
3243 
3244 
3245 // Check if both items are identical.
3246 // For that, check name, copy number, transformation
3247 // special case for "non Touchables", do not check the PO index, check only the name
3248 bool G4OpenGLQtViewer::isSameSceneTreeElement(
3249  QTreeWidgetItem* parentOldItem
3250  ,QTreeWidgetItem* parentNewItem
3251 ) {
3252 
3253  int newPO = -1;
3254  int oldPO = -1;
3255 
3256  int newCpNumber = -1;
3257  int oldCpNumber = -1;
3258 
3259  bool firstWhile = true;
3260 
3261  while ((parentOldItem != NULL) && (parentNewItem != NULL)) {
3262 
3263  // check transform, optimize getting data(..,..) that consume lot of time
3264  if (!firstWhile) {
3265  oldPO = parentOldItem->data(0,Qt::UserRole).toInt();
3266  newPO = parentNewItem->data(0,Qt::UserRole).toInt();
3267  }
3268  firstWhile = false;
3269 
3270  if ((oldPO >= 0) &&
3271  (newPO >= 0)) {
3272  const PVPath& oldFullPath = fOldTreeItemModels[oldPO];
3273  const PVPath& newFullPath = fTreeItemModels[newPO];
3274  if ((oldFullPath.size() > 0) &&
3275  (newFullPath.size() > 0)) {
3276  if (oldFullPath.size() != newFullPath.size()) {
3277  return false;
3278  }
3279  if (oldFullPath.at(oldFullPath.size()-1).GetTransform () == newFullPath.at(newFullPath.size()-1).GetTransform ()) {
3280  newCpNumber = newFullPath.at(newFullPath.size()-1).GetCopyNo();
3281  oldCpNumber = oldFullPath.at(oldFullPath.size()-1).GetCopyNo();
3282  // ok
3283  } else {
3284  return false;
3285  }
3286  }
3287  }
3288 
3289  // Check copy Number
3290  if (oldCpNumber == -1) {
3291  oldCpNumber = parentOldItem->data(1,Qt::UserRole).toInt();
3292  }
3293  if (newCpNumber == -1) {
3294  newCpNumber = parentNewItem->data(1,Qt::UserRole).toInt();
3295  }
3296  if ((oldCpNumber != newCpNumber) ||
3297  // Check name
3298  (parentOldItem->text(0) != parentNewItem->text(0)) ) {
3299  // try to optimize
3300  return false;
3301  } else if ((parentOldItem->text(0) != parentNewItem->text(0)) || // Logical Name
3302  (parentOldItem->text(3) != parentNewItem->text(3))) { // Check logical name
3303  return false;
3304  } else {
3305  parentOldItem = parentOldItem->parent();
3306  parentNewItem = parentNewItem->parent();
3307  }
3308  } // end while
3309 
3310  return true;
3311 }
3312 
3313 
3314 void G4OpenGLQtViewer::addNonPVSceneTreeElement(
3315  const G4String& model
3316  ,int currentPOIndex
3317  ,const std::string& modelDescription
3318  ,const G4Visible& visible
3319 ) {
3320 
3321  QString modelShortName = getModelShortName(model);
3322  G4Colour color;
3323 
3324  // Special case for text
3325  try {
3326  const G4Text& g4Text = dynamic_cast<const G4Text&>(visible);
3327  color = fSceneHandler.GetTextColour(g4Text);
3328  }
3329  catch (const std::bad_cast&) {
3330  color = fSceneHandler.GetColour();
3331  }
3332  if (modelShortName == "") {
3333  return ;
3334  }
3335  // try to init it
3336  if (fSceneTreeComponentTreeWidget == NULL) {
3337  createSceneTreeComponent();
3338  }
3339 
3340  // if no UI
3341  if (fSceneTreeComponentTreeWidget == NULL) {
3342  return;
3343  }
3344 
3345  fSceneTreeComponentTreeWidget->blockSignals(true);
3346 
3347  // Create the "Model" node if not
3348 
3349  QList<QTreeWidgetItem *> resItem;
3350  resItem = fSceneTreeComponentTreeWidget->findItems (modelShortName, Qt::MatchExactly, 0 );
3351  QTreeWidgetItem * currentItem = NULL;
3352  const PVPath tmpFullPath;
3353 
3354  if (resItem.empty()) {
3355  currentItem = createTreeWidgetItem(tmpFullPath,
3356  modelShortName,
3357  0, // currentPVCopyNb
3358  -1, // currentPVPOIndex
3359  "",
3360  Qt::Checked,
3361  NULL,
3362  color);
3363  } else {
3364  currentItem = resItem.first();
3365  }
3366 
3367  // Is this volume already in the tree AND PO is not the same?
3368  const QList<QTreeWidgetItem *>&
3369  resItems = fSceneTreeComponentTreeWidget->findItems (QString(modelDescription.c_str()), Qt::MatchFixedString| Qt::MatchCaseSensitive|Qt::MatchRecursive, 0 );
3370 
3371  bool alreadyPresent = false;
3372  for (int i = 0; i < resItems.size(); ++i) {
3373  if (currentPOIndex == resItems.at(i)->data(0,Qt::UserRole).toInt()) {
3374  alreadyPresent = true;
3375  }
3376  }
3377  if (!alreadyPresent) {
3378  createTreeWidgetItem(tmpFullPath,
3379  QString(modelDescription.c_str()),
3380  0, // currentPVCopyNb
3381  currentPOIndex,
3382  "",
3383  Qt::Checked,
3384  currentItem,
3385  color);
3386  }
3387  fSceneTreeComponentTreeWidget->blockSignals(false);
3388 
3389 }
3390 
3391 
3395 QString G4OpenGLQtViewer::getModelShortName(const G4String& model) {
3396 
3397  QString modelShortName = model.data();
3398  if (modelShortName.mid(0,modelShortName.indexOf(" ")) == "G4PhysicalVolumeModel") {
3399  modelShortName = fTouchableVolumes;
3400  } else {
3401  if (modelShortName.mid(0,2) == "G4") {
3402  modelShortName = modelShortName.mid(2);
3403  }
3404  if (modelShortName.indexOf("Model") != -1) {
3405  modelShortName = modelShortName.mid(0,modelShortName.indexOf("Model"));
3406  }
3407  }
3408  return modelShortName;
3409 }
3410 
3411 
3412 
3413 bool G4OpenGLQtViewer::isTouchableVisible(int POindex){
3414 
3415  // If no scene tree (Immediate viewer)
3416  if (fSceneTreeComponentTreeWidget == NULL) {
3417  return false;
3418  }
3419 
3420  // should be the next one
3421  // Prevent to get out the std::map
3422  if (fLastSceneTreeWidgetAskForIterator != fLastSceneTreeWidgetAskForIteratorEnd) {
3423  fLastSceneTreeWidgetAskForIterator++;
3424  }
3425  QTreeWidgetItem* item = getTreeWidgetItem(POindex);
3426 
3427  if (item != NULL) {
3428  if ( item->checkState(0) == Qt::Checked) {
3429  return true;
3430  }
3431  }
3432  return false;
3433 }
3434 
3435 
3436 bool G4OpenGLQtViewer::parseAndCheckVisibility(QTreeWidgetItem * treeNode,int POindex){
3437  bool isFound = false;
3438  for (int i = 0; i < treeNode->childCount() ; ++i) {
3439 
3440  if (treeNode->child(i)->data(0,Qt::UserRole).toInt() == POindex) {
3441  if (treeNode->child(i)->checkState(0) == Qt::Checked) {
3442  return true;
3443  }
3444  }
3445  isFound = parseAndCheckVisibility(treeNode->child(i),POindex);
3446  if (isFound) {
3447  return true;
3448  }
3449  } // end for
3450  return false;
3451 }
3452 
3453 
3454 std::string G4OpenGLQtViewer::parseSceneTreeAndSaveState(){
3455  std::string commandLine = "";
3456  for (int b=0;b<fSceneTreeComponentTreeWidget->topLevelItemCount();b++) {
3457  commandLine += parseSceneTreeElementAndSaveState(fSceneTreeComponentTreeWidget->topLevelItem(b),1)+"\n";
3458  }
3459  if (commandLine != "") {
3460  commandLine = std::string("# Disable auto refresh and quieten vis messages whilst scene and\n") +
3461  "# trajectories are established:\n" +
3462  "/vis/viewer/set/autoRefresh false\n" +
3463  "/vis/verbose errors" +
3464  commandLine +
3465  "# Re-establish auto refreshing and verbosity:\n" +
3466  "/vis/viewer/set/autoRefresh true\n" +
3467  "/vis/verbose confirmations\n";
3468  }
3469  return commandLine;
3470 }
3471 
3472 
3473 std::string G4OpenGLQtViewer::parseSceneTreeElementAndSaveState(QTreeWidgetItem* item, unsigned int level){
3474  // parse current item
3475  std::string str( level, ' ' );
3476  std::string commandLine = "\n#"+ str + "PV Name: " + item->text(0).toStdString();
3477 
3478  if (item->text(3) != "") {
3479  commandLine += " LV Name: "+item->text(3).toStdString()+"\n";
3480  // save check state
3481  commandLine += "/vis/geometry/set/visibility " + item->text(3).toStdString() + " ! "; // let default value for depth
3482  if (item->checkState(0) == Qt::Checked) {
3483  commandLine += "1";
3484  }
3485  if (item->checkState(0) == Qt::Unchecked) {
3486  commandLine += "0";
3487  }
3488  commandLine +="\n";
3489 
3490  // save color
3491  const QColor& c = item->data(2,Qt::UserRole).value<QColor>();
3492  std::stringstream red;
3493  red << ((double)c.red())/255;
3494  std::stringstream green;
3495  green << (double)c.green()/255;
3496  std::stringstream blue;
3497  blue << ((double)c.blue())/255;
3498  std::stringstream alpha;
3499  alpha << ((double)c.alpha())/255;
3500 
3501  commandLine += "/vis/geometry/set/colour " + item->text(3).toStdString() + " ! " + red.str() + " " + green.str() + " " + blue.str() + " " + alpha.str()+"\n";
3502 
3503  } else {
3504  commandLine += "\n";
3505  }
3506 
3507  // parse childs
3508  for (int b=0;b< item->childCount();b++) {
3509  commandLine += parseSceneTreeElementAndSaveState(item->child(b),level+1);
3510  }
3511 
3512  return commandLine;
3513 }
3514 
3515 
3516 void G4OpenGLQtViewer::sceneTreeComponentItemChanged(QTreeWidgetItem* item, int) {
3517 
3518  if (fCheckSceneTreeComponentSignalLock == false) {
3519  fCheckSceneTreeComponentSignalLock = true;
3520  G4bool checked = false;
3521  if (item->checkState(0) == Qt::Checked) {
3522  checked = true;
3523  }
3524  setCheckComponent(item,checked);
3525  updateQWidget();
3526 
3527  fCheckSceneTreeComponentSignalLock = false;
3528  }
3529 }
3530 
3531 
3532 void G4OpenGLQtViewer::sceneTreeComponentSelected() {
3533 }
3534 
3535 void G4OpenGLQtViewer::changeDepthInSceneTree (int val){
3536 
3537  // If no scene tree (Immediate viewer)
3538  if (fSceneTreeComponentTreeWidget == NULL) {
3539  return;
3540  }
3541 
3542  // max depth : fSceneTreeDepth
3543  // val is between 0 and 1
3544  // 0 .1 .2 .3 .4 .5 .6 .7 .8 .9 1
3545  // 1 1.4 2
3546  // 1 2 3 4
3547 
3548  // Get the depth :
3549  double depth = 1 + ((double)val)/1000 * ((double)fSceneTreeDepth+1);
3550 
3551  // lock update on scene tree items
3552  fCheckSceneTreeComponentSignalLock = true;
3553 
3554  // Disable redraw each time !
3555  G4bool currentAutoRefresh = fVP.IsAutoRefresh();
3556  fVP.SetAutoRefresh(false);
3557 
3558  for (int b=0;b<fSceneTreeComponentTreeWidget->topLevelItemCount();b++) {
3559  changeDepthOnSceneTreeItem(depth,1.,fSceneTreeComponentTreeWidget->topLevelItem(b));
3560  }
3561 
3562  // Enable redraw !
3563  fVP.SetAutoRefresh(currentAutoRefresh);
3564  updateQWidget();
3565 
3566  // unlock update on scene tree items
3567  fCheckSceneTreeComponentSignalLock = false;
3568 
3569 }
3570 
3571 
3572 void G4OpenGLQtViewer::changeColorAndTransparency(QTreeWidgetItem* item,int) {
3573 
3574  if (item == NULL) {
3575  return;
3576  }
3577  const QColor& old = QColor(item->data(2,Qt::UserRole).value<QColor>());
3578 
3579 #if QT_VERSION < 0x040500
3580  bool a;
3581  const QColor& color = QColor(QColorDialog::getRgba (old.rgba(),&a,fSceneTreeComponentTreeWidget));
3582 #else
3583  const QColor& color = QColorDialog::getColor(old,
3584  fSceneTreeComponentTreeWidget,
3585  " Get color and transparency",
3586  QColorDialog::ShowAlphaChannel);
3587 #endif
3588 
3589  if (color.isValid()) {
3590 
3591  changeColorAndTransparency(item->data(0,Qt::UserRole).toInt(),
3592  G4Colour (((G4double)color.red())/255,
3593  ((G4double)color.green())/255,
3594  ((G4double)color.blue())/255,
3595  ((G4double)color.alpha())/255));
3596 
3597  // set scene tree parameters
3598  changeQColorForTreeWidgetItem(item,color);
3599  }
3600 }
3601 
3602 
3603 void G4OpenGLQtViewer::changeColorAndTransparency(GLuint index, G4Color color) {
3604 
3605  // change vis attributes to set new colour
3606  G4int iPO = index;
3607  if (iPO >= 0 && fTreeItemModels.find(iPO) != fTreeItemModels.end()) {
3608  const PVPath& fullPath = fTreeItemModels[iPO];
3609  // If a physical volume
3610  if (fullPath.size()) {
3611  SetTouchable(fullPath);
3612  TouchableSetColour(fullPath, color);
3613  fMouseOnSceneTree = true;
3614  }
3615  }
3616 }
3617 
3618 
3619 G4Colour G4OpenGLQtViewer::getColorForPoIndex(int poIndex) {
3620  // FIXME 09/2014 : Could be optimize by searching in a tab instead of item->data
3621  QTreeWidgetItem* item = getTreeWidgetItem(poIndex);
3622 
3623  if (item != NULL) {
3624 
3625  const QColor& color = item->data(2,Qt::UserRole).value<QColor>();
3626  G4Colour g4c(((G4double)color.red())/255,
3627  ((G4double)color.green())/255,
3628  ((G4double)color.blue())/255,
3629  ((G4double)color.alpha())/255);
3630 
3631  return g4c;
3632  }
3633  return G4Colour();
3634 }
3635 
3636 
3637 const std::vector<G4ModelingParameters::VisAttributesModifier>*
3638 G4OpenGLQtViewer::GetPrivateVisAttributesModifiers() const
3639 {
3640  static std::vector<G4ModelingParameters::VisAttributesModifier>
3641  privateVisAttributesModifiers;
3642 
3643  privateVisAttributesModifiers.clear();
3644 
3645 // I don't think we need this. (JA Sep 2016).
3646 // // For each modified touchable...
3647 // std::map<int,PVPath>::const_iterator i;
3648 // for (i = fTreeItemModels.begin();
3649 // i != fTreeItemModels.end();
3650 // ++i) {
3651 //
3652 // // How do I know if it's been modified or not?
3653 //
3654 // int iPO = i->first;
3655 // const PVPath& fullPath = i->second;
3656 //
3657 // // If a physical volume
3658 // if (fullPath.size()) {
3659 //
3660 // // const G4bool& visibilityChanged = ???
3661 // // const G4bool& visibility = ???
3662 // // const G4bool& colourChanged = ???
3663 // // const QColor& colour = ???
3664 // // G4Colour g4colour(((G4double)colour.red())/255,
3665 // // ((G4double)colour.green())/255,
3666 // // ((G4double)colour.blue())/255,
3667 // // ((G4double)colour.alpha())/255);
3668 // // Next 4 lines are for testing, to be replaced by the above...
3669 // G4bool visibilityChanged = true;
3670 // G4bool visibility = true;
3671 // G4bool colourChanged = true;
3672 // G4Colour g4colour(G4Colour::Red());
3673 //
3674 // // Instantiate a working copy of a G4VisAttributes object...
3675 // G4VisAttributes workingVisAtts;
3676 // // ...and use it to create vis attribute modifiers...
3677 // if (visibilityChanged) {
3678 // workingVisAtts.SetVisibility(visibility);
3679 // privateVisAttributesModifiers.push_back
3680 // (G4ModelingParameters::VisAttributesModifier
3681 // (workingVisAtts,
3682 // G4ModelingParameters::VASVisibility,
3683 // fullPath));
3684 // }
3685 // if (colourChanged) {
3686 // workingVisAtts.SetColour(g4colour);
3687 // privateVisAttributesModifiers.push_back
3688 // (G4ModelingParameters::VisAttributesModifier
3689 // (workingVisAtts,
3690 // G4ModelingParameters::VASColour,
3691 // fullPath));
3692 // }
3693 // }
3694 // }
3695 
3696  return &privateVisAttributesModifiers;
3697 }
3698 
3699 
3700 void G4OpenGLQtViewer::changeSearchSelection()
3701 {
3702  const QString& searchText = fFilterOutput->text();
3703  if (fSceneTreeComponentTreeWidget == NULL) {
3704  return;
3705  }
3706 
3707  // unselect all
3708  for (int a=0; a<fSceneTreeComponentTreeWidget->topLevelItemCount(); a++) {
3709  fSceneTreeComponentTreeWidget->topLevelItem(a)->setExpanded(false);
3710  fSceneTreeComponentTreeWidget->topLevelItem(a)->setSelected(false);
3711  clearSceneTreeSelection(fSceneTreeComponentTreeWidget->topLevelItem(a));
3712  }
3713 
3714  QList<QTreeWidgetItem *> itemList = fSceneTreeComponentTreeWidget->findItems (searchText,Qt::MatchContains | Qt::MatchRecursive,0);
3715 
3716  for (int i = 0; i < itemList.size(); ++i) {
3717  QTreeWidgetItem* expandParentItem = itemList.at(i);
3718  while (expandParentItem->parent() != NULL) {
3719  expandParentItem->parent()->setExpanded(true);
3720  expandParentItem = expandParentItem->parent();
3721  }
3722  itemList.at(i)->setSelected(true);
3723  }
3724 
3725 }
3726 
3727 
3728 void G4OpenGLQtViewer::clearSceneTreeSelection(QTreeWidgetItem* item) {
3729  for (int a=0; a<item->childCount(); a++) {
3730  item->child(a)->setSelected(false);
3731  item->child(a)->setExpanded(false);
3732  clearSceneTreeSelection(item->child(a));
3733  }
3734 
3735 }
3736 
3737 
3738 bool G4OpenGLQtViewer::isPVVolume(QTreeWidgetItem* item) {
3739  QTreeWidgetItem* sParent = item;
3740  while (sParent->parent() != NULL) {
3741  sParent = sParent->parent();
3742  }
3743  if (sParent->text(0) != fTouchableVolumes) {
3744  return false;
3745  }
3746  // item is the "Touchable" node
3747  if (item->text(0) == fTouchableVolumes) {
3748  return false;
3749  }
3750  return true;
3751 }
3752 
3753 
3754 void G4OpenGLQtViewer::changeDepthOnSceneTreeItem(
3755  double lookForDepth
3756  ,double currentDepth
3757  ,QTreeWidgetItem* item
3758 ) {
3759  double transparencyLevel = 0.;
3760 
3761  // look for a 2.2 depth and we are at level 3
3762  // -> Set all theses items to Opaque
3763  // ONLY if it is a PV volume !
3764  if (isPVVolume(item)) {
3765  if ((lookForDepth-currentDepth) < 0) {
3766  item->setCheckState(0,Qt::Checked);
3767  updatePositivePoIndexSceneTreeWidgetQuickMap(item->data(0,Qt::UserRole).toInt(),item);
3768  transparencyLevel = 1;
3769  } else if ((lookForDepth-currentDepth) > 1 ){
3770  item->setCheckState(0,Qt::Unchecked);
3771  updatePositivePoIndexSceneTreeWidgetQuickMap(item->data(0,Qt::UserRole).toInt(),item);
3772  transparencyLevel = 0;
3773  } else {
3774  item->setCheckState(0,Qt::Checked);
3775  updatePositivePoIndexSceneTreeWidgetQuickMap(item->data(0,Qt::UserRole).toInt(),item);
3776  transparencyLevel = 1-(lookForDepth-currentDepth);
3777  }
3778  }
3779 
3780  if (item->data(0,Qt::UserRole).toInt() >= 0) {
3781  const G4Colour& color = getColorForPoIndex(item->data(0,Qt::UserRole).toInt());
3782 
3783  // We are less depper (ex:tree depth:2) than lookForDepth (ex:3.1)
3784  // -> Have to hide this level ONLY if it was not hidden before
3785 
3786  // Not on a top level item case
3787  // Do not set if it was already set
3788 
3789  // Should add them all the time in case of an older command has change transparency
3790  // before. Should be checked in changeDepthInSceneTree for duplicated commands
3791  // Do not change transparency if not visible by humain (and avoid precision value
3792  // problems..)
3793  if (((color.GetAlpha()-transparencyLevel) > 0.000001) ||
3794  ((color.GetAlpha()-transparencyLevel) < -0.000001)) {
3795  if ((item->text(3) != "")) {
3796  // FIXME : Should not test this here because of transparent
3797  // volume that will came after and with a different alpha level
3798  // Good thing to do is to check and suppress doubles in changeDepthInSceneTree
3799  // and then check if last (transparents volumes) has to change alpha
3800 
3801  changeQColorForTreeWidgetItem(item,QColor((int)(color.GetRed()*255),
3802  (int)(color.GetGreen()*255),
3803  (int)(color.GetBlue()*255),
3804  (int)(transparencyLevel*255)));
3805  }
3806  }
3807  }
3808 
3809  for (int b=0;b< item->childCount();b++) {
3810  changeDepthOnSceneTreeItem(lookForDepth,currentDepth+1,item->child(b));
3811  }
3812 }
3813 
3814 
3815 void G4OpenGLQtViewer::clearTreeWidget(){
3816  // be careful about calling this twice
3817 
3818  if (fSceneTreeComponentTreeWidget) {
3819 
3820  if (fSceneTreeComponentTreeWidget->topLevelItemCount () > 0) {
3821 
3822  fPVRootNodeCreate = false;
3823 
3824  // reset all old
3825  fOldPositivePoIndexSceneTreeWidgetQuickMap.clear();
3826  fOldNullPoIndexSceneTreeWidgetQuickVector.clear();
3827  fOldTreeItemModels.clear();
3828 
3829  // Clone everything
3830  for (int b =0; b <fSceneTreeComponentTreeWidget->topLevelItemCount();b++) {
3831  // All tree widgets are in :
3832  // then we could get the old POindex and get
3833  // .visible/Hidden
3834  // .Check/Uncheck
3835  // .selected
3836  // .colour status from std::map
3837 
3838  // clone top level items
3839  int poIndex = fSceneTreeComponentTreeWidget->topLevelItem(b)->data(0,Qt::UserRole).toInt();
3840  if (poIndex != -1) {
3841  fOldPositivePoIndexSceneTreeWidgetQuickMap.insert(std::pair <int, QTreeWidgetItem*> (poIndex,cloneWidgetItem(fSceneTreeComponentTreeWidget->topLevelItem(b))));
3842  } else {
3843  fOldNullPoIndexSceneTreeWidgetQuickVector.push_back(cloneWidgetItem(fSceneTreeComponentTreeWidget->topLevelItem(b)));
3844  }
3845 
3846  // clone leaves
3847  cloneSceneTree(fSceneTreeComponentTreeWidget->topLevelItem(b));
3848  }
3849  // delete all elements
3850 
3851  fOldTreeItemModels.insert(fTreeItemModels.begin(), fTreeItemModels.end());
3852 
3853  // all is copy, then clear scene tree
3854  int tmp2 = fSceneTreeComponentTreeWidget->topLevelItemCount();
3855  while (tmp2 > 0) {
3856  delete fSceneTreeComponentTreeWidget->takeTopLevelItem (0);
3857  tmp2 = fSceneTreeComponentTreeWidget->topLevelItemCount();
3858  }
3859  fPositivePoIndexSceneTreeWidgetQuickMap.clear();
3860 
3861  // put correct value in paramaters
3862  fOldLastSceneTreeWidgetAskForIterator = fOldPositivePoIndexSceneTreeWidgetQuickMap.begin();
3863  fOldLastSceneTreeWidgetAskForIteratorEnd = fOldPositivePoIndexSceneTreeWidgetQuickMap.end();
3864  fSceneTreeDepth = 1;
3865  fModelShortNameItem = NULL;
3866  fMaxPOindexInserted = -1;
3867 
3868  }
3869  }
3870 }
3871 
3872 
3879 QTreeWidgetItem * G4OpenGLQtViewer::cloneWidgetItem(QTreeWidgetItem* item) {
3880 
3881  QTreeWidgetItem* cloneItem = new QTreeWidgetItem();
3882 
3883  // Clone what is create createTreeWidgetItem step
3884 
3885  cloneItem->setText(0,item->text(0));
3886  cloneItem->setData(1,Qt::UserRole,item->data(1,Qt::UserRole).toInt());
3887  cloneItem->setText(2,item->text(2));
3888  cloneItem->setData(0, Qt::UserRole,item->data(0,Qt::UserRole).toInt());
3889  cloneItem->setText(3,item->text(3));
3890  cloneItem->setFlags(item->flags());
3891  cloneItem->setToolTip(0,item->toolTip(0));
3892  cloneItem->setCheckState(0,item->checkState(0));
3893  cloneItem->setSelected(item->isSelected());
3894  cloneItem->setExpanded(item->isExpanded ());
3895 
3896  cloneItem->setData(2,Qt::UserRole,item->data(2,Qt::UserRole).value<QColor>());
3897 
3898  return cloneItem;
3899 }
3900 
3901 
3905 void G4OpenGLQtViewer::cloneSceneTree(
3906  QTreeWidgetItem* rootItem
3907 ) {
3908 
3909  for (int b=0;b< rootItem->childCount();b++) {
3910 
3911  QTreeWidgetItem *child = rootItem->child(b);
3912 
3913  // clone top level items
3914  int poIndex = child->data(0,Qt::UserRole).toInt();
3915  if (poIndex != -1) {
3916  fOldPositivePoIndexSceneTreeWidgetQuickMap.insert(std::pair <int, QTreeWidgetItem*> (poIndex,cloneWidgetItem(child)));
3917  } else {
3918  fOldNullPoIndexSceneTreeWidgetQuickVector.push_back(cloneWidgetItem(child));
3919  }
3920  cloneSceneTree(child);
3921  }
3922 }
3923 
3924 
3928  void G4OpenGLQtViewer::updatePositivePoIndexSceneTreeWidgetQuickMap(int POindex,QTreeWidgetItem* item) {
3929 
3930  // Check state
3931  std::map <int, QTreeWidgetItem*>::iterator i;
3932  i = fPositivePoIndexSceneTreeWidgetQuickMap.find(POindex);
3933 
3934  if (i == fPositivePoIndexSceneTreeWidgetQuickMap.end()) {
3935  fPositivePoIndexSceneTreeWidgetQuickMap.insert(std::pair <int, QTreeWidgetItem*> (POindex,item) );
3936  fLastSceneTreeWidgetAskForIterator = fPositivePoIndexSceneTreeWidgetQuickMap.end();
3937  fLastSceneTreeWidgetAskForIteratorEnd = fPositivePoIndexSceneTreeWidgetQuickMap.end();
3938  } else {
3939  i->second = item;
3940  }
3941  }
3942 
3943 
3944 
3945 void G4OpenGLQtViewer::changeQColorForTreeWidgetItem(QTreeWidgetItem* item,const QColor& qc) {
3946 
3947  int POIndex = item->data(0,Qt::UserRole).toInt();
3948  updatePositivePoIndexSceneTreeWidgetQuickMap(POIndex,item );
3949 
3950  QPixmap pixmap = QPixmap(QSize(16, 16));
3951  if (item->data(0,Qt::UserRole).toInt() != -1) {
3952  pixmap.fill (qc);
3953  } else {
3954  pixmap.fill (QColor(255,255,255,255));
3955  }
3956  QPainter painter(&pixmap);
3957  painter.setPen(Qt::black);
3958  painter.drawRect(0,0,15,15); // Draw contour
3959 
3960  item->setIcon(0,pixmap);
3961  item->setData(2,Qt::UserRole,qc);
3962 }
3963 
3964 
3965 
3970 QTreeWidgetItem* G4OpenGLQtViewer::getTreeWidgetItem(int POindex){
3971 
3972  // -1 is not a visible item
3973  if (POindex == -1) {
3974  return NULL;
3975  }
3976 
3977  if (fPositivePoIndexSceneTreeWidgetQuickMap.size() == 0){
3978  return NULL;
3979  }
3980 
3981  if (fLastSceneTreeWidgetAskForIterator != fLastSceneTreeWidgetAskForIteratorEnd) {
3982  if (POindex == fLastSceneTreeWidgetAskForIterator->first) {
3983  if (fLastSceneTreeWidgetAskForIterator->second != NULL) {
3984  return fLastSceneTreeWidgetAskForIterator->second;
3985  }
3986  }
3987  }
3988 
3989  // if not, use the "find" algorithm
3990  fLastSceneTreeWidgetAskForIterator = fPositivePoIndexSceneTreeWidgetQuickMap.find(POindex);
3991  fLastSceneTreeWidgetAskForIteratorEnd = fPositivePoIndexSceneTreeWidgetQuickMap.end();
3992 
3993  if (fLastSceneTreeWidgetAskForIterator != fPositivePoIndexSceneTreeWidgetQuickMap.end()) {
3994  return fLastSceneTreeWidgetAskForIterator->second;
3995  }
3996  return NULL;
3997 }
3998 
4003 QTreeWidgetItem* G4OpenGLQtViewer::getOldTreeWidgetItem(int POindex){
4004 
4005 
4006  // -1 is not a visible item
4007  if (POindex == -1) {
4008  return NULL;
4009  }
4010 
4011  if (fOldPositivePoIndexSceneTreeWidgetQuickMap.size() == 0){
4012  return NULL;
4013  }
4014 
4015  // Should be call only once by item addition
4016  // Prevent to get out the std::map
4017  if (fOldLastSceneTreeWidgetAskForIterator != fOldLastSceneTreeWidgetAskForIteratorEnd) {
4018  fOldLastSceneTreeWidgetAskForIterator++;
4019  }
4020 
4021  if (fOldLastSceneTreeWidgetAskForIterator != fOldPositivePoIndexSceneTreeWidgetQuickMap.end()) {
4022  if (POindex == fOldLastSceneTreeWidgetAskForIterator->first) {
4023  if (fOldLastSceneTreeWidgetAskForIterator->second != NULL) {
4024  return fOldLastSceneTreeWidgetAskForIterator->second;
4025  }
4026  }
4027  }
4028 
4029  // if not, use the "find" algorithm
4030  fOldLastSceneTreeWidgetAskForIterator = fOldPositivePoIndexSceneTreeWidgetQuickMap.find(POindex);
4031  fOldLastSceneTreeWidgetAskForIteratorEnd = fOldPositivePoIndexSceneTreeWidgetQuickMap.end();
4032 
4033  if (fOldLastSceneTreeWidgetAskForIterator != fOldPositivePoIndexSceneTreeWidgetQuickMap.end()) {
4034  return fOldLastSceneTreeWidgetAskForIterator->second;
4035  }
4036  return NULL;
4037 }
4038 
4039 
4040 
4045 void G4OpenGLQtViewer::displaySceneTreeComponent() {
4046  // no UI
4047  if (fUISceneTreeWidget == NULL) {
4048  return;
4049  }
4050  if (fSceneTreeComponentTreeWidget == NULL) {
4051  return;
4052  }
4053 
4054  // sort tree items
4055  fSceneTreeComponentTreeWidget->sortItems (0, Qt::AscendingOrder );
4056 
4057  return;
4058 }
4059 
4060 
4067 void G4OpenGLQtViewer::updateToolbarAndMouseContextMenu(){
4068  if (fBatchMode) {
4069  return;
4070  }
4071 
4073  d_style = fVP.GetDrawingStyle();
4074 
4075  // Surface style
4076  if (d_style == G4ViewParameters::wireframe) {
4077  if (fUiQt) fUiQt->SetIconWireframeSelected();
4078  if (fContextMenu) {
4079  fDrawingWireframe->setChecked(true);
4080  fDrawingLineRemoval->setChecked(false);
4081  fDrawingSurfaceRemoval->setChecked(false);
4082  fDrawingLineSurfaceRemoval->setChecked(false);
4083  }
4084  } else if (d_style == G4ViewParameters::hlr) {
4085  if (fUiQt) fUiQt->SetIconHLRSelected();
4086  if (fContextMenu) {
4087  fDrawingLineRemoval->setChecked(true);
4088  fDrawingWireframe->setChecked(false);
4089  fDrawingSurfaceRemoval->setChecked(false);
4090  fDrawingLineSurfaceRemoval->setChecked(false);
4091  }
4092  } else if (d_style == G4ViewParameters::hsr) {
4093  if (fUiQt) fUiQt->SetIconSolidSelected();
4094  if (fContextMenu) {
4095  fDrawingSurfaceRemoval->setChecked(true);
4096  fDrawingWireframe->setChecked(false);
4097  fDrawingLineRemoval->setChecked(false);
4098  fDrawingLineSurfaceRemoval->setChecked(false);
4099  }
4100  } else if (d_style == G4ViewParameters::hlhsr) {
4101  if (fUiQt) fUiQt->SetIconHLHSRSelected();
4102  if (fContextMenu) {
4103  fDrawingLineSurfaceRemoval->setChecked(true);
4104  fDrawingWireframe->setChecked(false);
4105  fDrawingLineRemoval->setChecked(false);
4106  fDrawingSurfaceRemoval->setChecked(false);
4107  fDrawingLineSurfaceRemoval->setChecked(false);
4108  }
4109  }
4110 
4111 
4112  // projection style
4113  G4double d_proj = fVP.GetFieldHalfAngle () ;
4114  if (d_proj == 0.) { // ortho
4115  if (fUiQt) fUiQt->SetIconOrthoSelected();
4116  if (fContextMenu) {
4117  fProjectionOrtho->setChecked(true);
4118  fProjectionPerspective->setChecked(false);
4119  }
4120  } else {
4121  if (fUiQt) fUiQt->SetIconPerspectiveSelected();
4122  if (fContextMenu) {
4123  fProjectionPerspective->setChecked(true);
4124  fProjectionOrtho->setChecked(false);
4125  }
4126  }
4127 
4128 
4129  // mouse style : They are controlled by UI !
4130  if (fUiQt && fContextMenu) {
4131  if (fUiQt->IsIconPickSelected()) {
4132  fMousePickAction->setChecked(true);
4133  fMouseZoomOutAction->setChecked(false);
4134  fMouseZoomInAction->setChecked(false);
4135  fMouseRotateAction->setChecked(false);
4136  fMouseMoveAction->setChecked(false);
4137  } else if (fUiQt->IsIconZoomOutSelected()) {
4138  fMouseZoomOutAction->setChecked(true);
4139  fMousePickAction->setChecked(false);
4140  fMouseZoomInAction->setChecked(false);
4141  fMouseRotateAction->setChecked(false);
4142  fMouseMoveAction->setChecked(false);
4143  } else if (fUiQt->IsIconZoomInSelected()) {
4144  fMouseZoomInAction->setChecked(true);
4145  fMousePickAction->setChecked(false);
4146  fMouseZoomOutAction->setChecked(false);
4147  fMouseRotateAction->setChecked(false);
4148  fMouseMoveAction->setChecked(false);
4149  } else if (fUiQt->IsIconRotateSelected()) {
4150  fMouseRotateAction->setChecked(true);
4151  fMousePickAction->setChecked(false);
4152  fMouseZoomOutAction->setChecked(false);
4153  fMouseZoomInAction->setChecked(false);
4154  fMouseMoveAction->setChecked(false);
4155  } else if (fUiQt->IsIconMoveSelected()) {
4156  fMouseMoveAction->setChecked(true);
4157  fMousePickAction->setChecked(false);
4158  fMouseZoomOutAction->setChecked(false);
4159  fMouseZoomInAction->setChecked(false);
4160  fMouseRotateAction->setChecked(false);
4161  }
4162  }
4163 }
4164 
4168 void G4OpenGLQtViewer::updateSceneTreeWidget() {
4169  // Ensure case where closing a UI tab close the widget
4170  if (!fSceneTreeWidget) {
4171  createSceneTreeWidget();
4172  }
4173 }
4174 
4175 
4180 void G4OpenGLQtViewer::updateViewerPropertiesTableWidget() {
4181 
4182  if (!isCurrentWidget()) {
4183  return;
4184  }
4185 
4186  // Ensure case where closing a UI tab close the widget
4187  if (!fViewerPropertiesTableWidget) {
4188  createViewerPropertiesWidget();
4189  }
4190  int treeWidgetInfosIgnoredCommands = 0;
4192  G4UIcommandTree * commandTreeTop = UI->GetTree();
4193  G4UIcommandTree* path = commandTreeTop->FindCommandTree("/vis/viewer/set/");
4194 
4195  if (!path) {
4196  return;
4197  }
4198 
4199  // clear old table
4200  if ((path->GetCommandEntry()-fTreeWidgetInfosIgnoredCommands) != fViewerPropertiesTableWidget->rowCount()) {
4201  fViewerPropertiesTableWidget->clear();
4202  }
4203 
4204  fViewerPropertiesTableWidget->blockSignals(true);
4205  // TODO : Could be optimized by comparing current command to old commands. That should not change so much
4206 
4207  fViewerPropertiesTableWidget->setColumnCount (2);
4208  fViewerPropertiesTableWidget->setRowCount (path->GetCommandEntry()-fTreeWidgetInfosIgnoredCommands);
4209  fViewerPropertiesTableWidget->setHorizontalHeaderLabels(QStringList() << tr("Property")
4210  << tr("Value"));
4211  fViewerPropertiesTableWidget->verticalHeader()->setVisible(false);
4212  fViewerPropertiesTableWidget->setAlternatingRowColors (true);
4213 
4214  // For the moment, we do only command that have a "set" command in UI
4215 
4216  for (int a=0;a<path->GetCommandEntry();a++) {
4217  G4UIcommand* commandTmp = path->GetCommand(a+1);
4218 
4219  // get current parameters
4220  QString params = "";
4221 
4222  if(commandTmp->GetCommandName() == "autoRefresh") {
4223  if (fVP.IsAutoRefresh()) {
4224  params = "True";
4225  } else {
4226  params = "False";
4227  }
4228  } else if(commandTmp->GetCommandName() == "auxiliaryEdge") {
4229  if (fVP.IsAuxEdgeVisible()) {
4230  params = "True";
4231  } else {
4232  params = "False";
4233  }
4234  } else if(commandTmp->GetCommandName() == "background") {
4235  params = QString().number(fVP.GetBackgroundColour().GetRed()) + " "+
4236  QString().number(fVP.GetBackgroundColour().GetGreen()) + " "+
4237  QString().number(fVP.GetBackgroundColour().GetBlue()) + " "+
4238  QString().number(fVP.GetBackgroundColour().GetAlpha());
4239 
4240  } else if(commandTmp->GetCommandName() == "culling") {
4241  params = QString().number(fVP. IsCulling ());
4242  } else if(commandTmp->GetCommandName() == "cutawayMode") {
4243  if (fVP.GetCutawayMode() == G4ViewParameters::cutawayUnion) {
4244  params = "union";
4245  } else {
4246  params = "intersection";
4247  }
4248 
4249  } else if(commandTmp->GetCommandName() == "defaultColour") {
4250  params = QString().number(fVP.GetDefaultVisAttributes()->GetColor().GetRed()) + " "+
4251  QString().number(fVP.GetDefaultVisAttributes()->GetColor().GetGreen()) + " "+
4252  QString().number(fVP.GetDefaultVisAttributes()->GetColor().GetBlue()) + " "+
4253  QString().number(fVP.GetDefaultVisAttributes()->GetColor().GetAlpha());
4254 
4255  } else if(commandTmp->GetCommandName() == "defaultTextColour") {
4256  params = QString().number(fVP.GetDefaultTextVisAttributes()->GetColor().GetRed()) + " "+
4257  QString().number(fVP.GetDefaultTextVisAttributes()->GetColor().GetGreen()) + " "+
4258  QString().number(fVP.GetDefaultTextVisAttributes()->GetColor().GetBlue()) + " "+
4259  QString().number(fVP.GetDefaultTextVisAttributes()->GetColor().GetAlpha());
4260 
4261  } else if(commandTmp->GetCommandName() == "edge") {
4262  G4ViewParameters::DrawingStyle existingStyle = fVP.GetDrawingStyle();
4263  params = "False";
4264  if (existingStyle == G4ViewParameters::hsr) {
4265  params = "True";
4266  }
4267 
4268  } else if(commandTmp->GetCommandName() == "explodeFactor") {
4269  params = QString().number(fVP.GetExplodeFactor()) + " " + QString(G4String(G4BestUnit(fVP.GetExplodeFactor(),"Length")).data());
4270 
4271  } else if(commandTmp->GetCommandName() == "globalLineWidthScale") {
4272  params = QString().number(fVP.GetGlobalLineWidthScale());
4273 
4274  } else if(commandTmp->GetCommandName() == "globalMarkerScale") {
4275  params = QString().number(fVP.GetGlobalMarkerScale());
4276 
4277  } else if(commandTmp->GetCommandName() == "hiddenEdge") {
4278  G4ViewParameters::DrawingStyle style = fVP.GetDrawingStyle();
4279  if ((style == G4ViewParameters::hlr) ||
4280  (style == G4ViewParameters::hlhsr)) {
4281  params = "True";
4282  } else {
4283  params = "False";
4284  }
4285 
4286  } else if(commandTmp->GetCommandName() == "hiddenMarker") {
4287  if (fVP.IsMarkerNotHidden()) {
4288  params = "False";
4289  } else {
4290  params = "True";
4291  }
4292 
4293  } else if(commandTmp->GetCommandName() == "lightsMove") {
4294  if (fVP.GetLightsMoveWithCamera()) {
4295  params = "camera";
4296  } else {
4297  params = "object";
4298  }
4299  } else if(commandTmp->GetCommandName() == "lightsThetaPhi") {
4300  G4Vector3D direction = fVP.GetLightpointDirection();
4301  // degree
4302  params = QString().number(direction.theta()/CLHEP::degree)+ " "+ QString().number(direction.phi()/CLHEP::degree)+" deg";
4303  if (commandTmp->GetParameterEntries() == 3) {
4304  if (commandTmp->GetParameter(2)->GetDefaultValue() != "deg") {
4305  params = QString().number(direction.theta())+ " "+ QString().number(direction.phi())+" "+commandTmp->GetParameter(2)->GetDefaultValue().data();
4306  }
4307  }
4308  } else if(commandTmp->GetCommandName() == "lightsVector") {
4309  params = QString().number(fVP.GetLightpointDirection().x()) + " "+
4310  QString().number(fVP.GetLightpointDirection().y()) + " "+
4311  QString().number(fVP.GetLightpointDirection().z());
4312 
4313  } else if(commandTmp->GetCommandName() == "lineSegmentsPerCircle") {
4314  params = QString().number(fVP.GetNoOfSides());
4315 
4316  } else if(commandTmp->GetCommandName() == "picking") {
4317  if (fVP.IsPicking()) {
4318  params = "True";
4319  } else {
4320  params = "False";
4321  }
4322 
4323  } else if(commandTmp->GetCommandName() == "projection") {
4324  if (fVP.GetFieldHalfAngle() == 0.) {
4325  params = "orthogonal";
4326  } else {
4327  params = QString("perspective ") + QString().number(fVP.GetFieldHalfAngle()/CLHEP::degree) + " deg";
4328  }
4329 
4330  } else if(commandTmp->GetCommandName() == "rotationStyle") {
4331  if (fVP.GetRotationStyle() == G4ViewParameters::constrainUpDirection) {
4332  params = "constrainUpDirection";
4333  } else {
4334  params = "freeRotation";
4335  }
4336 
4337  } else if(commandTmp->GetCommandName() == "sectionPlane") {
4338  if (fVP.IsSection()) {
4339  params = QString("on ") +
4340  G4String(G4BestUnit(fVP.GetSectionPlane().point(),"Length")).data()+
4341  QString().number(fVP.GetSectionPlane().normal().x())
4342  + " " + QString().number(fVP.GetSectionPlane().normal().y())
4343  + " " + QString().number(fVP.GetSectionPlane().normal().z());
4344  } else {
4345  params = "off";
4346  }
4347 
4348  } else if(commandTmp->GetCommandName() == "style") {
4349  if (fVP.GetDrawingStyle() == G4ViewParameters::wireframe || fVP.GetDrawingStyle() == G4ViewParameters::hlr) {
4350  params = "wireframe";
4351  } else {
4352  params = "surface";
4353  }
4354 
4355 
4356  } else if(commandTmp->GetCommandName() == "targetPoint") {
4357  G4Point3D point = fVP.GetCurrentTargetPoint();
4358  if (fSceneHandler.GetScene()) {
4359  G4String b = G4BestUnit(fSceneHandler.GetScene()->GetStandardTargetPoint() + fVP.GetCurrentTargetPoint(),"Length");
4360  params = b.data();
4361  }
4362  } else if(commandTmp->GetCommandName() == "upThetaPhi") {
4363  G4Vector3D up = fVP.GetUpVector();
4364  // degree
4365  params = QString().number(up.theta()/CLHEP::degree)+ " "+ QString().number(up.phi()/CLHEP::degree)+" deg";
4366  if (commandTmp->GetParameterEntries() == 3) {
4367  if (commandTmp->GetParameter(2)->GetDefaultValue() != "deg") {
4368  params = QString().number(up.theta())+ " "+ QString().number(up.phi())+" "+commandTmp->GetParameter(2)->GetDefaultValue().data();
4369  }
4370  }
4371  } else if(commandTmp->GetCommandName() == "upVector") {
4372  G4Vector3D up = fVP.GetUpVector();
4373  params = QString().number(up.x())+ " "+ QString().number(up.y())+" "+QString().number(up.z())+ " ";
4374 
4375  } else if(commandTmp->GetCommandName() == "viewpointThetaPhi") {
4376  G4Vector3D direction = fVP.GetViewpointDirection();
4377  // degree
4378  params = QString().number(direction.theta()/CLHEP::degree)+ " "+ QString().number(direction.phi()/CLHEP::degree)+" deg";
4379  if (commandTmp->GetParameterEntries() == 3) {
4380  if (commandTmp->GetParameter(2)->GetDefaultValue() != "deg") {
4381  params = QString().number(direction.theta())+ " "+ QString().number(direction.phi())+" "+commandTmp->GetParameter(2)->GetDefaultValue().data();
4382  }
4383  }
4384  } else if(commandTmp->GetCommandName() == "viewpointVector") {
4385  G4Vector3D direction = fVP.GetViewpointDirection();
4386  params = QString().number(direction.x())+ " "+ QString().number(direction.y())+" "+QString().number(direction.z());
4387  } else {
4388  // No help
4389  }
4390 
4391  /* DO NOT DISPLAY COMMANDS WITHOUT ANY PARAMETERS SET
4392  if (params == "") {
4393  // TODO : display default parameters // should not be editable ?
4394 
4395  for( G4int i_thParameter=0; i_thParameter<commandTmp->GetParameterEntries(); i_thParameter++ ) {
4396  commandParam = commandTmp->GetParameter(i_thParameter);
4397 
4398  if (QString(QChar(commandParam->GetParameterType())) == "b") {
4399  if (commandParam->GetDefaultValue().data()) {
4400  params += "True";
4401  } else {
4402  params += "False";
4403  }
4404  } else {
4405  params += QString((char*)(commandParam->GetDefaultValue()).data());
4406  }
4407  if (i_thParameter<commandTmp->GetParameterEntries()-1) {
4408  params += " ";
4409  }
4410  }
4411  }
4412  */
4413 
4414  if (params != "") {
4415 
4416  QTableWidgetItem *nameItem;
4417  QTableWidgetItem *paramItem;
4418 
4419  // already present ?
4420  QList<QTableWidgetItem *> list = fViewerPropertiesTableWidget->findItems (commandTmp->GetCommandName().data(),Qt::MatchExactly);
4421  if (list.size() == 1) {
4422  nameItem = list.first();
4423  paramItem = fViewerPropertiesTableWidget->item(nameItem->row(),1);
4424 
4425  } else {
4426  nameItem = new QTableWidgetItem();
4427  paramItem = new QTableWidgetItem();
4428  fViewerPropertiesTableWidget->setItem(a-treeWidgetInfosIgnoredCommands, 0, nameItem);
4429  fViewerPropertiesTableWidget->setItem(a-treeWidgetInfosIgnoredCommands, 1, paramItem);
4430 
4431  // Set Guidance
4432  QString guidance;
4433  G4int n_guidanceEntry = commandTmp->GetGuidanceEntries();
4434  for( G4int i_thGuidance=0; i_thGuidance < n_guidanceEntry; i_thGuidance++ ) {
4435  guidance += QString((char*)(commandTmp->GetGuidanceLine(i_thGuidance)).data()) + "\n";
4436  }
4437 
4438  nameItem->setToolTip(guidance);
4439  paramItem->setToolTip(GetCommandParameterList(commandTmp));
4440 
4441  fViewerPropertiesTableWidget->setRowHeight(a-treeWidgetInfosIgnoredCommands,15);
4442  }
4443 
4444  // set current name and parameters
4445  nameItem->setText(commandTmp->GetCommandName().data());
4446  paramItem->setText(params);
4447 
4448  nameItem->setFlags(Qt::NoItemFlags);
4449  nameItem->setForeground(QBrush());
4450 
4451  } else {
4452  treeWidgetInfosIgnoredCommands++;
4453  }
4454  }
4455  // remove empty content row
4456  for (int i=0; i<treeWidgetInfosIgnoredCommands; i++) {
4457  fViewerPropertiesTableWidget->removeRow (fViewerPropertiesTableWidget->rowCount() - 1);
4458  }
4459 
4460  // The resize should done only at creation
4461  if (!fViewerPropertiesTableWidgetIsInit) {
4462  fViewerPropertiesTableWidgetIsInit = true;
4463 
4464  fViewerPropertiesTableWidget->resizeColumnsToContents();
4465 
4466  int x = fViewerPropertiesTableWidget->horizontalHeader()->length();
4467  int y = fViewerPropertiesTableWidget->verticalHeader()->length()+ fViewerPropertiesTableWidget->horizontalHeader()->sizeHint().height() + 2;
4468 
4469  // fViewerPropertiesTableWidget->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
4470  // fViewerPropertiesTableWidget->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
4471 
4472  // resize to fit content
4473  QDialog* dial = static_cast<QDialog*> (fUIViewerPropertiesWidget->parent());
4474  if (dial) {
4475  dial->resize(x+56,y+46); // more or less (margins) ...
4476  }
4477  }
4478  fViewerPropertiesTableWidget->blockSignals(false);
4479 
4480  fTreeWidgetInfosIgnoredCommands = treeWidgetInfosIgnoredCommands;
4481 }
4482 
4483 
4487 void G4OpenGLQtViewer::updatePickInfosWidget(int aX, int aY) {
4488  fLastPickPoint = QPoint(aX,aY);
4489 
4490  if (!isCurrentWidget()) {
4491  return;
4492  }
4493  // Ensure case where closing a UI tab close the widget
4494  if (!fPickInfosWidget) {
4495  createPickInfosWidget();
4496  }
4497 
4498  const std::vector < G4OpenGLViewerPickMap* > & pickMapVector = GetPickDetails(aX,aY);
4499 
4500  // remove all previous widgets
4501  if (fPickInfosWidget) {
4502  QLayoutItem * wItem;
4503  if (fPickInfosWidget->layout()->count()) {
4504  while ((wItem = fPickInfosWidget->layout()->takeAt(0)) != 0) {
4505  delete wItem->widget();
4506  delete wItem;
4507  }
4508  }
4509  } else {
4510  // Ensure case where closing a UI tab close the widget
4511  if (!fPickInfosWidget) {
4512  createPickInfosWidget();
4513  }
4514  }
4515 
4516  // Create a new signalMapper
4517 #if QT_VERSION < 0x050600
4518  delete fSignalMapperPicking;
4519  fSignalMapperPicking = new QSignalMapper(this);
4520 #endif
4521 
4522  // parse all pick results
4523  G4int nPickedObjectsWithAttributes = 0;
4524  for (unsigned int a=0; a< pickMapVector.size(); a++) {
4525  const auto& pickMap = pickMapVector[a];
4526  // Add a box inside the pick viewer box
4527  std::ostringstream label;
4528  std::ostringstream content;
4529  std::string txt = pickMap->getAttributes()[0].data();
4530  if (pickMapVector[a]->getAttributes().size()) {
4531  ++nPickedObjectsWithAttributes;
4532 
4533  std::size_t pos1 = txt.find(':');
4534  std::string storeKey = txt.substr(0,pos1);
4535 
4536  if (storeKey == "G4PhysicalVolumeModel") {
4537 
4538  label << "Volume:";
4539  std::size_t pos2 = txt.find(':',pos1+1);
4540  std::size_t pos3 = txt.find('\n',pos2+1);
4541  label << txt.substr(pos2+1,pos3-pos2-1);
4542 
4543  } else if (storeKey == "G4TrajectoriesModel") {
4544 
4545  label << "Trajectory:";
4546  std::size_t pos2 = txt.find(':',pos1+1);
4547  std::size_t pos3 = txt.find('\n',pos2+1);
4548  label << " Run:" << txt.substr(pos2+1,pos3-pos2-1);
4549  std::size_t pos4 = txt.find(':',pos3+1);
4550  std::size_t pos5 = txt.find('\n',pos4+1);
4551  label << ", Event:" << txt.substr(pos4+1,pos5-pos4-1);
4552 
4553  } else {
4554 
4555  label << "Hit number:" << a << ", PickName: " << pickMap->getPickName();
4556 
4557  }
4558 
4559  // Accumulate all content with the same pickname
4560  content << pickMap->print().data();
4561  G4int thisPickName = pickMap->getPickName();
4562  while (++a < pickMapVector.size()) {
4563  const auto& a_pickMap = pickMapVector[a];
4564  if (a_pickMap->getPickName() == thisPickName) {
4565  content << a_pickMap->print().data();
4566  } else {
4567  a--;
4568  break;
4569  }
4570  }
4571 
4572  QPushButton* pickCoutButton = new QPushButton(label.str().c_str());
4573  pickCoutButton->setStyleSheet ("text-align: left; padding: 1px; border: 0px;");
4574  pickCoutButton->setIcon(*fTreeIconClosed);
4575  fPickInfosWidget->layout()->addWidget(pickCoutButton);
4576 
4577  QStringList newStr;
4578 
4579  // Add to stringList
4580  newStr = QStringList(QString(content.str().c_str()).trimmed());
4581 
4582  QTextEdit* ed = new QTextEdit();
4583  ed->setReadOnly(true);
4584  fPickInfosWidget->layout()->addWidget(ed);
4585  ed->setVisible((false));
4586  ed->append(newStr.join(""));
4587 
4588 #if QT_VERSION < 0x050600
4589  connect(pickCoutButton, SIGNAL(clicked()), fSignalMapperPicking, SLOT(map()));
4590  fSignalMapperPicking->setMapping(pickCoutButton,fPickInfosWidget->layout()->count()-1);
4591 #else
4592  std::cout << pickCoutButton->text().toStdString() << " "<< fPickInfosWidget->layout()->count()-1<< std::endl;
4593  int tmp = fPickInfosWidget->layout()->count()-1;
4594  connect(pickCoutButton, &QPushButton::clicked , [=](){ this->toggleSceneTreeComponentPickingCout(tmp);});
4595 #endif
4596  }
4597  }
4598 #if QT_VERSION < 0x050600
4599  connect(fSignalMapperPicking, SIGNAL(mapped(int)),this, SLOT(toggleSceneTreeComponentPickingCout(int)));
4600 #endif
4601 
4602  // add a label to push everything up!
4603  QLabel * pushUp = new QLabel("");
4604  QSizePolicy vPolicy = QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum);
4605  vPolicy.setVerticalStretch(10);
4606  pushUp->setSizePolicy(vPolicy);
4607  fPickInfosWidget->layout()->addWidget(pushUp);
4608 
4609  // highlight the first one :
4610 
4611  // first un-highlight the last selected
4612  changeColorAndTransparency(fLastHighlightName,fLastHighlightColor);
4613 
4614  if (pickMapVector.size() > 0 ) {
4615  // get the new one
4616  fLastHighlightName = pickMapVector[0]->getPickName();
4617  fLastHighlightColor = getColorForPoIndex(fLastHighlightName);
4618  // set the new one
4619  changeColorAndTransparency(fLastHighlightName,G4Color(1,1,1,1));
4620 
4621  updateQWidget();
4622  }
4623  QDialog* dial = static_cast<QDialog*> (fUIPickInfosWidget->parent());
4624  if (dial) {
4625  // change name
4626  std::ostringstream oss;
4627  if (nPickedObjectsWithAttributes == 0) {
4628  oss << "No object";
4629  } else if (nPickedObjectsWithAttributes == 1) {
4630  oss << "1 object";
4631  } else {
4632  oss << nPickedObjectsWithAttributes << " objects";
4633  }
4634  oss << " selected - " << GetName();
4635  dial->setWindowTitle(oss.str().c_str());
4636  }
4637  // set picking cout visible
4638  fPickInfosScrollArea->setVisible(true);
4639 }
4640 
4641 
4642 void G4OpenGLQtViewer::toggleSceneTreeComponentPickingCout(int pickItem) {
4643 
4644  QWidget* w;
4645  // close other items, it could take too much space
4646 
4647  for (int a=0; a<fPickInfosWidget->layout()->count(); a++) {
4648  w = fPickInfosWidget->layout()->itemAt(a)->widget();
4649  QTextEdit* ed = dynamic_cast<QTextEdit*>(w);
4650  QPushButton* button;
4651  if (ed) {
4652  if (a == pickItem) {
4653  w->setVisible(!w->isVisible());
4654  } else {
4655  w->setVisible(false);
4656  }
4657  if (a >= 1) {
4658  button = dynamic_cast<QPushButton*>(fPickInfosWidget->layout()->itemAt(a-1)->widget());
4659  if (button) {
4660  if (button->isVisible()) {
4661  button->setIcon(*fTreeIconOpen);
4662  } else {
4663  button->setIcon(*fTreeIconClosed);
4664  }
4665  }
4666  }
4667  }
4668  }
4669 }
4670 
4671 
4672 void G4OpenGLQtViewer::currentTabActivated(int currentTab) {
4673  if (fUiQt->GetViewerTabWidget()->tabText(currentTab) == GetName()) {
4674  createViewerPropertiesWidget();
4675  createPickInfosWidget();
4676  createSceneTreeWidget();
4677  }
4678 }
4679 
4680 
4681 void G4OpenGLQtViewer::tableWidgetViewerSetItemChanged(QTableWidgetItem * item) {
4683  if(UI != NULL) {
4684  QTableWidgetItem* previous = fViewerPropertiesTableWidget->item(fViewerPropertiesTableWidget->row(item),0);
4685  if (previous) {
4686  fViewerPropertiesTableWidget->blockSignals(true);
4687  UI->ApplyCommand((std::string("/vis/viewer/set/")
4688  + previous->text().toStdString()
4689  + " "
4690  + item->text().toStdString()).c_str());
4691  fViewerPropertiesTableWidget->blockSignals(false);
4692  }
4693  }
4694 }
4695 
4696 bool G4OpenGLQtViewer::isCurrentWidget(){
4697  G4Qt* interactorManager = G4Qt::getInstance ();
4698  if (!interactorManager->IsExternalApp()) {
4699 
4700  // Prevent from repainting a hidden tab (the current tab name has to be the one of th GL viewer)
4701  if ( GetName() != fUiQt->GetViewerTabWidget()->tabText(fUiQt->GetViewerTabWidget()->currentIndex()).toStdString().c_str()) {
4702  return false;
4703  }
4704  }
4705  return true;
4706 }
4707 
4715 QString G4OpenGLQtViewer::GetCommandParameterList (
4716  const G4UIcommand *aCommand
4717  )
4718 {
4719  G4int n_parameterEntry = aCommand->GetParameterEntries();
4720  QString txt;
4721 
4722  if( n_parameterEntry > 0 ) {
4723  G4UIparameter *param;
4724 
4725  // Re-implementation of G4UIparameter.cc
4726 
4727  for( G4int i_thParameter=0; i_thParameter<n_parameterEntry; i_thParameter++ ) {
4728  param = aCommand->GetParameter(i_thParameter);
4729  txt += "\nParameter : " + QString((char*)(param->GetParameterName()).data()) + "\n";
4730  if( ! param->GetParameterGuidance().isNull() )
4731  txt += QString((char*)(param->GetParameterGuidance()).data())+ "\n" ;
4732  txt += " Parameter type : " + QString(QChar(param->GetParameterType())) + "\n";
4733  if(param->IsOmittable()){
4734  txt += " Omittable : True\n";
4735  } else {
4736  txt += " Omittable : False\n";
4737  }
4738  if( param->GetCurrentAsDefault() ) {
4739  txt += " Default value : taken from the current value\n";
4740  } else if( ! param->GetDefaultValue().isNull() ) {
4741  txt += " Default value : " + QString((char*)(param->GetDefaultValue()).data())+ "\n";
4742  }
4743  if( ! param->GetParameterRange().isNull() ) {
4744  txt += " Parameter range : " + QString((char*)(param->GetParameterRange()).data())+ "\n";
4745  }
4746  if( ! param->GetParameterCandidates().isNull() ) {
4747  txt += " Candidates : " + QString((char*)(param->GetParameterCandidates()).data())+ "\n";
4748  }
4749  }
4750  }
4751  return txt;
4752 }
4753 
4754 #ifdef G4MULTITHREADED
4755 
4756 void G4OpenGLQtViewer::DoneWithMasterThread()
4757 {
4758  // Called by Main Thread !
4759 
4760  // Useful to avoid two vis thread at the same time
4761  //G4MUTEXLOCK(&mWaitForVisSubThreadQtOpenGLContextInitialized);
4762  if(!lWaitForVisSubThreadQtOpenGLContextInitialized->owns_lock())
4763  lWaitForVisSubThreadQtOpenGLContextInitialized->lock();
4764 }
4765 
4766 void G4OpenGLQtViewer::SwitchToVisSubThread()
4767 {
4768  // Called by VisSub Thread !
4769 
4770  QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
4771  if (! qGLW) {
4772  return;
4773  }
4774 
4775  // Set the current QThread to its static variable
4776  SetQGLContextVisSubThread(QThread::currentThread());
4777 
4778  // - Wait for the vis thread to set its QThread
4779  G4CONDITIONBROADCAST(&c1_VisSubThreadQtOpenGLContextInitialized);
4780  // a condition without a locked mutex is an undefined behavior.
4781  // we check if the mutex owns the lock, and if not, we lock it
4782  if(!lWaitForVisSubThreadQtOpenGLContextMoved->owns_lock())
4783  lWaitForVisSubThreadQtOpenGLContextMoved->lock();
4784 
4785  // Unlock the vis thread if it is Qt Viewer
4786  G4CONDITIONWAIT(&c2_VisSubThreadQtOpenGLContextMoved,
4787  lWaitForVisSubThreadQtOpenGLContextMoved);
4788 
4789  // make context current
4790  qGLW->makeCurrent();
4791 }
4792 
4793 void G4OpenGLQtViewer::DoneWithVisSubThread()
4794 {
4795  // Called by vis sub thread
4796  QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
4797  if (! qGLW) {
4798  return;
4799  }
4800 
4801  // finish with this vis sub thread context
4802  qGLW->doneCurrent();
4803 
4804 #if QT_VERSION > 0x050000
4805  // and move it back to the main thread
4806  qGLW->context()->moveToThread(fQGLContextMainThread);
4807 #endif
4808 }
4809 
4810 void G4OpenGLQtViewer::SwitchToMasterThread()
4811 {
4812  // Called by VisSub Thread !
4813 
4814  QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
4815  if (! qGLW) {
4816  return;
4817  }
4818 
4819  // Useful to avoid two vis thread at the same time
4820  //G4MUTEXUNLOCK(&mWaitForVisSubThreadQtOpenGLContextInitialized);
4821  if(lWaitForVisSubThreadQtOpenGLContextInitialized->owns_lock())
4822  lWaitForVisSubThreadQtOpenGLContextInitialized->unlock();
4823 
4824  qGLW->makeCurrent();
4825 }
4826 
4827 
4828 void G4OpenGLQtViewer::MovingToVisSubThread(){
4829  // Called by Main Thread !
4830 
4831  QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
4832  if (! qGLW) {
4833  return;
4834  }
4835 
4836  // a condition without a locked mutex is an undefined behavior.
4837  // we check if the mutex owns the lock, and if not, we lock it
4838  if(!lWaitForVisSubThreadQtOpenGLContextInitialized->owns_lock())
4839  lWaitForVisSubThreadQtOpenGLContextInitialized->lock();
4840 
4841  // - Wait for the vis sub thread to set its QThread
4842  G4CONDITIONWAIT(&c1_VisSubThreadQtOpenGLContextInitialized,
4843  lWaitForVisSubThreadQtOpenGLContextInitialized);
4844 
4845  // Set current QThread for the way back
4846  SetQGLContextMainThread(QThread::currentThread());
4847 
4848  // finish with this main thread context
4849  qGLW->doneCurrent();
4850 #if QT_VERSION > 0x050000
4851  qGLW->context()->moveToThread(fQGLContextVisSubThread);
4852 #endif
4853 
4854  G4CONDITIONBROADCAST(&c2_VisSubThreadQtOpenGLContextMoved);
4855 }
4856 
4857 #endif
4858 
4859 
4860 /*
4861 
4862 void MultiLayer::exportToSVG(const QString& fname)
4863 {
4864 QPicture picture;
4865 QPainter p(&picture);
4866 for (int i=0;i<(int)graphsList->count();i++)
4867 {
4868 Graph *gr=(Graph *)graphsList->at(i);
4869 Plot *myPlot= (Plot *)gr->plotWidget();
4870 
4871 QPoint pos=gr->pos();
4872 
4873 int width=int(myPlot->frameGeometry().width());
4874 int height=int(myPlot->frameGeometry().height());
4875 
4876 myPlot->print(&p, QRect(pos,QSize(width,height)));
4877 }
4878 
4879 p.end();
4880 picture.save(fname, "svg");
4881 }
4882 */
4883 #endif