RTXI  2.4
The Real-Time eXperiment Interface Documentation
main_window.cpp
Go to the documentation of this file.
1 /*
2  The Real-Time eXperiment Interface (RTXI)
3  Copyright (C) 2011 Georgia Institute of Technology, University of Utah, Weill Cornell Medical College
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 
20 #include <debug.h>
21 #include <algorithm>
22 #include <settings.h>
23 #include <rtxi_config.h>
24 #include <stdlib.h>
25 #include <main_window.h>
26 #include <mutex.h>
27 #include <plugin.h>
28 
29 MainWindow::MainWindow (void) : QMainWindow(NULL, Qt::Window)
30 {
31 
32  // Make central RTXI parent widget
33  mdiArea = new QMdiArea;
34  setCentralWidget(mdiArea);
35 
36  /* Initialize Window Settings */
37  setWindowTitle("RTXI - Real-time eXperimental Interface");
38  setWindowIcon(QIcon("/usr/local/share/rtxi/RTXI-icon.png"));
39 
40  /* Set Qt Settings Information */
41  QCoreApplication::setOrganizationName("RTXI");
42  QCoreApplication::setOrganizationDomain("rtxi.org");
43  QCoreApplication::setApplicationName("RTXI");
44 
45  /* Initialize Menus */
46  createFileActions();
47  createFileMenu();
48 
49  /* Initialize Module Menu */
50  createModuleMenu();
51 
52  /* Initialize Utilities menu */
53  createUtilMenu();
54 
55  /* Initialize System Menu */
56  createSystemMenu();
57 
58  /* Initialize Windows Menu */
59  createWindowsMenu();
60 
61  /* Initialize Help Menu */
62  createHelpActions();
63  createHelpMenu();
64 }
65 
67 {
68 }
69 
71 {
72  return moduleMenu->addSeparator();
73 }
74 
75 QAction* MainWindow::createFileMenuItem(const QString &text)
76 {
77  return fileMenu->addAction(text);
78 }
79 
81 {
82  // Clear but add back default actions
83  fileMenu->clear();
84  fileMenu->addAction(load);
85  fileMenu->addAction(save);
86  fileMenu->addAction(reset);
87  fileMenu->addSeparator();
88  fileMenu->addAction(quit);
89  fileMenu->addSeparator();
90 }
91 
92 QAction* MainWindow::createModuleMenuItem(const QString &text)
93 {
94  return moduleMenu->addAction(text);
95 }
96 
97 QAction* MainWindow::createModuleMenuItem(const QString &text, const QObject *receiver, const char *member)
98 {
99  return moduleMenu->addAction(text, receiver, member);
100 }
101 
102 void MainWindow::setModuleMenuItemParameter (QAction *action, int parameter)
103 {
104  action->setData(parameter);
105 }
106 
108 {
109  moduleMenu->clear();
110 }
111 
112 void MainWindow::changeModuleMenuItem (QAction *action, QString text)
113 {
114  action->setText(text);
115 }
116 
117 void MainWindow::removeModuleMenuItem (QAction *action)
118 {
119  QList<QAction *> actionList = moduleMenu->actions();
120  if(!actionList.empty())
121  moduleMenu->removeAction(action);
122 }
123 
124 QAction* MainWindow::createUtilMenuItem(const QString &text, const QObject * receiver, const char *member)
125 {
126  return utilMenu->addAction (text, receiver, member);
127 }
128 
129 void MainWindow::createFileMenu()
130 {
131  fileMenu = menuBar()->addMenu(tr("&File"));
132  fileMenu->addAction(load);
133  fileMenu->addAction(save);
134  fileMenu->addAction(reset);
135  fileMenu->addSeparator();
136  fileMenu->addAction(quit);
137  fileMenu->addSeparator();
138  connect(fileMenu, SIGNAL(triggered(QAction*)), this, SLOT(fileMenuActivated(QAction*)));
139 }
140 
141 void MainWindow::createModuleMenu()
142 {
143  moduleMenu = menuBar()->addMenu(tr("&Modules"));
144  connect(moduleMenu, SIGNAL(triggered(QAction*)), this, SLOT(modulesMenuActivated(QAction*)));
145 }
146 
147 void MainWindow::createUtilMenu()
148 {
149  utilMenu = menuBar()->addMenu(tr("&Utilities"));
150  filtersSubMenu = utilMenu->addMenu(tr("&Filters"));
151  signalsSubMenu = utilMenu->addMenu(tr("&Signals"));
152  utilitiesSubMenu = utilMenu->addMenu(tr("&Utilities"));
153  connect(utilMenu, SIGNAL(triggered(QAction*)), this, SLOT(utilitiesMenuActivated(QAction*)));
154 
155  QDir libsDir("/usr/local/lib/rtxi/");
156  if(!libsDir.exists())
157  return;
158 
159  libsDir.setNameFilters(QStringList("*.so"));
160  for(int i = 0; i < libsDir.entryList().size(); i++)
161  {
162  utilItem = new QAction(libsDir.entryList().at(i), this);
163  if(libsDir.entryList().at(i).contains("analysis"))
164  utilitiesSubMenu->addAction(utilItem);
165  else if(libsDir.entryList().at(i).contains("sync"))
166  utilitiesSubMenu->addAction(utilItem);
167  else if(libsDir.entryList().at(i).contains("mimic"))
168  utilitiesSubMenu->addAction(utilItem);
169  else if(libsDir.entryList().at(i).contains("iir"))
170  filtersSubMenu->addAction(utilItem);
171  else if(libsDir.entryList().at(i).contains("fir"))
172  filtersSubMenu->addAction(utilItem);
173  else if(libsDir.entryList().at(i).contains("signal"))
174  signalsSubMenu->addAction(utilItem);
175  else if(libsDir.entryList().at(i).contains("noise"))
176  signalsSubMenu->addAction(utilItem);
177  else if(libsDir.entryList().at(i).contains("ttl"))
178  signalsSubMenu->addAction(utilItem);
179  else if(libsDir.entryList().at(i).contains("maker"))
180  signalsSubMenu->addAction(utilItem);
181  }
182 }
183 
184 void MainWindow::createSystemMenu()
185 {
186  systemMenu = menuBar()->addMenu(tr("&System"));
187 }
188 
189 void MainWindow::createWindowsMenu()
190 {
191  windowsMenu = menuBar()->addMenu(tr("&Windows"));
192  connect(windowsMenu,SIGNAL(aboutToShow(void)),this,SLOT(windowsMenuAboutToShow(void)));
193 }
194 
195 void MainWindow::createHelpMenu()
196 {
197  helpMenu = menuBar()->addMenu(tr("&Help"));
198  helpMenu->addSeparator();
199  helpMenu->addAction(artxi);
200  helpMenu->addAction(axeno);
201  helpMenu->addAction(aqt);
202  helpMenu->addSeparator();
203  helpMenu->addAction(adocs);
204  helpMenu->addAction(sub_issue);
205 }
206 
207 void MainWindow::createFileActions()
208 {
209  load = new QAction(tr("&Load Workspace"), this);
210  load->setShortcuts(QKeySequence::Open);
211  load->setStatusTip(tr("Load a saved workspace"));
212  connect(load, SIGNAL(triggered()), this, SLOT(loadSettings()));
213 
214  save = new QAction(tr("&Save Workspace"), this);
215  save->setShortcuts(QKeySequence::Save);
216  save->setStatusTip(tr("Save current workspace"));
217  connect(save, SIGNAL(triggered()), this, SLOT(saveSettings()));
218 
219  reset = new QAction(tr("&Reset Workspace"), this);
220  reset->setStatusTip(tr("Reset to default RTXI workspace"));
221  connect(reset, SIGNAL(triggered()), this, SLOT(resetSettings()));
222 
223  quit = new QAction(tr("&Quit"), this);
224  quit->setShortcut(tr("Ctrl+Q"));
225  quit->setStatusTip(tr("Quit RTXI"));
226  connect(qApp, SIGNAL(aboutToQuit()), mdiArea, SLOT(closeAllSubWindows()));
227  connect(quit, SIGNAL(triggered()), this, SLOT(close()));
228 }
229 
230 void MainWindow::createMdi(QMdiSubWindow *subWindow)
231 {
232  mdiArea->addSubWindow(subWindow);
233 }
234 
235 void MainWindow::createHelpActions()
236 {
237  artxi = new QAction(tr("About &RTXI"),this);
238  connect(artxi, SIGNAL(triggered()), this, SLOT(about()));
239 
240  axeno = new QAction(tr("About &Xenomai"),this);
241  connect(axeno, SIGNAL(triggered()), this, SLOT(aboutXeno()));
242 
243  aqt = new QAction(tr("About &Qt"),this);
244  connect(aqt, SIGNAL(triggered()), this, SLOT(aboutQt()));
245 
246  adocs = new QAction(tr("&Documentation"), this);
247  connect(adocs, SIGNAL(triggered()), this, SLOT(openDocs()));
248 
249  sub_issue = new QAction(tr("&Submit Issue"), this);
250  connect(sub_issue, SIGNAL(triggered()), this, SLOT(openSubIssue()));
251 }
252 
253 QAction* MainWindow::createSystemMenuItem (const QString &text, const QObject *receiver, const char *member)
254 {
255  return systemMenu->addAction(text, receiver, member);
256 }
257 
258 void MainWindow::about(void)
259 {
260  QMessageBox::about(this, "About RTXI", "RTXI Version " + QString(VERSION)
261  + "\n\nReleased under the GPLv3.\nSee www.rtxi.org for details.");
262 }
263 
264 void MainWindow::aboutQt (void)
265 {
266  QMessageBox::aboutQt(this);
267 }
268 
269 void MainWindow::aboutXeno (void)
270 {
271 #if CONFIG_XENO_VERSION_MAJOR
272  FILE *fp;
273  char xeno_buff[8];
274  fp = fopen("/proc/xenomai/version","r");
275  fscanf(fp, "%s", xeno_buff);
276  fclose(fp);
277  QMessageBox::about(this, "About Xenomai", "Xenomai Version " + QString(xeno_buff));
278 #else
279  QMessageBox::about(this, "About Xenomai", "Running POSIX (non-RT)");
280 #endif
281 }
282 
283 void MainWindow::openDocs(void)
284 {
285  QDesktopServices::openUrl(QUrl("http://rtxi.org/docs/", QUrl::TolerantMode));
286 }
287 
288 void MainWindow::openSubIssue(void)
289 {
290  QDesktopServices::openUrl(QUrl("https://github.com/rtxi/rtxi/issues", QUrl::TolerantMode));
291 }
292 
293 /*
294  * Load MainWindow settings
295  */
297 {
298  QSettings userprefs;
299  userprefs.setPath (QSettings::NativeFormat, QSettings::SystemScope, "/usr/local/share/rtxi/");
300  userprefs.beginGroup("MainWindow");
301  restoreGeometry(userprefs.value("geometry", saveGeometry()).toByteArray());
302  move(userprefs.value("pos", pos()).toPoint());
303  resize(userprefs.value("size", size()).toSize());
304  if(userprefs.value("maximized", isMaximized()).toBool())
305  showMaximized();
306  userprefs.endGroup();
307  show();
308 }
309 
310 void MainWindow::loadSettings (void)
311 {
312  QSettings userprefs;
313  userprefs.setPath (QSettings::NativeFormat, QSettings::SystemScope, "/usr/local/share/rtxi/");
314 
315  QString filename = QFileDialog::getOpenFileName(this,
316  tr("Load saved workspace"), userprefs.value("/dirs/setfiles", getenv("HOME")).toString(), tr("Settings (*.set)"));
317 
318  if (QFile(filename).exists())
319  {
320  systemMenu->clear();
321  mdiArea->closeAllSubWindows();
322  Settings::Manager::getInstance()->load(filename.toStdString());
323  }
324 }
325 
326 void MainWindow::saveSettings(void)
327 {
328  QSettings userprefs;
329  userprefs.setPath (QSettings::NativeFormat, QSettings::SystemScope, "/usr/local/share/rtxi/");
330 
331  QString filename = QFileDialog::getSaveFileName(this,
332  tr("Save current workspace"), userprefs.value("/dirs/setfiles", getenv("HOME")).toString(), tr("Settings (*.set)"));
333 
334  if (!filename.isEmpty())
335  {
336  if (!filename.endsWith(".set"))
337  filename = filename+".set";
338  if (QFileInfo (filename).exists() && QMessageBox::warning(this,
339  "File Exists", "Do you wish to overwrite " + filename + "?",
340  QMessageBox::Yes | QMessageBox::Default,
341  QMessageBox::No | QMessageBox::Escape) != QMessageBox::Yes)
342  {
343  //DEBUG_MSG ("MainWindow::saveSettings : canceled overwrite\n");
344  return;
345  }
346  Settings::Manager::getInstance()->save(filename.toStdString());
347  }
348 }
349 
350 void MainWindow::resetSettings(void)
351 {
352  systemMenu->clear();
353  mdiArea->closeAllSubWindows();
354  Settings::Manager::getInstance()->load("/usr/local/share/rtxi/rtxi.conf");
355 }
356 
357 void MainWindow::utilitiesMenuActivated(QAction *id)
358 {
359  Plugin::Manager::getInstance()->load(id->text());
360 }
361 
362 void MainWindow::windowsMenuAboutToShow(void)
363 {
364 
365  // Clear previous entries
366  windowsMenu->clear();
367 
368  // Add default options
369  windowsMenu->addAction(tr("Cascade"),mdiArea,SLOT(cascadeSubWindows()));
370  windowsMenu->addAction(tr("Tile"),mdiArea,SLOT(tileSubWindows()));
371  windowsMenu->addSeparator();
372 
373  // Get list of open subwindows in Mdi Area
374  subWindows = mdiArea->subWindowList();
375 
376  // Make sure it isn't empty
377  if(subWindows.isEmpty())
378  return;
379 
380  // Create windows list based off of what's open
381  for(int i = 0; i < subWindows.size(); i++)
382  {
383  QAction *item = new QAction(subWindows.at(i)->widget()->windowTitle(), this);
384  windowsMenu->addAction(item);
385  }
386  connect(windowsMenu, SIGNAL(triggered(QAction*)), this, SLOT(windowsMenuActivated(QAction*)));
387 }
388 
389 void MainWindow::windowsMenuActivated(QAction *id)
390 {
391 
392  // Get list of open subwindows in Mdi Area
393  subWindows = mdiArea->subWindowList();
394 
395  // Make sure it isn't empty
396  if(subWindows.isEmpty())
397  return;
398 
399  for(uint16_t i = 0; i < subWindows.size(); i++)
400  if(subWindows.at(i)->widget()->windowTitle() == id->text())
401  mdiArea->setActiveSubWindow(subWindows.at(i));
402 }
403 
404 void MainWindow::modulesMenuActivated(QAction *id)
405 {
406  // Annoying but the best way to do it is to tie an action to the entire menu
407  // so we have to tell it to ignore the first two modules
408  if(id->text().contains("Load Plugin"))
409  return;
410 
411  // Have to trim the first three characters before loading
412  // or else parser will include qstring formatting
413  Plugin::Manager::getInstance()->load(id->text().remove(0,3));
414 }
415 
416 void MainWindow::fileMenuActivated(QAction *id)
417 {
418  // Annoying but the best way to do it is to tie an action to the entire menu
419  // so we have to tell it to ignore the first three items
420  if(id->text().contains("Load Workspace") ||
421  id->text().contains("Save Workspace") ||
422  id->text().contains("Reset Workspace") ||
423  id->text().contains("Quit"))
424  return;
425 
426  // Have to trim the first three characters before loading
427  // or else parser will include qstring formatting
428  systemMenu->clear();
429  mdiArea->closeAllSubWindows();
430  Settings::Manager::getInstance()->load(id->text().remove(0,3).toStdString());
431 }
432 
433 void MainWindow::closeEvent(QCloseEvent *)
434 {
435  /*
436  * Save MainWindow settings
437  */
438  QSettings userprefs;
439  userprefs.setPath (QSettings::NativeFormat, QSettings::SystemScope, "/usr/local/share/rtxi/");
440  userprefs.beginGroup("MainWindow");
441  userprefs.setValue("geometry", saveGeometry());
442  userprefs.setValue("maximized", isMaximized());
443  if(!isMaximized())
444  {
445  userprefs.setValue("pos", pos());
446  userprefs.setValue("size", size());
447  }
448  userprefs.endGroup();
449 }
450 
451 static Mutex mutex;
452 MainWindow * MainWindow::instance = 0;
453 
455 {
456  if (instance)
457  return instance;
458 
459  /*************************************************************************
460  * Seems like alot of hoops to jump through, but static allocation isn't *
461  * thread-safe. So effort must be taken to ensure mutual exclusion. *
462  *************************************************************************/
463 
464  Mutex::Locker lock (&::mutex);
465  if (!instance)
466  {
467  static MainWindow mainwindow;
468  instance = &mainwindow;
469  }
470  return instance;
471 }
MainWindow::createSystemMenuItem
QAction * createSystemMenuItem(const QString &label, const QObject *handler, const char *slot)
Definition: main_window.cpp:253
VERSION
#define VERSION
Definition: rtxi_config.h:77
Plugin::Manager::load
Object * load(const QString &library)
Definition: plugin.cpp:46
Settings::Manager::getInstance
static Manager * getInstance(void)
Definition: settings.cpp:534
settings.h
MainWindow::~MainWindow
virtual ~MainWindow(void)
Definition: main_window.cpp:66
MainWindow::createMdi
void createMdi(QMdiSubWindow *)
Definition: main_window.cpp:230
plugin.h
MainWindow::clearFileMenu
void clearFileMenu(void)
Definition: main_window.cpp:80
Mutex
Definition: mutex.h:28
MainWindow::clearModuleMenu
void clearModuleMenu(void)
Definition: main_window.cpp:107
MainWindow::loadWindow
void loadWindow(void)
Definition: main_window.cpp:296
rtxi_config.h
MainWindow::insertModuleMenuSeparator
QAction * insertModuleMenuSeparator(void)
Definition: main_window.cpp:70
mutex.h
Settings::Manager::load
int load(const std::string &)
Definition: settings.cpp:230
MainWindow::setModuleMenuItemParameter
void setModuleMenuItemParameter(QAction *action, int parameter)
Definition: main_window.cpp:102
Plugin::Manager::getInstance
static Manager * getInstance(void)
Definition: plugin.cpp:188
Mutex::Locker
Definition: mutex.h:36
Settings::Manager::save
int save(const std::string &)
Definition: settings.cpp:358
MainWindow::changeModuleMenuItem
void changeModuleMenuItem(QAction *action, QString text)
Definition: main_window.cpp:112
MainWindow::removeModuleMenuItem
void removeModuleMenuItem(QAction *action)
Definition: main_window.cpp:117
MainWindow::createModuleMenuItem
QAction * createModuleMenuItem(const QString &text)
Definition: main_window.cpp:92
MainWindow::getInstance
static MainWindow * getInstance(void)
Definition: main_window.cpp:454
MainWindow::createFileMenuItem
QAction * createFileMenuItem(const QString &label)
Definition: main_window.cpp:75
MainWindow
Definition: main_window.h:35
debug.h
MainWindow::createUtilMenuItem
QAction * createUtilMenuItem(const QString &label, const QObject *handler, const char *slot)
Definition: main_window.cpp:124
main_window.h