CustusX  20.03-rc1
An IGT application
cxMainWindowActions.cpp
Go to the documentation of this file.
1 #include "cxMainWindowActions.h"
2 
3 #include <QtConcurrent>
4 #include <QWidget>
5 #include <QFileDialog>
6 #include <QAction>
7 #include <QScreen>
8 #include <QDesktopWidget>
9 #include <QMessageBox>
10 #include <QApplication>
11 #include <QDesktopServices>
12 #include <QDockWidget>
13 #include <QAction>
14 
15 #include "boost/bind.hpp"
16 #include "boost/function.hpp"
17 #include "cxReporter.h"
18 #include "cxLogger.h"
19 #include "cxConfig.h"
20 #include "cxDataLocations.h"
21 #include "cxProfile.h"
22 #include "cxLogicManager.h"
23 #include "cxTrackingService.h"
24 #include "cxSettings.h"
25 #include "cxVideoService.h"
26 #include "cxNavigation.h"
27 #include "cxImage.h"
28 #include "cxPatientModelService.h"
29 #include "cxViewService.h"
30 #include "cxViewGroupData.h"
32 #include "cxVisServices.h"
33 #include "cxVLCRecorder.h"
34 #include "cxImportDataDialog.h"
35 #include "cxExportDataDialog.h"
37 #include "cxViewCollectionWidget.h"
39 #include "cxFileHelpers.h"
40 #include "cxFileManagerService.h"
42 #include "cxApplication.h"
43 
44 namespace cx
45 {
46 
48  QObject(parent),
49  mServices(services),
50  mScreenShotWriter(ScreenShotImageWriter::create(services->patient()))
51 {
52  this->createActions();
53 }
54 
55 QAction* MainWindowActions::getAction(QString uid)
56 {
57  if (!mActions.count(uid))
58  CX_LOG_ERROR() << QString("Could not find action %1 in MainWindowActions object").arg(uid);
59  return mActions[uid];
60 }
61 
62 void MainWindowActions::createActions()
63 {
64  this->createAction("GotoDocumentation", "Web Documentation",
65  QIcon(":/icons/open_icon_library/applications-internet.png"),
66  QKeySequence(""), "",
67  &MainWindowActions::onGotoDocumentation);
68 
69  this->createAction("StartLogConsole", "Start Log Console",
70  QIcon(),
71  QKeySequence("Ctrl+D"), "Open Log Console as external application",
72  &MainWindowActions::onStartLogConsole);
73 
74  this->createAction("ShootScreen", "Shoot Screen",
75  QIcon(":/icons/screenshot-screen.png"),
76  QKeySequence("Ctrl+f"), "Save a screenshot to the patient folder.",
77  &MainWindowActions::shootScreen);
78 
79  this->createAction("ShootWindow", "Shoot Window",
80  QIcon(":/icons/screenshot-window.png"),
81  QKeySequence("Ctrl+Shift+f"), "Save an image of the application to the patient folder.",
82  &MainWindowActions::shootWindow);
83 
84  mRecordFullscreenStreamingAction = this->createAction("RecordFullscreen", "Record Fullscreen",
85  QIcon(),
86  QKeySequence("F8"), "Record a video of the full screen.",
87  &MainWindowActions::recordFullscreen);
88  connect(vlc(), &VLCRecorder::stateChanged, this, &MainWindowActions::updateRecordFullscreenActionSlot);
89  this->updateRecordFullscreenActionSlot();
90 
91  mShowPointPickerAction = this->createAction("ShowPointPicker", "Point Picker",
92  QIcon(":/icons/point_picker.png"),
93  QKeySequence(""), "Activate the 3D Point Picker Probe",
94  &MainWindowActions::togglePointPickerActionSlot);
95  mShowPointPickerAction->setCheckable(true);
96 
97  if (mServices->view()->getGroup(0))
98  connect(mServices->view()->getGroup(0).get(), &ViewGroupData::optionsChanged, this, &MainWindowActions::updatePointPickerActionSlot);
99  this->updatePointPickerActionSlot();
100 
101  mStartStreamingAction = this->createAction("StartStreaming", "Start Streaming",
102  QIcon(":/icons/open_icon_library/.png"),
103  QKeySequence("Ctrl+V"), "",
104  &MainWindowActions::toggleStreamingSlot);
105  connect(mServices->video().get(), &VideoService::connected, this, &MainWindowActions::updateStreamingActionSlot);
106  this->updateStreamingActionSlot();
107 
108  this->createAction("CenterToImageCenter", "Center Image",
109  QIcon(":/icons/center_image.png"),
110  QKeySequence(), "",
111  &MainWindowActions::centerToImageCenterSlot);
112 
113  this->createAction("CenterToTooltip", "Center Tool",
114  QIcon(":/icons/center_tool.png"),
115  QKeySequence(""), "",
116  &MainWindowActions::centerToTooltipSlot);
117 
118  this->createPatientActions();
119  this->createTrackingActions();
120 }
121 
122 void MainWindowActions::createTrackingActions()
123 {
124  this->createAction("ConfigureTools", "Tool configuration",
125  QIcon(), QKeySequence(), "",
126  &MainWindowActions::configureSlot);
127 
128  boost::function<void()> finit = boost::bind(&TrackingService::setState, mServices->tracking(), Tool::tsINITIALIZED);
129  this->createAction("InitializeTools", "Initialize",
130  QIcon(), QKeySequence(), "",
131  finit);
132 
133  mTrackingToolsAction = this->createAction("TrackingTools", "Start tracking",
134  QIcon(), QKeySequence("Ctrl+T"), "",
135  &MainWindowActions::toggleTrackingSlot);
136 
137  connect(mServices->tracking().get(), &TrackingService::stateChanged, this, &MainWindowActions::updateTrackingActionSlot);
138  this->updateTrackingActionSlot();
139 }
140 
141 void MainWindowActions::createPatientActions()
142 {
143  this->createAction("NewPatient", "New Patient",
144  QIcon(":/icons/open_icon_library/document-new-8.png"),
145  QKeySequence("Ctrl+N"),
146  "Create a new patient file",
147  &MainWindowActions::newPatientSlot);
148 
149  this->createAction("SaveFile", "Save Patient",
150  QIcon(":/icons/open_icon_library/document-save-5.png"),
151  QKeySequence("Ctrl+S"),
152  "Save patient file",
153  &MainWindowActions::savePatientFileSlot);
154 
155  this->createAction("LoadFile", "Load Patient",
156  QIcon(":/icons/open_icon_library/document-open-7.png"),
157  QKeySequence("Ctrl+L"),
158  "Load patient file",
159  &MainWindowActions::loadPatientFileSlot);
160 
161  this->createAction("LoadFileCopy", "Load from Patient template",
162  QIcon(":/icons/open_icon_library/document-open-7.png"),
163  QKeySequence(),
164  "Create a new patient based on a template",
165  &MainWindowActions::loadPatientFileCopySlot);
166 
167  this->createAction("ClearPatient", "Clear Patient",
168  QIcon(),
169  QKeySequence(),
170  "Clear the current patient from the application",
171  &MainWindowActions::clearPatientSlot);
172 
173  this->createAction("ExportPatient", "Export Patient",
174  QIcon(),
175  QKeySequence(),
176  "Export patient data to a folder",
177  &MainWindowActions::exportDataSlot);
178 
179  this->createAction("ImportData", "Import data",
180  QIcon(":/icons/open_icon_library/document-import-2.png"),
181  QKeySequence("Ctrl+I"),
182  "Import image data",
183  &MainWindowActions::importDataSlot);
184 }
185 
186 template <class T>
187 QAction* MainWindowActions::createAction(QString uid, QString text, QIcon icon,
188  QKeySequence shortcut, QString help,
189  T triggerSlot)
190 {
191  QAction* retval = new QAction(icon, text, this);
192  retval->setObjectName(uid);
193  retval->setShortcut(shortcut);
194  retval->setStatusTip(help);
195  connect(retval, &QAction::triggered, this, triggerSlot);
196  mActions[uid] = retval;
197  return retval;
198 }
199 
200 namespace
201 {
202 QString timestampFormatFolderFriendly()
203 {
204  return QString("yyyy-MM-dd_hh-mm");
205 }
206 }
207 
208 QWidget* MainWindowActions::parentWidget()
209 {
210  return dynamic_cast<QWidget*>(this->parent());
211 }
212 
213 
214 void MainWindowActions::newPatientSlot()
215 {
216  QString choosenDir = this->selectNewPatientFolder();
217  if(choosenDir.isEmpty())
218  return;
219 
220  // Update global patient number
221  int patientNumber = settings()->value("globalPatientNumber").toInt();
222  settings()->setValue("globalPatientNumber", ++patientNumber);
223 
224  mServices->session()->load(choosenDir);
225 }
226 
227 QString MainWindowActions::selectNewPatientFolder()
228 {
229  QString patientDatafolder = this->getExistingSessionFolder();
230 
231  QString timestamp = QDateTime::currentDateTime().toString(timestampFormatFolderFriendly());
232  QString filename = QString("%1_%2_%3.cx3")
233  .arg(timestamp)
234  .arg(profile()->getName())
235  .arg(settings()->value("globalPatientNumber").toString());
236 
237  QString choosenDir = patientDatafolder + "/" + filename;
238 
239  QFileDialog dialog(this->parentWidget(), tr("Select directory to save patient in"), patientDatafolder + "/");
240  dialog.setOption(QFileDialog::DontUseNativeDialog, true);
241  dialog.setOption(QFileDialog::ShowDirsOnly, true);
242  dialog.selectFile(filename);
243  if (!dialog.exec())
244  return QString();
245  choosenDir = dialog.selectedFiles().front();
246 
247  if (!choosenDir.endsWith(".cx3"))
248  choosenDir += QString(".cx3");
249 
250  return choosenDir;
251 }
252 
253 QString MainWindowActions::getExistingSessionFolder()
254 {
255  return profile()->getSessionRootFolder();
256 }
257 
258 void MainWindowActions::clearPatientSlot()
259 {
260  mServices->session()->clear();
261 }
262 
263 void MainWindowActions::savePatientFileSlot()
264 {
265  if (mServices->patient()->getActivePatientFolder().isEmpty())
266  {
267  reportWarning("No patient selected, select or create patient before saving!");
268  this->newPatientSlot();
269  return;
270  }
271 
272  mServices->session()->save();
273 }
274 
275 void MainWindowActions::loadPatientFileSlot()
276 {
277  QString patientDatafolder = this->getExistingSessionFolder();
278 
279  // Open file dialog
280  QString folder = QFileDialog::getExistingDirectory(this->parentWidget(), "Select patient", patientDatafolder, QFileDialog::ShowDirsOnly);
281  if (folder.isEmpty())
282  return;
283 
284  mServices->session()->load(folder);
285 }
286 
287 void MainWindowActions::loadPatientFileCopySlot()
288 {
289  QString patientDatafolder = profile()->getPatientTemplatePath();
290 
291  // Open file dialog
292  QString folder = QFileDialog::getExistingDirectory(this->parentWidget(), "Select template patient to copy", patientDatafolder, QFileDialog::ShowDirsOnly);
293  if (folder.isEmpty())
294  return;
295 
296  QString newFolder = this->selectNewPatientFolder();
297  if (newFolder.isEmpty())
298  return;
299 
300  if(!copyRecursively(folder, newFolder, true))
301  {
302  CX_LOG_WARNING() << "MainWindowActions::loadPatientFileCopySlot(): Cannot copy patient folder: " << folder;
303  return;
304  }
305 
306  mServices->session()->load(newFolder);
307 }
308 
309 void MainWindowActions::exportDataSlot()
310 {
311  this->savePatientFileSlot();
312 
313  ExportDataDialog* wizard = new ExportDataDialog(mServices->patient(), this->parentWidget());
314  wizard->exec(); //calling exec() makes the wizard dialog modal which prevents other user interaction with the system
315 }
316 
317 void MainWindowActions::importDataSlot()
318 {
319  this->savePatientFileSlot();
320 
321  QDockWidget* importDockWidget = findMainWindowChildWithObjectName<QDockWidget*>("import_widgetDockWidget");
322  if(!importDockWidget)
323  {
324  CX_LOG_ERROR() << "Cannot find DockWidget for ImportWidget";
325  return;
326  }
327 
328  importDockWidget->show();
329  importDockWidget->raise();
330 
331  QWidget* widget = findMainWindowChildWithObjectName<QWidget*>("import_widget");
332  if(!widget)
333  {
334  CX_LOG_ERROR() << "Cannot find ImportWidget";
335  return;
336  }
337 
338  QList<QAction*> actions = widget->actions();
339  foreach(QAction* action, actions)
340  {
341  if(action->text().contains("AddMoreFilesButtonClickedAction"))
342  action->trigger();
343  }
344 }
345 
346 void MainWindowActions::shootScreen()
347 {
348  mScreenShotWriter->grabAllScreensToFile();
349 }
350 
351 void MainWindowActions::shootWindow()
352 {
353 // this->shootOneLayout(0);
354 
355  int index=0;
356  while (mServices->view()->getLayoutWidget(index))
357  this->shootOneLayout(index++);
358 }
359 
360 void MainWindowActions::shootOneLayout(int index)
361 {
362  QWidget* widget = mServices->view()->getLayoutWidget(index);
363  ViewCollectionWidget* vcWidget = dynamic_cast<ViewCollectionWidget*>(widget);
364 
365  ViewCollectionImageWriter grabber(vcWidget);
367  mScreenShotWriter->save(pm, QString("_layout%1").arg(index));
368 }
369 
370 void MainWindowActions::recordFullscreen()
371 {
372  QString path = mServices->patient()->generateFilePath("Screenshots", "mp4");
373 
374  if(vlc()->isRecording())
375  vlc()->stopRecording();
376  else
377  vlc()->startRecording(path);
378 }
379 
380 void MainWindowActions::updateRecordFullscreenActionSlot()
381 {
382  mRecordFullscreenStreamingAction->setCheckable(true);
383  mRecordFullscreenStreamingAction->blockSignals(true);
384  mRecordFullscreenStreamingAction->setChecked(vlc()->isRecording());
385  mRecordFullscreenStreamingAction->blockSignals(false);
386 
387  if(vlc()->isRecording())
388  {
389  mRecordFullscreenStreamingAction->setIcon(QIcon(":/icons/Video-icon_green.png"));
390  }
391  else
392  {
393  mRecordFullscreenStreamingAction->setIcon(QIcon(":/icons/Video-icon_gray.png"));
394  }
395 
396 }
397 
398 void MainWindowActions::onStartLogConsole()
399 {
400  QString fullname = DataLocations::findExecutableInStandardLocations("LogConsole");
401 // std::cout << "MainWindowActions::onStartLogConsole() " << fullname << std::endl;
402  mLocalVideoServerProcess.reset(new ProcessWrapper(QString("LogConsole")));
403  mLocalVideoServerProcess->launchWithRelativePath(fullname, QStringList());
404 }
405 
406 void MainWindowActions::toggleStreamingSlot()
407 {
408  if (mServices->video()->isConnected())
409  mServices->video()->closeConnection();
410  else
411  mServices->video()->openConnection();
412 }
413 
414 void MainWindowActions::updateStreamingActionSlot()
415 {
416  if (mServices->video()->isConnected())
417  {
418  mStartStreamingAction->setIcon(QIcon(":/icons/streaming_green.png"));
419  mStartStreamingAction->setText("Stop Streaming");
420  }
421  else
422  {
423  mStartStreamingAction->setIcon(QIcon(":/icons/streaming_red.png"));
424  mStartStreamingAction->setText("Start Streaming");
425  }
426 }
427 
428 void MainWindowActions::centerToImageCenterSlot()
429 {
430  mServices->view()->centerToImageCenterInActiveViewGroup();
431 }
432 
433 void MainWindowActions::centerToTooltipSlot()
434 {
435  NavigationPtr nav = mServices->view()->getNavigation();
436  nav->centerToTooltip();
437 }
438 
439 void MainWindowActions::togglePointPickerActionSlot()
440 {
441  ViewGroupDataPtr data = mServices->view()->getGroup(0);
442  ViewGroupData::Options options = data->getOptions();
443  options.mShowPointPickerProbe = !options.mShowPointPickerProbe;
444  data->setOptions(options);
445 }
446 void MainWindowActions::updatePointPickerActionSlot()
447 {
448  if (!mServices->view()->getGroup(0))
449  return;
450  bool show = mServices->view()->getGroup(0)->getOptions().mShowPointPickerProbe;
451  mShowPointPickerAction->setChecked(show);
452 }
453 
454 void MainWindowActions::updateTrackingActionSlot()
455 {
456  if (mServices->tracking()->getState() >= Tool::tsTRACKING)
457  {
458  mTrackingToolsAction->setIcon(QIcon(":/icons/polaris-green.png"));
459  mTrackingToolsAction->setText("Stop Tracking");
460  }
461  else
462  {
463  mTrackingToolsAction->setIcon(QIcon(":/icons/polaris-red.png"));
464  mTrackingToolsAction->setText("Start Tracking");
465  }
466 }
467 
468 void MainWindowActions::configureSlot()
469 {
470  mServices->tracking()->setState(Tool::tsCONFIGURED);
471 }
472 
473 void MainWindowActions::toggleTrackingSlot()
474 {
475  if (mServices->tracking()->getState() >= Tool::tsTRACKING)
476  mServices->tracking()->setState(Tool::tsINITIALIZED);
477  else
478  mServices->tracking()->setState(Tool::tsTRACKING);
479 }
480 
481 void MainWindowActions::onGotoDocumentation()
482 {
484  QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode));
485 }
486 
487 
488 
489 } // namespace cx
cxResource_EXPORT ProfilePtr profile()
Definition: cxProfile.cpp:160
boost::shared_ptr< class ViewGroupData > ViewGroupDataPtr
Definition: cxViewGroup.h:29
void connected(bool on)
boost::shared_ptr< class VisServices > VisServicesPtr
Definition: cxMainWindow.h:40
static QString getWebsiteUserDocumentationURL()
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Definition: cxSettings.cpp:66
void startRecording(QString saveFile)
bool copyRecursively(QString sourceDir, QString destinationDir, bool overWriteDirectory)
configured with basic info
Definition: cxTool.h:75
void setValue(const QString &key, const QVariant &value)
Definition: cxSettings.cpp:58
static QImage vtkImageData2QImage(vtkImageDataPtr input)
void reportWarning(QString msg)
Definition: cxLogger.cpp:70
#define CX_LOG_ERROR
Definition: cxLogger.h:99
MainWindowActions(VisServicesPtr services, QWidget *parent)
virtual void setState(const Tool::State val)=0
Settings * settings()
Shortcut for accessing the settings instance.
Definition: cxSettings.cpp:21
connected to hardware, if any, ready to use
Definition: cxTool.h:76
QAction * getAction(QString uid)
#define CX_LOG_WARNING
Definition: cxLogger.h:98
static QString findExecutableInStandardLocations(QString filename)
look for an exe in the same folder as the executable or bundle.
emitting tracking data
Definition: cxTool.h:77
boost::shared_ptr< class Navigation > NavigationPtr
VLCRecorder * vlc()
Shortcut for accessing the vlc recorder.
Namespace for all CustusX production code.