CustusX  15.3.4-beta
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxMainWindow.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 #include "cxMainWindow.h"
34 
35 #include <QtWidgets>
36 #include "boost/bind.hpp"
37 
38 #include "cxConfig.h"
39 #include "cxDataLocations.h"
40 #include "cxProfile.h"
41 #include "cxLogicManager.h"
42 #include "cxTrackingService.h"
43 #include "cxSettings.h"
44 #include "cxVideoService.h"
45 #include "cxStateService.h"
46 #include "cxNavigation.h"
47 #include "cxImage.h"
48 #include "cxPatientModelService.h"
49 #include "cxViewService.h"
50 #include "cxViewGroupData.h"
52 #include "cxVisServices.h"
53 #include "cxAudioImpl.h"
54 #include "cxLayoutInteractor.h"
55 #include "cxVLCRecorder.h"
56 #include "cxCameraControl.h"
57 
58 #include "cxDockWidgets.h"
59 #include "cxStatusBar.h"
60 #include "cxImportDataDialog.h"
61 #include "cxExportDataDialog.h"
62 #include "cxSecondaryMainWindow.h"
64 #include "cxSamplerWidget.h"
65 #include "cxHelperWidgets.h"
66 
69 #include "cxToolManagerWidget.h"
70 #include "cxFrameTreeWidget.h"
71 #include "cxNavigationWidget.h"
73 #include "cxToolPropertiesWidget.h"
74 #include "cxPreferencesDialog.h"
76 #include "cxMeshInfoWidget.h"
77 #include "cxTrackPadWidget.h"
78 #include "cxConsoleWidget.h"
79 #include "cxMetricWidget.h"
80 #include "cxPlaybackWidget.h"
81 #include "cxEraserWidget.h"
82 #include "cxAllFiltersWidget.h"
84 
85 
86 namespace cx
87 {
88 
89 MainWindow::MainWindow(std::vector<GUIExtenderServicePtr> guiExtenders) :
90  mFullScreenAction(NULL), mStandard3DViewActions(new QActionGroup(this)), mControlPanel(NULL), mDockWidgets(new DockWidgets(this))
91 {
92  this->setObjectName("MainWindow");
93 
94  mServices = VisServices::create(logicManager()->getPluginContext());
95  mLayoutInteractor.reset(new LayoutInteractor());
96 
97  this->setCentralWidget(viewService()->getLayoutWidget(this, 0));
98 
99  this->createActions();
100  this->createMenus();
101  this->createToolBars();
102  this->setStatusBar(new StatusBar());
103 
104  reporter()->setAudioSource(AudioPtr(new AudioImpl()));
105 
109 
110  this->updateWindowTitle();
111 
112  this->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
113 
114  this->addAsDockWidget(new PlaybackWidget(this), "Browsing");
115  this->addAsDockWidget(new VideoConnectionWidget(mServices, this), "Utility");
116  this->addAsDockWidget(new EraserWidget(this), "Properties");
117  this->addAsDockWidget(new MetricWidget(mServices->visualizationService, mServices->patientModelService, this), "Utility");
118  this->addAsDockWidget(new SlicePropertiesWidget(mServices->patientModelService, mServices->visualizationService, this), "Properties");
119  this->addAsDockWidget(new VolumePropertiesWidget(mServices->patientModelService, mServices->visualizationService, this), "Properties");
120  this->addAsDockWidget(new MeshInfoWidget(mServices->patientModelService, mServices->visualizationService, this), "Properties");
121  this->addAsDockWidget(new StreamPropertiesWidget(mServices->patientModelService, mServices->visualizationService, this), "Properties");
122  this->addAsDockWidget(new TrackPadWidget(this), "Utility");
123  this->addAsDockWidget(new ToolPropertiesWidget(this), "Properties");
124  this->addAsDockWidget(new NavigationWidget(this), "Properties");
125  this->addAsDockWidget(new ConsoleWidget(this, "ConsoleWidget", "Console"), "Utility");
126  this->addAsDockWidget(new ConsoleWidget(this, "ConsoleWidget2", "Extra Console"), "Utility");
127 // this->addAsDockWidget(new ConsoleWidgetCollection(this, "ConsoleWidgets", "Consoles"), "Utility");
128  this->addAsDockWidget(new FrameTreeWidget(mServices->patientModelService, this), "Browsing");
129  this->addAsDockWidget(new ToolManagerWidget(this), "Debugging");
130  this->addAsDockWidget(new PluginFrameworkWidget(this), "Browsing");
131  this->addAsDockWidget(new AllFiltersWidget(VisServices::create(logicManager()->getPluginContext()), this), "Algorithms");
132 
133 
135  connect(qApp, &QApplication::focusChanged, this, &MainWindow::focusChanged);
136 
137  // insert all widgets from all guiExtenders
138  for (unsigned i = 0; i < guiExtenders.size(); ++i)
139  this->addGUIExtender(guiExtenders[i].get());
140 
141  this->setupGUIExtenders();
142 
143  // window menu must be created after all dock widgets are created
144  QMenu* popupMenu = this->createPopupMenu();
145  popupMenu->setTitle("Window");
146  this->menuBar()->insertMenu(mHelpMenuAction, popupMenu);
147 
148  // Restore saved window states
149  // Must be done after all DockWidgets are created
150  if (restoreGeometry(settings()->value("mainWindow/geometry").toByteArray()))
151  {
152  this->show();
153  }
154  else
155  {
156  this->showMaximized();
157  }
158 
159  if (settings()->value("gui/fullscreen").toBool())
160  this->setWindowState(this->windowState() | Qt::WindowFullScreen);
161 }
162 
163 void MainWindow::changeEvent(QEvent * event)
164 {
165  QMainWindow::changeEvent(event);
166 
167  if (event->type() == QEvent::WindowStateChange)
168  {
169  if (mFullScreenAction)
170  mFullScreenAction->setChecked(this->windowState() & Qt::WindowFullScreen);
171  }
172 }
173 
174 void MainWindow::setupGUIExtenders()
175 {
176  mServiceListener.reset(new ServiceTrackerListener<GUIExtenderService>(
177  LogicManager::getInstance()->getPluginContext(),
178  boost::bind(&MainWindow::onPluginBaseAdded, this, _1),
179  boost::bind(&MainWindow::onPluginBaseModified, this, _1),
180  boost::bind(&MainWindow::onPluginBaseRemoved, this, _1)
181  ));
182  mServiceListener->open();
183 }
184 
185 void MainWindow::addGUIExtender(GUIExtenderService* service)
186 {
187  std::vector<GUIExtenderService::CategorizedWidget> widgets = service->createWidgets();
188  for (unsigned j = 0; j < widgets.size(); ++j)
189  {
190  QWidget* widget = this->addCategorizedWidget(widgets[j]);
191  mWidgetsByPlugin[service].push_back(widget);
192  }
193 
194  std::vector<QToolBar*> toolBars = service->createToolBars();
195  for(unsigned j = 0; j < toolBars.size(); ++j)
196  {
197  addToolBar(toolBars[j]);
198  this->registerToolBar(toolBars[j], "Toolbar");
199  }
200 }
201 
202 QWidget *MainWindow::addCategorizedWidget(GUIExtenderService::CategorizedWidget categorizedWidget)
203 {
204  QWidget* retval;
205  retval = this->addAsDockWidget(categorizedWidget.mWidget, categorizedWidget.mCategory);
206  return retval;
207 }
208 
209 void MainWindow::removeGUIExtender(GUIExtenderService* service)
210 {
211  while (!mWidgetsByPlugin[service].empty())
212  {
213  // TODO: must remove widget from several difference data structures: simplify!
214  QWidget* widget = mWidgetsByPlugin[service].back();
215  mWidgetsByPlugin[service].pop_back();
216 
217  QDockWidget* dockWidget = dynamic_cast<QDockWidget*>(widget);
218  this->removeDockWidget(dockWidget);
219 
220  mDockWidgets->erase(dockWidget);
221 
222  if (dockWidget)
223  {
224  for (std::map<QString, QActionGroup*>::iterator iter=mWidgetGroupsMap.begin(); iter!=mWidgetGroupsMap.end(); ++iter)
225  {
226  iter->second->removeAction(dockWidget->toggleViewAction());
227  }
228  }
229  }
230 }
231 
233 {
234  this->addGUIExtender(service);
235 }
236 
238 {
239 }
240 
242 {
243  this->removeGUIExtender(service);
244 }
245 
247 {
248  if (val)
249  this->focusInsideDockWidget(sender());
250 }
251 
252 void MainWindow::focusChanged(QWidget * old, QWidget * now)
253 {
254  this->focusInsideDockWidget(now);
255 }
256 
257 void MainWindow::focusInsideDockWidget(QObject *dockWidget)
258 {
259  // Assume structure: QDockWidget->QScrollArea->QWidget,
260  // as defined in MainWindow::addAsDockWidget()
261  QDockWidget* dw = dynamic_cast<QDockWidget*>(dockWidget);
262  if (!dw)
263  return;
264  if (dw->parent()!=this) // avoid events from other mainwindows
265  return;
266  QScrollArea* sa = dynamic_cast<QScrollArea*>(dw->widget());
267  if (!sa)
268  return;
269  QTimer::singleShot(0, sa->widget(), SLOT(setFocus())); // avoid loops etc by send async event.
270 }
271 
272 
273 void MainWindow::addToWidgetGroupMap(QAction* action, QString groupname)
274 {
275  action->setMenuRole(QAction::NoRole);
276  if (mWidgetGroupsMap.find(groupname) != mWidgetGroupsMap.end())
277  {
278  mWidgetGroupsMap[groupname]->addAction(action);
279  }
280  else
281  {
282  QActionGroup* group = new QActionGroup(this);
283  group->setExclusive(false);
284  mWidgetGroupsMap[groupname] = group;
285  QAction* heading = new QAction(groupname, this);
286  heading->setDisabled(true);
287  mWidgetGroupsMap[groupname]->addAction(heading);
288  mWidgetGroupsMap[groupname]->addAction(action);
289  }
290 }
291 
293 {
294  reporter()->setAudioSource(AudioPtr()); // important! QSound::play fires a thread, causes segfault during shutdown
295  mServiceListener.reset();
296 }
297 
299 {
300  QMenu* popupMenu = new QMenu(this);
301  std::map<QString, QActionGroup*>::iterator it = mWidgetGroupsMap.begin();
302  for (; it != mWidgetGroupsMap.end(); ++it)
303  {
304  popupMenu->addSeparator();
305  popupMenu->addActions(it->second->actions());
306  }
307 
308  return popupMenu;
309 }
310 
311 void MainWindow::createActions()
312 {
313  CameraControlPtr cameraControl = viewService()->getCameraControl();
314  if (cameraControl)
315  mStandard3DViewActions = cameraControl->createStandard3DViewActions();
316 
317  // File
318  mNewPatientAction = new QAction(QIcon(":/icons/open_icon_library/document-new-8.png"), tr(
319  "&New patient"), this);
320  mNewPatientAction->setShortcut(tr("Ctrl+N"));
321  mNewPatientAction->setStatusTip(tr("Create a new patient file"));
322  mSaveFileAction = new QAction(QIcon(":/icons/open_icon_library/document-save-5.png"), tr(
323  "&Save Patient"), this);
324  mSaveFileAction->setShortcut(tr("Ctrl+S"));
325  mSaveFileAction->setStatusTip(tr("Save patient file"));
326  mLoadFileAction = new QAction(QIcon(":/icons/open_icon_library/document-open-7.png"), tr(
327  "&Load Patient"), this);
328  mLoadFileAction->setShortcut(tr("Ctrl+L"));
329  mLoadFileAction->setStatusTip(tr("Load patient file"));
330  mClearPatientAction = new QAction(tr("&Clear Patient"), this);
331  mExportPatientAction = new QAction(tr("&Export Patient"), this);
332 
333  connect(mNewPatientAction, &QAction::triggered, this, &MainWindow::newPatientSlot);
334  connect(mLoadFileAction, &QAction::triggered, this, &MainWindow::loadPatientFileSlot);
335  connect(mSaveFileAction, &QAction::triggered, this, &MainWindow::savePatientFileSlot);
336  connect(mSaveFileAction, &QAction::triggered, this, &MainWindow::saveDesktopSlot);
337  connect(mExportPatientAction, &QAction::triggered, this, &MainWindow::exportDataSlot);
338  connect(mClearPatientAction, &QAction::triggered, this, &MainWindow::clearPatientSlot);
339 
340  mShowControlPanelAction = new QAction("Show Control Panel", this);
341  connect(mShowControlPanelAction, &QAction::triggered, this, &MainWindow::showControlPanelActionSlot);
342  mSecondaryViewLayoutWindowAction = new QAction("Show Secondary View Layout Window", this);
343  connect(mSecondaryViewLayoutWindowAction, &QAction::triggered, this, &MainWindow::showSecondaryViewLayoutWindowActionSlot);
344 
345  // Application
346  mAboutAction = new QAction(tr("About"), this);
347  mAboutAction->setStatusTip(tr("Show the application's About box"));
348  mPreferencesAction = new QAction(tr("Preferences"), this);
349  mPreferencesAction->setShortcut(tr("Ctrl+,"));
350  mPreferencesAction->setStatusTip(tr("Show the preferences dialog"));
351 
352  mStartLogConsoleAction = new QAction(tr("&Start Log Console"), this);
353  mStartLogConsoleAction->setShortcut(tr("Ctrl+D"));
354  mStartLogConsoleAction->setStatusTip(tr("Open Log Console as external application"));
355  connect(mStartLogConsoleAction, &QAction::triggered, this, &MainWindow::onStartLogConsole);
356 
357  mFullScreenAction = new QAction(tr("Fullscreen"), this);
358  mFullScreenAction->setShortcut(tr("F11"));
359  mFullScreenAction->setStatusTip(tr("Toggle full screen"));
360  mFullScreenAction->setCheckable(true);
361  mFullScreenAction->setChecked(this->windowState() & Qt::WindowFullScreen);
362  connect(mFullScreenAction, &QAction::triggered, this, &MainWindow::toggleFullScreenSlot);
363 
364  mQuitAction = new QAction(tr("&Quit"), this);
365  mQuitAction->setShortcut(tr("Ctrl+Q"));
366  mQuitAction->setStatusTip(tr("Exit the application"));
367 
368  connect(mAboutAction, &QAction::triggered, this, &MainWindow::aboutSlot);
369  connect(mPreferencesAction, &QAction::triggered, this, &MainWindow::preferencesSlot);
370  connect(mQuitAction, &QAction::triggered, this, &MainWindow::quitSlot);
371 
372  mShootScreenAction = new QAction(tr("Shoot Screen"), this);
373  mShootScreenAction->setIcon(QIcon(":/icons/screenshot-screen.png"));
374  mShootScreenAction->setShortcut(tr("Ctrl+f"));
375  mShootScreenAction->setStatusTip(tr("Save a screenshot to the patient folder."));
376  connect(mShootScreenAction, &QAction::triggered, this, &MainWindow::shootScreen);
377 
378  mShootWindowAction = new QAction(tr("Shoot Window"), this);
379  mShootWindowAction->setIcon(QIcon(":/icons/screenshot-window.png"));
380  mShootWindowAction->setShortcut(tr("Ctrl+Shift+f"));
381  mShootWindowAction->setStatusTip(tr("Save an image of the application to the patient folder."));
382  connect(mShootWindowAction, &QAction::triggered, this, &MainWindow::shootWindow);
383 
384  mRecordFullscreenAction = new QAction(tr("Record Fullscreen"), this);
385  mRecordFullscreenAction->setShortcut(tr("F8"));
386  mRecordFullscreenAction->setStatusTip(tr("Record a video of the full screen."));
387  connect(mRecordFullscreenAction, &QAction::triggered, this, &MainWindow::recordFullscreen);
388 
389  //data
390  mImportDataAction = new QAction(QIcon(":/icons/open_icon_library/document-import-2.png"), tr("&Import data"), this);
391  mImportDataAction->setShortcut(tr("Ctrl+I"));
392  mImportDataAction->setStatusTip(tr("Import image data"));
393 
394  mDeleteDataAction = new QAction(tr("Delete current image"), this);
395  mDeleteDataAction->setStatusTip(tr("Delete selected volume"));
396 
397  connect(mImportDataAction, &QAction::triggered, this, &MainWindow::importDataSlot);
398  connect(mDeleteDataAction, &QAction::triggered, this, &MainWindow::deleteDataSlot);
399 
400  mShowPointPickerAction = new QAction(tr("Point Picker"), this);
401  mShowPointPickerAction->setCheckable(true);
402  mShowPointPickerAction->setToolTip("Activate the 3D Point Picker Probe");
403  mShowPointPickerAction->setIcon(QIcon(":/icons/point_picker.png"));
404  connect(mShowPointPickerAction, &QAction::triggered, this, &MainWindow::togglePointPickerActionSlot);
405 
406  if (viewService()->getGroup(0))
409 
410  //tool
411  mToolsActionGroup = new QActionGroup(this);
412  mConfigureToolsAction = new QAction(tr("Tool configuration"), mToolsActionGroup);
413  mInitializeToolsAction = new QAction(tr("Initialize"), mToolsActionGroup);
414  mTrackingToolsAction = new QAction(tr("Start tracking"), mToolsActionGroup);
415  mTrackingToolsAction->setShortcut(tr("Ctrl+T"));
416 
417  mToolsActionGroup->setExclusive(false); // must turn off to get the checkbox independent.
418 
419  mStartStreamingAction = new QAction(tr("Start Streaming"), mToolsActionGroup);
420  mStartStreamingAction->setShortcut(tr("Ctrl+V"));
421  connect(mStartStreamingAction, &QAction::triggered, this, &MainWindow::toggleStreamingSlot);
424 
425  mConfigureToolsAction->setChecked(true);
426 
427  connect(mConfigureToolsAction, &QAction::triggered, this, &MainWindow::configureSlot);
428  boost::function<void()> finit = boost::bind(&TrackingService::setState, trackingService(), Tool::tsINITIALIZED);
429  connect(mInitializeToolsAction, &QAction::triggered, finit);
430  connect(mTrackingToolsAction, &QAction::triggered, this, &MainWindow::toggleTrackingSlot);
433  this->updateTrackingActionSlot();
434 
435  mCenterToImageCenterAction = new QAction(tr("Center Image"), this);
436  mCenterToImageCenterAction->setIcon(QIcon(":/icons/center_image.png"));
437  connect(mCenterToImageCenterAction, &QAction::triggered, this, &MainWindow::centerToImageCenterSlot);
438  mCenterToTooltipAction = new QAction(tr("Center Tool"), this);
439  mCenterToTooltipAction->setIcon(QIcon(":/icons/center_tool.png"));
440  connect(mCenterToTooltipAction, &QAction::triggered, this, &MainWindow::centerToTooltipSlot);
441 
442  mSaveDesktopAction = new QAction(QIcon(":/icons/workflow_state_save.png"), tr("Save desktop"), this);
443  mSaveDesktopAction->setToolTip("Save desktop for workflow step");
444  connect(mSaveDesktopAction, &QAction::triggered, this, &MainWindow::saveDesktopSlot);
445  mResetDesktopAction = new QAction(QIcon(":/icons/workflow_state_revert.png"), tr("Reset desktop"), this);
446  mResetDesktopAction->setToolTip("Reset desktop for workflow step");
447  connect(mResetDesktopAction, &QAction::triggered, this, &MainWindow::resetDesktopSlot);
448 
449  mInteractorStyleActionGroup = viewService()->createInteractorStyleActionGroup();
450 }
451 
453 {
454  this->setWindowState(this->windowState() ^ Qt::WindowFullScreen);
455 
456  settings()->setValue("gui/fullscreen", (this->windowState() & Qt::WindowFullScreen)!=0);
457 }
458 
460 {
461  QDesktopWidget* desktop = qApp->desktop();
462  QList<QScreen*> screens = qApp->screens();
463 
464  for (int i=0; i<desktop->screenCount(); ++i)
465  {
466  QWidget* screenWidget = desktop->screen(i);
467  WId screenWinId = screenWidget->winId();
468  QRect geo = desktop->screenGeometry(i);
469  QString name = "";
470  if (desktop->screenCount()>1)
471  name = screens[i]->name().split(" ").join("");
472  this->saveScreenShot(screens[i]->grabWindow(screenWinId, geo.left(), geo.top(), geo.width(), geo.height()), name);
473  }
474 }
475 
477 {
478  QScreen* screen = qApp->primaryScreen();
479  this->saveScreenShot(screen->grabWindow(this->winId()));
480 }
481 
483 {
484  QString path = patientService()->generateFilePath("Screenshots", "mp4");
485 
486  if(vlc()->isRecording())
487  vlc()->stopRecording();
488  else
489  vlc()->startRecording(path);
490 
491 }
492 
494 {
495  QString fullname = DataLocations::findExecutableInStandardLocations("LogConsole");
496 // std::cout << "MainWindow::onStartLogConsole() " << fullname << std::endl;
497  mLocalVideoServerProcess.reset(new ProcessWrapper(QString("LogConsole")));
498  mLocalVideoServerProcess->launchWithRelativePath(fullname, QStringList());
499 }
500 
501 void MainWindow::saveScreenShot(QPixmap pixmap, QString id)
502 {
503  QString ending = "png";
504  if (!id.isEmpty())
505  ending = id + "." + ending;
506  QString path = patientService()->generateFilePath("Screenshots", ending);
507  QtConcurrent::run(boost::bind(&MainWindow::saveScreenShotThreaded, this, pixmap.toImage(), path));
508 }
509 
513 void MainWindow::saveScreenShotThreaded(QImage pixmap, QString filename)
514 {
515  pixmap.save(filename, "png");
516  report("Saved screenshot to " + filename);
517  reporter()->playScreenShotSound();
518 }
519 
521 {
522  if (videoService()->isConnected())
523  videoService()->closeConnection();
524  else
525  videoService()->openConnection();
526 }
527 
529 {
530  if (videoService()->isConnected())
531  {
532  mStartStreamingAction->setIcon(QIcon(":/icons/streaming_green.png"));
533  mStartStreamingAction->setText("Stop Streaming");
534  }
535  else
536  {
537  mStartStreamingAction->setIcon(QIcon(":/icons/streaming_red.png"));
538  mStartStreamingAction->setText("Start Streaming");
539  }
540 }
541 
543 {
544  NavigationPtr nav = viewService()->getNavigation();
545 
546  if (patientService()->getActiveImage())
547  nav->centerToData(patientService()->getActiveImage());
548  else if (!viewService()->groupCount())
549  nav->centerToView(viewService()->getGroup(0)->getData());
550  else
551  nav->centerToGlobalDataCenter();
552 }
553 
555 {
556  NavigationPtr nav = viewService()->getNavigation();
557  nav->centerToTooltip();
558 }
559 
561 {
562  ViewGroupDataPtr data = viewService()->getGroup(0);
563  ViewGroupData::Options options = data->getOptions();
564  options.mShowPointPickerProbe = !options.mShowPointPickerProbe;
565  data->setOptions(options);
566 }
568 {
569  if (!viewService()->getGroup(0))
570  return;
571  bool show = viewService()->getGroup(0)->getOptions().mShowPointPickerProbe;
572  mShowPointPickerAction->setChecked(show);
573 }
574 
576 {
577  if (trackingService()->getState() >= Tool::tsTRACKING)
578  {
579  mTrackingToolsAction->setIcon(QIcon(":/icons/polaris-green.png"));
580  mTrackingToolsAction->setText("Stop Tracking");
581  }
582  else
583  {
584  mTrackingToolsAction->setIcon(QIcon(":/icons/polaris-red.png"));
585  mTrackingToolsAction->setText("Start Tracking");
586  }
587 }
588 
590 {
591  if (trackingService()->getState() >= Tool::tsTRACKING)
593  else
594  trackingService()->setState(Tool::tsTRACKING);
595 }
596 
597 namespace
598 {
599 QString timestampFormatFolderFriendly()
600 {
601  return QString("yyyy-MM-dd_hh-mm");
602 }
603 }
604 
606 {
607  QString patientDatafolder = this->getExistingSessionFolder();
608 
609  QString timestamp = QDateTime::currentDateTime().toString(timestampFormatFolderFriendly());
610  QString filename = QString("%1_%2_%3.cx3")
611  .arg(timestamp)
612  .arg(profile()->getName())
613  .arg(settings()->value("globalPatientNumber").toString());
614 
615  QString choosenDir = patientDatafolder + "/" + filename;
616 
617  QFileDialog dialog(this, tr("Select directory to save patient in"), patientDatafolder + "/");
618  dialog.setOption(QFileDialog::DontUseNativeDialog, true);
619  dialog.setOption(QFileDialog::ShowDirsOnly, true);
620  dialog.selectFile(filename);
621  if (!dialog.exec())
622  return;
623  choosenDir = dialog.selectedFiles().front();
624 
625  if (!choosenDir.endsWith(".cx3"))
626  choosenDir += QString(".cx3");
627 
628  // Update global patient number
629  int patientNumber = settings()->value("globalPatientNumber").toInt();
630  settings()->setValue("globalPatientNumber", ++patientNumber);
631 
632  mServices->getSession()->load(choosenDir);
633 }
634 
635 QString MainWindow::getExistingSessionFolder()
636 {
637  QString folder = settings()->value("globalPatientDataFolder").toString();
638 
639  // Create folders
640  if (!QDir().exists(folder))
641  {
642  QDir().mkdir(folder);
643  report("Made a new patient folder: " + folder);
644  }
645 
646  return folder;
647 }
648 
650 {
651  mServices->getSession()->clear();
652 }
653 
655 {
656  if (patientService()->getActivePatientFolder().isEmpty())
657  {
658  reportWarning("No patient selected, select or create patient before saving!");
659  this->newPatientSlot();
660  return;
661  }
662 
663  mServices->getSession()->save();
664 }
665 
667 {
668  this->updateWindowTitle();
669 }
670 
671 void MainWindow::updateWindowTitle()
672 {
673  QString profileName = stateService()->getApplicationStateName();
674  QString versionName = stateService()->getVersionName();
675 
676  QString activePatientFolder = patientService()->getActivePatientFolder();
677  if (activePatientFolder.endsWith('/'))
678  activePatientFolder.chop(1);
679  QString patientName;
680 
681  if (!activePatientFolder.isEmpty())
682  {
683  QFileInfo info(activePatientFolder);
684  patientName = info.completeBaseName();
685  }
686 
687  QString format("%1 %2 - %3 - %4 (not approved for medical use)");
688  QString title = format
689  .arg(qApp->applicationDisplayName())
690  .arg(versionName)
691  .arg(profileName)
692  .arg(patientName);
693  this->setWindowTitle(title);
694 }
695 
697 {
698  Desktop desktop = stateService()->getActiveDesktop();
699 
700  this->mDockWidgets->hideAll();
701 // for (std::set<QToolBar*>::iterator i=mToolbars.begin(); i!=mToolbars.end(); ++i)
702 // (*i)->hide();
703 // for (std::set<QToolBar*>::iterator i=mToolbars.begin(); i!=mToolbars.end(); ++i)
704 // this->removeToolBar(*i);
705 // for (std::set<QToolBar*>::iterator i=mToolbars.begin(); i!=mToolbars.end(); ++i)
706 // this->addToolBar(*i);
707 
708  viewService()->setActiveLayout(desktop.mLayoutUid, 0);
709  viewService()->setActiveLayout(desktop.mSecondaryLayoutUid, 1);
710  this->restoreState(desktop.mMainWindowState);
711  patientService()->autoSave();
712 
713 #ifdef CX_APPLE
714  // HACK
715  // Toolbars are not correctly refreshed on mac 10.8,
716  // Cause is related to QVTKWidget (removing it removes the problem)
717  // The following "force refresh by resize" solves repaint, but
718  // inactive toolbars are still partly clickable.
719  QSize size = this->size();
720  this->resize(size.width()-1, size.height());
721  this->resize(size);
722 #endif
723 }
724 
726 {
727  Desktop desktop;
728  desktop.mMainWindowState = this->saveState();
729  desktop.mLayoutUid = viewService()->getActiveLayout(0);
730  desktop.mSecondaryLayoutUid = viewService()->getActiveLayout(1);
731  stateService()->saveDesktop(desktop);
732 }
733 
735 {
736  stateService()->resetDesktop();
738 }
739 
741 {
742  if (!mControlPanel)
743  mControlPanel = new SecondaryMainWindow(this);
744  mControlPanel->show();
745 }
746 
748 {
749  if (!mSecondaryViewLayoutWindow)
750  mSecondaryViewLayoutWindow = new SecondaryViewLayoutWindow(this);
751  mSecondaryViewLayoutWindow->tryShowOnSecondaryScreen();
752 }
753 
755 {
756  QString patientDatafolder = this->getExistingSessionFolder();
757 
758  // Open file dialog
759  QString folder = QFileDialog::getExistingDirectory(this, "Select patient", patientDatafolder, QFileDialog::ShowDirsOnly);
760  if (folder.isEmpty())
761  return;
762 
763  mServices->getSession()->load(folder);
764 }
765 
767 {
768  this->savePatientFileSlot();
769 
770  ExportDataDialog* wizard = new ExportDataDialog(mServices->patientModelService, this);
771  wizard->exec(); //calling exec() makes the wizard dialog modal which prevents other user interaction with the system
772 }
773 
775 {
776  this->savePatientFileSlot();
777 
778  QString folder = mLastImportDataFolder;
779  if (folder.isEmpty())
780  folder = settings()->value("globalPatientDataFolder").toString();
781 
782  QStringList fileName = QFileDialog::getOpenFileNames(this, QString(tr("Select data file(s) for import")),
783  folder, tr("Image/Mesh (*.mhd *.mha *.stl *.vtk *.mnc)"));
784  if (fileName.empty())
785  {
786  report("Import canceled");
787  return;
788  }
789 
790  mLastImportDataFolder = QFileInfo(fileName[0]).absolutePath();
791 
792  for (int i=0; i<fileName.size(); ++i)
793  {
794  ImportDataDialog* wizard = new ImportDataDialog(mServices->patientModelService, fileName[i], this);
795  wizard->exec(); //calling exec() makes the wizard dialog modal which prevents other user interaction with the system
796  }
797 }
798 
800 {
801  this->updateWindowTitle();
802 }
803 
804 void MainWindow::createMenus()
805 {
806 #ifdef CX_LINUX
807  // shortcuts defined on actions in the global menubar is not reachable on Qt5+Ubuntu14.04,
808  // solve by reverting to old style.
809  // This will create a double menubar: remove by autohiding menubar or using
810  // sudo apt-get autoremove appmenu-gtk appmenu-gtk3 appmenu-qt
811  // and reboot
812  this->menuBar()->setNativeMenuBar(false);
813 #endif
814  mFileMenu = new QMenu(tr("File"), this);
815  mWorkflowMenu = new QMenu(tr("Workflow"), this);
816  mToolMenu = new QMenu(tr("Tracking"), this);
817  mLayoutMenu = new QMenu(tr("Layouts"), this);
818  mNavigationMenu = new QMenu(tr("Navigation"), this);
819  mHelpMenu = new QMenu(tr("Help"), this);
820 
821  // File
822  mFileMenu->addAction(mPreferencesAction);
823  this->menuBar()->addMenu(mFileMenu);
824  mFileMenu->addAction(mNewPatientAction);
825  mFileMenu->addAction(mSaveFileAction);
826  mFileMenu->addAction(mLoadFileAction);
827  mFileMenu->addAction(mClearPatientAction);
828  mFileMenu->addSeparator();
829  mFileMenu->addAction(mExportPatientAction);
830  mFileMenu->addAction(mImportDataAction);
831  mFileMenu->addAction(mDeleteDataAction);
832  mFileMenu->addSeparator();
833  mFileMenu->addAction(mFullScreenAction);
834  mFileMenu->addAction(mStartLogConsoleAction);
835  mFileMenu->addAction(mShootScreenAction);
836  mFileMenu->addAction(mShootWindowAction);
837  mFileMenu->addAction(mRecordFullscreenAction);
838  mFileMenu->addSeparator();
839  mFileMenu->addAction(mShowControlPanelAction);
840  mFileMenu->addAction(mSecondaryViewLayoutWindowAction);
841 
842  mFileMenu->addAction(mQuitAction);
843 
844  //workflow
845  this->menuBar()->addMenu(mWorkflowMenu);
846  QList<QAction*> actions = stateService()->getWorkflowActions()->actions();
847  for (int i=0; i<actions.size(); ++i)
848  {
849  mWorkflowMenu->addAction(actions[i]);
850  }
851 
852  mWorkflowMenu->addSeparator();
853  mWorkflowMenu->addAction(mSaveDesktopAction);
854  mWorkflowMenu->addAction(mResetDesktopAction);
855 
856  //tool
857  this->menuBar()->addMenu(mToolMenu);
858  mToolMenu->addAction(mConfigureToolsAction);
859  mToolMenu->addAction(mInitializeToolsAction);
860  mToolMenu->addAction(mTrackingToolsAction);
861  mToolMenu->addSeparator();
862  mToolMenu->addAction(mStartStreamingAction);
863  mToolMenu->addSeparator();
864 
865  //layout
866  this->menuBar()->addMenu(mLayoutMenu);
867  mLayoutInteractor->connectToMenu(mLayoutMenu);
868 
869  this->menuBar()->addMenu(mNavigationMenu);
870  mNavigationMenu->addAction(mCenterToImageCenterAction);
871  mNavigationMenu->addAction(mCenterToTooltipAction);
872  mNavigationMenu->addAction(mShowPointPickerAction);
873  mNavigationMenu->addSeparator();
874  mNavigationMenu->addActions(mInteractorStyleActionGroup->actions());
875 
876  mHelpMenuAction = this->menuBar()->addMenu(mHelpMenu);
877  mHelpMenu->addAction(mAboutAction);
878  mHelpMenu->addAction(QWhatsThis::createAction(this));
879 }
880 
881 void MainWindow::createToolBars()
882 {
883  mDataToolBar = addToolBar("Data");
884  mDataToolBar->setObjectName("DataToolBar");
885  mDataToolBar->addAction(mNewPatientAction);
886  mDataToolBar->addAction(mLoadFileAction);
887  mDataToolBar->addAction(mSaveFileAction);
888  mDataToolBar->addAction(mImportDataAction);
889  this->registerToolBar(mDataToolBar, "Toolbar");
890 
891  mToolToolBar = addToolBar("Tools");
892  mToolToolBar->setObjectName("ToolToolBar");
893  mToolToolBar->addAction(mTrackingToolsAction);
894  mToolToolBar->addAction(mStartStreamingAction);
895  this->registerToolBar(mToolToolBar, "Toolbar");
896 
897  mNavigationToolBar = addToolBar("Navigation");
898  mNavigationToolBar->setObjectName("NavigationToolBar");
899  mNavigationToolBar->addAction(mCenterToImageCenterAction);
900  mNavigationToolBar->addAction(mCenterToTooltipAction);
901  mNavigationToolBar->addAction(mShowPointPickerAction);
902  this->registerToolBar(mNavigationToolBar, "Toolbar");
903 
904  mInteractorStyleToolBar = addToolBar("InteractorStyle");
905  mInteractorStyleToolBar->setObjectName("InteractorStyleToolBar");
906 
907  mInteractorStyleToolBar->addActions(mInteractorStyleActionGroup->actions());
908  this->registerToolBar(mInteractorStyleToolBar, "Toolbar");
909 
910  mWorkflowToolBar = addToolBar("Workflow");
911  mWorkflowToolBar->setObjectName("WorkflowToolBar");
912 
913  QList<QAction*> actions = stateService()->getWorkflowActions()->actions();
914  for (int i=0; i<actions.size(); ++i)
915  {
916  mWorkflowToolBar->addAction(actions[i]);
917  }
918 
919  this->registerToolBar(mWorkflowToolBar, "Toolbar");
920 
921  mDesktopToolBar = addToolBar("Desktop");
922  mDesktopToolBar->setObjectName("DesktopToolBar");
923  mDesktopToolBar->addAction(mSaveDesktopAction);
924  mDesktopToolBar->addAction(mResetDesktopAction);
925  this->registerToolBar(mDesktopToolBar, "Toolbar");
926 
927  mHelpToolBar = addToolBar("Help");
928  mHelpToolBar->setObjectName("HelpToolBar");
929  mHelpToolBar->addAction(QWhatsThis::createAction(this));
930  this->registerToolBar(mHelpToolBar, "Toolbar");
931 
932  mScreenshotToolBar = addToolBar("Screenshot");
933  mScreenshotToolBar->setObjectName("ScreenshotToolBar");
934  mScreenshotToolBar->addAction(mShootScreenAction);
935  this->registerToolBar(mScreenshotToolBar, "Toolbar");
936 
937  QToolBar* camera3DViewToolBar = addToolBar("Camera 3D Views");
938  camera3DViewToolBar->setObjectName("Camera3DViewToolBar");
939  camera3DViewToolBar->addActions(mStandard3DViewActions->actions());
940  this->registerToolBar(camera3DViewToolBar, "Toolbar");
941 
942  QToolBar* samplerWidgetToolBar = addToolBar("Sampler");
943  samplerWidgetToolBar->setObjectName("SamplerToolBar");
944  samplerWidgetToolBar->addWidget(new SamplerWidget(this));
945  this->registerToolBar(samplerWidgetToolBar, "Toolbar");
946 
947  QToolBar* toolOffsetToolBar = addToolBar("Tool Offset");
948  toolOffsetToolBar->setObjectName("ToolOffsetToolBar");
949  toolOffsetToolBar->addWidget(createDataWidget(mServices->visualizationService, mServices->patientModelService, this, DoublePropertyActiveToolOffset::create()));
950  this->registerToolBar(toolOffsetToolBar, "Toolbar");
951 }
952 
953 void MainWindow::registerToolBar(QToolBar* toolbar, QString groupname)
954 {
955  this->addToWidgetGroupMap(toolbar->toggleViewAction(), groupname);
956  // this avoids overpopulation of gui at startup, and is the same functionality as for dockwidgets.
957  // also gives correct size of mainwindow at startup.
958  mToolbars.insert(toolbar);
959  if (!mToolbars.empty())
960  toolbar->hide();
961 }
962 
964 {
965  QString doc_path = DataLocations::getDocPath();
966  QString appName = qApp->applicationDisplayName();
967  QString url_github("https://github.com/SINTEFMedtek/CustusX");
968  QString url_license = QString("file://%1/license.txt").arg(doc_path);
969  QString url_config = QString("file://%1/cxConfigDescription.txt").arg(doc_path);
970 
971  QString text(""
972  "<h2>%1</h2>"
973  "<h4>%2</h4>"
974  "<p>A Research Platform for Image-Guided Therapy<p>"
975  "<p>%1 is NOT approved for medical use.<p>"
976  ""
977  "<p><a href=%3> website </a><p>"
978  "<p><a href=%4> license </a><p>"
979  "<p><a href=%5> configuration </a><p>");
980 
981  QMessageBox::about(this, tr("About %1").arg(appName), text
982  .arg(appName)
983  .arg(CustusX_VERSION_STRING)
984  .arg(url_github)
985  .arg(url_license)
986  .arg(url_config)
987  );
988 }
989 
991 {
992  PreferencesDialog prefDialog(mServices->visualizationService, mServices->patientModelService, this);
993  prefDialog.exec();
994 }
995 
997 {
998  report("Shutting down CustusX");
999  viewService()->deactivateLayout();
1000 
1001  patientService()->autoSave();
1002 
1003  settings()->setValue("mainWindow/geometry", saveGeometry());
1004  settings()->setValue("mainWindow/windowState", saveState());
1005  settings()->sync();
1006  report("Closing: Save geometry and window state");
1007 
1008  qApp->quit();
1009 }
1010 
1012 {
1013  if (!patientService()->getActiveImage())
1014  return;
1015  QString text = QString("Do you really want to delete data %1?").arg(patientService()->getActiveImage()->getName());
1016  if (QMessageBox::question(this, "Data delete", text, QMessageBox::StandardButtons(QMessageBox::Ok | QMessageBox::Cancel))!=QMessageBox::Ok)
1017  return;
1018  mServices->patientModelService->removeData(patientService()->getActiveImageUid());
1019 }
1020 
1022 {
1023  trackingService()->setState(Tool::tsCONFIGURED);
1024 }
1025 
1026 void MainWindow::closeEvent(QCloseEvent *event)
1027 {
1028  QMainWindow::closeEvent(event);
1029  this->quitSlot();
1030 }
1031 
1032 QDockWidget* MainWindow::addAsDockWidget(QWidget* widget, QString groupname)
1033 {
1034  QDockWidget* dockWidget = mDockWidgets->addAsDockWidget(widget, groupname);
1035  this->addToWidgetGroupMap(dockWidget->toggleViewAction(), groupname);
1036  QMainWindow::addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
1037  this->restoreDockWidget(dockWidget); // restore if added after construction
1038  return dockWidget;
1039 }
1040 
1041 }//namespace cx
void newPatientSlot()
Create new patient with directory structure.
Widget for controlling camera follow style.
cxResource_EXPORT ProfilePtr profile()
Definition: cxProfile.cpp:142
void toggleStreamingSlot()
boost::shared_ptr< class ViewGroupData > ViewGroupDataPtr
Definition: cxViewGroup.h:50
void onPluginBaseModified(GUIExtenderService *service)
void dockWidgetVisibilityChanged(bool val)
virtual QMenu * createPopupMenu()
ReporterPtr reporter()
Definition: cxReporter.cpp:59
void changeEvent(QEvent *event)
void connected(bool on)
Statusbar with extended functionality.
Definition: cxStatusBar.h:92
void applicationStateChanged()
void updateTrackingActionSlot()
void onStartLogConsole()
void showSecondaryViewLayoutWindowActionSlot()
void onPluginBaseAdded(GUIExtenderService *service)
void clearPatientSlot()
clear current patient (debug)
void focusChanged(QWidget *old, QWidget *now)
void savePatientFileSlot()
Save all application data to XML file.
void patientChangedSlot()
static VisServicesPtr create(ctkPluginContext *context)
cxLogicManager_EXPORT StateServicePtr stateService()
Experimental class for IPad usage.This detached main window can be moved onto a secondary screen...
QWidget * createDataWidget(VisualizationServicePtr visualizationService, PatientModelServicePtr patientModelService, QWidget *parent, PropertyPtr data, QGridLayout *gridLayout, int row)
Create a widget capable of displaying the input data.
Widget for displaying status messages.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Definition: cxSettings.cpp:99
Handles dock widgets for main window.
Definition: cxDockWidgets.h:25
void startRecording(QString saveFile)
void togglePointPickerActionSlot()
boost::shared_ptr< class Navigation > NavigationPtr
Definition: cxViewGroup.h:54
Widget for displaying and manipulating various 3D Volume properties.
void toggleTrackingSlot()
void onApplicationStateChangedSlot()
configured with basic info
Definition: cxTool.h:81
void resetDesktopSlot()
void updatePointPickerActionSlot()
void setValue(const QString &key, const QVariant &value)
Definition: cxSettings.cpp:91
GUI for setting up a connection to a video stream.
Widget for controlling the camera in the 3D view.This widget is designed for use on a touchpad device...
Experimental class for IPad usage.
void workflowStateAboutToChange()
void toggleFullScreenSlot()
void reportWarning(QString msg)
Definition: cxLogger.cpp:91
void importDataSlot()
loads data(images) into the datamanager
MainWindow(std::vector< GUIExtenderServicePtr > guiExtenders=std::vector< GUIExtenderServicePtr >())
void preferencesSlot()
void onPluginBaseRemoved(GUIExtenderService *service)
void centerToTooltipSlot()
void saveDesktopSlot()
void loadPatientFileSlot()
Load all application data from XML file.
virtual void setState(const Tool::State val)=0
QByteArray mMainWindowState
QDockWidget * addAsDockWidget(QWidget *widget, QString groupname="")
static LogicManager * getInstance()
void recordFullscreen()
Widget interface to PlaybackTime.
Settings * settings()
Shortcut for accessing the settings instance.
Definition: cxSettings.cpp:42
Widget for displaying the FrameForest object.
void updateStreamingActionSlot()
connected to hardware, if any, ready to use
Definition: cxTool.h:82
Widget for displaying and manipulating TrackedStream properties.
static boost::shared_ptr< DoublePropertyActiveToolOffset > create()
Helper class for listening to services being added, modified and removed.
LogicManager * logicManager()
void workflowStateChanged()
Data class for CustusX desktop.
void showControlPanelActionSlot()
void centerToImageCenterSlot()
boost::shared_ptr< class CameraControl > CameraControlPtr
Definition: cxMainWindow.h:57
QString mLayoutUid
cxLogicManager_EXPORT ViewServicePtr viewService()
virtual ~MainWindow()
void report(QString msg)
Definition: cxLogger.cpp:90
void deleteDataSlot()
deletes data(image) from the patient
cxLogicManager_EXPORT VideoServicePtr videoService()
static QString findExecutableInStandardLocations(QString filename)
look for an exe in the same folder as the executable or bundle.
cxLogicManager_EXPORT PatientModelServicePtr patientService()
QString mSecondaryLayoutUid
Designed as a debugging widget for the cxToolManager.
emitting tracking data
Definition: cxTool.h:83
cxLogicManager_EXPORT TrackingServicePtr trackingService()
void onWorkflowStateChangedSlot()
static QString getDocPath()
return path to folder containing documentation files
Widget for displaying information about meshes.
Set application preferences.
boost::shared_ptr< Audio > AudioPtr
Definition: cxAudio.h:68
void erase(QDockWidget *dockWidget)
void configureSlot()
lets the user choose which configuration files to use for the navigation
Widget for erasing parts of images/meshes.
VLCRecorder * vlc()
Shortcut for accessing the vlc recorder.