1 /**
2 * UGENE - Integrated Bioinformatics Tools.
3 * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4 * http://ugene.net
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #include "ExternalToolSupportSettingsController.h"
23
24 #include <QMessageBox>
25 #include <QToolButton>
26
27 #include <U2Core/AppContext.h>
28 #include <U2Core/AppSettings.h>
29 #include <U2Core/CustomExternalTool.h>
30 #include <U2Core/L10n.h>
31 #include <U2Core/Settings.h>
32 #include <U2Core/Theme.h>
33 #include <U2Core/U2SafePoints.h>
34 #include <U2Core/UserApplicationsSettings.h>
35
36 #include <U2Gui/DialogUtils.h>
37 #include <U2Gui/GUIUtils.h>
38 #include <U2Gui/LastUsedDirHelper.h>
39 #include <U2Gui/ShowHideSubgroupWidget.h>
40
41 #include "ExternalToolSupportSettings.h"
42 #include "custom_tools/ImportCustomToolsTask.h"
43 #include "custom_tools/ImportExternalToolDialog.h"
44
45 namespace U2 {
46
47 static const int TOOLKIT_TYPE = QTreeWidgetItem::UserType + 1;
48
49 /////////////////////////////////////////////
50 ////ExternalToolSupportSettingsPageController
ExternalToolSupportSettingsPageController(QObject * p)51 ExternalToolSupportSettingsPageController::ExternalToolSupportSettingsPageController(QObject *p)
52 : AppSettingsGUIPageController(tr("External Tools"), ExternalToolSupportSettingsPageId, p) {
53 }
54
getSavedState()55 AppSettingsGUIPageState *ExternalToolSupportSettingsPageController::getSavedState() {
56 return new ExternalToolSupportSettingsPageState(AppContext::getExternalToolRegistry()->getAllEntries());
57 }
58
saveState(AppSettingsGUIPageState *)59 void ExternalToolSupportSettingsPageController::saveState(AppSettingsGUIPageState * /*state*/) {
60 ExternalToolSupportSettings::saveExternalToolsToAppConfig();
61 }
62
createWidget(AppSettingsGUIPageState * state)63 AppSettingsGUIPageWidget *ExternalToolSupportSettingsPageController::createWidget(AppSettingsGUIPageState *state) {
64 ExternalToolSupportSettingsPageWidget *r = new ExternalToolSupportSettingsPageWidget(this);
65 r->setState(state);
66 return r;
67 }
68
getHelpPageId() const69 const QString &ExternalToolSupportSettingsPageController::getHelpPageId() const {
70 return helpPageId;
71 }
72
73 const QString ExternalToolSupportSettingsPageController::helpPageId = QString("65929361");
74
75 //////////////////////////////////////////////
76 ////ExternalToolSupportSettingsPageState
77
ExternalToolSupportSettingsPageState(const QList<ExternalTool * > & ets)78 ExternalToolSupportSettingsPageState::ExternalToolSupportSettingsPageState(const QList<ExternalTool *> &ets)
79 : externalTools(ets) {
80 }
81
getExternalTools() const82 QList<ExternalTool *> ExternalToolSupportSettingsPageState::getExternalTools() const {
83 return externalTools;
84 }
85
86 /////////////////////////////////////////////
87 ////ExternalToolSupportSettingsPageWidget
88
89 const QString ExternalToolSupportSettingsPageWidget::INSTALLED = QObject::tr("Installed");
90 const QString ExternalToolSupportSettingsPageWidget::NOT_INSTALLED = QObject::tr("Not installed");
91 const QString ExternalToolSupportSettingsPageWidget::ET_DOWNLOAD_INFO = QObject::tr("<html><head/><body><p>Download <a href=\"http://ugene.net/download-all.html\"><span style=\" text-decoration: underline; color:#1866af;\">tools executables</span></a> and configure the tools paths. </p></body></html>");
92
93 const QString ExternalToolSupportSettingsPageWidget::SUPPORTED_ID = "integrated tools";
94 const QString ExternalToolSupportSettingsPageWidget::CUSTOM_ID = "custom tools";
95 const QString ExternalToolSupportSettingsPageWidget::INFORMATION_ID = "info";
96
ExternalToolSupportSettingsPageWidget(ExternalToolSupportSettingsPageController * ctrl)97 ExternalToolSupportSettingsPageWidget::ExternalToolSupportSettingsPageWidget(ExternalToolSupportSettingsPageController *ctrl) {
98 Q_UNUSED(ctrl);
99
100 setupUi(this);
101 defaultDescriptionText = descriptionTextBrowser->toPlainText();
102
103 selectToolPackLabel->setText(ET_DOWNLOAD_INFO);
104 versionLabel->hide();
105 binaryPathLabel->hide();
106
107 supportedToolsShowHideWidget = new ShowHideSubgroupWidget(SUPPORTED_ID, tr("Supported tools"), integratedToolsInnerWidget, true);
108 integratedToolsContainerWidget->layout()->addWidget(supportedToolsShowHideWidget);
109
110 customToolsShowHideWidget = new ShowHideSubgroupWidget(CUSTOM_ID, tr("Custom tools"), customToolsInnerWidget, false);
111 customToolsContainerWidget->layout()->addWidget(customToolsShowHideWidget);
112
113 infoShowHideWidget = new ShowHideSubgroupWidget(INFORMATION_ID, tr("Additional information"), infoInnerWidget, true);
114 infoContainerWidget->layout()->addWidget(infoShowHideWidget);
115
116 twIntegratedTools->setColumnWidth(0, this->geometry().width() / 3);
117 twCustomTools->setColumnWidth(0, this->geometry().width() / 3);
118
119 twIntegratedTools->installEventFilter(this);
120 twCustomTools->installEventFilter(this);
121
122 connect(pbImport, SIGNAL(clicked()), SLOT(sl_importCustomToolButtonClicked()));
123 connect(pbDelete, SIGNAL(clicked()), SLOT(sl_deleteCustomToolButtonClicked()));
124 connect(selectToolPackButton, SIGNAL(clicked()), this, SLOT(sl_onBrowseToolPackPath()));
125 connect(selectToolPackLabel, SIGNAL(linkActivated(QString)), this, SLOT(sl_linkActivated(QString)));
126 connect(twCustomTools, SIGNAL(itemSelectionChanged()), SLOT(sl_itemSelectionChanged()));
127 connect(twIntegratedTools, SIGNAL(itemSelectionChanged()), SLOT(sl_itemSelectionChanged()));
128
129 ExternalToolRegistry *etRegistry = AppContext::getExternalToolRegistry();
130 connect(etRegistry, SIGNAL(si_toolAdded(const QString &)), SLOT(sl_externalToolAdded(const QString &)));
131 connect(etRegistry, SIGNAL(si_toolIsAboutToBeRemoved(const QString &)), SLOT(sl_externalToolIsAboutToBeRemoved(const QString &)));
132 }
133
~ExternalToolSupportSettingsPageWidget()134 ExternalToolSupportSettingsPageWidget::~ExternalToolSupportSettingsPageWidget() {
135 saveShowHideSubgroupsState();
136 }
137
createPathEditor(QWidget * parent,const QString & path) const138 QWidget *ExternalToolSupportSettingsPageWidget::createPathEditor(QWidget *parent, const QString &path) const {
139 QWidget *widget = new QWidget(parent);
140
141 PathLineEdit *toolPathEdit = new PathLineEdit("", "executable", false, widget);
142 toolPathEdit->setObjectName("PathLineEdit");
143 toolPathEdit->setFrame(false);
144 toolPathEdit->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
145 toolPathEdit->setText(QDir::toNativeSeparators(path));
146
147 widget->setFocusProxy(toolPathEdit);
148 connect(toolPathEdit, SIGNAL(si_focusIn()), this, SLOT(sl_onPathEditWidgetClick()));
149 connect(toolPathEdit, SIGNAL(editingFinished()), this, SLOT(sl_toolPathChanged()));
150
151 QToolButton *selectToolPathButton = new QToolButton(widget);
152 selectToolPathButton->setObjectName("ResetExternalTool");
153 selectToolPathButton->setVisible(true);
154 selectToolPathButton->setText("...");
155 selectToolPathButton->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
156
157 connect(selectToolPathButton, SIGNAL(clicked()), this, SLOT(sl_onPathEditWidgetClick()));
158 connect(selectToolPathButton, SIGNAL(clicked()), toolPathEdit, SLOT(sl_onBrowse()));
159
160 QToolButton *clearToolPathButton = new QToolButton(widget);
161 clearToolPathButton->setObjectName("ClearToolPathButton");
162 clearToolPathButton->setVisible(true);
163 clearToolPathButton->setIcon(QIcon(":external_tool_support/images/cancel.png"));
164 clearToolPathButton->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
165 clearToolPathButton->setEnabled(!path.isEmpty());
166
167 connect(clearToolPathButton, SIGNAL(clicked()), this, SLOT(sl_onPathEditWidgetClick()));
168 connect(clearToolPathButton, SIGNAL(clicked()), toolPathEdit, SLOT(sl_clear()));
169
170 QHBoxLayout *layout = new QHBoxLayout(widget);
171 layout->setSpacing(0);
172 layout->setMargin(0);
173 layout->addWidget(toolPathEdit);
174
175 QHBoxLayout *buttonsLayout = new QHBoxLayout();
176 buttonsLayout->addWidget(selectToolPathButton);
177 buttonsLayout->addWidget(clearToolPathButton);
178
179 layout->addLayout(buttonsLayout);
180 buttonsWidth = buttonsLayout->minimumSize().width();
181 descriptionTextBrowser->setOpenLinks(false);
182 connect(descriptionTextBrowser, SIGNAL(anchorClicked(const QUrl &)), SLOT(sl_onClickLink(const QUrl &)));
183
184 return widget;
185 }
186
createToolkitItem(QTreeWidget * treeWidget,const QString & toolkitName,const QIcon & icon)187 QTreeWidgetItem *ExternalToolSupportSettingsPageWidget::createToolkitItem(QTreeWidget *treeWidget, const QString &toolkitName, const QIcon &icon) {
188 QTreeWidgetItem *toolkitItem = new QTreeWidgetItem({toolkitName}, TOOLKIT_TYPE);
189 toolkitItem->setData(0, Qt::ItemDataRole::UserRole, toolkitName);
190 toolkitItem->setIcon(0, icon);
191 treeWidget->addTopLevelItem(toolkitItem);
192
193 //draw widget for path select button
194 QWidget *widget = new QWidget(treeWidget);
195 QToolButton *selectToolKitPathButton = new QToolButton(widget);
196 selectToolKitPathButton->setVisible(true);
197 selectToolKitPathButton->setText("...");
198 selectToolKitPathButton->setMinimumWidth(buttonsWidth);
199 selectToolKitPathButton->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
200
201 connect(selectToolKitPathButton, SIGNAL(clicked()), this, SLOT(sl_onPathEditWidgetClick()));
202 connect(selectToolKitPathButton, SIGNAL(clicked()), this, SLOT(sl_onBrowseToolKitPath()));
203
204 QHBoxLayout *layout = new QHBoxLayout(widget);
205 layout->setSpacing(0);
206 layout->setMargin(0);
207 layout->addStretch();
208 layout->addWidget(selectToolKitPathButton);
209 treeWidget->setItemWidget(toolkitItem, 1, widget);
210
211 toolkitItem->setExpanded(true);
212 return toolkitItem;
213 }
214
sl_onClickLink(const QUrl & url)215 void ExternalToolSupportSettingsPageWidget::sl_onClickLink(const QUrl &url) {
216 const QAbstractItemModel *model = twIntegratedTools->selectionModel()->model();
217 QModelIndexList items = model->match(model->index(0, 0), Qt::DisplayRole, QVariant::fromValue(url.toEncoded()), 2, Qt::MatchRecursive);
218 if (items.isEmpty()) {
219 return;
220 }
221 twIntegratedTools->setCurrentIndex(items[0]);
222 }
223
sl_importCustomToolButtonClicked()224 void ExternalToolSupportSettingsPageWidget::sl_importCustomToolButtonClicked() {
225 //UGENE-6553 temporary removed
226 //QObjectScopedPointer<ImportExternalToolDialog> dialog = new ImportExternalToolDialog(this);
227 //dialog->exec();
228
229 LastUsedDirHelper lod("import external tool");
230 const QString filter = DialogUtils::prepareFileFilter("UGENE external tool config file", {"xml"}, true, {});
231 lod.url = U2FileDialog::getOpenFileName(this, tr("Select configuration file to import"), lod.dir, filter);
232 if (!lod.url.isEmpty()) {
233 AppContext::getTaskScheduler()->registerTopLevelTask(new ImportCustomToolsTask(QDir::toNativeSeparators(lod.url)));
234 }
235 }
236
sl_deleteCustomToolButtonClicked()237 void ExternalToolSupportSettingsPageWidget::sl_deleteCustomToolButtonClicked() {
238 QList<QTreeWidgetItem *> selectedItems = twCustomTools->selectedItems();
239 CHECK(!selectedItems.isEmpty(), );
240 const QString toolId = externalToolsItems.key(selectedItems.first());
241 CHECK(!toolId.isEmpty(), );
242
243 CustomExternalTool *tool = qobject_cast<CustomExternalTool *>(AppContext::getExternalToolRegistry()->getById(toolId));
244 SAFE_POINT(nullptr != tool, "Can't get CustomExternalTool from the registry", );
245 const QString configFilePath = tool->getConfigFilePath();
246
247 AppContext::getExternalToolRegistry()->unregisterEntry(toolId);
248 QFile configFile(configFilePath);
249 const bool fileRemoved = configFile.remove();
250
251 if (!fileRemoved) {
252 coreLog.details(tr("Can't remove custom external tool config file from the storage folder: %1").arg(configFilePath));
253 }
254 }
255
sl_externalToolAdded(const QString & id)256 void ExternalToolSupportSettingsPageWidget::sl_externalToolAdded(const QString &id) {
257 ExternalTool *tool = AppContext::getExternalToolRegistry()->getById(id);
258
259 ExternalToolInfo info;
260 info.id = id;
261 info.dirName = tool->getDirName();
262 info.name = tool->getName();
263 info.path = tool->getPath();
264 info.description = tool->getDescription();
265 info.isValid = tool->isValid();
266 info.version = tool->getVersion();
267 info.isModule = tool->isModule();
268 externalToolsInfo.insert(info.id, info);
269
270 connect(tool, SIGNAL(si_toolValidationStatusChanged(bool)), SLOT(sl_toolValidationStatusChanged(bool)));
271
272 QTreeWidget *treeWidget = tool->isCustom() ? twCustomTools : twIntegratedTools;
273 appendToolItem(treeWidget->invisibleRootItem(), tool);
274 }
275
sl_externalToolIsAboutToBeRemoved(const QString & id)276 void ExternalToolSupportSettingsPageWidget::sl_externalToolIsAboutToBeRemoved(const QString &id) {
277 externalToolsInfo.remove(id);
278
279 ExternalTool *tool = AppContext::getExternalToolRegistry()->getById(id);
280 disconnect(tool, SIGNAL(si_toolValidationStatusChanged(bool)), this, SLOT(sl_toolValidationStatusChanged(bool)));
281
282 QTreeWidgetItem *item = externalToolsItems.value(id, nullptr);
283 if (nullptr != item) {
284 QTreeWidgetItem *parentItem = item->parent();
285 if (nullptr == parentItem) {
286 parentItem = item->treeWidget()->invisibleRootItem();
287 }
288 parentItem->takeChild(parentItem->indexOfChild(item));
289 delete item;
290
291 if (TOOLKIT_TYPE == parentItem->type() && 0 == parentItem->childCount()) {
292 QTreeWidgetItem *grandParentItem = parentItem->treeWidget()->invisibleRootItem();
293 grandParentItem->takeChild(grandParentItem->indexOfChild(parentItem));
294 }
295 externalToolsItems.remove(id);
296 }
297 }
298
sl_linkActivated(const QString & url)299 void ExternalToolSupportSettingsPageWidget::sl_linkActivated(const QString &url) {
300 GUIUtils::runWebBrowser(url);
301 }
302
extractCustomTools(QList<QList<ExternalTool * >> & toolKitList,QList<ExternalTool * > & customTools)303 static void extractCustomTools(QList<QList<ExternalTool *>> &toolKitList, QList<ExternalTool *> &customTools) {
304 for (QList<ExternalTool *> &toolList : toolKitList) {
305 for (ExternalTool *tool : toolList) {
306 if (tool->isCustom()) {
307 customTools << tool;
308 toolList.removeAll(tool);
309 }
310 }
311 }
312 }
313
314 /** Returns master ExternalTool if tools list contains only 1 tool and 0+ modules or nullptr otherwise. */
isMasterWithModules(const QList<ExternalTool * > & toolsList)315 static ExternalTool *isMasterWithModules(const QList<ExternalTool *> &toolsList) {
316 ExternalTool *master = nullptr;
317 for (ExternalTool *tool : qAsConst(toolsList)) {
318 if (tool->isModule()) {
319 continue;
320 }
321 if (master != nullptr) {
322 return nullptr;
323 }
324 master = tool;
325 }
326 return master;
327 }
328
setState(AppSettingsGUIPageState * s)329 void ExternalToolSupportSettingsPageWidget::setState(AppSettingsGUIPageState *s) {
330 ExternalToolSupportSettingsPageState *state = qobject_cast<ExternalToolSupportSettingsPageState *>(s);
331 SAFE_POINT(state != nullptr, "ExternalToolSupportSettingsPageState is absent", );
332
333 const QList<ExternalTool *> toolList = state->getExternalTools();
334 for (ExternalTool *tool : qAsConst(toolList)) {
335 ExternalToolInfo info;
336 info.id = tool->getId();
337 info.dirName = tool->getDirName();
338 info.name = tool->getName();
339 info.path = tool->getPath();
340 info.description = tool->getDescription();
341 info.isValid = tool->isValid();
342 info.version = tool->getVersion();
343 info.isModule = tool->isModule();
344 externalToolsInfo.insert(info.id, info);
345
346 connect(tool, SIGNAL(si_toolValidationStatusChanged(bool)), SLOT(sl_toolValidationStatusChanged(bool)));
347 }
348
349 QList<QList<ExternalTool *>> toolsPerToolkitList = AppContext::getExternalToolRegistry()->getAllEntriesSortedByToolKits();
350 QList<ExternalTool *> customToolList;
351 extractCustomTools(toolsPerToolkitList, customToolList);
352
353 QTreeWidgetItem *rootItem = twIntegratedTools->invisibleRootItem();
354 for (QList<ExternalTool *> toolsList : qAsConst(toolsPerToolkitList)) {
355 CHECK_CONTINUE(!toolsList.isEmpty());
356
357 if (toolsList.length() == 1) {
358 appendToolItem(rootItem, toolsList[0]);
359 continue;
360 }
361 ExternalTool *groupTool = isMasterWithModules(toolsList);
362 if (groupTool != nullptr) {
363 QTreeWidgetItem *masterItem = appendToolItem(rootItem, groupTool);
364 masterItem->setExpanded(false);
365 toolsList.removeOne(groupTool);
366 for (ExternalTool *tool : qAsConst(toolsList)) {
367 appendToolItem(masterItem, tool, true);
368 }
369 } else {
370 groupTool = toolsList[0];
371 QTreeWidgetItem *toolkitItem = createToolkitItem(twIntegratedTools, groupTool->getToolKitName(), groupTool->getIcon());
372 for (ExternalTool *tool : qAsConst(toolsList)) {
373 appendToolItem(toolkitItem, tool);
374 }
375 }
376 }
377
378 QTreeWidgetItem *customToolsRootItem = twCustomTools->invisibleRootItem();
379 for (ExternalTool *tool : qAsConst(customToolList)) {
380 appendToolItem(customToolsRootItem, tool);
381 }
382
383 Settings *settings = AppContext::getSettings();
384 supportedToolsShowHideWidget->setSubgroupOpened(settings->getValue(ExternalToolSupportSettingsPageWidget::SUPPORTED_ID, true).toBool());
385 customToolsShowHideWidget->setSubgroupOpened(settings->getValue(ExternalToolSupportSettingsPageWidget::CUSTOM_ID, false).toBool());
386 infoShowHideWidget->setSubgroupOpened(settings->getValue(ExternalToolSupportSettingsPageWidget::INFORMATION_ID, true).toBool());
387 }
388
appendToolItem(QTreeWidgetItem * rootItem,const ExternalTool * tool,bool isModule)389 QTreeWidgetItem *ExternalToolSupportSettingsPageWidget::appendToolItem(QTreeWidgetItem *rootItem, const ExternalTool *tool, bool isModule) {
390 QTreeWidgetItem *item = new QTreeWidgetItem(QStringList() << tool->getName());
391 item->setData(0, Qt::ItemDataRole::UserRole, tool->getId());
392
393 externalToolsItems.insert(tool->getId(), item);
394 rootItem->addChild(item);
395
396 const ExternalToolInfo &toolInfo = externalToolsInfo.value(tool->getId());
397 QTreeWidget *treeWidget = rootItem->treeWidget();
398
399 QWidget *toolItemWidget = isModule ? new QLabel(toolInfo.isValid ? INSTALLED : NOT_INSTALLED)
400 : createPathEditor(treeWidget, toolInfo.path);
401
402 treeWidget->setItemWidget(item, 1, toolItemWidget);
403
404 QIcon icon = toolInfo.path.isEmpty() ? tool->getGrayIcon()
405 : (toolInfo.isValid ? tool->getIcon()
406 : tool->getWarnIcon());
407 item->setIcon(0, icon);
408 return item;
409 }
410
setToolState(ExternalTool * tool)411 void ExternalToolSupportSettingsPageWidget::setToolState(ExternalTool *tool) {
412 QTreeWidgetItem *item = externalToolsItems.value(tool->getId(), nullptr);
413 SAFE_POINT(nullptr != item, QString("Tree item for the tool %1 not found").arg(tool->getName()), );
414
415 externalToolsInfo[tool->getId()].isValid = tool->isValid();
416 QLabel *moduleToolLabel = qobject_cast<QLabel *>(twIntegratedTools->itemWidget(item, 1));
417 QString moduleToolState;
418 QString toolStateDesc;
419
420 if (tool->isValid()) {
421 item->setIcon(0, AppContext::getExternalToolRegistry()->getById(tool->getId())->getIcon());
422 moduleToolState = INSTALLED;
423 } else if (!tool->getPath().isEmpty()) {
424 toolStateDesc = getToolStateDescription(tool);
425 item->setIcon(0, AppContext::getExternalToolRegistry()->getById(tool->getId())->getWarnIcon());
426 moduleToolState = NOT_INSTALLED;
427 } else {
428 item->setIcon(0, AppContext::getExternalToolRegistry()->getById(tool->getId())->getGrayIcon());
429 moduleToolState = "";
430 }
431
432 if (moduleToolLabel) {
433 moduleToolLabel->setText(moduleToolState);
434 }
435
436 externalToolsInfo[tool->getId()].path = tool->getPath();
437 if (!tool->getVersion().isEmpty()) {
438 externalToolsInfo[tool->getId()].version = tool->getVersion();
439 } else {
440 externalToolsInfo[tool->getId()].version = "unknown";
441 }
442
443 QList<QTreeWidgetItem *> selectedItems = twIntegratedTools->selectedItems();
444 CHECK(selectedItems.length() > 0, );
445 QString selectedName = selectedItems.at(0)->text(0);
446
447 if (selectedName == tool->getName()) {
448 setDescription(tool);
449 }
450 }
451
getToolLink(const QString & toolName) const452 QString ExternalToolSupportSettingsPageWidget::getToolLink(const QString &toolName) const {
453 return "<a href='" + toolName + "'>" + toolName + "</a>";
454 }
455
getToolStateDescription(ExternalTool * tool) const456 QString ExternalToolSupportSettingsPageWidget::getToolStateDescription(ExternalTool *tool) const {
457 QString result;
458
459 SAFE_POINT(tool, "Tool pointer is NULL", result);
460 ExternalToolRegistry *etRegistry = AppContext::getExternalToolRegistry();
461 SAFE_POINT(etRegistry, "External tool registry is NULL", result);
462 ExternalToolManager *etManager = etRegistry->getManager();
463 SAFE_POINT(etManager, "External tool manager is NULL", result);
464
465 ExternalToolManager::ExternalToolState state = etManager->getToolState(tool->getId());
466
467 if (state == ExternalToolManager::NotValidByDependency) {
468 QString text = tr("External tool '%1' cannot be validated as it "
469 "depends on other tools, some of which are not valid. "
470 "The list of tools is the following: ")
471 .arg(tool->getName());
472
473 QStringList invalidDependencies;
474 QStringList dependencies = tool->getDependencies();
475 for (const QString &masterId : qAsConst(dependencies)) {
476 if (etManager->getToolState(masterId) != ExternalToolManager::Valid) {
477 QString masterName = AppContext::getExternalToolRegistry()->getToolNameById(masterId);
478 if (tool->getId() != masterId && tool->getToolKitName() != masterName) {
479 invalidDependencies << getToolLink(masterName);
480 } else {
481 invalidDependencies << masterName;
482 }
483 }
484 }
485 result = warn(text + invalidDependencies.join(", ")) + "<br><br>";
486 }
487
488 if (state == ExternalToolManager::NotValid) {
489 if (tool->isModule()) {
490 QStringList toolDependencies = tool->getDependencies();
491 SAFE_POINT(!toolDependencies.isEmpty(), QString("Empty dependency list for "
492 "the '%1' module tool")
493 .arg(tool->getName()),
494 result);
495 QString masterId = toolDependencies.first();
496 QString text = tr("'%1' is %2 module and it is not installed. "
497 "Install it and restart UGENE or set another "
498 "%2 with already installed '%1' module.")
499 .arg(tool->getName())
500 .arg(AppContext::getExternalToolRegistry()->getToolNameById(masterId));
501
502 result = warn(text) + "<br><br>";
503 }
504
505 if (tool->hasAdditionalErrorMessage()) {
506 result += warn(tool->getAdditionalErrorMessage()) + "<br><br>";
507 }
508 }
509 return result;
510 }
511
resetDescription()512 void ExternalToolSupportSettingsPageWidget::resetDescription() {
513 descriptionTextBrowser->setPlainText(defaultDescriptionText);
514 }
515
setDescription(ExternalTool * tool)516 void ExternalToolSupportSettingsPageWidget::setDescription(ExternalTool *tool) {
517 QString desc = tr("No description");
518 if (tool != nullptr) {
519 desc = getToolStateDescription(tool);
520 if (desc.size() == 0) {
521 desc = tool->getDescription();
522 } else {
523 desc += tool->getDescription();
524 }
525 if (tool->isValid()) {
526 desc += tr("<br><br>Version: ");
527 if (!externalToolsInfo[tool->getId()].version.isEmpty()) {
528 desc += externalToolsInfo[tool->getId()].version;
529 } else {
530 desc += tr("unknown");
531 }
532 }
533
534 if (!externalToolsInfo[tool->getId()].path.isEmpty()) {
535 desc += tr("<br><br>Binary path: ");
536 desc += externalToolsInfo[tool->getId()].path;
537 }
538 }
539 descriptionTextBrowser->setText(desc + "<a href='1'></a>");
540 }
541
warn(const QString & text) const542 QString ExternalToolSupportSettingsPageWidget::warn(const QString &text) const {
543 return "<span style=\"color:" + Theme::errorColorLabelStr() + "; font:bold;\">" + text + "</span>";
544 }
545
eventFilter(QObject * watched,QEvent * event)546 bool ExternalToolSupportSettingsPageWidget::eventFilter(QObject *watched, QEvent *event) {
547 CHECK(event->type() == QEvent::FocusIn, false);
548
549 QTreeWidgetItem *item = nullptr;
550 QList<QTreeWidgetItem *> selectedItems;
551 if (watched == twIntegratedTools) {
552 selectedItems = twIntegratedTools->selectedItems();
553 } else if (watched == twCustomTools) {
554 selectedItems = twCustomTools->selectedItems();
555 }
556
557 if (!selectedItems.isEmpty()) {
558 item = selectedItems.first();
559 }
560
561 bool itemSelected = item != nullptr;
562 if (itemSelected) {
563 QString toolId = externalToolsItems.key(item);
564 setDescription(AppContext::getExternalToolRegistry()->getById(toolId));
565 } else {
566 resetDescription();
567 }
568
569 return false;
570 }
571
saveShowHideSubgroupsState() const572 void ExternalToolSupportSettingsPageWidget::saveShowHideSubgroupsState() const {
573 Settings *settings = AppContext::getSettings();
574 settings->setValue(ExternalToolSupportSettingsPageWidget::SUPPORTED_ID, QVariant(supportedToolsShowHideWidget->isSubgroupOpened()));
575 settings->setValue(ExternalToolSupportSettingsPageWidget::CUSTOM_ID, QVariant(customToolsShowHideWidget->isSubgroupOpened()));
576 settings->setValue(ExternalToolSupportSettingsPageWidget::INFORMATION_ID, QVariant(infoShowHideWidget->isSubgroupOpened()));
577 }
578
getState(QString & err) const579 AppSettingsGUIPageState *ExternalToolSupportSettingsPageWidget::getState(QString &err) const {
580 Q_UNUSED(err);
581
582 QList<ExternalTool *> externalTools;
583 const QList<ExternalToolInfo> toolInfoList = externalToolsInfo.values();
584 for (const ExternalToolInfo &info : qAsConst(toolInfoList)) {
585 auto externalTool = new ExternalTool(info.id, info.dirName, info.name, info.path);
586 externalTool->setValid(info.isValid);
587 externalTool->setVersion(info.version);
588 externalTools.append(externalTool);
589 }
590 return new ExternalToolSupportSettingsPageState(externalTools);
591 }
592
sl_toolPathChanged()593 void ExternalToolSupportSettingsPageWidget::sl_toolPathChanged() {
594 PathLineEdit *s = qobject_cast<PathLineEdit *>(sender());
595
596 if (!s || !s->isModified()) {
597 return;
598 }
599
600 QWidget *par = s->parentWidget();
601 QString path = s->text();
602 s->setModified(false);
603
604 QList<QTreeWidgetItem *> listOfItems = twIntegratedTools->findItems("", Qt::MatchContains | Qt::MatchRecursive) << twCustomTools->findItems("", Qt::MatchContains | Qt::MatchRecursive);
605 SAFE_POINT(listOfItems.length() != 0, "ExternalToolSupportSettings, NO items are selected", );
606
607 twIntegratedTools->clearSelection();
608 foreach (QTreeWidgetItem *item, listOfItems) {
609 QWidget *itemWid = item->treeWidget()->itemWidget(item, 1);
610 if (par == itemWid) { //may be no good method for check QTreeWidgetItem
611 emit si_setLockState(true);
612 QString toolId = item->data(0, Qt::ItemDataRole::UserRole).toString();
613 if (path.isEmpty()) {
614 item->setIcon(0, AppContext::getExternalToolRegistry()->getById(toolId)->getGrayIcon());
615 }
616
617 ExternalToolManager *etManager = AppContext::getExternalToolRegistry()->getManager();
618 SAFE_POINT(etManager != nullptr, "External tool manager is null", );
619
620 ExternalToolValidationListener *listener = new ExternalToolValidationListener(toolId);
621 connect(listener, SIGNAL(si_validationComplete()), SLOT(sl_validationComplete()));
622 StrStrMap pathMap;
623 pathMap[toolId] = path;
624 etManager->validate(QStringList() << toolId, pathMap, listener);
625 }
626 }
627 }
628
sl_validationComplete()629 void ExternalToolSupportSettingsPageWidget::sl_validationComplete() {
630 ExternalToolValidationListener *listener = qobject_cast<ExternalToolValidationListener *>(sender());
631 SAFE_POINT(nullptr != listener, "Unexpected message sender", );
632
633 listener->deleteLater();
634
635 ExternalToolRegistry *etRegistry = AppContext::getExternalToolRegistry();
636 CHECK(etRegistry, );
637
638 foreach (const QString &toolId, listener->getToolIds()) {
639 ExternalTool *tool = etRegistry->getById(toolId);
640 SAFE_POINT(nullptr != tool, QString("External tool %1 not found in the registry.").arg(toolId), );
641 setToolState(tool);
642 }
643 emit si_setLockState(false);
644 }
645
sl_toolValidationStatusChanged(bool isValid)646 void ExternalToolSupportSettingsPageWidget::sl_toolValidationStatusChanged(bool isValid) {
647 Q_UNUSED(isValid);
648
649 ExternalTool *s = qobject_cast<ExternalTool *>(sender());
650 SAFE_POINT(nullptr != s, "Unexpected message sender", );
651
652 setToolState(s);
653 }
654
sl_itemSelectionChanged()655 void ExternalToolSupportSettingsPageWidget::sl_itemSelectionChanged() {
656 QTreeWidget *treeWidget = qobject_cast<QTreeWidget *>(sender());
657 QList<QTreeWidgetItem *> selectedItems = treeWidget->selectedItems();
658
659 pbDelete->setEnabled(!twCustomTools->selectedItems().isEmpty());
660
661 if (selectedItems.length() == 0) {
662 descriptionTextBrowser->setText(tr("Select an external tool to view more information about it."));
663 return;
664 }
665 SAFE_POINT(selectedItems.length() != 0, "ExternalToolSupportSettings, no items selected", );
666
667 QString id = selectedItems.at(0)->data(0, Qt::ItemDataRole::UserRole).toString();
668
669 if (selectedItems.at(0)->type() == TOOLKIT_TYPE) {
670 QString text = AppContext::getExternalToolRegistry()->getToolkitDescription(id);
671 if (!text.isEmpty()) {
672 descriptionTextBrowser->setText(text);
673 return;
674 }
675 }
676
677 //no description or tool custom description
678 ExternalTool *tool = AppContext::getExternalToolRegistry()->getById(id);
679 setDescription(tool);
680 }
681
sl_onPathEditWidgetClick()682 void ExternalToolSupportSettingsPageWidget::sl_onPathEditWidgetClick() {
683 QWidget *s = qobject_cast<QWidget *>(sender());
684 SAFE_POINT(s != nullptr, "Unexpected message sender", );
685
686 QList<QTreeWidgetItem *> listOfItems = twIntegratedTools->findItems("", Qt::MatchContains | Qt::MatchRecursive);
687 listOfItems << twCustomTools->findItems("", Qt::MatchContains | Qt::MatchRecursive);
688 SAFE_POINT(listOfItems.length() != 0, "No items were found in the tree", );
689
690 twIntegratedTools->clearSelection();
691 twCustomTools->clearSelection();
692 foreach (QTreeWidgetItem *item, listOfItems) {
693 QWidget *par = s->parentWidget();
694 QWidget *itemWid = item->treeWidget()->itemWidget(item, 1);
695 if (itemWid == par) {
696 item->setSelected(true);
697 }
698 }
699 }
700
701 //looks in selected folder +1 level 1 subfolders
sl_onBrowseToolKitPath()702 void ExternalToolSupportSettingsPageWidget::sl_onBrowseToolKitPath() {
703 LastUsedDirHelper lod("toolkit path");
704 QString dir;
705
706 lod.url = dir = U2FileDialog::getExistingDirectory(this, tr("Choose Folder With Executables"), lod.dir, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
707 if (!dir.isEmpty()) {
708 assert(twIntegratedTools->selectedItems().isEmpty() == 0);
709 QString toolKitName = twIntegratedTools->selectedItems().first()->text(0);
710 QList<QTreeWidgetItem *> listOfItems = twIntegratedTools->findItems("", Qt::MatchContains | Qt::MatchRecursive);
711 assert(listOfItems.length() != 0);
712
713 QStringList toolIds;
714 StrStrMap toolPaths;
715 foreach (QTreeWidgetItem *item, listOfItems) {
716 if (!externalToolsItems.values().contains(item)) {
717 continue;
718 }
719 QString itemId = item->data(0, Qt::UserRole).toString();
720 ExternalTool *tool = AppContext::getExternalToolRegistry()->getById(itemId);
721 if (tool != nullptr && tool->getToolKitName() == toolKitName) {
722 QWidget *itemWid = twIntegratedTools->itemWidget(item, 1);
723 PathLineEdit *lineEdit = itemWid->findChild<PathLineEdit *>("PathLineEdit");
724 LimitedDirIterator it(dir);
725 bool fileNotFound = true;
726 QString executableFileName = tool->getExecutableFileName();
727 while (it.hasNext() && fileNotFound) {
728 it.next();
729 QString fpath = it.filePath() + QDir::separator() + executableFileName;
730
731 QFileInfo info(fpath);
732 if (info.exists() && info.isFile()) {
733 QString path = QDir::toNativeSeparators(fpath);
734 lineEdit->setText(path);
735 lineEdit->setModified(false);
736 externalToolsInfo[itemId].path = path;
737 QToolButton *clearToolPathButton = itemWid->findChild<QToolButton *>("ClearToolPathButton");
738 assert(clearToolPathButton);
739 clearToolPathButton->setEnabled(true);
740 toolIds << itemId;
741 toolPaths.insert(itemId, path);
742 fileNotFound = false;
743 }
744 }
745 }
746 }
747 if (!toolIds.isEmpty()) {
748 emit si_setLockState(true);
749 ExternalToolManager *etManager = AppContext::getExternalToolRegistry()->getManager();
750 ExternalToolValidationListener *listener = new ExternalToolValidationListener(toolIds);
751 connect(listener, SIGNAL(si_validationComplete()), SLOT(sl_validationComplete()));
752 etManager->validate(toolIds, toolPaths, listener);
753 }
754 }
755 }
756
sl_onBrowseToolPackPath()757 void ExternalToolSupportSettingsPageWidget::sl_onBrowseToolPackPath() {
758 LastUsedDirHelper lod("toolpack path");
759 QString dirPath;
760 lod.dir = dirPath = U2FileDialog::getExistingDirectory(this, tr("Select Folder With External Tools Package"), lod.dir, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
761
762 if (!dirPath.isEmpty()) {
763 QDir dir = QDir(dirPath);
764 QList<QTreeWidgetItem *> listOfItems = twIntegratedTools->findItems("", Qt::MatchContains | Qt::MatchRecursive);
765 assert(listOfItems.length() != 0);
766 QStringList toolIds;
767 StrStrMap toolPaths;
768 bool isValidExternalToolsFolder = false;
769
770 const QList<ExternalTool *> toolList = AppContext::getExternalToolRegistry()->getAllEntries();
771 for (const ExternalTool *externalTool : qAsConst(toolList)) {
772 if (externalTool->isModule()) {
773 continue;
774 }
775 QTreeWidgetItem *item = externalToolsItems.value(externalTool->getId(), nullptr);
776 SAFE_POINT(item != nullptr, QString("Tree item not found for the tool %1").arg(externalTool->getName()), );
777
778 const QStringList dirList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
779 for (QString dirName : qAsConst(dirList)) {
780 if (externalTool->getDirName() != dirName) {
781 continue;
782 }
783 isValidExternalToolsFolder = true;
784 QWidget *itemWid = twIntegratedTools->itemWidget(item, 1);
785 PathLineEdit *lineEdit = itemWid->findChild<PathLineEdit *>("PathLineEdit");
786
787 LimitedDirIterator it(dirPath + "/" + dirName);
788 QString executableFileName = AppContext::getExternalToolRegistry()->getById(externalTool->getId())->getExecutableFileName();
789 while (it.hasNext()) {
790 it.next();
791 QString executableFilePath = it.filePath() + "/" + executableFileName;
792 if (QFileInfo(executableFilePath).isFile()) {
793 QString path = QDir::toNativeSeparators(executableFilePath);
794 lineEdit->setText(path);
795 lineEdit->setModified(false);
796 externalToolsInfo[item->data(0, Qt::UserRole).toString()].path = path;
797
798 QToolButton *clearToolPathButton = itemWid->findChild<QToolButton *>("ClearToolPathButton");
799 SAFE_POINT(clearToolPathButton != nullptr, "ClearToolPathButton not found!", );
800 clearToolPathButton->setEnabled(true);
801
802 toolIds << externalTool->getId();
803 toolPaths.insert(externalTool->getId(), path);
804 break;
805 }
806 }
807 }
808 }
809
810 if (!isValidExternalToolsFolder) {
811 QMessageBox::warning(this, L10N::warningTitle(), tr("Not a valid external tools folder"), QMessageBox::Ok);
812 }
813 if (!toolIds.isEmpty()) {
814 emit si_setLockState(true);
815 ExternalToolManager *etManager = AppContext::getExternalToolRegistry()->getManager();
816 ExternalToolValidationListener *listener = new ExternalToolValidationListener(toolIds);
817 connect(listener, SIGNAL(si_validationComplete()), SLOT(sl_validationComplete()));
818 etManager->validate(toolIds, toolPaths, listener);
819 }
820 }
821 }
822
823 ////////////////////////////////////////
824 //PathLineEdit
sl_onBrowse()825 void PathLineEdit::sl_onBrowse() {
826 LastUsedDirHelper lod(type);
827
828 QString name;
829 if (text().isEmpty()) {
830 lod.url = name = U2FileDialog::getOpenFileName(nullptr, tr("Select a file"), lod.dir, FileFilter, 0, QFileDialog::DontConfirmOverwrite);
831 } else {
832 lod.url = name = U2FileDialog::getOpenFileName(nullptr, tr("Select a file"), text(), FileFilter, 0, QFileDialog::DontConfirmOverwrite);
833 }
834 if (!name.isEmpty()) {
835 setText(QDir::toNativeSeparators(name));
836 setModified(true);
837 emit editingFinished();
838 }
839 QToolButton *clearToolPathButton = this->parentWidget()->findChild<QToolButton *>("ClearToolPathButton");
840 assert(clearToolPathButton);
841 clearToolPathButton->setEnabled(!text().isEmpty());
842 setFocus();
843 }
844
sl_clear()845 void PathLineEdit::sl_clear() {
846 QToolButton *s = qobject_cast<QToolButton *>(sender());
847 assert(s);
848 setText("");
849 s->setEnabled(false);
850 setModified(true);
851 emit editingFinished();
852 }
853
focusInEvent(QFocusEvent *)854 void PathLineEdit::focusInEvent(QFocusEvent * /*event*/) {
855 emit si_focusIn();
856 }
857
858 } // namespace U2
859