19 #include <QCoreApplication> 23 #include <QJsonDocument> 24 #include <QJsonObject> 25 #include <QMessageBox> 34 #include "rtxiConfig.h" 42 , readmeWindow(new QTextEdit)
43 , availableListWidget(new QListWidget(this))
46 "Module Wizard enables management of all RTXI modules. You can download " 47 "and install new modules directly from the GitHub site..etc");
48 install_prefix.setPath(QCoreApplication::applicationDirPath()
49 + QString(
"/rtxi_modules/"));
50 auto* customLayout =
new QGridLayout;
52 auto* buttonBox =
new QGroupBox;
53 auto* buttonLayout =
new QHBoxLayout();
54 buttonBox->setLayout(buttonLayout);
55 syncButton =
new QPushButton(
"Sync",
this);
56 cloneButton =
new QPushButton(
"Install",
this);
57 cloneButton->setEnabled(
false);
58 buttonLayout->addWidget(syncButton);
59 buttonLayout->addWidget(cloneButton);
61 auto* installedBox =
new QGroupBox(
"Installed");
62 auto* installedLayout =
new QVBoxLayout;
63 installedBox->setLayout(installedLayout);
64 installedListWidget =
new QListWidget(installedBox);
65 installedListWidget->setFixedWidth(175);
66 installedListWidget->setSortingEnabled(
true);
67 installedLayout->addWidget(installedListWidget);
69 auto* moduleBox =
new QGroupBox(
"Available");
70 auto* moduleLayout =
new QVBoxLayout;
71 moduleBox->setLayout(moduleLayout);
73 availableListWidget->setFixedWidth(175);
74 availableListWidget->setSortingEnabled(
true);
75 moduleLayout->addWidget(availableListWidget);
77 readmeWindow->setReadOnly(
true);
80 customLayout->addWidget(buttonBox, 0, 0);
81 customLayout->addWidget(moduleBox, 1, 0);
82 customLayout->addWidget(installedBox, 2, 0);
83 customLayout->addWidget(readmeWindow, 0, 1, 3, 1);
84 customLayout->setColumnStretch(0, 0);
85 customLayout->setColumnStretch(1, 1);
87 QObject::connect(syncButton, SIGNAL(clicked()),
this, SLOT(getRepos()));
88 QObject::connect(cloneButton, SIGNAL(clicked()),
this, SLOT(cloneModule()));
89 QObject::connect(availableListWidget,
90 SIGNAL(itemClicked(QListWidgetItem*)),
93 QObject::connect(availableListWidget,
94 SIGNAL(itemClicked(QListWidgetItem*)),
96 SLOT(updateButton()));
97 QObject::connect(installedListWidget,
98 SIGNAL(itemClicked(QListWidgetItem*)),
101 QObject::connect(installedListWidget,
102 SIGNAL(itemClicked(QListWidgetItem*)),
104 SLOT(updateButton()));
106 setLayout(customLayout);
107 setWindowTitle(
"Module Wizard");
113 void RTXIWizard::Panel::initParameters()
116 exclude_list = std::vector<QString>({QString(
"rtxi"),
117 QString(
"rtxi.github.io"),
118 QString(
"genicam-camera"),
119 QString(
"rtxi-crawler"),
120 QString(
"matlab-tools"),
121 QString(
"tutorials"),
123 QString(
"camera-control"),
125 QString(
"dynamo-examples"),
127 QString(
"python-plugin"),
129 QString(
"user-manual"),
131 QString(
"live-image"),
132 QString(
"conference-2015")});
133 button_mode = DOWNLOAD;
138 void RTXIWizard::Panel::updateButton()
140 auto* parent = qobject_cast<QListWidget*>(sender());
142 if (parent == availableListWidget) {
143 cloneButton->setText(
"Install");
144 button_mode = DOWNLOAD;
145 }
else if (parent == installedListWidget) {
146 cloneButton->setText(
"Update");
147 button_mode = UPDATE;
152 void RTXIWizard::Panel::cloneModule()
154 cloneButton->setEnabled(
false);
155 availableListWidget->setDisabled(
true);
156 installedListWidget->setDisabled(
true);
160 switch (button_mode) {
162 name = availableListWidget->currentItem()->text();
165 name = installedListWidget->currentItem()->text();
168 ERROR_MSG(
"ERROR: default in switch block in cloneModule()");
172 installFromString(name.toStdString());
176 void RTXIWizard::Panel::getRepos()
178 availableListWidget->setDisabled(
true);
179 installedListWidget->setDisabled(
true);
181 if (availableListWidget->count() == 0) {
182 const QUrl url(
"https://api.github.com/orgs/rtxi/repos?per_page=100");
183 reposNetworkReply = qnam.get(QNetworkRequest(url));
185 reposNetworkReply, SIGNAL(finished()),
this, SLOT(parseRepos()));
187 availableListWidget->setDisabled(
false);
188 installedListWidget->setDisabled(
false);
200 void RTXIWizard::Panel::getReadme()
202 auto* parent = qobject_cast<QListWidget*>(sender());
203 if (parent->currentRow() < 0) {
206 const QString name = parent->currentItem()->text();
207 availableListWidget->setDisabled(
true);
208 installedListWidget->setDisabled(
true);
211 if (modules[parent->currentItem()->text()].readme ==
"") {
212 readmeNetworkReply = qnam.get(QNetworkRequest(modules[name].readme_url));
214 readmeNetworkReply, SIGNAL(finished()),
this, SLOT(parseReadme()));
217 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) 218 readmeWindow->setText(modules[parent->currentItem()->text()].readme);
220 readmeWindow->setMarkdown(modules[parent->currentItem()->text()].readme);
222 availableListWidget->setDisabled(
false);
223 installedListWidget->setDisabled(
false);
229 void RTXIWizard::Panel::parseReadme()
231 const QByteArray network_reply_data = readmeNetworkReply->readAll();
232 const QString markdown_data = QString(network_reply_data.constData());
233 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) 234 this->readmeWindow->setText(markdown_data);
236 this->readmeWindow->setMarkdown(markdown_data);
239 switch (button_mode) {
241 modules[availableListWidget->currentItem()->text()].readme =
245 modules[installedListWidget->currentItem()->text()].readme =
249 ERROR_MSG(
"ERROR: default in switch block in cloneModule()");
254 readmeWindow->show();
255 readmeNetworkReply->deleteLater();
258 cloneButton->setEnabled(
true);
259 availableListWidget->setDisabled(
false);
260 installedListWidget->setDisabled(
false);
264 void RTXIWizard::Panel::parseRepos()
266 const QJsonDocument jsonDoc =
267 QJsonDocument::fromJson(reposNetworkReply->readAll().data());
268 const QJsonArray jsonArr = jsonDoc.array();
270 const QString readmeUrlPrefix =
"https://raw.githubusercontent.com/RTXI/";
271 const QString readmeUrlSuffix =
"/master/README.md";
273 for (
auto&& idx : jsonArr) {
274 QJsonObject newObj = (idx).toObject();
275 newObj.find(
"name").key();
278 if (std::find(exclude_list.begin(),
280 newObj.value(
"name").toString())
281 == exclude_list.end())
285 const QString name = newObj.value(
"name").toString();
286 module.readme_url = QUrl(readmeUrlPrefix + newObj.value(
"name").toString()
288 module.clone_url = QUrl(newObj.value(
"clone_url").toString());
291 QFileInfo::exists(install_prefix.path() + QString(
"/")
292 + QString(
"lib") + name + QString(
".so"));
293 modules[name] = module;
297 reposNetworkReply->deleteLater();
299 rebuildListWidgets();
300 availableListWidget->setDisabled(
false);
301 installedListWidget->setDisabled(
false);
306 availableListWidget->clear();
307 installedListWidget->clear();
309 for (
auto& module : modules) {
310 if (module.second.installed) {
311 installedListWidget->addItem(module.first);
313 availableListWidget->addItem(module.first);
317 installedListWidget->sortItems(Qt::AscendingOrder);
318 availableListWidget->sortItems(Qt::AscendingOrder);
327 const QString name = QString(module_name.c_str());
330 new QProgressDialog(
"Installing plugin",
"Cancel", 0, 5,
this);
331 progress->setMinimumDuration(0);
332 progress->setWindowModality(Qt::WindowModal);
333 progress->setLabelText(
"Starting...");
339 const QByteArray url = modules[name].clone_url.toString().toLatin1();
340 const QByteArray installpath = install_prefix.path().toLatin1();
341 const QString mod_location =
342 QDir::temp().absolutePath() + QDir::separator() + QString(
"rtxi_modules");
343 const QString source_location =
344 mod_location + QDir::separator() + QString(module_name.c_str());
345 QDir(source_location).removeRecursively();
347 progress->setLabelText(
"Downloading extension...");
348 progress->setValue(1);
351 auto* command =
new QProcess();
352 const QStringList clone_args = {
360 const std::string git_command(GIT_COMMAND);
361 if (!(QDir(source_location)).exists()) {
362 command->start(QString::fromStdString(git_command), clone_args);
363 command->waitForFinished();
366 if (command->exitStatus() != QProcess::NormalExit) {
367 ERROR_MSG(
"Could not complete installation for module {}",
371 cloneButton->setEnabled(
true);
372 rebuildListWidgets();
373 availableListWidget->setDisabled(
false);
374 installedListWidget->setDisabled(
false);
379 QDir package_dir = install_prefix;
382 const QString build_location = source_location + QString(
"/build");
383 const QString make_cmd =
"cmake";
384 const QStringList make_config_args = {
389 QString(
"-DRTXI_PACKAGE_PATH=") + package_dir.path(),
390 QString(
"-DCMAKE_BUILD_TYPE=")
391 + QString::fromStdString(std::string(RTXI_BUILD_TYPE)),
392 QString(
"-DRTXI_CMAKE_SCRIPTS=")
393 + QString::fromStdString(std::string(RTXI_CMAKE_SCRIPTS))};
394 const QStringList make_build_args = {
"--build", build_location,
"-j2"};
395 const QStringList make_install_args = {
"--install", build_location};
397 progress->setLabelText(
"Configuring...");
398 progress->setValue(2);
402 command->start(make_cmd, make_config_args);
403 command->waitForFinished();
404 if (command->exitStatus() != QProcess::NormalExit || command->exitCode() != 0)
406 QMessageBox::critical(
409 "Could not Configure plugin. Email help@rtxi.org for assistance");
410 const QByteArray err_str = command->readAllStandardError();
412 ERROR_MSG(
"Configure command for module {} failed with command {}",
414 make_cmd.toStdString() + std::string(
" ")
415 + make_config_args.join(
" ").toStdString());
416 cloneButton->setEnabled(
true);
417 rebuildListWidgets();
418 availableListWidget->setDisabled(
false);
419 installedListWidget->setDisabled(
false);
425 progress->setLabelText(
"Building...");
426 progress->setValue(3);
428 command->start(make_cmd, make_build_args);
429 command->waitForFinished();
430 if (command->exitStatus() != QProcess::NormalExit || command->exitCode() != 0)
432 QMessageBox::critical(
435 "Could not build plugin. Email help@rtxi.org for assistance");
436 const QByteArray err_str = command->readAllStandardError();
438 ERROR_MSG(
"Build command for module {} failed with command {}",
440 make_cmd.toStdString() + std::string(
" ")
441 + make_build_args.join(
" ").toStdString());
442 cloneButton->setEnabled(
true);
443 rebuildListWidgets();
444 availableListWidget->setDisabled(
false);
445 installedListWidget->setDisabled(
false);
451 progress->setLabelText(
"Installing...");
452 progress->setValue(4);
454 command->start(make_cmd, make_install_args);
455 command->waitForFinished();
456 if (command->exitStatus() != QProcess::NormalExit || command->exitCode() != 0)
458 QMessageBox::critical(
461 "Could not install plugin. Email help@rtxi.org for assistance");
462 const QByteArray err_str = command->readAllStandardError();
464 ERROR_MSG(
"Install command for module {} failed with command {}",
466 make_cmd.toStdString() + std::string(
" ")
467 + make_install_args.join(
" ").toStdString());
468 cloneButton->setEnabled(
true);
469 rebuildListWidgets();
470 availableListWidget->setDisabled(
false);
471 installedListWidget->setDisabled(
false);
477 modules[name].installed =
true;
478 progress->setValue(5);
482 cloneButton->setEnabled(
true);
483 rebuildListWidgets();
484 availableListWidget->setDisabled(
false);
485 installedListWidget->setDisabled(
false);
491 return std::make_unique<RTXIWizard::Plugin>(ev_manager);
void installFromString(const std::string &module_name)
void rebuildListWidgets()
Panel(QMainWindow *mwindow, Event::Manager *ev_manager)
void ERROR_MSG(const std::string &errmsg, Args... args)
constexpr std::string_view MODULE_NAME
Widgets::FactoryMethods getFactories()
std::unique_ptr< Widgets::Plugin > createRTXIPlugin(Event::Manager *ev_manager)
Widgets::Panel * createRTXIPanel(QMainWindow *main_window, Event::Manager *ev_manager)
std::unique_ptr< Widgets::Component > createRTXIComponent(Widgets::Plugin *host_plugin)