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