TopicReplayerWidgetController.cpp
Go to the documentation of this file.
1 /*
2 
3  * This file is part of ArmarX.
4  *
5  * ArmarX is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * ArmarX is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  *
17  * \package ArmarXGui::gui-plugins::TopicReplayerWidgetController
18  * \author Stefan Reither ( stef dot reither at web dot de )
19  * \date 2016
20  * \copyright http://www.gnu.org/licenses/gpl-2.0.txt
21  * GNU General Public License
22  */
23 
25 
26 #include <string>
27 
28 #include <QDateTime>
29 #include <QFileDialog>
30 #include <QMessageBox>
31 #include <QProgressDialog>
32 #include <qnamespace.h>
33 
34 #include <IceUtil/UUID.h>
35 
39 
40 #define REQUEST_TIMEKEEPER_TIME_FREQUENCY 30
41 
42 namespace armarx
43 {
45  {
46  widget.setupUi(getWidget());
47  }
48 
50  {
51  }
52 
53  void
55  {
56  }
57 
58  void
60  {
61  }
62 
63  void
65  {
66  this->setPausedGuiMode();
67  widget.pushButton_play->setEnabled(false);
68  widget.pushButton_load->setFocus();
69  }
70 
71  void
73  {
74  connect(widget.pushButton_load, SIGNAL(clicked()), this, SLOT(loadFile()));
75  connect(widget.pushButton_play, SIGNAL(clicked()), this, SLOT(resumeReplay()));
76  connect(widget.pushButton_pause, SIGNAL(clicked()), this, SLOT(pauseReplay()));
77  connect(widget.checkBox_loop, SIGNAL(toggled()), this, SLOT(loopReplay()));
78  connect(widget.horizontalSlider_replaySpeed,
79  SIGNAL(valueChanged(int)),
80  this,
81  SLOT(replaySpeedSliderChanged()));
82  connect(widget.doubleSpinBox_replaySpeed,
83  SIGNAL(editingFinished()),
84  this,
85  SLOT(replaySpeedSpinBoxChanged()));
86 
87  connect(widget.horizontalSlider_replayPosition,
88  SIGNAL(valueChanged(int)),
89  this,
90  SLOT(replayPositionSliderChanged()));
91 
92  connect(widget.horizontalSlider_replayPosition,
93  SIGNAL(sliderPressed()),
94  this,
95  SLOT(stopSliderUpdater()));
96  connect(widget.horizontalSlider_replayPosition,
97  SIGNAL(sliderReleased()),
98  this,
99  SLOT(startSliderUpdater()));
100 
101  connect(widget.horizontalSlider_replayPosition,
102  SIGNAL(sliderReleased()),
103  this,
104  SLOT(jumpToPosition()));
105  }
106 
107  void
108  TopicReplayerWidgetController::onDisconnectComponent()
109  {
110  this->killTimer(replayPositionSliderUpdaterTimer);
111  if (topicReplayer)
112  {
113  getArmarXManager()->removeObjectNonBlocking(topicReplayer->getName());
114  }
115  }
116 
117  void
118  armarx::TopicReplayerWidgetController::loadFile()
119  {
120  widget.pushButton_load->setEnabled(false);
121 
122  QFileDialog fileDialog(getWidget(), "Open Topic Recording File");
123  fileDialog.setFileMode(QFileDialog::ExistingFile);
124  QStringList filters;
125  filters << tr("TopicRecorder files (*.bag)");
126  filters << tr("All files (*.*)");
127  fileDialog.setNameFilters(filters);
128 
129 
130  fileDialog.setViewMode(QFileDialog::Detail);
131  fileDialog.setVisible(true);
132 
133  QString fileName;
134  if (fileDialog.exec() == QDialog::Accepted)
135  {
136  fileName = fileDialog.selectedFiles().first();
137  if (topicReplayer)
138  {
139  getArmarXManager()->removeObjectBlocking(topicReplayer->getName());
140  }
141 
142  if (!fileName.isEmpty())
143  {
145  properties->setProperty("ArmarX.TopicReplayer.RecordFile", fileName.toStdString());
146  topicReplayer = armarx::Component::create<TopicReplayer>(properties);
147  topicReplayer->setAutoplay(false);
148  widget.doubleSpinBox_replaySpeed->setValue(1.0);
149  QProgressDialog dProgress;
150  dProgress.setMaximum(0);
151  dProgress.setMinimum(0);
152  getArmarXManager()->addObject(topicReplayer,
153  false,
154  topicReplayer->getDefaultName() +
155  IceUtil::generateUUID());
156  dProgress.show();
157  // waiting for TopicReplayer to set up
158  while (topicReplayer->getObjectScheduler()->getObject()->getState() <
159  eManagedIceObjectStarted)
160  {
161  usleep(100000);
162  }
163 
164  // Checks whether opened file has database-format, if not, abort
165  if (topicReplayer->getReplayLength().toMilliSeconds() == 0)
166  {
167  this->setPausedGuiMode();
168  widget.pushButton_play->setEnabled(false);
169  widget.lineEdit_fileName->setText("");
170  widget.horizontalSlider_replayPosition->setValue(0);
171  widget.horizontalSlider_replayPosition->setEnabled(false);
172  widget.horizontalSlider_replaySpeed->setEnabled(false);
173  widget.listWidget_topics->clear();
174 
175  QMessageBox msg;
176  msg.setWindowTitle("TopicReplayerGui");
177  msg.setText("The format of the selected file is not supported.");
178  msg.setIcon(QMessageBox::Warning);
179  msg.exec();
180  }
181  else
182  {
183  widget.lineEdit_fileName->setText(fileName);
184  this->fillListOfRecordedTopics();
185  this->setUpReplayPositionSlider();
186  widget.pushButton_play->setEnabled(true);
187  widget.horizontalSlider_replayPosition->setEnabled(true);
188  widget.horizontalSlider_replaySpeed->setEnabled(true);
189 
190  replayPositionSliderUpdaterTimer =
191  this->startTimer(REQUEST_TIMEKEEPER_TIME_FREQUENCY);
192  }
193  }
194  }
195 
196  widget.pushButton_load->setEnabled(true);
197  }
198 
199  void
200  armarx::TopicReplayerWidgetController::pauseReplay()
201  {
202  this->setPausedGuiMode();
203 
204  if (topicReplayer)
205  {
206  topicReplayer->pauseReplay();
207  }
208  }
209 
210  void
211  armarx::TopicReplayerWidgetController::loopReplay()
212  {
213  // if (topicReplayer)
214  // {
215  // topicReplayer->setLoop(widget.checkBox_loop->isChecked());
216  // }
217  }
218 
219  void
220  armarx::TopicReplayerWidgetController::resumeReplay()
221  {
222  if (topicReplayer && !(this->replayLength.toMilliSeconds() ==
223  widget.horizontalSlider_replayPosition->value()))
224  {
225  std::vector<std::string> replayingTopics;
226  for (int i = 0; i < widget.listWidget_topics->count(); i++)
227  {
228  auto item = widget.listWidget_topics->item(i);
229  if (item->checkState() == Qt::Checked)
230  {
231  replayingTopics.push_back(item->text().toStdString());
232  }
233  }
234  topicReplayer->setReplayingTopics(replayingTopics);
235 
236  setReplaySpeed();
237  topicReplayer->resumeReplay();
238 
239  this->setPlayingGuiMode();
240  }
241  }
242 
243  void
244  armarx::TopicReplayerWidgetController::setReplaySpeed()
245  {
246  if (topicReplayer)
247  {
248  topicReplayer->setReplaySpeed(widget.doubleSpinBox_replaySpeed->value());
249  }
250  }
251 
252  void
253  armarx::TopicReplayerWidgetController::replaySpeedSliderChanged()
254  {
255  updateReplayPositionSlider();
256 
257  double spinBoxValue = 0.0;
258  int sliderValue = widget.horizontalSlider_replaySpeed->value();
259  int m = widget.horizontalSlider_replaySpeed->maximum() / 2;
260 
261  if (sliderValue < m)
262  {
263  spinBoxValue = (double)sliderValue / (double)m;
264  }
265  else
266  {
267  spinBoxValue = 1 + 9.0 * ((double)sliderValue / (double)m - 1);
268  }
269 
270  widget.doubleSpinBox_replaySpeed->setValue(spinBoxValue);
271  setReplaySpeed();
272  }
273 
274  void
275  TopicReplayerWidgetController::replaySpeedSpinBoxChanged()
276  {
277  double spinBoxValue = widget.doubleSpinBox_replaySpeed->value();
278  int sliderValue = 0;
279  int m = widget.horizontalSlider_replaySpeed->maximum() / 2;
280 
281  if (spinBoxValue <= 1.0)
282  {
283  sliderValue = (int)(spinBoxValue * m);
284  }
285  else
286  {
287  sliderValue = (int)(m * (1 + (spinBoxValue - 1) / 9));
288  }
289 
290  widget.horizontalSlider_replaySpeed->setValue(sliderValue);
291  setReplaySpeed();
292  }
293 
294  void
295  TopicReplayerWidgetController::fillListOfRecordedTopics()
296  {
297  QListWidget* topicsListWidget = widget.listWidget_topics;
298  topicsListWidget->clear();
299 
300  const Qt::CheckState checkState = widget.checkBoxLoadTopicsEnabled->checkState();
301 
302  if (this->topicReplayer)
303  {
304  std::vector<std::string> recordedTopics = topicReplayer->getRecordedTopics();
305  std::sort(recordedTopics.begin(), recordedTopics.end());
306 
307  for (std::string topic : recordedTopics)
308  {
309  QListWidgetItem* item = new QListWidgetItem;
310  item->setData(Qt::DisplayRole, QString::fromStdString(topic));
311  item->setData(Qt::CheckStateRole, checkState);
312  topicsListWidget->addItem(item);
313  }
314  }
315  }
316 
317  void
318  TopicReplayerWidgetController::setPausedGuiMode()
319  {
320  widget.pushButton_pause->setEnabled(false);
321 
322  widget.pushButton_load->setEnabled(true);
323  widget.pushButton_play->setEnabled(true);
324  widget.pushButton_play->setFocus();
325  widget.listWidget_topics->setEnabled(true);
326 
327  this->stopSliderUpdater();
328  }
329 
330  void
331  TopicReplayerWidgetController::setPlayingGuiMode()
332  {
333  widget.pushButton_load->setEnabled(false);
334  widget.listWidget_topics->setEnabled(false);
335  widget.pushButton_play->setEnabled(false);
336 
337  widget.pushButton_pause->setEnabled(true);
338  widget.pushButton_pause->setFocus();
339 
340  widget.horizontalSlider_replayPosition->setEnabled(true);
341  widget.horizontalSlider_replaySpeed->setEnabled(true);
342 
343  this->startSliderUpdater();
344  }
345 
346  void
347  TopicReplayerWidgetController::setUpReplayPositionSlider()
348  {
349  if (topicReplayer)
350  {
351  replayLength = topicReplayer->getReplayLength();
352  QTime t(0, 0, 0, 0);
353  t = t.addMSecs((int)replayLength.toMilliSeconds());
354  widget.label_replayLength->setText(t.toString("h:mm:ss.zzz"));
355  widget.horizontalSlider_replayPosition->setMaximum((int)replayLength.toMilliSeconds());
356  widget.horizontalSlider_replayPosition->setTickInterval(
357  (int)replayLength.toMilliSeconds() / 100);
358  widget.horizontalSlider_replayPosition->setSingleStep(
359  (int)replayLength.toMilliSeconds() / 100);
360  widget.horizontalSlider_replayPosition->setValue(0);
361  }
362  }
363 
364  void
365  TopicReplayerWidgetController::updateReplayPositionSlider()
366  {
367  if (topicReplayer)
368  {
369  int currentTime = (int)topicReplayer->getCurrentTimePosition().toMilliSeconds();
370  widget.horizontalSlider_replayPosition->setValue(currentTime);
371  if (currentTime >= replayLength.toMilliSeconds())
372  {
373  this->pauseReplay();
374 
375  if (widget.checkBox_loop->isChecked())
376  {
377  widget.horizontalSlider_replayPosition->setSliderPosition(0);
378  jumpToPosition();
379  resumeReplay();
380  }
381  }
382  }
383  }
384 
385  void
386  TopicReplayerWidgetController::replayPositionSliderChanged()
387  {
388  QTime t(0, 0, 0, 0);
389  t = t.addMSecs(widget.horizontalSlider_replayPosition->value());
390  widget.label_replayPosition->setText(t.toString("h:mm:ss.zzz"));
391  }
392 
393  void
394  TopicReplayerWidgetController::timerEvent(QTimerEvent* event)
395  {
396  if (event->timerId() == this->replayPositionSliderUpdaterTimer)
397  {
398  this->updateReplayPositionSlider();
399  }
400  }
401 
402  void
403  TopicReplayerWidgetController::stopSliderUpdater()
404  {
405  this->killTimer(replayPositionSliderUpdaterTimer);
406  }
407 
408  void
409  TopicReplayerWidgetController::startSliderUpdater()
410  {
411  replayPositionSliderUpdaterTimer = this->startTimer(REQUEST_TIMEKEEPER_TIME_FREQUENCY);
412  }
413 
414  void
415  TopicReplayerWidgetController::jumpToPosition()
416  {
417  if (topicReplayer)
418  {
419  topicReplayer->jumpToPosition(
420  IceUtil::Time().milliSeconds(widget.horizontalSlider_replayPosition->value()));
421  }
422  }
423 } // namespace armarx
ArmarXManager.h
REQUEST_TIMEKEEPER_TIME_FREQUENCY
#define REQUEST_TIMEKEEPER_TIME_FREQUENCY
Definition: TopicReplayerWidgetController.cpp:40
armarx::ManagedIceObject::getArmarXManager
ArmarXManagerPtr getArmarXManager() const
Returns the ArmarX manager used to add and remove components.
Definition: ManagedIceObject.cpp:360
TopicReplayerWidgetController.h
armarx::TopicReplayerWidgetController::~TopicReplayerWidgetController
~TopicReplayerWidgetController() override
Controller destructor.
Definition: TopicReplayerWidgetController.cpp:49
armarx::TopicReplayerWidgetController::onInitComponent
void onInitComponent() override
Definition: TopicReplayerWidgetController.cpp:64
IceInternal::Handle<::Ice::Properties >
armarx::TopicReplayerWidgetController::saveSettings
void saveSettings(QSettings *settings) override
Definition: TopicReplayerWidgetController.cpp:59
armarx::TopicReplayerWidgetController::TopicReplayerWidgetController
TopicReplayerWidgetController()
Controller Constructor.
Definition: TopicReplayerWidgetController.cpp:44
Ice::createProperties
Ice::PropertiesPtr createProperties()
armarx::TopicReplayerWidgetController::loadSettings
void loadSettings(QSettings *settings) override
Definition: TopicReplayerWidgetController.cpp:54
ArmarXObjectScheduler.h
armarx::armem::Time
armarx::core::time::DateTime Time
Definition: forward_declarations.h:13
CMakePackageFinder.h
armarx::TopicReplayerWidgetController::onConnectComponent
void onConnectComponent() override
Definition: TopicReplayerWidgetController.cpp:72
armarx::ArmarXWidgetController::getWidget
virtual QPointer< QWidget > getWidget()
getWidget returns a pointer to the a widget of this controller.
Definition: ArmarXWidgetController.cpp:54
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27