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


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Jun 19 2023 03:01:38