RTXI  2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
default_gui_model.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 <default_gui_model.h>
21 #include <main_window.h>
22 #include <iostream>
23 
24 namespace
25 {
26 class SyncEvent: public RT::Event
27 {
28 public:
29  int callback(void)
30  {
31  return 0;
32  };
33 };
34 };
35 
36 DefaultGUILineEdit::DefaultGUILineEdit(QWidget *parent):QLineEdit(parent)
37 {
38  QObject::connect(this,SIGNAL(textChanged(const QString &)),this,SLOT(redden(void)));
39 }
40 
42 {
43 }
44 
46 {
47  palette.setBrush(this->foregroundRole(), QApplication::palette().color(QPalette::WindowText));
48  this->setPalette(palette);
49  setModified(false);
50 }
51 
53 {
54  if(isModified())
55  {
56  palette.setBrush(this->foregroundRole(), Qt::red);
57  this->setPalette(palette);
58  }
59 }
60 
62  QWidget(MainWindow::getInstance()->centralWidget()), Workspace::Instance(name, var, size), myname(name)
63 {
64  setWindowTitle(QString::number(getID()) + " " + QString::fromStdString(name));
65 
66  QTimer *timer = new QTimer(this);
67  timer->setTimerType(Qt::PreciseTimer);
68  timer->start(1000);
69  QObject::connect(timer,SIGNAL(timeout(void)),this,SLOT(refresh(void)));
70 }
71 
73 {
74  // Ensure that the realtime thread isn't in the middle of executing DefaultGUIModel::execute()
75  setActive( false );
76  SyncEvent event;
78 
79  for (std::map<QString, param_t>::iterator i = parameter.begin(); i
80  != parameter.end(); ++i)
81  if (i->second.type & PARAMETER)
82  delete i->second.str_value;
83 }
84 
86 {
87 
88  // Make Mdi
89  subWindow = new QMdiSubWindow;
90  subWindow->setAttribute(Qt::WA_DeleteOnClose);
91  subWindow->setWindowIcon(QIcon("/usr/local/share/rtxi/RTXI-widget-icon.png"));
92  subWindow->setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint);
93  subWindow->setOption(QMdiSubWindow::RubberBandResize, true);
94  subWindow->setOption(QMdiSubWindow::RubberBandMove, true);
96 
97  // Create main layout
98  layout = new QGridLayout;
99 
100  // Create child widget and gridLayout
101  QScrollArea *gridArea = new QScrollArea;
102  gridBox = new QWidget;
103  gridArea->setWidget(gridBox);
104  gridArea->ensureWidgetVisible(gridBox, 0, 0);
105  gridArea->setWidgetResizable(true);
106  QGridLayout *gridLayout = new QGridLayout;
107 
108  size_t nstate = 0, nparam = 0, nevent = 0, ncomment = 0;
109  for (size_t i = 0; i < size; i++)
110  {
111  if (var[i].flags & (PARAMETER | STATE | EVENT | COMMENT))
112  {
113  param_t param;
114 
115  param.label = new QLabel(QString::fromStdString(var[i].name), gridBox);
116  gridLayout->addWidget(param.label, parameter.size(), 0);
117  param.edit = new DefaultGUILineEdit(gridBox);
118  gridLayout->addWidget(param.edit, parameter.size(), 1);
119 
120  param.label->setToolTip(QString::fromStdString(var[i].description));
121  param.edit->setToolTip(QString::fromStdString(var[i].description));
122 
123  if (var[i].flags & PARAMETER)
124  {
125  if (var[i].flags & DOUBLE)
126  {
127  param.edit->setValidator(new QDoubleValidator(param.edit));
128  param.type = PARAMETER | DOUBLE;
129  }
130  else if (var[i].flags & UINTEGER)
131  {
132  QIntValidator *validator = new QIntValidator(param.edit);
133  param.edit->setValidator(validator);
134  validator->setBottom(0);
135  param.type = PARAMETER | UINTEGER;
136  }
137  else if (var[i].flags & INTEGER)
138  {
139  param.edit->setValidator(new QIntValidator(param.edit));
140  param.type = PARAMETER | INTEGER;
141  }
142  else
143  param.type = PARAMETER;
144  param.index = nparam++;
145  param.str_value = new QString;
146  }
147  else if (var[i].flags & STATE)
148  {
149  param.edit->setReadOnly(true);
150  palette.setBrush(param.edit->foregroundRole(), Qt::darkGray);
151  param.edit->setPalette(palette);
152  param.type = STATE;
153  param.index = nstate++;
154  }
155  else if (var[i].flags & EVENT)
156  {
157  param.edit->setReadOnly(true);
158  param.type = EVENT;
159  param.index = nevent++;
160  }
161  else if (var[i].flags & COMMENT)
162  {
163  param.type = COMMENT;
164  param.index = ncomment++;
165  }
166  parameter[QString::fromStdString(var[i].name)] = param;
167  }
168  }
169 
170  // Create child widget
171  buttonGroup = new QGroupBox;
172  QHBoxLayout *buttonLayout = new QHBoxLayout;
173 
174  // Create elements
175  pauseButton = new QPushButton("Pause", this);
176  pauseButton->setCheckable(true);
177  QObject::connect(pauseButton,SIGNAL(toggled(bool)),this,SLOT(pause(bool)));
178  buttonLayout->addWidget(pauseButton);
179 
180  modifyButton = new QPushButton("Modify", this);
181  QObject::connect(modifyButton,SIGNAL(clicked(void)),this,SLOT(modify(void)));
182  buttonLayout->addWidget(modifyButton);
183 
184  unloadButton = new QPushButton("Unload", this);
185  QObject::connect(unloadButton,SIGNAL(clicked(void)),this,SLOT(exit(void)));
186  buttonLayout->addWidget(unloadButton);
187 
188  // Add layout to box
189  gridBox->setLayout(gridLayout);
190  buttonGroup->setLayout(buttonLayout);
191 
192  // Keep one row of space above for users to place in grid
193  layout->addWidget(gridArea, 1, 0);
194 
195  // Attempt to put these at the bottom at all times
196  layout->addWidget(buttonGroup, 10, 0);
197 
198  // Set layout to Mdi and show
199  setLayout(layout);
200  subWindow->setWidget(this);
201  subWindow->show();
202 }
203 
205 {
206 }
207 
209 {
210  subWindow->adjustSize();
211 }
212 
214 {
215  // Ensure that the realtime thread isn't in the middle of executing DefaultGUIModel::execute()
216  setActive(false);
217  SyncEvent event;
219 
220  update(EXIT);
222  subWindow->close();
223 }
224 
226 {
227  for (std::map<QString, param_t>::iterator i = parameter.begin(); i!= parameter.end(); ++i)
228  {
229  if (i->second.type & (STATE | EVENT))
230  {
231  i->second.edit->setText(QString::number(getValue(i->second.type, i->second.index)));
232  palette.setBrush(i->second.edit->foregroundRole(), Qt::darkGray);
233  i->second.edit->setPalette(palette);
234  }
235  else if ((i->second.type & PARAMETER) && !i->second.edit->isModified()
236  && i->second.edit->text() != *i->second.str_value)
237  {
238  i->second.edit->setText(*i->second.str_value);
239  }
240  else if ((i->second.type & COMMENT) && !i->second.edit->isModified()
241  && i->second.edit->text() != QString::fromStdString(getValueString(COMMENT, i->second.index)))
242  {
243  i->second.edit->setText(QString::fromStdString(getValueString(COMMENT, i->second.index)));
244  }
245  }
246  pauseButton->setChecked(!getActive());
247 }
248 
250 {
251  bool active = getActive();
252  setActive(false);
253  // Ensure that the realtime thread isn't in the middle of executing DefaultGUIModel::execute()
254  SyncEvent event;
256 
257  for (std::map<QString, param_t>::iterator i = parameter.begin(); i != parameter.end(); ++i)
258  if (i->second.type & COMMENT)
259  {
260  QByteArray textData = i->second.edit->text().toLatin1();
261  const char *text = textData.constData();
262  Workspace::Instance::setComment(i->second.index, text);
263  }
264 
265  update(MODIFY);
266  setActive(active);
267 
268  for (std::map<QString, param_t>::iterator i = parameter.begin(); i != parameter.end(); ++i)
269  i->second.edit->blacken();
270 }
271 
272 QString DefaultGUIModel::getComment(const QString &name)
273 {
274  std::map<QString, param_t>::iterator n = parameter.find(name);
275  if (n != parameter.end() && (n->second.type & COMMENT))
276  return QString::fromStdString(getValueString(COMMENT, n->second.index));
277  return "";
278 }
279 
280 void DefaultGUIModel::setComment(const QString &name, QString comment)
281 {
282  std::map<QString, param_t>::iterator n = parameter.find(name);
283  if (n != parameter.end() && (n->second.type & COMMENT))
284  {
285  n->second.edit->setText(comment);
286  QByteArray textData = comment.toLatin1();
287  const char *text = textData.constData();
288  Workspace::Instance::setComment(n->second.index, text);
289  }
290 }
291 
292 QString DefaultGUIModel::getParameter(const QString &name)
293 {
294  std::map<QString, param_t>::iterator n = parameter.find(name);
295  if ((n != parameter.end()) && (n->second.type & PARAMETER))
296  {
297  *n->second.str_value = n->second.edit->text();
298  setValue(n->second.index, n->second.edit->text().toDouble());
299  return n->second.edit->text();
300  }
301  return "";
302 }
303 
304 void DefaultGUIModel::setParameter(const QString &name, double value)
305 {
306  std::map<QString, param_t>::iterator n = parameter.find(name);
307  if ((n != parameter.end()) && (n->second.type & PARAMETER))
308  {
309  n->second.edit->setText(QString::number(value));
310  *n->second.str_value = n->second.edit->text();
311  setValue(n->second.index, n->second.edit->text().toDouble());
312  }
313 }
314 
315 void DefaultGUIModel::setParameter(const QString &name, const QString value)
316 {
317  std::map<QString, param_t>::iterator n = parameter.find(name);
318  if ((n != parameter.end()) && (n->second.type & PARAMETER))
319  {
320  n->second.edit->setText(value);
321  *n->second.str_value = n->second.edit->text();
322  setValue(n->second.index, n->second.edit->text().toDouble());
323  }
324 }
325 
326 void DefaultGUIModel::setState(const QString &name, double &ref)
327 {
328  std::map<QString, param_t>::iterator n = parameter.find(name);
329  if ((n != parameter.end()) && (n->second.type & STATE))
330  {
331  setData(Workspace::STATE, n->second.index, &ref);
332  n->second.edit->setText(QString::number(ref));
333  }
334 }
335 
336 void DefaultGUIModel::setEvent(const QString &name, double &ref)
337 {
338  std::map<QString, param_t>::iterator n = parameter.find(name);
339  if ((n != parameter.end()) && (n->second.type & EVENT))
340  {
341  setData(Workspace::EVENT, n->second.index, &ref);
342  n->second.edit->setText(QString::number(ref));
343  }
344 }
345 
347 {
348  if (pauseButton->isChecked() != p)
349  pauseButton->setDown(p);
350 
351  setActive(!p);
352  if (p)
353  update(PAUSE);
354  else
355  update(UNPAUSE);
356 }
357 
359 {
360  setWindowTitle(QString::number(getID()) + " " + QString::fromStdString(myname));
361 }
362 
364 {
365  for (std::map<QString, param_t>::iterator i = parameter.begin(); i
366  != parameter.end(); ++i)
367  i->second.edit->setText(QString::fromStdString(s.loadString((i->first).toStdString())));
368  if (s.loadInteger("Maximized"))
369  showMaximized();
370  else if (s.loadInteger("Minimized"))
371  showMinimized();
372  // this only exists in RTXI versions >1.3
373  if (s.loadInteger("W") != NULL)
374  {
375  resize(s.loadInteger("W"), s.loadInteger("H"));
376  parentWidget()->move(s.loadInteger("X"), s.loadInteger("Y"));
377  }
378 
379  pauseButton->setChecked(s.loadInteger("paused"));
380  modify();
381 }
382 
384 {
385  s.saveInteger("paused", pauseButton->isChecked());
386  if (isMaximized())
387  s.saveInteger("Maximized", 1);
388  else if (isMinimized())
389  s.saveInteger("Minimized", 1);
390 
391  QPoint pos = parentWidget()->pos();
392  s.saveInteger("X", pos.x());
393  s.saveInteger("Y", pos.y());
394  s.saveInteger("W", width());
395  s.saveInteger("H", height());
396 
397  for (std::map<QString, param_t>::const_iterator i = parameter.begin(); i
398  != parameter.end(); ++i)
399  s.saveString((i->first).toStdString(), (i->second.edit->text()).toStdString());
400 }
401 
403 {
404  if (event->getName() == Event::RT_PREPERIOD_EVENT)
405  {
407  setActive(false);
408  }
409  else if (event->getName() == Event::RT_POSTPERIOD_EVENT)
410  {
411 #ifdef DEBUG
412  if (getActive())
413  ERROR_MSG("DefaultGUIModel::receiveEvent : model unpaused during a period update\n");
414 #endif
415  update(PERIOD);
417  }
418 }
DefaultGUIModel(std::string name, variable_t *variables, size_t size)
static MainWindow * getInstance(void)
QString getParameter(const QString &name)
virtual void modify(void)
void setParameter(const QString &name, double value)
void doSave(Settings::Object::State &) const
static const IO::flags_t INTEGER
static const IO::flags_t UINTEGER
bool getActive(void) const
Definition: rt.h:581
static const IO::flags_t DOUBLE
void doLoad(const Settings::Object::State &)
std::vector< var_t > event
Definition: workspace.h:205
virtual void pause(bool)
static const IO::flags_t EVENT
DefaultGUILineEdit * edit
const char * RT_PREPERIOD_EVENT
Definition: event.cpp:25
QMdiSubWindow * subWindow
#define ERROR_MSG(fmt, args...)
Definition: debug.h:41
static const IO::flags_t COMMENT
static const IO::flags_t STATE
QGroupBox * buttonGroup
QPushButton * pauseButton
void unload(Object *object)
Definition: plugin.cpp:99
void saveString(const std::string &name, const std::string &value)
Definition: settings.cpp:119
virtual int callback(void)=0
QGridLayout * layout
void setState(const QString &name, double &ref)
QPushButton * modifyButton
virtual void exit(void)
void createMdi(QMdiSubWindow *)
QString getComment(const QString &name)
void receiveEvent(const Event::Object *)
void setEvent(const QString &name, double &ref)
int loadInteger(const std::string &name) const
Definition: settings.cpp:77
QPushButton * unloadButton
void setActive(bool)
Definition: rt.cpp:152
bool active
Definition: rt.h:589
const char * RT_POSTPERIOD_EVENT
Definition: event.cpp:26
static const IO::flags_t PARAMETER
Definition: rt.h:70
virtual void update(update_flags_t flag)
void setValue(size_t index, double value)
Definition: workspace.cpp:231
std::map< QString, param_t > parameter
void setData(IO::flags_t type, size_t index, double *value)
Definition: workspace.cpp:272
void saveInteger(const std::string &name, int)
Definition: settings.cpp:112
ID getID(void) const
Definition: settings.h:131
static Manager * getInstance(void)
Definition: plugin.cpp:186
std::string getValueString(IO::flags_t type, size_t index) const
Definition: workspace.cpp:204
void createGUI(DefaultGUIModel::variable_t *var, int size)
Internal Control Oriented Classes.
Definition: workspace.h:30
void setComment(const QString &name, const QString comment)
static System * getInstance(void)
Definition: rt.cpp:361
void setComment(size_t index, std::string comment)
Definition: workspace.cpp:253
std::string loadString(const std::string &name) const
Definition: settings.cpp:93
void doDeferred(const Settings::Object::State &)
virtual void refresh(void)
std::string name
Definition: io.h:325
int postEvent(Event *event, bool blocking=true)
Definition: rt.cpp:218
double getValue(IO::flags_t type, size_t index) const
Definition: workspace.cpp:182
virtual ~DefaultGUIModel(void)
const char * getName(void) const
Definition: event.h:136