ArmarXPlotter.cpp
Go to the documentation of this file.
1/*
2* This file is part of ArmarX.
3*
4* ArmarX is free software; you can redistribute it and/or modify
5* it under the terms of the GNU General Public License version 2 as
6* published by the Free Software Foundation.
7*
8* ArmarX is distributed in the hope that it will be useful, but
9* WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>.
15*
16* @package ArmarX::Gui
17* @author Mirko Waechter ( mirko.waechter at kit dot edu)
18* @date 2012
19* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20* GNU General Public License
21*/
22
23#include "ArmarXPlotter.h"
24
25#include <SimoxUtility/algorithm/string/string_tools.h>
26
31
32#include "ArmarXPlotterDialog.h"
33
34//QT
35#include <filesystem>
36#include <sstream>
37
38#include <QDir>
39#include <QSettings>
40#include <QStackedLayout>
41#include <QTextEdit>
42#include <QTime>
43#include <QTimer>
44
45#include <IceUtil/IceUtil.h>
46
47namespace armarx
48{
49 ArmarXPlotter::ArmarXPlotter() : startUpTime(QDateTime::currentDateTime())
50 {
51 plotterController = new PlotterController{this};
52 setTag("Plotter");
53 ui.setupUi(getWidget());
55 loggingDir = (QDir::currentPath());
56 dialog->ui.editLoggingDirectory->setText(loggingDir);
57
58 plotterController->setGraphStyle(ui.CBgraphStyle->currentText().toStdString());
59 ui.verticalLayout->insertWidget(0, plotterController->getPlotterWidget());
60 }
61
63 {
64 // if(dialog && this->getState() == eManagedIceObjectInitialized)
65 // getArmarXManager()->removeObjectNonBlocking(dialog);
66 // delete dialog;
67 }
68
69 void
73
74 void
76 {
77 ARMARX_VERBOSE << "ArmarXPlotter started" << flush;
78 dialog->setIceManager(getIceManager());
79 plotterController->setIceManager(getIceManager());
80 connect(dialog, SIGNAL(accepted()), this, SLOT(configDone()));
81 connect(ui.BTNEdit, SIGNAL(clicked()), this, SLOT(configDialog()));
82 connect(ui.BTNPlotterStatus,
83 SIGNAL(toggled(bool)),
84 plotterController,
85 SLOT(plottingPaused(bool)));
86
87 connect(ui.BTNAutoScale, SIGNAL(toggled(bool)), plotterController, SLOT(autoScale(bool)));
88
89 connect(ui.btnLogToFile, SIGNAL(toggled(bool)), this, SLOT(toggleLogging(bool)));
90
91 connect(ui.CBgraphStyle,
92 SIGNAL(currentTextChanged(QString)),
93 this,
94 SLOT(onGraphStyleChanged(QString)));
95
96 connect(ui.btnClearHistory, SIGNAL(clicked()), plotterController, SLOT(clearHistory()));
97
98 if (!QMetaObject::invokeMethod(plotterController, "setupCurves"))
99 {
100 ARMARX_WARNING << "Failed to invoke setupCurves";
101 }
102
103 usingTopic("TopicReplayerListener");
104 }
105
106 void
108 {
109 // unsubscribeFromTopic("TopicReplayerListener");
110 plotterController->deleteLater();
111 }
112
113 void
115 {
116 ARMARX_VERBOSE << "closing" << flush;
117 timer->stop();
118
119 if (logstream.is_open())
120 {
121 logstream.close();
122 }
123 }
124
125 void
129
130 void
132 {
133 if (!dialog)
134 {
135 return;
136 }
137
138 dialog->ui.spinBoxUpdateInterval->setValue(plotterController->getUpdateInterval());
139 dialog->ui.spinBoxShownInterval->setValue(plotterController->getShownInterval());
140 dialog->ui.syncDataLogging->setChecked(syncDataLogging);
141 dialog->ui.listWidget->clear();
142 dialog->ui.listWidget->addItems(plotterController->getSelectedDatafields());
143 // if(dialog->exec())
144 // configDone();
145 dialog->setModal(true);
146 dialog->show();
147 // dialog->raise();
148 // dialog->activateWindow();
149 // dialog->setParent(0);
150 }
151
152 void
154 {
155 {
156 // plotterController->clear();
157 std::unique_lock lock(dataMutex);
158 plotterController->setUpdateInterval(dialog->ui.spinBoxUpdateInterval->value());
159 plotterController->setShownInterval(dialog->ui.spinBoxShownInterval->value());
160 plotterController->setPollingInterval(dialog->ui.spinBoxPollingInterval->value());
161 // selectedChannels = dialog->getSelectedChannels();
162 loggingDir = dialog->ui.editLoggingDirectory->text();
163 syncDataLogging = dialog->ui.syncDataLogging->isChecked();
164 ui.btnLogToFile->setChecked(false);
165 ui.BTNPlotterStatus->setChecked(false);
166 plotterController->setSelectedDatafields(dialog->getSelectedDatafields());
167 }
168
169 // plotterController->setupCurves();
170 }
171
172 void
174 {
175 std::lock_guard<std::mutex> lock(mutex);
176
177 if (toggled)
178 {
179 std::filesystem::path outputPath;
180 if (filename.empty())
181 {
182 outputPath = loggingDir.toStdString() + "/datalog.csv";
183
184 std::string time = IceUtil::Time::now().toDateTime();
185 time = simox::alg::replace_all(time, "/", "-");
186 time = simox::alg::replace_all(time, " ", "_");
187 time = simox::alg::replace_all(time, ":", "-");
188 outputPath = outputPath.parent_path() / (outputPath.stem().string() + "-" + time +
189 outputPath.extension().string());
190 }
191 else
192 {
193 std::filesystem::path path = filename;
194 outputPath = loggingDir.toStdString() + "/" + path.stem().string() + ".csv";
195 }
196
197 ARMARX_INFO << "Logging to " << outputPath.string();
198 logstream.open(outputPath.string());
199 logStartTime = IceUtil::Time::now();
200
201 if (!logstream.is_open())
202 {
203 ARMARX_ERROR << "Could not open file for logging: " << outputPath.string();
204 ui.btnLogToFile->setChecked(false);
205 }
206 else
207 {
208 std::lock_guard<std::mutex> lock(fileMutex);
209
210 csvHeader = plotterController->getSelectedDatafieldsKeys();
211
212 logstream << "Timestamp";
213 for (const auto& s : csvHeader)
214 {
215 logstream << "," << s;
216 }
217 logstream << std::endl;
218
219 connect(plotterController,
220 SIGNAL(newDataAvailable(long, std::map<std::string, VariantPtr>)),
221 this,
222 SLOT(logToFile(long, std::map<std::string, VariantPtr>)));
223 }
224 }
225 else
226 {
227 filename = "";
228 QObject::disconnect(plotterController,
229 SIGNAL(newDataAvailable(long, std::map<std::string, VariantPtr>)),
230 this,
231 SLOT(logToFile(long, std::map<std::string, VariantPtr>)));
232
233 std::lock_guard<std::mutex> lock(fileMutex);
234
235 logstream.flush();
236 ARMARX_INFO << "done writing log";
237 logstream.close();
238
239 csvHeader.clear();
240 }
241 }
242
243 void
245 {
246 const auto st = style.toStdString();
247 plotterController->setGraphStyle(st);
248 if (plotterController->getGraphStyle() != st)
249 {
250 if (style == "Bar chart")
251 {
252 ui.BTNAutoScale->setDisabled(true);
253 }
254 else
255 {
256 ui.BTNAutoScale->setDisabled(false);
257 }
258 }
259 }
260
261 void
263 {
264 std::unique_lock lock(dataMutex);
265 settings->setValue("updateInterval", plotterController->getUpdateInterval());
266 settings->setValue("shownInterval", plotterController->getShownInterval());
267 settings->setValue("pollingInterval", plotterController->getPollingInterval());
268 settings->setValue("selectedChannels", plotterController->getSelectedDatafields());
269 settings->setValue("autoScaleActive", ui.BTNAutoScale->isChecked());
270 settings->setValue("syncDataLogging", syncDataLogging);
271 }
272
273 void
275 {
276 std::unique_lock lock(dataMutex);
277 plotterController->setUpdateInterval(settings->value("updateInterval", 100).toInt());
278 plotterController->setShownInterval(settings->value("shownInterval", 60).toInt());
279 plotterController->setPollingInterval(settings->value("pollingInterval", 33).toInt());
280 plotterController->setSelectedDatafields(
281 settings->value("selectedChannels", QStringList()).toStringList());
282 ui.BTNAutoScale->setChecked(settings->value("autoScaleActive", true).toBool());
283 syncDataLogging = settings->value("syncDataLogging", false).toBool();
284
285 ARMARX_VERBOSE << "Settings loaded";
286 }
287
288 void
290 const std::map<std::string, VariantPtr>& dataMaptoAppend)
291 {
292 std::lock_guard<std::mutex> lock(fileMutex);
293
294 if (!logstream.is_open() || !dataMaptoAppend.size())
295 {
296 return;
297 }
298
299 logstream << (IceUtil::Time::microSeconds(timestamp) - logStartTime).toMilliSecondsDouble();
300
301 for (const auto& f : csvHeader)
302 {
303 logstream << ",";
304 if (dataMaptoAppend.count(f))
305 {
306 logstream << dataMaptoAppend.at(f)->Variant::getOutputValueOnly();
307 }
308 }
309 logstream << std::endl;
310 }
311} // namespace armarx
std::string timestamp()
std::string currentDateTime()
void onInitComponent() override
Pure virtual hook for the subclass.
void toggleLogging(bool toggled)
void loadSettings(QSettings *settings) override
Implement to load the settings that are part of the GUI configuration.
void saveSettings(QSettings *settings) override
Implement to save the settings as part of the GUI configuration.
std::shared_ptr< QSettings > settings
void onGraphStyleChanged(const QString &style)
Ui::ArmarXPlotter ui
void onConnectComponent() override
Pure virtual hook for the subclass.
void logToFile(long timestamp, const std::map< std::string, VariantPtr > &dataMaptoAppend)
void onCloseWidget(QCloseEvent *event)
emits the closeRequest signal
QPointer< ArmarXPlotterDialog > dialog
void onExitComponent() override
Hook for subclass.
virtual QPointer< QWidget > getWidget()
getWidget returns a pointer to the a widget of this controller.
void setTag(const LogTag &tag)
Definition Logging.cpp:54
void usingTopic(const std::string &name, bool orderedPublishing=false)
Registers a proxy for subscription after initialization.
IceManagerPtr getIceManager() const
Returns the IceManager.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
This file offers overloads of toIce() and fromIce() functions for STL container types.
const LogSender::manipulator flush
Definition LogSender.h:251