main.cpp
Go to the documentation of this file.
1 /*
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
5  */
6 
7 #include "mainwindow.h"
8 #include <iostream>
9 #include <QApplication>
10 #include <QSplashScreen>
11 #include <QThread>
12 #include <QCommandLineParser>
13 #include <QDesktopWidget>
14 #include <QFontDatabase>
15 #include <QSettings>
16 #include <QPushButton>
17 #include <QNetworkAccessManager>
18 #include <QNetworkReply>
19 #include <QJsonDocument>
20 #include <QDir>
21 #include <QDialog>
22 #include <QUuid>
23 #include <QDesktopServices>
24 
31 #include "transforms/moving_rms.h"
35 
36 #include "new_release_dialog.h"
37 #include "ui_changelog_dialog.h"
38 
39 #ifdef COMPILED_WITH_CATKIN
40 #include <ros/ros.h>
41 #endif
42 #ifdef COMPILED_WITH_AMENT
43 #include <rclcpp/rclcpp.hpp>
44 #endif
45 
46 static QString VERSION_STRING =
47  QString("%1.%2.%3").arg(PJ_MAJOR_VERSION).arg(PJ_MINOR_VERSION).arg(PJ_PATCH_VERSION);
48 
49 inline int GetVersionNumber(QString str)
50 {
51  QStringList online_version = str.split('.');
52  if (online_version.size() != 3)
53  {
54  return 0;
55  }
56  int major = online_version[0].toInt();
57  int minor = online_version[1].toInt();
58  int patch = online_version[2].toInt();
59  return major * 10000 + minor * 100 + patch;
60 }
61 
63 {
64  QDialog* dialog = new QDialog();
65  auto ui = new Ui::ChangelogDialog();
66  ui->setupUi(dialog);
67 
68  QObject::connect(ui->buttonChangelog, &QPushButton::clicked, dialog, [](bool) {
69  QDesktopServices::openUrl(QUrl("https://bit.ly/plotjuggler-update"));
70  QSettings settings;
71  settings.setValue("Changelog/first", false);
72  });
73 
74  QObject::connect(ui->checkBox, &QCheckBox::toggled, dialog, [](bool toggle) {
75  QSettings settings;
76  settings.setValue("Changelog/dont", toggle);
77  });
78 
79  dialog->exec();
80 }
81 
82 void OpenNewReleaseDialog(QNetworkReply* reply)
83 {
84  if (reply->error())
85  {
86  qDebug() << "reply error";
87  return;
88  }
89 
90  QString answer = reply->readAll();
91  QJsonDocument document = QJsonDocument::fromJson(answer.toUtf8());
92  QJsonObject data = document.object();
93  QString url = data["html_url"].toString();
94  QString name = data["name"].toString();
95  QString tag_name = data["tag_name"].toString();
96  QSettings settings;
97  int online_number = GetVersionNumber(tag_name);
98  QString dont_show =
99  settings.value("NewRelease/dontShowThisVersion", VERSION_STRING).toString();
100  int dontshow_number = GetVersionNumber(dont_show);
101  int current_number = GetVersionNumber(VERSION_STRING);
102 
103  if (online_number > current_number && online_number > dontshow_number)
104  {
105  NewReleaseDialog* dialog = new NewReleaseDialog(nullptr, tag_name, name, url);
106  dialog->exec();
107  }
108 }
109 
111 {
112  QSettings settings;
113  srand(time(nullptr));
114 
115  auto getNum = []() {
116  const int last_image_num = 94;
117  int n = rand() % (last_image_num + 2);
118  if (n > last_image_num)
119  {
120  n = 0;
121  }
122  return n;
123  };
124  std::set<int> previous_set;
125  std::list<int> previous_nums;
126 
127  QStringList previous_list = settings.value("previousFunnyMemesList").toStringList();
128  for (auto str : previous_list)
129  {
130  int num = str.toInt();
131  previous_set.insert(num);
132  previous_nums.push_back(num);
133  }
134 
135  int n = getNum();
136  while (previous_set.count(n) != 0)
137  {
138  n = getNum();
139  }
140 
141  while (previous_nums.size() >= 10)
142  {
143  previous_nums.pop_front();
144  }
145  previous_nums.push_back(n);
146 
147  QStringList new_list;
148  for (int num : previous_nums)
149  {
150  new_list.push_back(QString::number(num));
151  }
152 
153  settings.setValue("previousFunnyMemesList", new_list);
154  auto filename = QString("://resources/memes/meme_%1.jpg").arg(n, 2, 10, QChar('0'));
155  return QPixmap(filename);
156 }
157 
158 std::vector<std::string> MergeArguments(const std::vector<std::string>& args)
159 {
160 #ifdef PJ_DEFAULT_ARGS
161  auto default_cmdline_args = QString(PJ_DEFAULT_ARGS).split(" ", PJ::SkipEmptyParts);
162 
163  std::vector<std::string> new_args;
164  new_args.push_back(args.front());
165 
166  // Add the remain arguments, replacing escaped characters if necessary.
167  // Escaping needed because some chars cannot be entered easily in the -DPJ_DEFAULT_ARGS
168  // preprocessor directive
169  // _0x20_ --> ' ' (space)
170  // _0x3b_ --> ';' (semicolon)
171  for (auto cmdline_arg : default_cmdline_args)
172  {
173  // replace(const QString &before, const QString &after, Qt::CaseSensitivity cs =
174  // Qt::CaseSensitive)
175  cmdline_arg = cmdline_arg.replace("_0x20_", " ", Qt::CaseSensitive);
176  cmdline_arg = cmdline_arg.replace("_0x3b_", ";", Qt::CaseSensitive);
177  new_args.push_back(strdup(cmdline_arg.toLocal8Bit().data()));
178  }
179 
180  // If an argument appears repeated, the second value overrides previous one.
181  // Do this after adding default_cmdline_args so the command-line override default
182  for (size_t i = 1; i < args.size(); ++i)
183  {
184  new_args.push_back(args[i]);
185  }
186 
187  return new_args;
188 
189 #else
190  return args;
191 #endif
192 }
193 
194 int main(int argc, char* argv[])
195 {
196  std::vector<std::string> args;
197 
198 #if !defined(COMPILED_WITH_CATKIN) && !defined(COMPILED_WITH_AMENT)
199  for (int i = 0; i < argc; i++)
200  {
201  args.push_back(argv[i]);
202  }
203 #elif defined(COMPILED_WITH_CATKIN)
204  ros::removeROSArgs(argc, argv, args);
205 #elif defined(COMPILED_WITH_AMENT)
206  args = rclcpp::remove_ros_arguments(argc, argv);
207 #endif
208 
210 
211  int new_argc = args.size();
212  std::vector<char*> new_argv;
213  for (int i = 0; i < new_argc; i++)
214  {
215  new_argv.push_back(args[i].data());
216  }
217 
218  QApplication app(new_argc, new_argv.data());
219 
220  //-------------------------
221 
222  QCoreApplication::setOrganizationName("PlotJuggler");
223  QCoreApplication::setApplicationName("PlotJuggler-3");
224  QSettings::setDefaultFormat(QSettings::IniFormat);
225 
226  QSettings settings;
227 
228  if (!settings.isWritable())
229  {
230  qDebug() << "ERROR: the file [" << settings.fileName()
231  << "] is not writable. This may happen when you run PlotJuggler with sudo. "
232  "Change the permissions of the file (\"sudo chmod 666 <file_name>\"on "
233  "linux)";
234  }
235 
236  app.setApplicationVersion(VERSION_STRING);
237 
238  //---------------------------
239  TransformFactory::registerTransform<FirstDerivative>();
240  TransformFactory::registerTransform<ScaleTransform>();
241  TransformFactory::registerTransform<MovingAverageFilter>();
242  TransformFactory::registerTransform<MovingRMS>();
243  TransformFactory::registerTransform<OutlierRemovalFilter>();
244  TransformFactory::registerTransform<IntegralTransform>();
245  TransformFactory::registerTransform<AbsoluteTransform>();
246  TransformFactory::registerTransform<MovingVarianceFilter>();
247  TransformFactory::registerTransform<SamplesCountFilter>();
248  //---------------------------
249 
250  QCommandLineParser parser;
251  parser.setApplicationDescription("PlotJuggler: the time series visualization"
252  " tool that you deserve ");
253  parser.addVersionOption();
254  parser.addHelpOption();
255 
256  QCommandLineOption nosplash_option(QStringList() << "n"
257  << "nosplash",
258  "Don't display the splashscreen");
259  parser.addOption(nosplash_option);
260 
261  QCommandLineOption test_option(QStringList() << "t"
262  << "test",
263  "Generate test curves at startup");
264  parser.addOption(test_option);
265 
266  QCommandLineOption loadfile_option(QStringList() << "d"
267  << "datafile",
268  "Load a file containing data", "file_path");
269  parser.addOption(loadfile_option);
270 
271  QCommandLineOption layout_option(QStringList() << "l"
272  << "layout",
273  "Load a file containing the layout configuration",
274  "file_path");
275  parser.addOption(layout_option);
276 
277  QCommandLineOption publish_option(QStringList() << "p"
278  << "publish",
279  "Automatically start publisher when loading the "
280  "layout file");
281  parser.addOption(publish_option);
282 
283  QCommandLineOption folder_option(QStringList() << "plugin_folders",
284  "Add semicolon-separated list of folders where you "
285  "should look "
286  "for additional plugins.",
287  "directory_paths");
288  parser.addOption(folder_option);
289 
290  QCommandLineOption buffersize_option(QStringList() << "buffer_size",
291  QCoreApplication::translate("main", "Change the "
292  "maximum size "
293  "of the "
294  "streaming "
295  "buffer "
296  "(minimum: 10 "
297  "default: "
298  "60)"),
299  QCoreApplication::translate("main", "seconds"));
300 
301  parser.addOption(buffersize_option);
302 
303  QCommandLineOption nogl_option(QStringList() << "disable_opengl", "Disable OpenGL "
304  "display before "
305  "starting the "
306  "application. "
307  "You can enable it "
308  "again in the "
309  "'Preferences' "
310  "menu.");
311 
312  parser.addOption(nogl_option);
313 
314  QCommandLineOption enabled_plugins_option(QStringList() << "enabled_plugins",
315  "Limit the loaded plugins to ones in the "
316  "semicolon-separated list",
317  "name_list");
318  parser.addOption(enabled_plugins_option);
319 
320  QCommandLineOption disabled_plugins_option(QStringList() << "disabled_plugins",
321  "Do not load any of the plugins in the "
322  "semicolon separated list",
323  "name_list");
324  parser.addOption(disabled_plugins_option);
325 
326  QCommandLineOption skin_path_option(QStringList() << "skin_path",
327  "New \"skin\". Refer to the sample in "
328  "[plotjuggler_app/resources/skin]",
329  "path to folder");
330  parser.addOption(skin_path_option);
331 
332  QCommandLineOption start_streamer(QStringList() << "start_streamer",
333  "Automatically start a Streaming Plugin with the "
334  "give filename",
335  "file_name (no extension)");
336  parser.addOption(start_streamer);
337 
338  QCommandLineOption window_title(QStringList() << "window_title", "Set the window title",
339  "window_title");
340  parser.addOption(window_title);
341 
342  parser.process(*qApp);
343 
344  if (parser.isSet(publish_option) && !parser.isSet(layout_option))
345  {
346  std::cerr << "Option [ -p / --publish ] is invalid unless [ -l / --layout ] is used "
347  "too."
348  << std::endl;
349  return -1;
350  }
351 
352  if (parser.isSet(enabled_plugins_option) && parser.isSet(disabled_plugins_option))
353  {
354  std::cerr << "Option [ --enabled_plugins ] and [ --disabled_plugins ] can't be used "
355  "together."
356  << std::endl;
357  return -1;
358  }
359 
360  if (parser.isSet(nogl_option))
361  {
362  settings.setValue("Preferences::use_opengl", false);
363  }
364 
365  if (parser.isSet(skin_path_option))
366  {
367  QDir path(parser.value(skin_path_option));
368  if (!path.exists())
369  {
370  qDebug() << "Skin path [" << parser.value(skin_path_option) << "] not found";
371  return -1;
372  }
373  }
374 
375  QIcon app_icon("://resources/plotjuggler.svg");
376  QApplication::setWindowIcon(app_icon);
377 
378  QNetworkAccessManager manager_new_release;
379  QObject::connect(&manager_new_release, &QNetworkAccessManager::finished,
381 
382  QNetworkRequest request_new_release;
383  request_new_release.setUrl(QUrl("https://api.github.com/repos/facontidavide/"
384  "PlotJuggler/releases/latest"));
385  manager_new_release.get(request_new_release);
386 
387  MainWindow* window = nullptr;
388 
389  /*
390  * You, fearless code reviewer, decided to start a journey into my source code.
391  * For your bravery, you deserve to know the truth.
392  * The splashscreen is useless; not only it is useless, it will make your start-up
393  * time slower by few seconds for absolutely no reason.
394  * But what are two seconds compared with the time that PlotJuggler will save you?
395  * The splashscreen is the connection between me and my users, the glue that keeps
396  * together our invisible relationship.
397  * Now, it is up to you to decide: you can block the splashscreen forever or not,
398  * reject a message that brings a little of happiness into your day, spent analyzing
399  * data. Please don't do it.
400  */
401 
402  bool first_changelog = settings.value("Changelog/first", true).toBool();
403  bool dont_changelog = settings.value("Changelog/dont", false).toBool();
404 
405  if (first_changelog && !dont_changelog)
406  {
408  }
409  else if (!parser.isSet(nosplash_option) &&
410  !(parser.isSet(loadfile_option) || parser.isSet(layout_option)))
411  // if(false) // if you uncomment this line, a kitten will die somewhere in the world.
412  {
413  QPixmap main_pixmap;
414 
415  if (parser.isSet(skin_path_option))
416  {
417  QDir path(parser.value(skin_path_option));
418  QFile splash = path.filePath("pj_splashscreen.png");
419  if (splash.exists())
420  {
421  main_pixmap = QPixmap(splash.fileName());
422  }
423  }
424 
425  if (main_pixmap.isNull())
426  {
427  main_pixmap = getFunnySplashscreen();
428  }
429 
430  QSplashScreen splash(main_pixmap, Qt::WindowStaysOnTopHint);
431  QDesktopWidget* desktop = QApplication::desktop();
432  const int scrn = desktop->screenNumber();
433  const QPoint currentDesktopsCenter = desktop->availableGeometry(scrn).center();
434  splash.move(currentDesktopsCenter - splash.rect().center());
435 
436  splash.show();
437  app.processEvents();
438 
439  auto deadline = QDateTime::currentDateTime().addMSecs(500);
440  while (QDateTime::currentDateTime() < deadline)
441  {
442  app.processEvents();
443  }
444 
445  window = new MainWindow(parser);
446 
447  deadline = QDateTime::currentDateTime().addMSecs(3000);
448  while (QDateTime::currentDateTime() < deadline && !splash.isHidden())
449  {
450  app.processEvents();
451  }
452  }
453 
454  if (!window)
455  {
456  window = new MainWindow(parser);
457  }
458 
459  window->show();
460 
461  if (parser.isSet(start_streamer))
462  {
464  }
465 
466  QNetworkAccessManager manager_message;
467  QObject::connect(&manager_message, &QNetworkAccessManager::finished,
468  [window](QNetworkReply* reply) {
469  if (reply->error())
470  {
471  return;
472  }
473  QString answer = reply->readAll();
474  QJsonDocument document = QJsonDocument::fromJson(answer.toUtf8());
475  QJsonObject data = document.object();
476  QString message = data["message"].toString();
477  window->setStatusBarMessage(message);
478  });
479 
480  QNetworkRequest request_message;
481  request_message.setUrl(QUrl("https://fastapi-example-7kz3.onrender.com"));
482  manager_message.get(request_message);
483 
484  return app.exec();
485 }
getFunnySplashscreen
QPixmap getFunnySplashscreen()
Definition: main.cpp:110
MergeArguments
std::vector< std::string > MergeArguments(const std::vector< std::string > &args)
Definition: main.cpp:158
MainWindow::setStatusBarMessage
void setStatusBarMessage(QString message)
Definition: mainwindow.cpp:1789
ros.h
VERSION_STRING
static QString VERSION_STRING
Definition: main.cpp:46
PJ::SkipEmptyParts
const auto SkipEmptyParts
Definition: plotdatabase.h:31
moving_average_filter.h
OpenNewReleaseDialog
void OpenNewReleaseDialog(QNetworkReply *reply)
Definition: main.cpp:82
transform_function.h
moving_rms.h
MainWindow
Definition: mainwindow.h:37
moving_variance.h
integral_transform.h
mqtt_test.time
float time
Definition: mqtt_test.py:17
absolute_transform.h
MainWindow::on_buttonStreamingStart_clicked
void on_buttonStreamingStart_clicked()
Definition: mainwindow.cpp:3392
udp_client.parser
parser
Definition: udp_client.py:9
new_release_dialog.h
samples_count.h
GetVersionNumber
int GetVersionNumber(QString str)
Definition: main.cpp:49
scale_transform.h
first_derivative.h
mqtt_test.data
dictionary data
Definition: mqtt_test.py:22
NewReleaseDialog
Definition: new_release_dialog.h:17
ShowChangelogDialog
void ShowChangelogDialog()
Definition: main.cpp:62
ros::removeROSArgs
ROSCPP_DECL void removeROSArgs(int argc, const char *const *argv, V_string &args_out)
mainwindow.h
outlier_removal.h
main
int main(int argc, char *argv[])
Definition: main.cpp:194
udp_client.args
args
Definition: udp_client.py:12


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Nov 11 2024 03:23:45