PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
QPlusDeviceSetSelectorWidget.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2 Program: Plus
3 Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4 See License.txt for details.
5 =========================================================Plus=header=end*/
6 
7 // Local includes
9 
10 // PlusLib includes
11 //#include <vtkIGSIOTransformRepository.h>
12 
13 // Qt includes
14 #include <QAbstractItemView>
15 #include <QAction>
16 #include <QComboBox>
17 #include <QDesktopServices>
18 #include <QDesktopWidget>
19 #include <QDomDocument>
20 #include <QFileDialog>
21 #include <QKeyEvent>
22 #include <QMenu>
23 #include <QMessageBox>
24 #include <QMimeData>
25 #include <QProcess>
26 #include <QTimer>
27 #include <QUrl>
28 
29 #if !defined(_WIN32)
30 #include <unistd.h>
31 #endif
32 
34 {
35  FileNameRole = Qt::UserRole + 0,
36  DescriptionRole = Qt::UserRole + 1
37 };
38 
39 //-----------------------------------------------------------------------------
40 
42  : QWidget(aParent)
43  , m_ConnectionSuccessful(false)
44  , m_EditMenu(NULL)
45  , m_EditorSelectAction(NULL)
46  , m_EditApplicationConfigFileAction(NULL)
47  , m_DeviceSetComboBoxMaximumSizeRatio(-1)
48 {
49  // Accept drop of files from explorer (and others)
50  setAcceptDrops(true);
51 
52  ui.setupUi(this);
53 
54  // Make the directory and configuration selector textbox/combobox the same height as the pushbuttons
55  // to make the layout nicer (they are shown in the same row, so it does not look nice if their height is different)
56  ui.lineEdit_ConfigurationDirectory->setFixedHeight(ui.pushButton_OpenConfigurationDirectory->sizeHint().height());
57  ui.comboBox_DeviceSet->setFixedHeight(ui.pushButton_EditConfiguration->sizeHint().height());
58 
59  ui.pushButton_EditConfiguration->setContextMenuPolicy(Qt::CustomContextMenu);
60 
61  connect(ui.pushButton_OpenConfigurationDirectory, SIGNAL(clicked()), this, SLOT(OpenConfigurationDirectory()));
62  connect(ui.pushButton_Connect, SIGNAL(clicked()), this, SLOT(InvokeConnect()));
63  connect(ui.pushButton_RefreshFolder, SIGNAL(clicked()), this, SLOT(RefreshFolder()));
64  connect(ui.pushButton_EditConfiguration, SIGNAL(clicked()), this, SLOT(EditConfiguration()));
65  connect(ui.comboBox_DeviceSet, SIGNAL(currentIndexChanged(int)), this, SLOT(DeviceSetSelected(int)));
66  connect(ui.pushButton_ResetTracker, SIGNAL(clicked()), this, SLOT(ResetTrackerButtonClicked()));
67  ui.pushButton_ResetTracker->setVisible(false);
68 
69  connect(ui.pushButton_EditConfiguration, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(ShowEditContextMenu(QPoint)));
70 
71  // Add a small delay to allow the Qt event loop system to make connections before SetConfigurationDirectory is called.
72  // This ensures that signals are fired on first launch
73  QTimer::singleShot(10, Qt::CoarseTimer, this, [this]() {SetConfigurationDirectory(vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationDirectory().c_str()); });
74 }
75 
76 //----------------------------------------------------------------------------
78 {
80 }
81 
82 //-----------------------------------------------------------------------------
84 {
85  if (this->m_EditMenu)
86  {
87  delete this->m_EditMenu;
88  m_EditMenu = NULL;
89  }
90  if (this->m_EditorSelectAction)
91  {
92  disconnect(m_EditorSelectAction, &QAction::triggered, this, &QPlusDeviceSetSelectorWidget::SelectEditor);
93  delete this->m_EditorSelectAction;
94  m_EditorSelectAction = NULL;
95  }
97  {
101  }
102 }
103 
104 //-----------------------------------------------------------------------------
106 {
107  LOG_TRACE("DeviceSetSelectorWidget::SetConfigurationDirectory(" << aDirectory.toStdString() << ")");
108 
109  // Try to parse up directory and set UI according to the result
110  if (ParseDirectory(aDirectory))
111  {
112  ui.lineEdit_ConfigurationDirectory->setText(aDirectory);
113  ui.lineEdit_ConfigurationDirectory->setToolTip(aDirectory);
114 
115  m_ConfigurationDirectory = aDirectory;
116 
117  // Save the selected directory to config object
120 
122 
123  return PLUS_SUCCESS;
124  }
125  else
126  {
127  ui.lineEdit_ConfigurationDirectory->setText(tr("Invalid configuration directory"));
128  ui.lineEdit_ConfigurationDirectory->setToolTip("No valid configuration files in directory, please select another");
129 
130  ui.textEdit_Description->setTextColor(QColor(Qt::darkRed));
131  ui.textEdit_Description->setText("Selected directory does not contain valid device set configuration files!\n\nPlease select another directory");
132 
133  return PLUS_FAIL;
134  }
135 }
136 
137 //----------------------------------------------------------------------------
139 {
140  QString fileName = QDir::toNativeSeparators(aFilename);
141  QFileInfo info(fileName);
142  if (info.exists())
143  {
144  if (this->SetConfigurationDirectory(info.absoluteDir().absolutePath()) == PLUS_SUCCESS)
145  {
146  QString fileName = QDir::toNativeSeparators(info.absoluteFilePath());
147  ui.comboBox_DeviceSet->setCurrentIndex(ui.comboBox_DeviceSet->findData(fileName));
148  return PLUS_SUCCESS;
149  }
150  }
151 
152  return PLUS_FAIL;
153 }
154 
155 //-----------------------------------------------------------------------------
157 {
158  LOG_TRACE("DeviceSetSelectorWidget::OpenConfigurationDirectoryClicked");
159 
160  // Directory open dialog for selecting configuration directory
161  QString dirName = QFileDialog::getExistingDirectory(NULL, QString(tr("Open configuration directory")), m_ConfigurationDirectory);
162  if (dirName.isNull())
163  {
164  return;
165  }
166 
167  if (SetConfigurationDirectory(dirName) != PLUS_SUCCESS)
168  {
169  LOG_ERROR("Unable to open selected directory!");
170  }
171 }
172 
173 //-----------------------------------------------------------------------------
175 {
176  LOG_TRACE("DeviceSetSelectorWidget::InvokeConnect");
177 
178  if (ui.comboBox_DeviceSet->currentIndex() < 0)
179  {
180  // combo box is empty
181  return;
182  }
183 
184  // Save selected device set configuration file name
185  std::string configFile = ui.comboBox_DeviceSet->itemData(ui.comboBox_DeviceSet->currentIndex(), FileNameRole).toString().toStdString();
188 
189  ui.pushButton_Connect->setEnabled(false);
190  QCoreApplication::processEvents();
191 
192  emit ConnectToDevicesByConfigFileInvoked(configFile);
193 }
194 
195 //-----------------------------------------------------------------------------
197 {
198  LOG_TRACE("DeviceSetSelectorWidget::GetSelectedDeviceSetConfigFilePath");
199 
200  return ui.comboBox_DeviceSet->itemData(ui.comboBox_DeviceSet->currentIndex(), FileNameRole).toString().toStdString();
201 }
202 
203 //-----------------------------------------------------------------------------
205 {
206  LOG_TRACE("DeviceSetSelectorWidget::GetSelectedDeviceSetDescription");
207 
208  return ui.comboBox_DeviceSet->itemData(ui.comboBox_DeviceSet->currentIndex(), DescriptionRole).toString().toStdString();
209 }
210 
211 //-----------------------------------------------------------------------------
213 {
214  LOG_TRACE("DeviceSetSelectorWidget::InvokeDisconnect");
215 
216  RefreshFolder();
217 
218  ui.pushButton_Connect->setEnabled(false);
219  QCoreApplication::processEvents();
220 
222 }
223 
224 //-----------------------------------------------------------------------------
226 {
227  LOG_TRACE("DeviceSetSelectorWidget::DeviceSetSelected(" << aIndex << ")");
228 
229  if ((aIndex < 0) || (aIndex >= ui.comboBox_DeviceSet->count()))
230  {
231  return;
232  }
233 
234  ui.textEdit_Description->setTextColor(QColor(Qt::black));
235 
236  ui.textEdit_Description->setText(ui.comboBox_DeviceSet->itemData(aIndex, DescriptionRole).toString());
237 
238  ui.comboBox_DeviceSet->setToolTip(ui.comboBox_DeviceSet->currentText() + "\n" + ui.comboBox_DeviceSet->itemData(aIndex, FileNameRole).toString());
239 
240  QString configurationFilePath = ui.comboBox_DeviceSet->itemData(ui.comboBox_DeviceSet->currentIndex(), FileNameRole).toString();
241 
242  emit DeviceSetSelected(configurationFilePath.toStdString());
243 }
244 
245 //-----------------------------------------------------------------------------
247 {
248  LOG_TRACE("DeviceSetSelectorWidget::SetConnectionSuccessful(" << (aConnectionSuccessful ? "true" : "false") << ")");
249 
250  m_ConnectionSuccessful = aConnectionSuccessful;
251 
252  // If connect button has been pushed
253  if (!ui.pushButton_Connect->property("connected").toBool())
254  {
256  {
257  ui.pushButton_Connect->setText(tr("Disconnect"));
258  ui.comboBox_DeviceSet->setEnabled(false);
259 
260  ui.textEdit_Description->setTextColor(QColor(Qt::black));
261  m_DescriptionPrefix = "Connection successful!";
262  m_DescriptionBody = ui.comboBox_DeviceSet->itemData(ui.comboBox_DeviceSet->currentIndex(), DescriptionRole).toString();
263  this->UpdateDescriptionText();
264 
265  // Change the function to be invoked on clicking on the now Disconnect button to InvokeDisconnect
266  disconnect(ui.pushButton_Connect, SIGNAL(clicked()), this, SLOT(InvokeConnect()));
267  connect(ui.pushButton_Connect, SIGNAL(clicked()), this, SLOT(InvokeDisconnect()));
268 
269  // Set last used device set config file
270  vtkPlusConfig::GetInstance()->SetDeviceSetConfigurationFileName(ui.comboBox_DeviceSet->itemData(ui.comboBox_DeviceSet->currentIndex(), FileNameRole).toString().toStdString());
271 
272  ui.pushButton_Connect->setProperty("connected", QVariant(true));
273  }
274  else
275  {
276  ui.textEdit_Description->setTextColor(QColor(Qt::darkRed));
277  m_DescriptionPrefix = "Connection failed!";
278  m_DescriptionBody = "Please select another device set and try again!";
279  this->UpdateDescriptionText();
280  }
281  }
282  else
283  {
284  // If disconnect button has been pushed
286  {
287  ui.pushButton_Connect->setProperty("connected", QVariant(false));
288  ui.pushButton_Connect->setText(tr("Connect"));
289  ui.comboBox_DeviceSet->setEnabled(true);
290 
291  ui.textEdit_Description->setTextColor(QColor(Qt::black));
292  if (ui.comboBox_DeviceSet->currentIndex() >= 0)
293  {
294  m_DescriptionPrefix = "";
295  m_DescriptionBody = ui.comboBox_DeviceSet->itemData(ui.comboBox_DeviceSet->currentIndex(), DescriptionRole).toString();
296  this->UpdateDescriptionText();
297  }
298 
299  // Change the function to be invoked on clicking on the now Connect button to InvokeConnect
300  disconnect(ui.pushButton_Connect, SIGNAL(clicked()), this, SLOT(InvokeDisconnect()));
301  connect(ui.pushButton_Connect, SIGNAL(clicked()), this, SLOT(InvokeConnect()));
302  }
303  else
304  {
305  LOG_ERROR("Disconnect failed!");
306  }
307  }
308 
309  ui.pushButton_Connect->setEnabled(true);
310 }
311 
312 //-----------------------------------------------------------------------------
314 {
315  LOG_TRACE("DeviceSetSelectorWidget::GetConnectionSuccessful");
316 
317  return m_ConnectionSuccessful;
318 }
319 
320 //-----------------------------------------------------------------------------
322 {
323  LOG_TRACE("DeviceSetSelectorWidget::ParseDirectory(" << aDirectory.toStdString() << ")");
324 
325  QDir configDir(aDirectory);
326  QStringList fileList(configDir.entryList());
327 
328  if (fileList.size() > 200)
329  {
330  if (QMessageBox::No == QMessageBox::question(this, tr("Many files in the directory"), tr("There are more than 200 files in the selected directory. Do you really want to continue parsing the files?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))
331  {
332  return PLUS_FAIL;
333  }
334  }
335 
336  // Block signals before we add items
337  ui.comboBox_DeviceSet->blockSignals(true);
338  ui.comboBox_DeviceSet->clear();
339 
340  QStringListIterator filesIterator(fileList);
341  QHash<QString, int> deviceSetVersion;
342 
343  while (filesIterator.hasNext())
344  {
345  QString fileName = QDir::toNativeSeparators(QString(configDir.absoluteFilePath(filesIterator.next())));
346  QString extension = fileName.mid(fileName.lastIndexOf("."));
347  if (!igsioCommon::IsEqualInsensitive(extension.toStdString(), ".xml"))
348  {
349  continue;
350  }
351 
352  QFile file(fileName);
353  QFileInfo fileInfo(fileName);
354  QDomDocument doc;
355 
356  // If file is not readable then skip
357  if (!file.open(QIODevice::ReadOnly))
358  {
359  continue;
360  }
361 
362  // If parsing is successful then check the content and if data collection config file is found then add it to combo box
363  if (doc.setContent(&file))
364  {
365  QDomElement docElem = doc.documentElement();
366 
367  // Check if the root element is PlusConfiguration and contains a DataCollection child
368  if (!docElem.tagName().compare("PlusConfiguration", Qt::CaseInsensitive))
369  {
370  QDomNodeList list = docElem.elementsByTagName("DataCollection");
371 
372  if (list.count() > 0)
373  {
374  // If it has a DataCollection children then use the first one
375  docElem = list.at(0).toElement();
376  }
377  else
378  {
379  // If it does not have a DataCollection then it cannot be used for connecting
380  continue;
381  }
382  }
383  else
384  {
385  continue;
386  }
387 
388  // Add the name attribute to the first node named DeviceSet to the combo box
389  QDomNodeList list(doc.elementsByTagName("DeviceSet"));
390  if (list.size() <= 0)
391  {
392  continue;
393  }
394 
395  // Detect previous calibrations and if so, display details
396  QString calibDetails;
397  vtkSmartPointer<vtkXMLDataElement> configRootElement = vtkSmartPointer<vtkXMLDataElement>::Take(vtkXMLUtilities::ReadElementFromFile(fileName.toStdString().c_str()));
398  if (configRootElement != NULL)
399  {
400  vtkNew<vtkIGSIOTransformRepository> tr;
401  if (tr->ReadConfiguration(configRootElement) == PLUS_SUCCESS)
402  {
403  QString pivotString;
404  pivotString = FindCalibrationDetails(doc, tr, "vtkPlusPivotCalibrationAlgo", "Pivot calibration: ", "ObjectPivotPointCoordinateFrame", "ObjectMarkerCoordinateFrame");
405  if (!pivotString.isEmpty())
406  {
407  calibDetails += pivotString;
408  }
409 
410  QString phantomString;
411  phantomString = FindCalibrationDetails(doc, tr, "vtkPlusPhantomLandmarkRegistrationAlgo", "Phantom calibration: ", "PhantomCoordinateFrame", "ReferenceCoordinateFrame");
412  if (!phantomString.isEmpty())
413  {
414  calibDetails += phantomString;
415  }
416 
417  QString probeString;
418  probeString = FindCalibrationDetails(doc, tr, "vtkPlusProbeCalibrationAlgo", "Probe calibration: ", "ImageCoordinateFrame", "ProbeCoordinateFrame");
419  if (!probeString.isEmpty())
420  {
421  calibDetails += probeString;
422  }
423  }
424  }
425 
426  QDomElement elem = list.at(0).toElement();
427 
428  QString name(elem.attribute("Name"));
429  QString description(elem.attribute("Description"));
430  if (name.isEmpty())
431  {
432  LOG_WARNING("Name field is empty in device set configuration file '" << fileName.toStdString() << "', it is not added to the list");
433  continue;
434  }
435 
436  if (!calibDetails.isEmpty())
437  {
438  description += "\n\n";
439  description += calibDetails;
440  }
441 
442  // Check if the same name already exists, add a version number if it does.
443  int foundIndex = ui.comboBox_DeviceSet->findText(name, Qt::MatchExactly);
444  if (foundIndex > -1)
445  {
446  QHash<QString, int>::iterator deviceIt = deviceSetVersion.find(name);
447  if (deviceIt == deviceSetVersion.end())
448  {
449  deviceSetVersion.insert(name, 0);
450  name.append(" [0]");
451  }
452  else
453  {
454  deviceIt.value() += 1;
455  name.append(" [" + QString::number(deviceIt.value()) + "]");
456  }
457  }
458 
459  ui.comboBox_DeviceSet->addItem(name, fileName);
460  int currentIndex = ui.comboBox_DeviceSet->findText(name, Qt::MatchExactly);
461 
462  ui.comboBox_DeviceSet->setItemData(currentIndex, description, DescriptionRole);
463 
464  // Add tooltip word wrapped rich text
465  name.prepend("<p>");
466  name.append(tr("</p> <p>") + fileInfo.fileName() + tr("</p> <p>") + description + tr("</p>"));
467  ui.comboBox_DeviceSet->setItemData(currentIndex, name, Qt::ToolTipRole);
468  }
469  else
470  {
471  LOG_WARNING("Unable to parse file '" << fileName.toStdString() << "' as an XML. It will not appear in the device set configuration file list!");
472  }
473  }
474 
475  // If no valid configuration files have been parsed then warn user
476  if (ui.comboBox_DeviceSet->count() < 1)
477  {
478  LOG_ERROR("Selected directory (" << aDirectory.toStdString() << ") does not contain valid device set configuration files!");
479  return PLUS_FAIL;
480  }
481 
482  // Set current index to default so that setting the last selected item raises the event even if it is the first item
483  ui.comboBox_DeviceSet->setCurrentIndex(-1);
484 
485  ui.comboBox_DeviceSet->model()->sort(0);
486 
487  // Unblock signals after we add items
488  ui.comboBox_DeviceSet->blockSignals(false);
489 
490  // Restore the saved selection
491  int lastSelectedDeviceSetIndex = ui.comboBox_DeviceSet->findData(QDir::toNativeSeparators(QString(vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationFileName().c_str())));
492  ui.comboBox_DeviceSet->setCurrentIndex(lastSelectedDeviceSetIndex);
493 
494  this->FixComboBoxDropDownListSizeAdjustemnt(ui.comboBox_DeviceSet);
495 
496  return PLUS_SUCCESS;
497 }
498 
499 //----------------------------------------------------------------------------
500 QString QPlusDeviceSetSelectorWidget::FindCalibrationDetails(const QDomDocument& aDocument,
501  vtkSmartPointer<vtkIGSIOTransformRepository> aTransformRepository,
502  const QString& aTagName,
503  const QString& aOutputPrefix,
504  const QString& aFirstFrame,
505  const QString& aSecondFrame)
506 {
507  QDomNodeList list(aDocument.elementsByTagName(aTagName));
508  if (list.count() > 0)
509  {
510  auto elem = list.at(0).toElement();
511  QString firstFrame(elem.attribute(aFirstFrame));
512  QString secondFrame(elem.attribute(aSecondFrame));
513  if (!firstFrame.isEmpty() && !secondFrame.isEmpty())
514  {
515  igsioTransformName tName(firstFrame.toStdString(), secondFrame.toStdString());
516  std::string date;
517  double error;
518  if (aTransformRepository->GetTransformDate(tName, date, true) == PLUS_SUCCESS &&
519  aTransformRepository->GetTransformError(tName, error, true) == PLUS_SUCCESS)
520  {
521  bool valid(false);
522  std::tm tm = {};
523  std::stringstream ss(date);
524  ss >> std::get_time(&tm, "%Y.%m.%d %H:%M:%S");
525  if (tm.tm_hour == 0 || tm.tm_mday == 0 || tm.tm_mon == 0 || tm.tm_year == 0)
526  {
527  if (date.length() == 13)
528  {
529  // %m%d%y_%H%M%S doesn't parse with std::get_time, reformat it manually
530  std::string month(date.substr(0, 2));
531  std::string day(date.substr(2, 2));
532  std::string year(date.substr(4, 2));
533  std::string hour(date.substr(7, 2));
534  std::string minute(date.substr(9, 2));
535  std::string second(date.substr(11, 2));
536  std::stringstream ss;
537  ss << month << " " << day << " " << year << "_" << hour << " " << minute << " " << second;
538  ss >> std::get_time(&tm, "%m %d %y_%H %M %S");
539 
540  if (!(tm.tm_hour == 0 || tm.tm_mday == 0 || tm.tm_mon == 0 || tm.tm_year == 0))
541  {
542  valid = true;
543  }
544  }
545  }
546  else
547  {
548  valid = true;
549  }
550 
551  QString output = aOutputPrefix;
552  if (valid)
553  {
554  std::stringstream ss;
555  ss << std::put_time(&tm, "%b %d %Y - %H:%M");
556  output += QString::fromStdString(ss.str());
557  }
558  else
559  {
560  output += QString::fromStdString(date);
561  }
562  return output + ", error: " + QString::number(error, 'g', 2) + "\n";
563  }
564  }
565  }
566 
567  return "";
568 }
569 
570 //----------------------------------------------------------------------------
572 {
573  if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() == 1)
574  {
575  QString filename = event->mimeData()->urls()[0].toLocalFile();
576  if (filename.lastIndexOf('.') == -1)
577  {
578  return;
579  }
580  QString extension = filename.mid(filename.lastIndexOf('.'));
581  if (extension.contains("xml"))
582  {
583  event->acceptProposedAction();
584  }
585  }
586 }
587 
588 //----------------------------------------------------------------------------
590 {
591  QUrl url = event->mimeData()->urls().first();
592  QString fileName = url.toLocalFile();
593 
594  this->SetConfigurationFile(fileName);
595 }
596 
597 //----------------------------------------------------------------------------
599 {
600  int scroll = cb->count() <= cb->maxVisibleItems() ? 0 :
601  QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent);
602 
603  int max = 0;
604 
605  for (int i = 0; i < cb->count(); i++)
606  {
607  int width = cb->view()->fontMetrics().width(cb->itemText(i));
608  if (max < width) { max = width; }
609  }
610 
611  cb->view()->setMinimumWidth(scroll + max);
612 }
613 
614 //----------------------------------------------------------------------------
616 {
617  QWidget::resizeEvent(event);
618 
620  {
621  QDesktopWidget desktop;
622  int screenWidth = desktop.screenGeometry(desktop.screenNumber(this)).width();
623  ui.comboBox_DeviceSet->setMaximumWidth(screenWidth * m_DeviceSetComboBoxMaximumSizeRatio);
624  }
625 }
626 
627 //----------------------------------------------------------------------------
629 {
630  QString text;
631  if (!m_DescriptionPrefix.isEmpty())
632  {
633  text += m_DescriptionPrefix + "\n\n";
634  }
635 
637 
638  if (!m_DescriptionSuffix.isEmpty())
639  {
640  text += "\n\n" + m_DescriptionSuffix;
641  }
642 
643  ui.textEdit_Description->setText(text);
644 }
645 
646 //-----------------------------------------------------------------------------
648 {
649  LOG_TRACE("DeviceSetSelectorWidget::RefreshFolderClicked");
650 
651  if (ParseDirectory(QString(vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationDirectory().c_str())) != PLUS_SUCCESS)
652  {
653  LOG_ERROR("Parsing up configuration files failed in: " << vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationDirectory());
654  }
655 }
656 
657 //-----------------------------------------------------------------------------
659 {
660  LOG_TRACE("DeviceSetSelectorWidget::EditConfiguration");
661 
662  QString configurationFilePath;
663  int deviceSetIndex = ui.comboBox_DeviceSet->currentIndex();
664  if (deviceSetIndex >= 0)
665  {
666  configurationFilePath = ui.comboBox_DeviceSet->itemData(deviceSetIndex).toStringList().at(0);
667  }
668  else
669  {
670  LOG_ERROR("Cannot edit configuration file. No configuration is selected.");
671  return;
672  }
673  QString editorApplicationExecutable(vtkPlusConfig::GetInstance()->GetEditorApplicationExecutable().c_str());
674 
675  if (!editorApplicationExecutable.isEmpty())
676  {
677  QFileInfo fileInfo(QDir::toNativeSeparators(configurationFilePath));
678  QString file = fileInfo.absoluteFilePath();
679 
680  QProcess::startDetached(editorApplicationExecutable, QStringList() << file);
681  return;
682  }
683 
684  // No editor application defined, try using the system default
685  if (!QDesktopServices::openUrl(QUrl("file:///" + configurationFilePath, QUrl::TolerantMode)))
686  {
687  LOG_ERROR("Failed to open file in default application: " << configurationFilePath.toStdString());
688  }
689 }
690 
691 //----------------------------------------------------------------------------
693 {
694  if (m_EditorSelectAction == NULL)
695  {
696  m_EditorSelectAction = new QAction(this);
697  m_EditorSelectAction->setText("Select Editor");
698  connect(m_EditorSelectAction, &QAction::triggered, this, &QPlusDeviceSetSelectorWidget::SelectEditor);
699  }
700 
702  {
703  m_EditApplicationConfigFileAction = new QAction(this);
704  m_EditApplicationConfigFileAction->setText("Edit App Config");
706  }
707 
708  if (m_EditMenu == NULL)
709  {
710  m_EditMenu = new QMenu(this);
711  m_EditMenu->addAction(m_EditorSelectAction);
713  }
714  m_EditMenu->exec(ui.pushButton_EditConfiguration->mapToGlobal(point));
715 }
716 
717 //-----------------------------------------------------------------------------
719 {
720  // File open dialog for selecting editor application
721  QString filter = QString(tr("Executables ( *.exe );;"));
722  QString fileName = QFileDialog::getOpenFileName(NULL, QString(tr("Select XML editor application")), "", filter);
723  if (fileName.isNull())
724  {
725  return;
726  }
727 
728  vtkPlusConfig::GetInstance()->SetEditorApplicationExecutable(fileName.toStdString());
730 }
731 
732 //----------------------------------------------------------------------------
734 {
735  LOG_TRACE("DeviceSetSelectorWidget::EditConfiguration");
736 
737  QString configurationFilePath = QString::fromStdString(vtkPlusConfig::GetInstance()->GetApplicationConfigurationFilePath());
738  QString editorApplicationExecutable(vtkPlusConfig::GetInstance()->GetEditorApplicationExecutable().c_str());
739 
740  if (!editorApplicationExecutable.isEmpty())
741  {
742  QFileInfo fileInfo(QDir::toNativeSeparators(configurationFilePath));
743  QString file = fileInfo.absoluteFilePath();
744 
745  QProcess::startDetached(editorApplicationExecutable, QStringList() << file);
746  return;
747  }
748 
749  // No editor application defined, try using the system default
750  if (!QDesktopServices::openUrl(QUrl("file:///" + configurationFilePath, QUrl::TolerantMode)))
751  {
752  LOG_ERROR("Failed to open file in default application: " << configurationFilePath.toStdString());
753  }
754 }
755 
756 //-----------------------------------------------------------------------------
758 {
759  LOG_TRACE("DeviceSetSelectorWidget::ResetTrackerButtonClicked()");
760 
761  emit ResetTracker();
762 }
763 
764 //-----------------------------------------------------------------------------
766 {
767  ui.pushButton_ResetTracker->setVisible(aValue);
768 }
769 
770 //-----------------------------------------------------------------------------
772 {
773  ui.pushButton_Connect->setText(text);
774 }
775 
776 //----------------------------------------------------------------------------
778 {
779  this->m_DescriptionSuffix = string;
780  this->UpdateDescriptionText();
781 }
782 
783 //----------------------------------------------------------------------------
785 {
786  this->SetDescriptionSuffix("");
787 }
void SetDescriptionSuffix(const QString &string)
void ConfigurationDirectoryChanged(std::string)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
virtual void dragEnterEvent(QDragEnterEvent *event)
virtual void dropEvent(QDropEvent *event)
virtual void resizeEvent(QResizeEvent *event)
for i
PlusStatus ParseDirectory(const QString &aDirectory)
#define PLUS_FAIL
Definition: PlusCommon.h:43
static vtkPlusConfig * GetInstance()
void DeviceSetSelected(std::string)
PlusStatus SaveApplicationConfigurationToFile()
PlusStatus SetConfigurationFile(const QString &aFilename)
QString FindCalibrationDetails(const QDomDocument &doc, vtkSmartPointer< vtkIGSIOTransformRepository > tr, const QString &tagName, const QString &outputPrefix, const QString &firstFrame, const QString &secondFrame)
PhidgetLCD_Font int int const char * text
Definition: phidget22.h:4287
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
void SetDeviceSetConfigurationDirectory(const std::string &aDir)
PhidgetLCD_Font int * width
Definition: phidget22.h:4275
PlusStatus SetConfigurationDirectory(const QString &aDirectory)
PhidgetGPS_Date * date
Definition: phidget22.h:3617
void ConnectToDevicesByConfigFileInvoked(std::string)
void SetDeviceSetConfigurationFileName(const std::string &aFilePath)
void FixComboBoxDropDownListSizeAdjustemnt(QComboBox *cb)
void SetConnectionSuccessful(bool aConnectionSuccessful)