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 <algorithm>
23 #include <functional>
24
25 #include <QBoxLayout>
26 #include <QClipboard>
27 #include <QComboBox>
28 #include <QGraphicsSceneMouseEvent>
29 #include <QMainWindow>
30 #include <QPainter>
31 #include <QPixmap>
32 #include <QShortcut>
33 #include <QSvgGenerator>
34 #include <QToolBar>
35
36 #include <U2Core/AppContext.h>
37 #include <U2Core/Counter.h>
38 #include <U2Core/GUrlUtils.h>
39 #include <U2Core/IOAdapterUtils.h>
40 #include <U2Core/Log.h>
41 #include <U2Core/ProjectService.h>
42 #include <U2Core/QObjectScopedPointer.h>
43 #include <U2Core/TaskSignalMapper.h>
44 #include <U2Core/U2OpStatusUtils.h>
45
46 #include <U2Designer/Dashboard.h>
47 #include <U2Designer/DashboardInfoRegistry.h>
48 #include <U2Designer/DesignerUtils.h>
49 #include <U2Designer/EstimationReporter.h>
50 #include <U2Designer/GrouperEditor.h>
51 #include <U2Designer/MarkerEditor.h>
52 #include <U2Designer/RemoveDashboardsTask.h>
53 #include <U2Designer/WizardController.h>
54
55 #include <U2Gui/DialogUtils.h>
56 #include <U2Gui/ExportImageDialog.h>
57 #include <U2Gui/ScriptEditorDialog.h>
58 #include <U2Gui/U2FileDialog.h>
59
60 #include <U2Lang/ActorModel.h>
61 #include <U2Lang/BaseActorCategories.h>
62 #include <U2Lang/BaseAttributes.h>
63 #include <U2Lang/GrouperSlotAttribute.h>
64 #include <U2Lang/HRSchemaSerializer.h>
65 #include <U2Lang/IncludedProtoFactory.h>
66 #include <U2Lang/MapDatatypeEditor.h>
67 #include <U2Lang/SchemaEstimationTask.h>
68 #include <U2Lang/WorkflowEnv.h>
69 #include <U2Lang/WorkflowManager.h>
70 #include <U2Lang/WorkflowRunTask.h>
71 #include <U2Lang/WorkflowSettings.h>
72
73 #include "BreakpointManagerView.h"
74 #include "ChooseItemDialog.h"
75 #include "CreateScriptWorker.h"
76 #include "DashboardsManagerDialog.h"
77 #include "GalaxyConfigConfigurationDialogImpl.h"
78 #include "ImportSchemaDialog.h"
79 #include "ItemViewStyle.h"
80 #include "PortAliasesConfigurationDialog.h"
81 #include "SceneSerializer.h"
82 #include "SchemaAliasesConfigurationDialogImpl.h"
83 #include "StartupDialog.h"
84 #include "WorkflowDesignerPlugin.h"
85 #include "WorkflowDocument.h"
86 #include "WorkflowEditor.h"
87 #include "WorkflowInvestigationWidgetsController.h"
88 #include "WorkflowMetaDialog.h"
89 #include "WorkflowPalette.h"
90 #include "WorkflowSamples.h"
91 #include "WorkflowSceneIOTasks.h"
92 #include "WorkflowTabView.h"
93 #include "WorkflowViewController.h"
94 #include "WorkflowViewItems.h"
95 #include "debug_messages_translation/WorkflowDebugMessageParserImpl.h"
96 #include "library/ExternalProcessWorker.h"
97 #include "library/ScriptWorker.h"
98 #include "library/create_cmdline_based_worker/CreateCmdlineBasedWorkerWizard.h"
99
100 namespace U2 {
101
102 // TODO: sync with SETTINGS in WorkflowSettings.cpp
103 #define SETTINGS QString("workflowview/")
104
105 #define LAST_DIR SETTINGS + "lastdir"
106 #define SPLITTER_STATE SETTINGS + "splitter"
107 #define EDITOR_STATE SETTINGS + "editor"
108 #define PALETTE_STATE SETTINGS + "palette"
109 #define TABS_STATE SETTINGS + "tabs"
110 #define CHECK_R_PACKAGE SETTINGS + "check_r_for_cistrome"
111
112 enum { ElementsTab,
113 SamplesTab };
114
115 #define WS 1000
116 #define MAX_FILE_SIZE 1000000
117
118 static const int ABSENT_WIDGET_TAB_NUMBER = -1;
119
120 /************************************************************************/
121 /* Utilities */
122 /************************************************************************/
123 class PercentValidator : public QRegExpValidator {
124 public:
PercentValidator(QObject * parent)125 PercentValidator(QObject *parent)
126 : QRegExpValidator(QRegExp("[1-9][0-9]*" + QObject::tr("%")), parent) {
127 }
fixup(QString & input) const128 void fixup(QString &input) const {
129 if (!input.endsWith(QObject::tr("%"))) {
130 input.append(QObject::tr("%"));
131 }
132 }
133 }; // PercentValidator
134
scaleCombo(WorkflowView * parent)135 static QComboBox *scaleCombo(WorkflowView *parent) {
136 QComboBox *sceneScaleCombo = new QComboBox(parent);
137 sceneScaleCombo->setEditable(true);
138 sceneScaleCombo->setValidator(new PercentValidator(parent));
139 QStringList scales;
140 scales << "25%"
141 << "50%"
142 << "75%"
143 << "100%"
144 << "125%"
145 << "150%"
146 << "200%";
147 sceneScaleCombo->addItems(scales);
148 sceneScaleCombo->setCurrentIndex(3);
149 QObject::connect(sceneScaleCombo, SIGNAL(currentIndexChanged(const QString &)), parent, SLOT(sl_rescaleScene(const QString &)));
150 // Some visual modifications for Mac:
151 sceneScaleCombo->lineEdit()->setStyleSheet("QLineEdit {margin-right: 1px;}");
152 sceneScaleCombo->setObjectName("wdScaleCombo");
153 return sceneScaleCombo;
154 }
155
addToggleDashboardAction(QToolBar * toolBar,QAction * action)156 static void addToggleDashboardAction(QToolBar *toolBar, QAction *action) {
157 QWidget *spacer = new QWidget();
158 spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
159 toolBar->addWidget(spacer);
160
161 toolBar->addAction(action);
162 QToolButton *b = dynamic_cast<QToolButton *>(toolBar->widgetForAction(action));
163 CHECK(nullptr != b, );
164 b->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
165 b->setAutoRaise(false);
166
167 #ifdef Q_OS_DARWIN
168 b->setStyleSheet("QToolButton {"
169 "font-size: 13px;"
170 "border: 1px solid gray;"
171 "border-radius: 6px;"
172 "margin-right: 5px;"
173 "height: 25px;"
174 "padding: 0px 5px;"
175 "}");
176 #endif
177 }
178
scriptMenu(WorkflowView * parent,const QList<QAction * > & scriptingActions)179 static QToolButton *scriptMenu(WorkflowView *parent, const QList<QAction *> &scriptingActions) {
180 QToolButton *scriptingModeButton = new QToolButton(parent);
181 QMenu *scriptingModeMenu = new QMenu(QObject::tr("Scripting mode"), parent);
182 foreach (QAction *a, scriptingActions) {
183 scriptingModeMenu->addAction(a);
184 }
185 scriptingModeButton->setDefaultAction(scriptingModeMenu->menuAction());
186 scriptingModeButton->setPopupMode(QToolButton::InstantPopup);
187 return scriptingModeButton;
188 }
189
DashboardManagerHelper(QAction * _dmAction,WorkflowView * _parent)190 DashboardManagerHelper::DashboardManagerHelper(QAction *_dmAction, WorkflowView *_parent)
191 : QObject(_parent),
192 dmAction(_dmAction),
193 parent(_parent) {
194 connect(dmAction, SIGNAL(triggered()), SLOT(sl_showDashboardsManagerDialog()));
195
196 DashboardInfoRegistry *dashboardInfoRegistry = AppContext::getDashboardInfoRegistry();
197 connect(dashboardInfoRegistry, SIGNAL(si_scanningStarted()), SLOT(sl_dashboardsScanningStarted()));
198 connect(dashboardInfoRegistry, SIGNAL(si_scanningFinished()), SLOT(sl_dashboardsScanningFinished()));
199 }
200
sl_result(int result)201 void DashboardManagerHelper::sl_result(int result) {
202 DashboardsManagerDialog *d = qobject_cast<DashboardsManagerDialog *>(sender());
203 if (QDialog::Accepted == result) {
204 DashboardInfoRegistry *dashboardInfoRegistry = AppContext::getDashboardInfoRegistry();
205
206 const QMap<QString, bool> dashboardsVisibility = d->getDashboardsVisibility();
207 QList<DashboardInfo> newDashboardInfos;
208 foreach (const QString &dashboardId, dashboardsVisibility.keys()) {
209 DashboardInfo newDashboardInfo = dashboardInfoRegistry->getById(dashboardId);
210 newDashboardInfo.opened = dashboardsVisibility[dashboardId];
211 newDashboardInfos << newDashboardInfo;
212 }
213 dashboardInfoRegistry->updateDashboardInfos(newDashboardInfos);
214
215 const QStringList dashboardsToRemove = d->removedDashboards();
216 if (!dashboardsToRemove.isEmpty()) {
217 dashboardInfoRegistry->removeDashboards(dashboardsToRemove);
218 }
219 }
220 }
221
sl_showDashboardsManagerDialog()222 void DashboardManagerHelper::sl_showDashboardsManagerDialog() {
223 if (AppContext::getDashboardInfoRegistry()->isEmpty()) {
224 QMessageBox *d = new QMessageBox(QMessageBox::Information, tr("No Dashboards Found"), tr("You do not have any dashboards yet. You need to run some workflow to use Dashboards Manager."), QMessageBox::NoButton, parent);
225 d->show();
226 return;
227 }
228
229 DashboardsManagerDialog *d = new DashboardsManagerDialog(parent);
230 connect(d, SIGNAL(finished(int)), SLOT(sl_result(int)));
231 d->setWindowModality(Qt::ApplicationModal);
232 d->show();
233 }
234
sl_dashboardsScanningStarted()235 void DashboardManagerHelper::sl_dashboardsScanningStarted() {
236 dmAction->setEnabled(false);
237 }
238
sl_dashboardsScanningFinished()239 void DashboardManagerHelper::sl_dashboardsScanningFinished() {
240 dmAction->setEnabled(true);
241 }
242
243 /********************************
244 * WorkflowView
245 ********************************/
createInstance(WorkflowGObject * go)246 WorkflowView *WorkflowView::createInstance(WorkflowGObject *go) {
247 MWMDIManager *mdiManager = AppContext::getMainWindow()->getMDIManager();
248 SAFE_POINT(nullptr != mdiManager, "NULL MDI manager", nullptr);
249
250 WorkflowView *view = new WorkflowView(go);
251 view->setWindowIcon(QIcon(":/workflow_designer/images/wd.png"));
252 mdiManager->addMDIWindow(view);
253 mdiManager->activateWindow(view);
254 return view;
255 }
256
openWD(WorkflowGObject * go)257 WorkflowView *WorkflowView::openWD(WorkflowGObject *go) {
258 if (WorkflowSettings::isOutputDirectorySet()) {
259 return createInstance(go);
260 }
261
262 QObjectScopedPointer<StartupDialog> d = new StartupDialog(AppContext::getMainWindow()->getQMainWindow());
263 d->exec();
264 CHECK(!d.isNull(), nullptr);
265
266 if (QDialog::Accepted == d->result()) {
267 return createInstance(go);
268 }
269 return nullptr;
270 }
271
WorkflowView(WorkflowGObject * go)272 WorkflowView::WorkflowView(WorkflowGObject *go)
273 : MWMDIWindow(tr("Workflow Designer")), running(false), sceneRecreation(false), go(go),
274 schema(QSharedPointer<Schema>::create()), currentProto(nullptr), currentActor(nullptr),
275 pasteCount(0), debugInfo(new WorkflowDebugStatus(this)), debugActions(), loadWorkflowSceneTask(nullptr) {
276 scriptingMode = WorkflowSettings::getScriptingMode();
277 elementsMenu = nullptr;
278 schema->setDeepCopyFlag(true);
279
280 setupScene();
281 setupPalette();
282 setupPropertyEditor();
283 setupErrorList();
284
285 infoSplitter = new QSplitter(Qt::Vertical);
286 infoSplitter->addWidget(sceneView);
287 infoSplitter->addWidget(errorList);
288 addBottomWidgetsToInfoSplitter();
289 setupMainSplitter();
290
291 loadUiSettings();
292
293 createActions();
294 sl_changeScriptMode();
295
296 if (go) {
297 loadSceneFromObject();
298 } else {
299 sl_newScene();
300 }
301
302 propertyEditor->reset();
303 }
304
~WorkflowView()305 WorkflowView::~WorkflowView() {
306 uiLog.trace("~WorkflowView");
307 if (!loadWorkflowSceneTask.isNull()) {
308 loadWorkflowSceneTask->cancel();
309 }
310 if (AppContext::getProjectService()) {
311 AppContext::getProjectService()->enableSaveAction(true);
312 }
313 WorkflowSettings::setScriptingMode(scriptingMode);
314 delete currentActor;
315 delete scene;
316 delete breakpointView;
317 }
318
setupScene()319 void WorkflowView::setupScene() {
320 SceneCreator sc(schema.get(), meta);
321 scene = sc.createScene(this);
322
323 sceneView = new GlassView(scene);
324 sceneView->setObjectName("sceneView");
325 sceneView->setAlignment(Qt::AlignCenter);
326
327 scene->views().at(0)->setDragMode(QGraphicsView::RubberBandDrag);
328
329 connect(scene, SIGNAL(processDblClicked()), SLOT(sl_toggleStyle()));
330 connect(scene, SIGNAL(selectionChanged()), SLOT(sl_editItem()));
331 connect(scene, SIGNAL(selectionChanged()), SLOT(sl_onSelectionChanged()));
332 connect(scene, SIGNAL(configurationChanged()), SLOT(sl_refreshActorDocs()));
333 connect(WorkflowSettings::watcher, SIGNAL(changed()), scene, SLOT(update()));
334 }
335
setupPalette()336 void WorkflowView::setupPalette() {
337 palette = new WorkflowPalette(WorkflowEnv::getProtoRegistry(), this);
338 palette->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored));
339 connect(palette, SIGNAL(processSelected(Workflow::ActorPrototype *, bool)), SLOT(sl_selectPrototype(Workflow::ActorPrototype *, bool)));
340 connect(palette, SIGNAL(si_prototypeIsAboutToBeRemoved(Workflow::ActorPrototype *)), SLOT(sl_prototypeIsAboutToBeRemoved(Workflow::ActorPrototype *)));
341 connect(palette, SIGNAL(si_protoListModified()), SLOT(sl_protoListModified()));
342 connect(palette, SIGNAL(si_protoChanged()), SLOT(sl_editItem()));
343 connect(palette, SIGNAL(si_protoChanged()), scene, SLOT(sl_updateDocs()));
344
345 tabs = new QTabWidget(this);
346 tabs->setObjectName("tabs");
347 tabs->insertTab(ElementsTab, palette, tr("Elements"));
348 samples = new SamplesWidget(scene);
349 samples->setObjectName("samples");
350 tabs->insertTab(SamplesTab, new SamplesWrapper(samples, this), tr("Samples"));
351 tabs->setTabPosition(QTabWidget::North);
352
353 connect(samples, SIGNAL(setupGlass(GlassPane *)), sceneView, SLOT(setGlass(GlassPane *)));
354 connect(samples, SIGNAL(sampleSelected(QString)), this, SLOT(sl_pasteSample(QString)));
355 connect(tabs, SIGNAL(currentChanged(int)), samples, SLOT(cancelItem()));
356 connect(tabs, SIGNAL(currentChanged(int)), palette, SLOT(resetSelection()));
357 connect(tabs, SIGNAL(currentChanged(int)), scene, SLOT(setHint(int)));
358 }
359
setupErrorList()360 void WorkflowView::setupErrorList() {
361 infoList = new QListWidget(this);
362 connect(infoList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), SLOT(sl_pickInfo(QListWidgetItem *)));
363 errorList = new QGroupBox();
364 {
365 errorList->setFlat(true);
366 errorList->setTitle(tr("Error list"));
367 QVBoxLayout *vl = new QVBoxLayout(errorList);
368 vl->setSpacing(0);
369 vl->setMargin(0);
370 vl->setContentsMargins(0, 0, 0, 0);
371 vl->addWidget(infoList);
372 }
373 errorList->hide();
374 }
375
setupPropertyEditor()376 void WorkflowView::setupPropertyEditor() {
377 propertyEditor = new WorkflowEditor(this);
378 }
379
loadSceneFromObject()380 void WorkflowView::loadSceneFromObject() {
381 LoadWorkflowTask::FileFormat format = LoadWorkflowTask::detectFormat(go->getSceneRawData());
382 go->setView(this);
383 QString err;
384 if (format == LoadWorkflowTask::HR) {
385 err = HRSchemaSerializer::string2Schema(go->getSceneRawData(), schema.get(), &meta);
386 } else if (format == LoadWorkflowTask::XML) {
387 QDomDocument xml;
388 QMap<ActorId, ActorId> remapping;
389 xml.setContent(go->getSceneRawData().toUtf8());
390 err = SchemaSerializer::xml2schema(xml.documentElement(), schema.get(), remapping);
391 SchemaSerializer::readMeta(&meta, xml.documentElement());
392 scene->setModified(false);
393 if (err.isEmpty()) {
394 QMessageBox::warning(this, tr("Warning!"), QObject::tr("You opened obsolete workflow in XML format. It is strongly recommended"
395 " to clear working space and create workflow from scratch."));
396 } else {
397 QMessageBox::warning(this, tr("Warning!"), QObject::tr("Sorry! This workflow is obsolete and cannot be opened."));
398 }
399 } else {
400 coreLog.error(tr("Undefined workflow format for %1").arg(go->getDocument() ? go->getDocument()->getURLString() : tr("file")));
401 sl_newScene();
402 }
403 scene->connectConfigurationEditors();
404
405 if (!err.isEmpty()) {
406 sl_newScene();
407 coreLog.error(err);
408 } else {
409 SceneCreator sc(schema.get(), meta);
410 sc.recreateScene(scene);
411 if (go->getDocument()) {
412 meta.url = go->getDocument()->getURLString();
413 }
414 sl_updateTitle();
415 scene->setModified(false);
416 rescale();
417 sl_refreshActorDocs();
418 }
419 }
420
loadUiSettings()421 void WorkflowView::loadUiSettings() {
422 Settings *settings = AppContext::getSettings();
423 if (settings->contains(SPLITTER_STATE)) {
424 splitter->restoreState(settings->getValue(SPLITTER_STATE).toByteArray());
425 }
426 if (settings->contains(PALETTE_STATE)) {
427 palette->restoreState(settings->getValue(PALETTE_STATE));
428 }
429 tabs->setCurrentIndex(settings->getValue(TABS_STATE, SamplesTab).toInt());
430 }
431
setupMainSplitter()432 void WorkflowView::setupMainSplitter() {
433 splitter = new QSplitter(this);
434 splitter->setObjectName("WorkflowViewMainSplitter");
435 {
436 splitter->addWidget(tabs);
437 splitter->addWidget(infoSplitter);
438 splitter->addWidget(propertyEditor);
439
440 splitter->setStretchFactor(0, 0);
441 splitter->setStretchFactor(1, 1);
442 splitter->setStretchFactor(2, 0);
443 }
444
445 tabView = new WorkflowTabView(this);
446 tabView->hide();
447 connect(tabView, SIGNAL(si_countChanged()), SLOT(sl_dashboardCountChanged()));
448
449 QHBoxLayout *layout = new QHBoxLayout();
450 layout->addWidget(tabView);
451 layout->addWidget(splitter);
452 layout->setSpacing(0);
453 layout->setMargin(0);
454 layout->setContentsMargins(0, 0, 0, 0);
455 setLayout(layout);
456
457 connect(debugInfo, SIGNAL(si_pauseStateChanged(bool)), scene, SLOT(update()));
458 connect(debugInfo, SIGNAL(si_pauseStateChanged(bool)), SLOT(sl_pause(bool)));
459 connect(investigationWidgets,
460 SIGNAL(si_updateCurrentInvestigation(const Workflow::Link *, int)),
461 debugInfo,
462 SIGNAL(si_busInvestigationIsRequested(const Workflow::Link *, int)));
463 connect(investigationWidgets, SIGNAL(si_countOfMessagesRequested(const Workflow::Link *)), debugInfo, SIGNAL(si_busCountOfMessagesIsRequested(const Workflow::Link *)));
464 connect(debugInfo,
465 SIGNAL(si_busInvestigationRespond(const WorkflowInvestigationData &, const Workflow::Link *)),
466 investigationWidgets,
467 SLOT(sl_currentInvestigationUpdateResponse(const WorkflowInvestigationData &, const Workflow::Link *)));
468 connect(debugInfo, SIGNAL(si_busCountOfMessagesResponse(const Workflow::Link *, int)), investigationWidgets, SLOT(sl_countOfMessagesResponse(const Workflow::Link *, int)));
469 connect(investigationWidgets, SIGNAL(si_convertionMessages2DocumentsIsRequested(const Workflow::Link *, const QString &, int)), SLOT(sl_convertMessages2Documents(const Workflow::Link *, const QString &, int)));
470 connect(debugInfo, SIGNAL(si_breakpointAdded(const ActorId &)), SLOT(sl_breakpointAdded(const ActorId &)));
471 connect(debugInfo, SIGNAL(si_breakpointEnabled(const ActorId &)), SLOT(sl_breakpointEnabled(const ActorId &)));
472 connect(debugInfo, SIGNAL(si_breakpointRemoved(const ActorId &)), SLOT(sl_breakpointRemoved(const ActorId &)));
473 connect(debugInfo, SIGNAL(si_breakpointDisabled(const ActorId &)), SLOT(sl_breakpointDisabled(const ActorId &)));
474 connect(debugInfo, SIGNAL(si_breakpointIsReached(const U2::ActorId &)), SLOT(sl_breakpointIsReached(const U2::ActorId &)));
475 }
476
sl_breakpointIsReached(const U2::ActorId & actor)477 void WorkflowView::sl_breakpointIsReached(const U2::ActorId &actor) {
478 propagateBreakpointToSceneItem(actor);
479 breakpointView->onBreakpointReached(actor);
480 }
481
addBottomWidgetsToInfoSplitter()482 void WorkflowView::addBottomWidgetsToInfoSplitter() {
483 bottomTabs = new QTabWidget(infoSplitter);
484
485 infoList = new QListWidget(this);
486 infoList->setObjectName("infoList");
487 connect(infoList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), SLOT(sl_pickInfo(QListWidgetItem *)));
488
489 QWidget *w = new QWidget(bottomTabs);
490 QVBoxLayout *vl = new QVBoxLayout(w);
491 vl->setSpacing(0);
492 vl->setMargin(0);
493 vl->setContentsMargins(0, 0, 0, 0);
494 vl->addWidget(infoList);
495 w->hide();
496 bottomTabs->addTab(w, tr("Error list"));
497
498 breakpointView = new BreakpointManagerView(debugInfo, schema, scene);
499 connect(breakpointView, SIGNAL(si_highlightingRequested(const ActorId &)), SLOT(sl_highlightingRequested(const ActorId &)));
500 connect(scene, SIGNAL(si_itemDeleted(const ActorId &)), breakpointView, SLOT(sl_breakpointRemoved(const ActorId &)));
501 if (WorkflowSettings::isDebuggerEnabled()) {
502 bottomTabs->addTab(breakpointView, QObject::tr("Breakpoints"));
503 }
504
505 investigationWidgets = new WorkflowInvestigationWidgetsController(bottomTabs);
506
507 infoSplitter->addWidget(bottomTabs);
508 bottomTabs->hide();
509 }
510
sl_rescaleScene(const QString & scale)511 void WorkflowView::sl_rescaleScene(const QString &scale) {
512 int percentPos = scale.indexOf(QObject::tr("%"));
513 meta.scalePercent = scale.left(percentPos).toInt();
514 rescale(false);
515 }
516
updateComboBox(QComboBox * scaleComboBox,int scalePercent)517 static void updateComboBox(QComboBox *scaleComboBox, int scalePercent) {
518 QString value = QString("%1%2").arg(scalePercent).arg(QObject::tr("%"));
519 bool isOk = true;
520 for (int i = 0; i < scaleComboBox->count(); i++) {
521 if (scaleComboBox->itemText(i) == value) {
522 scaleComboBox->setCurrentIndex(i);
523 return;
524 } else {
525 QString itemText = scaleComboBox->itemText(i).mid(0, scaleComboBox->itemText(i).size() - QObject::tr("%").size());
526 if (itemText.toInt(&isOk) > scalePercent && isOk) {
527 scaleComboBox->insertItem(i, value);
528 scaleComboBox->setCurrentIndex(i);
529 return;
530 }
531 }
532 }
533 scaleComboBox->addItem(value);
534 scaleComboBox->setCurrentIndex(scaleComboBox->count() - 1);
535 }
536
rescale(bool updateGui)537 void WorkflowView::rescale(bool updateGui) {
538 double newScale = meta.scalePercent / 100.0;
539 QGraphicsView *elementsView = scene->views().at(0);
540 elementsView->resetMatrix();
541 elementsView->scale(newScale, newScale);
542 if (updateGui) {
543 updateComboBox(scaleComboBox, meta.scalePercent);
544 }
545 }
546
createActions()547 void WorkflowView::createActions() {
548 runAction = new QAction(tr("&Run workflow"), this);
549 runAction->setObjectName("Run workflow");
550 runAction->setIcon(QIcon(":workflow_designer/images/run.png"));
551 runAction->setShortcut(QKeySequence("Ctrl+R"));
552 connect(runAction, SIGNAL(triggered()), SLOT(sl_launch()));
553 connect(runAction, SIGNAL(triggered()), debugInfo, SLOT(sl_resumeTriggerActivated()));
554
555 stopAction = new QAction(tr("S&top workflow"), this);
556 stopAction->setObjectName("Stop workflow");
557 stopAction->setIcon(QIcon(":workflow_designer/images/stopTask.png"));
558 stopAction->setEnabled(false);
559 connect(stopAction, SIGNAL(triggered()), debugInfo, SLOT(sl_executionFinished()));
560 connect(stopAction, SIGNAL(triggered()), SLOT(sl_stop()));
561
562 validateAction = new QAction(tr("&Validate workflow"), this);
563 validateAction->setObjectName("Validate workflow");
564 validateAction->setIcon(QIcon(":workflow_designer/images/ok.png"));
565 validateAction->setShortcut(QKeySequence("Ctrl+E"));
566 connect(validateAction, SIGNAL(triggered()), SLOT(sl_validate()));
567
568 estimateAction = new QAction(tr("&Estimate workflow"), this);
569 estimateAction->setObjectName("Estimate workflow");
570 estimateAction->setIcon(QIcon(":core/images/sum.png"));
571 estimateAction->setObjectName("Estimate workflow");
572 connect(estimateAction, SIGNAL(triggered()), SLOT(sl_estimate()));
573
574 pauseAction = new QAction(tr("&Pause workflow"), this);
575 pauseAction->setObjectName("Pause workflow");
576 pauseAction->setIcon(QIcon(":workflow_designer/images/pause.png"));
577 pauseAction->setShortcut(QKeySequence("Ctrl+P"));
578 pauseAction->setEnabled(false);
579 connect(pauseAction, SIGNAL(triggered()), debugInfo, SLOT(sl_pauseTriggerActivated()));
580 debugActions.append(pauseAction);
581
582 nextStepAction = new QAction(tr("&Next step"), this);
583 nextStepAction->setIcon(QIcon(":workflow_designer/images/next_step.png"));
584 nextStepAction->setShortcut(QKeySequence("F10"));
585 nextStepAction->setEnabled(false);
586 connect(nextStepAction, SIGNAL(triggered()), debugInfo, SLOT(sl_isolatedStepTriggerActivated()));
587 debugActions.append(nextStepAction);
588
589 toggleBreakpointAction = breakpointView->getNewBreakpointAction();
590 toggleBreakpointAction->setEnabled(false);
591
592 tickReadyAction = new QAction(tr("Process one &message"), this);
593 tickReadyAction->setIcon(QIcon(":workflow_designer/images/process_one_message.png"));
594 tickReadyAction->setShortcut(QKeySequence("Ctrl+M"));
595 tickReadyAction->setEnabled(false);
596 connect(tickReadyAction, SIGNAL(triggered()), SLOT(sl_processOneMessage()));
597 connect(tickReadyAction, SIGNAL(triggered()), scene, SLOT(update()));
598 connect(tickReadyAction, SIGNAL(triggered()), SLOT(sl_onSelectionChanged()));
599 connect(tickReadyAction, SIGNAL(triggered()), bottomTabs, SLOT(update()));
600 debugActions.append(tickReadyAction);
601
602 newAction = new QAction(tr("&New workflow..."), this);
603 newAction->setIcon(QIcon(":workflow_designer/images/filenew.png"));
604 newAction->setShortcuts(QKeySequence::New);
605 newAction->setObjectName("New workflow action");
606 connect(newAction, SIGNAL(triggered()), SLOT(sl_newScene()));
607
608 saveAction = new QAction(tr("&Save workflow"), this);
609 saveAction->setObjectName("Save workflow");
610 saveAction->setIcon(QIcon(":workflow_designer/images/filesave.png"));
611 saveAction->setShortcut(QKeySequence::Save);
612 saveAction->setShortcutContext(Qt::WindowShortcut);
613 connect(saveAction, SIGNAL(triggered()), SLOT(sl_saveScene()));
614
615 saveAsAction = new QAction(tr("&Save workflow as..."), this);
616 saveAsAction->setIcon(QIcon(":workflow_designer/images/filesaveas.png"));
617 connect(saveAsAction, SIGNAL(triggered()), SLOT(sl_saveSceneAs()));
618 saveAsAction->setObjectName("Save workflow action");
619
620 showWizard = new QAction(tr("Show wizard"), this);
621 showWizard->setObjectName("Show wizard");
622 QPixmap pm = QPixmap(":workflow_designer/images/wizard.png").scaled(16, 16);
623 showWizard->setIcon(QIcon(pm));
624 connect(showWizard, SIGNAL(triggered()), SLOT(sl_showWizard()));
625
626 toggleBreakpointManager = new QAction("Show or hide breakpoint manager", this);
627 toggleBreakpointManager->setIcon(QIcon(":workflow_designer/images/show_breakpoint_manager.png"));
628 toggleBreakpointManager->setObjectName("Show or hide breakpoint manager");
629 connect(toggleBreakpointManager, SIGNAL(triggered()), SLOT(sl_toggleBreakpointManager()));
630
631 { // toggle dashboard action
632 toggleDashboard = new QAction(this);
633 toggleDashboard->setObjectName("toggleDashboard");
634 connect(toggleDashboard, SIGNAL(triggered()), SLOT(sl_toggleDashboard()));
635 }
636
637 loadAction = new QAction(tr("&Load workflow"), this);
638 loadAction->setIcon(QIcon(":workflow_designer/images/fileopen.png"));
639 loadAction->setShortcut(QKeySequence("Ctrl+L"));
640 loadAction->setObjectName("Load workflow");
641 connect(loadAction, SIGNAL(triggered()), SLOT(sl_loadScene()));
642
643 exportAction = new QAction(tr("&Export workflow as image"), this);
644 exportAction->setIcon(QIcon(":workflow_designer/images/export.png"));
645 exportAction->setShortcut(QKeySequence("Ctrl+Shift+S"));
646 connect(exportAction, SIGNAL(triggered()), SLOT(sl_exportScene()));
647
648 deleteAction = new QAction(tr("Delete"), this);
649 deleteAction->setIcon(QIcon(":workflow_designer/images/delete.png"));
650 connect(deleteAction, SIGNAL(triggered()), scene, SLOT(sl_deleteItem()));
651
652 dmAction = new QAction(tr("Dashboards manager"), this);
653 dmAction->setIcon(QIcon(":workflow_designer/images/settings.png"));
654 dmAction->setObjectName("Dashboards manager");
655 new DashboardManagerHelper(dmAction, this);
656
657 { // Delete shortcut
658 deleteShortcut = new QAction(sceneView);
659 deleteShortcut->setShortcuts(QKeySequence::Delete);
660 deleteShortcut->setShortcutContext(Qt::WidgetShortcut);
661 connect(deleteShortcut, SIGNAL(triggered()), scene, SLOT(sl_deleteItem()));
662 sceneView->addAction(deleteShortcut);
663 }
664
665 { // Ctrl+A shortcut
666 QAction *selectShortcut = new QAction(sceneView);
667 selectShortcut->setShortcuts(QKeySequence::SelectAll);
668 selectShortcut->setShortcutContext(Qt::WidgetShortcut);
669 connect(selectShortcut, SIGNAL(triggered()), scene, SLOT(sl_selectAll()));
670 sceneView->addAction(selectShortcut);
671 }
672
673 configureParameterAliasesAction = new QAction(tr("Set parameter aliases..."), this);
674 configureParameterAliasesAction->setObjectName("Set parameter aliases");
675 configureParameterAliasesAction->setIcon(QIcon(":workflow_designer/images/table_relationship.png"));
676 connect(configureParameterAliasesAction, SIGNAL(triggered()), SLOT(sl_configureParameterAliases()));
677
678 configurePortAliasesAction = new QAction(tr("Set port and slot aliases..."), this);
679 configurePortAliasesAction->setIcon(QIcon(":workflow_designer/images/port_relationship.png"));
680 connect(configurePortAliasesAction, SIGNAL(triggered()), SLOT(sl_configurePortAliases()));
681
682 importSchemaToElement = new QAction(tr("Import workflow to element..."), this);
683 importSchemaToElement->setIcon(QIcon(":workflow_designer/images/import.png"));
684 connect(importSchemaToElement, SIGNAL(triggered()), SLOT(sl_importSchemaToElement()));
685
686 createGalaxyConfigAction = new QAction(tr("Create Galaxy tool config..."), this);
687 createGalaxyConfigAction->setObjectName("Create Galaxy tool config");
688 createGalaxyConfigAction->setIcon(QIcon(":workflow_designer/images/galaxy.png"));
689 connect(createGalaxyConfigAction, SIGNAL(triggered()), SLOT(sl_createGalaxyConfig()));
690
691 selectAction = new QAction(tr("Select all elements"), this);
692 connect(selectAction, SIGNAL(triggered()), scene, SLOT(sl_selectAll()));
693
694 copyAction = new QAction(tr("&Copy"), this);
695 copyAction->setIcon(QIcon(":workflow_designer/images/editcopy.png"));
696 copyAction->setShortcut(QKeySequence("Ctrl+C"));
697 copyAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
698 copyAction->setObjectName("Copy action");
699 connect(copyAction, SIGNAL(triggered()), SLOT(sl_copyItems()));
700 addAction(copyAction);
701
702 cutAction = new QAction(tr("Cu&t"), sceneView);
703 cutAction->setIcon(QIcon(":workflow_designer/images/editcut.png"));
704 cutAction->setShortcuts(QKeySequence::Cut);
705 cutAction->setShortcutContext(Qt::WidgetShortcut);
706 connect(cutAction, SIGNAL(triggered()), SLOT(sl_cutItems()));
707 addAction(cutAction);
708
709 pasteAction = new QAction(tr("&Paste"), this);
710 pasteAction->setIcon(QIcon(":workflow_designer/images/editpaste.png"));
711 pasteAction->setShortcuts(QKeySequence::Paste);
712 pasteAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
713 connect(pasteAction, SIGNAL(triggered()), SLOT(sl_pasteItems()));
714 addAction(pasteAction);
715
716 { // style
717 QAction *simpleStyle = new QAction(tr("Minimal"), this);
718 simpleStyle->setObjectName("Minimal");
719 simpleStyle->setData(QVariant(ItemStyles::SIMPLE));
720 styleActions << simpleStyle;
721 connect(simpleStyle, SIGNAL(triggered()), SLOT(sl_setStyle()));
722
723 QAction *extStyle = new QAction(tr("Extended"), this);
724 extStyle->setObjectName("Extended");
725 extStyle->setData(QVariant(ItemStyles::EXTENDED));
726 styleActions << extStyle;
727 connect(extStyle, SIGNAL(triggered()), SLOT(sl_setStyle()));
728 }
729
730 { // scripting mode
731 QAction *notShowScriptAction = new QAction(tr("Hide scripting options"), this);
732 notShowScriptAction->setObjectName("Hide scripting options");
733 notShowScriptAction->setCheckable(true);
734 scriptingActions << notShowScriptAction;
735 notShowScriptAction->setChecked(!scriptingMode);
736 connect(notShowScriptAction, SIGNAL(triggered()), SLOT(sl_changeScriptMode()));
737
738 QAction *showScriptAction = new QAction(tr("Show scripting options"), this);
739 showScriptAction->setObjectName("Show scripting options");
740 showScriptAction->setCheckable(true);
741 showScriptAction->setChecked(scriptingMode);
742 scriptingActions << showScriptAction;
743 connect(showScriptAction, SIGNAL(triggered()), SLOT(sl_changeScriptMode()));
744 }
745
746 unlockAction = new QAction(tr("Unlock Scene"), this);
747 unlockAction->setCheckable(true);
748 unlockAction->setChecked(true);
749 connect(unlockAction, SIGNAL(toggled(bool)), SLOT(sl_toggleLock(bool)));
750
751 createScriptAction = new QAction(tr("Create element with script..."), this);
752 createScriptAction->setObjectName("createScriptAction");
753 createScriptAction->setIcon(QIcon(":workflow_designer/images/script.png"));
754 connect(createScriptAction, SIGNAL(triggered()), SLOT(sl_createScript()));
755
756 editScriptAction = new QAction(tr("Edit script of the element..."), this);
757 editScriptAction->setObjectName("editScriptAction");
758 editScriptAction->setIcon(QIcon(":workflow_designer/images/script_edit.png"));
759 editScriptAction->setEnabled(false); // because user need to select actor with script to enable it
760 connect(editScriptAction, SIGNAL(triggered()), SLOT(sl_editScript()));
761
762 createCmdlineBasedWorkerAction = new QAction(tr("Create element with external tool..."), this);
763 createCmdlineBasedWorkerAction->setObjectName("createElementWithCommandLineTool");
764 createCmdlineBasedWorkerAction->setIcon(QIcon(":workflow_designer/images/external_cmd_tool.png"));
765 connect(createCmdlineBasedWorkerAction, SIGNAL(triggered()), SLOT(sl_createCmdlineBasedWorkerAction()));
766
767 editExternalToolAction = new QAction(tr("Edit configuration..."), this);
768 editExternalToolAction->setObjectName("editConfiguration");
769 editExternalToolAction->setIcon(QIcon(":workflow_designer/images/external_cmd_tool.png"));
770 editExternalToolAction->setEnabled(false); // because user need to select actor with script to enable it
771 connect(editExternalToolAction, SIGNAL(triggered()), SLOT(sl_editExternalTool()));
772
773 appendExternalTool = new QAction(tr("Add element with external tool..."), this);
774 appendExternalTool->setObjectName("AddElementWithCommandLineTool");
775 appendExternalTool->setIcon(QIcon(":workflow_designer/images/external_cmd_tool_add.png"));
776 connect(appendExternalTool, SIGNAL(triggered()), SLOT(sl_appendExternalToolWorker()));
777
778 findPrototypeAction = new QAction(this);
779 findPrototypeAction->setShortcut(QKeySequence::Find);
780 connect(findPrototypeAction, SIGNAL(triggered()), SLOT(sl_findPrototype()));
781 this->addAction(findPrototypeAction);
782
783 foreach (QAction *action, debugActions) {
784 action->setVisible(false);
785 }
786
787 scaleComboBox = scaleCombo(this);
788 }
789
sl_findPrototype()790 void WorkflowView::sl_findPrototype() {
791 tabs->currentWidget()->setFocus();
792 CHECK(tabs->currentWidget() == palette, );
793
794 static const int MIN_SIZE_FIND = 260;
795 QList<int> sizes = splitter->sizes();
796 int idx = splitter->indexOf(tabs);
797 CHECK(idx >= 0 && idx < sizes.size(), );
798 if (sizes.at(idx) < MIN_SIZE_FIND / 2) {
799 sizes[idx] = MIN_SIZE_FIND;
800 splitter->setSizes(sizes);
801 }
802 }
803
sl_createScript()804 void WorkflowView::sl_createScript() {
805 QObjectScopedPointer<CreateScriptElementDialog> dlg = new CreateScriptElementDialog(this);
806 dlg->exec();
807 CHECK(!dlg.isNull(), );
808
809 if (dlg->result() == QDialog::Accepted) {
810 QList<DataTypePtr> input = dlg->getInput();
811 QList<DataTypePtr> output = dlg->getOutput();
812 QList<Attribute *> attrs = dlg->getAttributes();
813 QString name = dlg->getName();
814 QString desc = dlg->getDescription();
815 if (LocalWorkflow::ScriptWorkerFactory::init(input, output, attrs, name, desc, dlg->getActorFilePath())) {
816 ActorPrototype *proto = WorkflowEnv::getProtoRegistry()->getProto(LocalWorkflow::ScriptWorkerFactory::ACTOR_ID + name);
817 QRectF rect = scene->sceneRect();
818 addProcess(createActor(proto, QVariantMap()), rect.center());
819 }
820 }
821 }
822
sl_createCmdlineBasedWorkerAction()823 void WorkflowView::sl_createCmdlineBasedWorkerAction() {
824 QString id = palette->createPrototype();
825 CHECK(!id.isEmpty(), );
826
827 ActorPrototype *proto = WorkflowEnv::getProtoRegistry()->getProto(id);
828 QRectF rect = scene->sceneRect();
829 addProcess(createActor(proto, QVariantMap()), rect.center());
830 }
831
832 namespace {
copyIntoUgene(const QString & url,U2OpStatus & os)833 QString copyIntoUgene(const QString &url, U2OpStatus &os) {
834 QDir dir(WorkflowSettings::getExternalToolDirectory());
835 if (!dir.exists()) {
836 bool created = dir.mkpath(dir.absolutePath());
837 if (!created) {
838 os.setError(QObject::tr("Can not create the folder: ") + dir.absolutePath());
839 return "";
840 }
841 }
842 QString filePath = GUrlUtils::rollFileName(dir.absolutePath() + "/" + QFileInfo(url).fileName(), "_");
843 if (QFile::exists(filePath)) {
844 os.setError(QObject::tr("The file '%1' already exists").arg(filePath));
845 return "";
846 }
847 bool copied = QFile::copy(url, filePath);
848 if (!copied) {
849 os.setError(QObject::tr("Can not copy the file here: ") + filePath);
850 return "";
851 }
852 return filePath;
853 }
854 } // namespace
855
sl_appendExternalToolWorker()856 void WorkflowView::sl_appendExternalToolWorker() {
857 QString filter = DialogUtils::prepareFileFilter(WorkflowUtils::tr("UGENE workflow element"), QStringList() << "etc", true);
858 QString url = U2FileDialog::getOpenFileName(this, tr("Add element"), QString(), filter);
859 if (!url.isEmpty()) {
860 IOAdapter *io = AppContext::getIOAdapterRegistry()->getIOAdapterFactoryById(IOAdapterUtils::url2io(GUrl(url)))->createIOAdapter();
861 if (!io->open(url, IOAdapterMode_Read)) {
862 coreLog.error(tr("Can't load element."));
863 return;
864 }
865 QByteArray data;
866 data.resize(MAX_FILE_SIZE);
867 data.fill(0);
868 io->readBlock(data.data(), MAX_FILE_SIZE);
869 io->close();
870
871 QScopedPointer<ExternalProcessConfig> cfg(HRSchemaSerializer::string2Actor(data.data()));
872 if (cfg.data()) {
873 if (WorkflowEnv::getProtoRegistry()->getProto(cfg->id)) {
874 coreLog.error(QString("Element with ID '%1' already exists").arg(cfg->id));
875 } else {
876 U2OpStatus2Log os;
877 QString internalUrl = copyIntoUgene(url, os);
878 CHECK_OP(os, );
879 cfg->filePath = internalUrl;
880 if (LocalWorkflow::ExternalProcessWorkerFactory::init(cfg.data())) {
881 ActorPrototype *proto = WorkflowEnv::getProtoRegistry()->getProto(cfg->id);
882 QRectF rect = scene->sceneRect();
883 addProcess(createActor(proto, QVariantMap()), rect.center());
884 cfg.take();
885 } else {
886 coreLog.error(tr("Can't register element."));
887 }
888 }
889 } else {
890 coreLog.error(tr("Can't load element."));
891 }
892 }
893 }
894
sl_editScript()895 void WorkflowView::sl_editScript() {
896 QList<Actor *> selectedActors = scene->getSelectedActors();
897 if (selectedActors.size() == 1) {
898 Actor *scriptActor = selectedActors.first();
899 AttributeScript *script = scriptActor->getScript();
900 if (script != nullptr) {
901 QObjectScopedPointer<ScriptEditorDialog> scriptDlg = new ScriptEditorDialog(this, AttributeScriptDelegate::createScriptHeader(*script), script->getScriptText());
902 scriptDlg->exec();
903 CHECK(!scriptDlg.isNull(), );
904
905 if (scriptDlg->result() == QDialog::Accepted) {
906 script->setScriptText(scriptDlg->getScriptText());
907 scriptActor->setScript(script);
908 }
909 }
910 }
911 }
912
sl_editExternalTool()913 void WorkflowView::sl_editExternalTool() {
914 QList<Actor *> selectedActors = scene->getSelectedActors();
915 if (selectedActors.size() == 1) {
916 ActorPrototype *proto = selectedActors.first()->getProto();
917 const bool edited = palette->editPrototype(proto);
918 if (edited) {
919 scene->sl_updateDocs();
920 }
921 }
922 }
923
sl_prototypeIsAboutToBeRemoved(Workflow::ActorPrototype * proto)924 void WorkflowView::sl_prototypeIsAboutToBeRemoved(Workflow::ActorPrototype *proto) {
925 if (currentProto == proto) {
926 currentProto = nullptr;
927 }
928
929 QList<WorkflowProcessItem *> deleteList;
930 foreach (QGraphicsItem *i, scene->items()) {
931 if (i->type() == WorkflowProcessItemType) {
932 WorkflowProcessItem *wItem = static_cast<WorkflowProcessItem *>(i);
933 if (wItem->getProcess()->getProto()->getId() == proto->getId()) {
934 deleteList << wItem;
935 }
936 }
937 }
938
939 foreach (WorkflowProcessItem *item, deleteList) {
940 removeProcessItem(item);
941 }
942 scene->update();
943 }
944
sl_protoListModified()945 void WorkflowView::sl_protoListModified() {
946 CHECK(nullptr != elementsMenu, );
947 palette->createMenu(elementsMenu);
948 }
949
addProcess(Actor * proc,const QPointF & pos)950 void WorkflowView::addProcess(Actor *proc, const QPointF &pos) {
951 schema->addProcess(proc);
952 removeEstimations();
953
954 WorkflowProcessItem *it = new WorkflowProcessItem(proc);
955 it->setPos(pos);
956 scene->addItem(it);
957 scene->setModified();
958
959 ConfigurationEditor *editor = proc->getEditor();
960 if (nullptr != editor) {
961 connect(editor, SIGNAL(si_configurationChanged()), scene, SIGNAL(configurationChanged()));
962 }
963 procItemAdded();
964 ActorPrototype *addedProto = it->getProcess()->getProto();
965 uiLog.trace(addedProto->getDisplayName() + " added");
966 if (WorkflowEnv::getExternalCfgRegistry()->getConfigById(addedProto->getId()) != nullptr) {
967 GCOUNTER(cvar, "Element with external tool is added to the scene");
968 }
969
970 update();
971 }
972
removeProcessItem(WorkflowProcessItem * item)973 void WorkflowView::removeProcessItem(WorkflowProcessItem *item) {
974 CHECK(nullptr != item, );
975 Actor *actor = item->getProcess();
976 scene->removeItem(item);
977 delete item;
978
979 scene->setModified();
980 schema->removeProcess(actor);
981 meta.removeActorMeta(actor->getId());
982 delete actor;
983
984 removeWizards();
985 removeEstimations();
986 }
987
removeWizards()988 void WorkflowView::removeWizards() {
989 qDeleteAll(schema->takeWizards());
990 sl_updateUi();
991 }
992
removeEstimations()993 void WorkflowView::removeEstimations() {
994 meta.estimationsCode.clear();
995 sl_updateUi();
996 }
997
removeBusItem(WorkflowBusItem * item)998 void WorkflowView::removeBusItem(WorkflowBusItem *item) {
999 Link *link = item->getBus();
1000 scene->removeItem(item);
1001 delete item;
1002 removeEstimations();
1003 scene->setModified();
1004 onBusRemoved(link);
1005 }
1006
onBusRemoved(Link * link)1007 void WorkflowView::onBusRemoved(Link *link) {
1008 if (!sceneRecreation) {
1009 schema->removeFlow(link);
1010 schema->update();
1011 }
1012 }
1013
sl_toggleLock(bool b)1014 void WorkflowView::sl_toggleLock(bool b) {
1015 running = !b;
1016 if (sender() != unlockAction) {
1017 unlockAction->setChecked(!running);
1018 breakpointView->setEnabled(b);
1019 toggleDebugActionsState(!b);
1020 investigationWidgets->deleteBusInvestigations();
1021 investigationWidgets->resetInvestigations();
1022 return;
1023 }
1024
1025 if (!running) {
1026 scene->setRunner(nullptr);
1027 }
1028
1029 newAction->setEnabled(!running);
1030 loadAction->setEnabled(!running);
1031 deleteAction->setEnabled(!running);
1032 deleteShortcut->setEnabled(!running);
1033 selectAction->setEnabled(!running);
1034 copyAction->setEnabled(!running);
1035 pasteAction->setEnabled(!running);
1036 cutAction->setEnabled(!running);
1037
1038 stopAction->setEnabled(running);
1039 runAction->setEnabled(!running);
1040 validateAction->setEnabled(!running);
1041 estimateAction->setEnabled(!running);
1042 configureParameterAliasesAction->setEnabled(!running);
1043 configurePortAliasesAction->setEnabled(!running);
1044 importSchemaToElement->setEnabled(!running);
1045
1046 propertyEditor->setEnabled(!running);
1047 propertyEditor->setSpecialPanelEnabled(!running);
1048 palette->setEnabled(!running);
1049 toggleDebugActionsState(!b);
1050 breakpointView->setEnabled(b);
1051 samples->setEnabled(!running);
1052
1053 setupActions();
1054 scene->setLocked(running);
1055 scene->update();
1056 }
1057
sl_setStyle()1058 void WorkflowView::sl_setStyle() {
1059 StyleId s = qobject_cast<QAction *>(sender())->data().value<StyleId>();
1060 QList<QGraphicsItem *> lst = scene->selectedItems();
1061 if (lst.isEmpty()) {
1062 lst = scene->items();
1063 }
1064 foreach (QGraphicsItem *it, lst) {
1065 switch (it->type()) {
1066 case WorkflowProcessItemType:
1067 case WorkflowPortItemType:
1068 case WorkflowBusItemType:
1069 (static_cast<StyledItem *>(it))->setStyle(s);
1070 }
1071 }
1072 scene->update();
1073 }
1074
sl_changeScriptMode()1075 void WorkflowView::sl_changeScriptMode() {
1076 QAction *a = qobject_cast<QAction *>(sender());
1077 if (a != nullptr) {
1078 if (a == scriptingActions[0]) {
1079 scriptingMode = false;
1080 } else if (a == scriptingActions[1]) {
1081 scriptingMode = true;
1082 }
1083 } // else invoked from constructor
1084
1085 scriptingActions[0]->setChecked(!scriptingMode);
1086 scriptingActions[1]->setChecked(scriptingMode);
1087 propertyEditor->changeScriptMode(scriptingMode);
1088 }
1089
sl_toggleStyle()1090 void WorkflowView::sl_toggleStyle() {
1091 foreach (QGraphicsItem *it, scene->selectedItems()) {
1092 StyleId s = (static_cast<StyledItem *>(it))->getStyle();
1093 if (s == ItemStyles::SIMPLE) {
1094 s = ItemStyles::EXTENDED;
1095 } else {
1096 s = ItemStyles::SIMPLE;
1097 }
1098 (static_cast<StyledItem *>(it))->setStyle(s);
1099 }
1100 scene->update();
1101 }
1102
sl_refreshActorDocs()1103 void WorkflowView::sl_refreshActorDocs() {
1104 foreach (QGraphicsItem *it, scene->items()) {
1105 if (it->type() == WorkflowProcessItemType) {
1106 Actor *a = qgraphicsitem_cast<WorkflowProcessItem *>(it)->getProcess();
1107 a->getDescription()->update(a->getValues());
1108 }
1109 }
1110 }
1111
setupMDIToolbar(QToolBar * tb)1112 void WorkflowView::setupMDIToolbar(QToolBar *tb) {
1113 tb->addAction(newAction);
1114 tb->addAction(loadAction);
1115 tb->addAction(saveAction);
1116 tb->addAction(saveAsAction);
1117 loadSep = tb->addSeparator();
1118 tb->addAction(showWizard);
1119 tb->addAction(validateAction);
1120 tb->addAction(estimateAction);
1121 tb->addAction(runAction);
1122 tb->addAction(pauseAction);
1123 tb->addAction(toggleBreakpointAction);
1124 tb->addAction(toggleBreakpointManager);
1125 tb->addAction(nextStepAction);
1126 tb->addAction(tickReadyAction);
1127 tb->addAction(stopAction);
1128 runSep = tb->addSeparator();
1129 tb->addAction(configureParameterAliasesAction);
1130 confSep = tb->addSeparator();
1131 tb->addAction(createCmdlineBasedWorkerAction);
1132 tb->addAction(appendExternalTool);
1133 extSep = tb->addSeparator();
1134 tb->addAction(deleteAction);
1135 scaleSep = tb->addSeparator();
1136 scaleAction = tb->addWidget(scaleComboBox);
1137 scaleSep = tb->addSeparator();
1138 scriptAction = tb->addWidget(scriptMenu(this, scriptingActions));
1139 tb->addAction(dmAction);
1140
1141 addToggleDashboardAction(tb, toggleDashboard);
1142
1143 sl_dashboardCountChanged();
1144 setDashboardActionDecoration(tabView->isVisible());
1145 setupActions();
1146 }
1147
setupActions()1148 void WorkflowView::setupActions() {
1149 bool dashboard = tabView->isVisible();
1150 bool editMode = !running && !dashboard;
1151
1152 newAction->setVisible(!dashboard);
1153 loadAction->setVisible(!dashboard);
1154 saveAction->setVisible(!dashboard);
1155 saveAsAction->setVisible(!dashboard);
1156 loadSep->setVisible(!dashboard);
1157
1158 showWizard->setVisible(editMode && !schema->getWizards().isEmpty());
1159 validateAction->setVisible(editMode);
1160 estimateAction->setVisible(editMode && !meta.estimationsCode.isEmpty());
1161 stopAction->setVisible(running);
1162 runSep->setVisible(editMode);
1163
1164 configureParameterAliasesAction->setVisible(editMode);
1165 confSep->setVisible(editMode);
1166
1167 createScriptAction->setVisible(editMode);
1168 editScriptAction->setVisible(editMode);
1169
1170 createCmdlineBasedWorkerAction->setVisible(editMode);
1171 appendExternalTool->setVisible(editMode);
1172 extSep->setVisible(editMode);
1173
1174 copyAction->setVisible(editMode);
1175 pasteAction->setVisible(editMode);
1176 cutAction->setVisible(editMode);
1177 deleteAction->setVisible(editMode);
1178
1179 scaleAction->setVisible(!dashboard);
1180 scaleSep->setVisible(!dashboard);
1181
1182 scriptAction->setVisible(editMode);
1183 }
1184
setupViewMenu(QMenu * m)1185 void WorkflowView::setupViewMenu(QMenu *m) {
1186 elementsMenu = palette->createMenu(tr("Add element"));
1187 m->addMenu(elementsMenu);
1188 m->addAction(copyAction);
1189 m->addAction(pasteAction);
1190 pasteAction->setEnabled(!lastPaste.isEmpty());
1191 m->addAction(cutAction);
1192 m->addAction(deleteAction);
1193 m->addAction(selectAction);
1194 m->addSeparator();
1195 m->addAction(newAction);
1196 m->addAction(loadAction);
1197 m->addAction(saveAction);
1198 m->addAction(saveAsAction);
1199 m->addAction(exportAction);
1200 m->addSeparator();
1201 m->addAction(validateAction);
1202 m->addAction(estimateAction);
1203 m->addAction(runAction);
1204 m->addAction(stopAction);
1205 m->addSeparator();
1206 m->addAction(configureParameterAliasesAction);
1207 m->addAction(createGalaxyConfigAction);
1208 m->addAction(configurePortAliasesAction);
1209 m->addAction(importSchemaToElement);
1210 m->addSeparator();
1211 m->addAction(createScriptAction);
1212 m->addAction(editScriptAction);
1213 m->addSeparator();
1214 m->addAction(createCmdlineBasedWorkerAction);
1215 m->addAction(appendExternalTool);
1216 m->addSeparator();
1217
1218 QMenu *ttMenu = new QMenu(tr("Element style"));
1219 foreach (QAction *a, styleActions) {
1220 ttMenu->addAction(a);
1221 }
1222 m->addMenu(ttMenu);
1223
1224 QMenu *scriptMenu = new QMenu(tr("Scripting mode"));
1225 foreach (QAction *a, scriptingActions) {
1226 scriptMenu->addAction(a);
1227 }
1228 m->addMenu(scriptMenu);
1229
1230 if (!unlockAction->isChecked()) {
1231 m->addSeparator();
1232 m->addAction(unlockAction);
1233 }
1234 m->addSeparator();
1235 m->addAction(dmAction);
1236 }
1237
setupContextMenu(QMenu * m)1238 void WorkflowView::setupContextMenu(QMenu *m) {
1239 if (!debugInfo->isPaused()) {
1240 if (!unlockAction->isChecked()) {
1241 return;
1242 }
1243
1244 if (!lastPaste.isEmpty()) {
1245 m->addAction(pasteAction);
1246 }
1247 QList<QGraphicsItem *> sel = scene->selectedItems();
1248 if (!sel.isEmpty()) {
1249 if (!((sel.size() == 1 && sel.first()->type() == WorkflowBusItemType) || sel.first()->type() == WorkflowPortItemType)) {
1250 m->addAction(copyAction);
1251 m->addAction(cutAction);
1252 }
1253 if (!(sel.size() == 1 && sel.first()->type() == WorkflowPortItemType)) {
1254 m->addAction(deleteAction);
1255 }
1256 m->addSeparator();
1257 if (sel.size() == 1 && sel.first()->type() == WorkflowProcessItemType) {
1258 WorkflowProcessItem *wit = qgraphicsitem_cast<WorkflowProcessItem *>(sel.first());
1259 Actor *scriptActor = wit->getProcess();
1260 AttributeScript *script = scriptActor->getScript();
1261 if (script) {
1262 m->addAction(editScriptAction);
1263 }
1264
1265 ActorPrototype *p = scriptActor->getProto();
1266 if (p->isExternalTool()) {
1267 m->addAction(editExternalToolAction);
1268 }
1269
1270 m->addSeparator();
1271
1272 QMenu *itMenu = new QMenu(tr("Element properties"));
1273 foreach (QAction *a, wit->getContextMenuActions()) {
1274 itMenu->addAction(a);
1275 }
1276 m->addMenu(itMenu);
1277 }
1278 if (!(sel.size() == 1 && (sel.first()->type() == WorkflowBusItemType || sel.first()->type() == WorkflowPortItemType))) {
1279 QMenu *ttMenu = new QMenu(tr("Element style"));
1280 foreach (QAction *a, styleActions) {
1281 ttMenu->addAction(a);
1282 }
1283 m->addMenu(ttMenu);
1284 }
1285 }
1286 m->addSeparator();
1287
1288 m->addAction(selectAction);
1289 m->addMenu(palette->createMenu(tr("Add element")));
1290 }
1291
1292 foreach (QGraphicsItem *item, scene->selectedItems()) {
1293 if (WorkflowProcessItemType == item->type()) {
1294 m->addAction(toggleBreakpointAction);
1295 break;
1296 }
1297 }
1298 }
1299
sl_pickInfo(QListWidgetItem * info)1300 void WorkflowView::sl_pickInfo(QListWidgetItem *info) {
1301 ActorId id = info->data(ACTOR_ID_REF).value<ActorId>();
1302 foreach (QGraphicsItem *it, scene->items()) {
1303 if (it->type() == WorkflowProcessItemType) {
1304 WorkflowProcessItem *proc = static_cast<WorkflowProcessItem *>(it);
1305 if (proc->getProcess()->getId() != id) {
1306 continue;
1307 }
1308 scene->clearSelection();
1309 QString pid = info->data(PORT_REF).toString();
1310 WorkflowPortItem *port = proc->getPort(pid);
1311 if (port) {
1312 port->setSelected(true);
1313 } else {
1314 proc->setSelected(true);
1315 }
1316 return;
1317 }
1318 }
1319 }
1320
sl_validate(bool notify)1321 bool WorkflowView::sl_validate(bool notify) {
1322 if (schema->getProcesses().isEmpty()) {
1323 QMessageBox::warning(this, tr("Empty workflow!"), tr("Nothing to run: empty workflow"));
1324 return false;
1325 }
1326
1327 propertyEditor->commit();
1328 infoList->clear();
1329 QList<QListWidgetItem *> lst;
1330 bool good = WorkflowUtils::validate(*schema, lst);
1331
1332 if (lst.count() != 0) {
1333 foreach (QListWidgetItem *wi, lst) {
1334 infoList->addItem(wi);
1335 }
1336 bottomTabs->show();
1337 bottomTabs->setCurrentWidget(infoList->parentWidget());
1338 infoList->parentWidget()->show();
1339 QList<int> s = infoSplitter->sizes();
1340 if (s[s.size() - 1] == 0) {
1341 s[s.size() - 1] = qMin(infoList->sizeHint().height(), 300);
1342 infoSplitter->setSizes(s);
1343 }
1344 } else if (bottomTabs->currentWidget() == infoList->parentWidget()) {
1345 bottomTabs->hide();
1346 }
1347 if (!good) {
1348 QMessageBox::warning(this, tr("Workflow cannot be executed"), tr("Please fix issues listed in the error list (located under workflow)."));
1349 } else {
1350 if (notify) {
1351 QString message = tr("Workflow is valid. \n");
1352 if (lst.isEmpty()) {
1353 message += tr("Well done!");
1354 } else {
1355 message += tr("There are non-critical warnings.");
1356 }
1357 QMessageBox::information(this, tr("Workflow is valid"), message);
1358 }
1359 }
1360 return good;
1361 }
1362
sl_estimate()1363 void WorkflowView::sl_estimate() {
1364 CHECK(sl_validate(false /*don't notify*/), );
1365 SAFE_POINT(!meta.estimationsCode.isEmpty(), "No estimation code", );
1366 estimateAction->setEnabled(false);
1367
1368 SchemaEstimationTask *t = new SchemaEstimationTask(schema, &meta);
1369 connect(t, SIGNAL(si_stateChanged()), SLOT(sl_estimationTaskFinished()));
1370 AppContext::getTaskScheduler()->registerTopLevelTask(t);
1371 }
1372
sl_estimationTaskFinished()1373 void WorkflowView::sl_estimationTaskFinished() {
1374 SchemaEstimationTask *t = dynamic_cast<SchemaEstimationTask *>(sender());
1375 CHECK(nullptr != t, );
1376 CHECK(t->isFinished(), );
1377 estimateAction->setEnabled(true);
1378 CHECK(!t->hasError(), );
1379 QMessageBox *d = EstimationReporter::createTimeMessage(t->result());
1380 QPushButton *rb = d->addButton(QObject::tr("Run workflow"), QMessageBox::AcceptRole);
1381 rb->setObjectName("Run workflow");
1382 connect(rb, SIGNAL(clicked()), SLOT(sl_launch()));
1383 d->setParent(this);
1384 d->setWindowModality(Qt::ApplicationModal);
1385 d->show();
1386 }
1387
localHostLaunch()1388 void WorkflowView::localHostLaunch() {
1389 if (!sl_validate(false)) {
1390 return;
1391 }
1392
1393 if (schema->getDomain().isEmpty()) {
1394 // TODO: user choice
1395 schema->setDomain(WorkflowEnv::getDomainRegistry()->getAllIds().value(0));
1396 }
1397
1398 if (meta.isSample()) {
1399 GCounter::increment(meta.name, "WDSample:run");
1400 }
1401
1402 foreach (const Actor *actor, schema->getProcesses()) {
1403 if (WorkflowEnv::getExternalCfgRegistry()->getConfigById(actor->getId()) != nullptr) {
1404 GCOUNTER(cvar, "Element(s) with command line tool is present in the launched workflow");
1405 break;
1406 }
1407 }
1408 debugInfo->setMessageParser(new WorkflowDebugMessageParserImpl());
1409 WorkflowAbstractRunner *t = new WorkflowRunTask(*schema, ActorMap(), debugInfo);
1410
1411 t->setReportingEnabled(true);
1412 if (WorkflowSettings::monitorRun()) {
1413 commitWarningsToMonitor(t);
1414 unlockAction->setChecked(false);
1415 scene->setRunner(t);
1416 connect(t, SIGNAL(si_ticked()), scene, SLOT(update()));
1417 TaskSignalMapper *signalMapper = new TaskSignalMapper(t);
1418 connect(signalMapper, SIGNAL(si_taskFinished(Task *)), debugInfo, SLOT(sl_executionFinished()));
1419 connect(signalMapper, SIGNAL(si_taskFinished(Task *)), SLOT(sl_toggleLock()));
1420 }
1421 AppContext::getTaskScheduler()->registerTopLevelTask(t);
1422 foreach (WorkflowMonitor *m, t->getMonitors()) {
1423 m->setSaveSchema(meta);
1424 tabView->addDashboard(m, meta.name);
1425 showDashboards();
1426 }
1427 }
1428
sl_launch()1429 void WorkflowView::sl_launch() {
1430 if (!debugInfo->isPaused()) {
1431 localHostLaunch();
1432 if (nullptr != scene->getRunner()) {
1433 stopAction->setEnabled(true);
1434 pauseAction->setEnabled(true);
1435 propertyEditor->setEnabled(false);
1436 toggleDebugActionsState(true);
1437 }
1438 }
1439 }
1440
sl_pause(bool isPause)1441 void WorkflowView::sl_pause(bool isPause) {
1442 pauseAction->setEnabled(!isPause);
1443 runAction->setEnabled(isPause);
1444 nextStepAction->setEnabled(isPause);
1445 propertyEditor->setEnabled(isPause);
1446 scene->setLocked(!isPause);
1447 breakpointView->setEnabled(isPause);
1448 investigationWidgets->setInvestigationWidgetsVisible(isPause);
1449 WorkflowAbstractRunner *runningWorkflow = scene->getRunner();
1450 if (nullptr != runningWorkflow && runningWorkflow->isRunning()) {
1451 foreach (WorkflowMonitor *m, runningWorkflow->getMonitors()) {
1452 if (isPause) {
1453 m->pause();
1454 } else {
1455 m->resume();
1456 }
1457 }
1458 }
1459 if (isPause && tabView->isVisible()) {
1460 hideDashboards();
1461 }
1462 }
1463
sl_stop()1464 void WorkflowView::sl_stop() {
1465 Task *runningWorkflow = scene->getRunner();
1466 if (nullptr != runningWorkflow) {
1467 runningWorkflow->cancel();
1468 }
1469 investigationWidgets->resetInvestigations();
1470 }
1471
toggleDebugActionsState(bool enable)1472 void WorkflowView::toggleDebugActionsState(bool enable) {
1473 if (WorkflowSettings::isDebuggerEnabled()) {
1474 foreach (QAction *action, debugActions) {
1475 action->setVisible(enable);
1476 }
1477 }
1478 }
1479
propagateBreakpointToSceneItem(ActorId actor)1480 void WorkflowView::propagateBreakpointToSceneItem(ActorId actor) {
1481 WorkflowProcessItem *processItem = findItemById(actor);
1482 Q_ASSERT(processItem->isBreakpointInserted());
1483 processItem->highlightItem();
1484 }
1485
sl_breakpointAdded(const ActorId & actor)1486 void WorkflowView::sl_breakpointAdded(const ActorId &actor) {
1487 changeBreakpointState(actor, true);
1488 }
1489
sl_breakpointRemoved(const ActorId & actor)1490 void WorkflowView::sl_breakpointRemoved(const ActorId &actor) {
1491 changeBreakpointState(actor, false);
1492 }
1493
sl_breakpointEnabled(const ActorId & actor)1494 void WorkflowView::sl_breakpointEnabled(const ActorId &actor) {
1495 changeBreakpointState(actor, false, true);
1496 }
1497
sl_breakpointDisabled(const ActorId & actor)1498 void WorkflowView::sl_breakpointDisabled(const ActorId &actor) {
1499 changeBreakpointState(actor, false, true);
1500 }
1501
changeBreakpointState(const ActorId & actor,bool isBreakpointBeingAdded,bool isBreakpointStateBeingChanged)1502 void WorkflowView::changeBreakpointState(const ActorId &actor, bool isBreakpointBeingAdded, bool isBreakpointStateBeingChanged) {
1503 WorkflowProcessItem *processItem = findItemById(actor);
1504 Q_ASSERT(nullptr != processItem);
1505
1506 if (processItem->isBreakpointInserted()) {
1507 if (!isBreakpointBeingAdded) {
1508 if (!isBreakpointStateBeingChanged) {
1509 processItem->toggleBreakpoint();
1510 } else {
1511 processItem->toggleBreakpointState();
1512 }
1513 }
1514 } else {
1515 if (isBreakpointBeingAdded) {
1516 if (!isBreakpointStateBeingChanged) {
1517 processItem->toggleBreakpoint();
1518 } else {
1519 Q_ASSERT(false);
1520 }
1521 }
1522 }
1523 scene->update();
1524 }
1525
sl_toggleBreakpointManager()1526 void WorkflowView::sl_toggleBreakpointManager() {
1527 if (!breakpointView->isVisible()) {
1528 bottomTabs->setVisible(true);
1529 bottomTabs->setCurrentWidget(breakpointView);
1530 } else {
1531 bottomTabs->hide();
1532 }
1533 }
1534
sl_highlightingRequested(const ActorId & actor)1535 void WorkflowView::sl_highlightingRequested(const ActorId &actor) {
1536 findItemById(actor)->highlightItem();
1537 }
1538
sl_processOneMessage()1539 void WorkflowView::sl_processOneMessage() {
1540 Q_ASSERT(debugInfo->isPaused());
1541 QList<QGraphicsItem *> selectedItems = scene->selectedItems();
1542 Q_ASSERT(1 == selectedItems.size());
1543 WorkflowProcessItem *processItem = qgraphicsitem_cast<WorkflowProcessItem *>(selectedItems.first());
1544 debugInfo->requestForSingleStep(processItem->getProcess()->getId());
1545 }
1546
sl_convertMessages2Documents(const Workflow::Link * bus,const QString & messageType,int messageNumber)1547 void WorkflowView::sl_convertMessages2Documents(const Workflow::Link *bus,
1548 const QString &messageType,
1549 int messageNumber) {
1550 debugInfo->convertMessagesToDocuments(bus, messageType, messageNumber, meta.name);
1551 }
1552
findItemById(ActorId actor) const1553 WorkflowProcessItem *WorkflowView::findItemById(ActorId actor) const {
1554 foreach (QGraphicsItem *item, scene->items()) {
1555 if (WorkflowProcessItemType == item->type()) {
1556 WorkflowProcessItem *processItem = qgraphicsitem_cast<WorkflowProcessItem *>(item);
1557 Q_ASSERT(nullptr != processItem);
1558 if (actor == processItem->getProcess()->getId()) {
1559 return processItem;
1560 }
1561 }
1562 }
1563 return nullptr;
1564 }
1565
paintEvent(QPaintEvent * event)1566 void WorkflowView::paintEvent(QPaintEvent *event) {
1567 const bool isWorkflowRunning = (nullptr != scene->getRunner());
1568 const bool isDebuggerEnabled = WorkflowSettings::isDebuggerEnabled();
1569 if (isDebuggerEnabled && ABSENT_WIDGET_TAB_NUMBER == bottomTabs->indexOf(breakpointView)) {
1570 bottomTabs->addTab(breakpointView, QObject::tr("Breakpoints"));
1571 } else if (!isDebuggerEnabled && ABSENT_WIDGET_TAB_NUMBER != bottomTabs->indexOf(breakpointView)) {
1572 breakpointView->sl_deleteAllBreakpoints();
1573 bottomTabs->removeTab(bottomTabs->indexOf(breakpointView));
1574 }
1575 foreach (QAction *action, debugActions) {
1576 action->setVisible(WorkflowSettings::isDebuggerEnabled() && isWorkflowRunning);
1577 }
1578 toggleBreakpointAction->setVisible(isDebuggerEnabled);
1579 toggleBreakpointManager->setVisible(isDebuggerEnabled);
1580
1581 if (isWorkflowRunning) {
1582 if (debugInfo->isPaused()) {
1583 sl_onSelectionChanged();
1584 } else {
1585 tickReadyAction->setEnabled(false);
1586 }
1587 }
1588 MWMDIWindow::paintEvent(event);
1589 }
sl_configureParameterAliases()1590 void WorkflowView::sl_configureParameterAliases() {
1591 QObjectScopedPointer<SchemaAliasesConfigurationDialogImpl> dlg = new SchemaAliasesConfigurationDialogImpl(*schema, this);
1592 int ret = QDialog::Accepted;
1593 do {
1594 ret = dlg->exec();
1595 CHECK(!dlg.isNull(), );
1596 if (ret == QDialog::Accepted) {
1597 if (!dlg->validateModel()) {
1598 QMessageBox::critical(this, tr("Bad input!"), tr("Aliases for workflow parameters should be different!"));
1599 continue;
1600 }
1601 // clear aliases before inserting new
1602 foreach (Actor *actor, schema->getProcesses()) {
1603 actor->getParamAliases().clear();
1604 }
1605 SchemaAliasesCfgDlgModel model = dlg->getModel();
1606 foreach (const ActorId &id, model.aliases.keys()) {
1607 foreach (const Descriptor &d, model.aliases.value(id).keys()) {
1608 Actor *actor = schema->actorById(id);
1609 assert(actor != nullptr);
1610 QString alias = model.aliases.value(id).value(d);
1611 assert(!alias.isEmpty());
1612 actor->getParamAliases().insert(d.getId(), alias);
1613 QString help = model.help.value(id).value(d);
1614 if (!help.isEmpty()) {
1615 actor->getAliasHelp().insert(alias, help);
1616 }
1617 }
1618 }
1619 break;
1620 } else if (ret == QDialog::Rejected) {
1621 break;
1622 } else {
1623 assert(false);
1624 }
1625 } while (ret == QDialog::Accepted);
1626 }
1627
sl_createGalaxyConfig()1628 void WorkflowView::sl_createGalaxyConfig() {
1629 bool schemeContainsAliases = schema->hasParamAliases();
1630 if (!schemeContainsAliases) {
1631 QMessageBox::critical(this, tr("Bad input!"), tr("Workflow does not contain any parameter aliases"));
1632 return;
1633 }
1634 if (meta.url.isEmpty()) {
1635 return;
1636 }
1637
1638 QObjectScopedPointer<GalaxyConfigConfigurationDialogImpl> dlg = new GalaxyConfigConfigurationDialogImpl(meta.url, this);
1639 dlg->exec();
1640 CHECK(!dlg.isNull(), );
1641
1642 if (QDialog::Accepted == dlg->result()) {
1643 bool created = dlg->createGalaxyConfigTask();
1644 if (!created) {
1645 QMessageBox::critical(this, tr("Internal error!"), tr("Can not create Galaxy config"));
1646 return;
1647 }
1648 }
1649 }
1650
sl_configurePortAliases()1651 void WorkflowView::sl_configurePortAliases() {
1652 QObjectScopedPointer<PortAliasesConfigurationDialog> dlg = new PortAliasesConfigurationDialog(*schema, this);
1653 dlg->exec();
1654 CHECK(!dlg.isNull(), );
1655
1656 if (QDialog::Accepted == dlg->result()) {
1657 PortAliasesCfgDlgModel model = dlg->getModel();
1658
1659 QList<PortAlias> portAliases;
1660 foreach (Port *port, model.ports.keys()) {
1661 PortAlias portAlias(port, model.ports.value(port).first, model.ports.value(port).second);
1662
1663 foreach (Descriptor slotDescr, model.aliases.value(port).keys()) {
1664 QString actorId;
1665 QString slotId;
1666 {
1667 if (port->isInput()) {
1668 actorId = port->owner()->getId();
1669 slotId = slotDescr.getId();
1670 } else {
1671 QStringList tokens = slotDescr.getId().split(':');
1672 assert(2 == tokens.size());
1673 actorId = tokens[0];
1674 slotId = tokens[1];
1675 }
1676 }
1677
1678 Port *sourcePort = nullptr;
1679 foreach (Port *p, schema->actorById(actorId)->getPorts()) {
1680 DataTypePtr dt = p->Port::getType();
1681 QList<Descriptor> descs = dt->getAllDescriptors();
1682 if (descs.contains(slotId)) {
1683 sourcePort = p;
1684 break;
1685 }
1686 }
1687 assert(nullptr != sourcePort);
1688
1689 portAlias.addSlot(sourcePort, slotId, model.aliases.value(port).value(slotDescr));
1690 }
1691 portAliases.append(portAlias);
1692 }
1693
1694 schema->setPortAliases(portAliases);
1695 }
1696 }
1697
sl_importSchemaToElement()1698 void WorkflowView::sl_importSchemaToElement() {
1699 QString error;
1700 if (!schema->getWizards().isEmpty()) {
1701 error = WorkflowView::tr("The workflow contains a wizard. Sorry, but current version of "
1702 "UGENE doesn't support of wizards in the includes.");
1703 QMessageBox::critical(this, tr("Error"), error);
1704 } else if (WorkflowUtils::validateSchemaForIncluding(*schema, error)) {
1705 QObjectScopedPointer<ImportSchemaDialog> d = new ImportSchemaDialog(this);
1706 d->exec();
1707 CHECK(!d.isNull(), );
1708
1709 if (QDialog::Accepted == d->result()) {
1710 Schema *s = new Schema();
1711 U2OpStatusImpl os;
1712 HRSchemaSerializer::deepCopy(*schema, s, os);
1713 SAFE_POINT_OP(os, );
1714 QString typeName = d->getTypeName();
1715
1716 s->setTypeName(typeName);
1717 QString text = HRSchemaSerializer::schema2String(*s, nullptr);
1718
1719 QString path = WorkflowSettings::getIncludedElementsDirectory() + typeName + "." + WorkflowUtils::WD_FILE_EXTENSIONS.first();
1720 QFile file(path);
1721 file.open(QIODevice::WriteOnly);
1722 file.write(text.toLatin1());
1723 file.close();
1724
1725 ActorPrototype *proto = IncludedProtoFactory::getSchemaActorProto(s, typeName, path);
1726 WorkflowEnv::getProtoRegistry()->registerProto(BaseActorCategories::CATEGORY_INCLUDES(), proto);
1727 WorkflowEnv::getSchemaActorsRegistry()->registerSchema(typeName, s);
1728 }
1729 } else {
1730 QMessageBox::critical(this, tr("Error"), error);
1731 }
1732 }
1733
sl_selectPrototype(Workflow::ActorPrototype * p,bool putToScene)1734 void WorkflowView::sl_selectPrototype(Workflow::ActorPrototype *p, bool putToScene) {
1735 propertyEditor->setEditable(!p);
1736 scene->clearSelection();
1737 currentProto = p;
1738
1739 propertyEditor->reset();
1740 if (!p) {
1741 scene->views().at(0)->unsetCursor();
1742 propertyEditor->changeScriptMode(scriptingMode);
1743 } else {
1744 delete currentActor;
1745 currentActor = createActor(p, QVariantMap());
1746 if (putToScene) {
1747 addProcess(currentActor, scene->getLastMousePressPoint());
1748 } else {
1749 propertyEditor->setDescriptor(p, tr("Drag an element to the scene to add it to the workflow."));
1750 scene->views().at(0)->setCursor(Qt::CrossCursor);
1751 }
1752 }
1753 }
1754
sl_copyItems()1755 void WorkflowView::sl_copyItems() {
1756 QList<WorkflowProcessItem *> procs;
1757 foreach (QGraphicsItem *item, scene->selectedItems()) {
1758 if (item->type() == WorkflowProcessItemType) {
1759 procs << qgraphicsitem_cast<WorkflowProcessItem *>(item);
1760 }
1761 }
1762 if (procs.isEmpty()) {
1763 return;
1764 }
1765
1766 QList<Actor *> actors = scene->getSelectedActors();
1767 Metadata actorMeta = getMeta(procs);
1768 lastPaste = HRSchemaSerializer::items2String(actors, &actorMeta);
1769 pasteAction->setEnabled(true);
1770 QApplication::clipboard()->setText(lastPaste);
1771 pasteCount = 0;
1772 }
1773
sl_cutItems()1774 void WorkflowView::sl_cutItems() {
1775 sl_copyItems();
1776 scene->sl_deleteItem();
1777 }
1778
sl_pasteSample(const QString & s)1779 void WorkflowView::sl_pasteSample(const QString &s) {
1780 tabs->setCurrentIndex(ElementsTab);
1781 infoList->clear();
1782 if (scene->items().isEmpty()) {
1783 // fixing bug with pasting same schema 2 times
1784 {
1785 lastPaste.clear();
1786 }
1787 sl_pasteItems(s, true);
1788 sl_updateTitle();
1789 sl_updateUi();
1790 scene->connectConfigurationEditors();
1791 scene->sl_deselectAll();
1792 scene->update();
1793 rescale();
1794 sl_refreshActorDocs();
1795 meta.setSampleMark(true);
1796 GCounter::increment(meta.name, "WDSample:open");
1797 startFirstAutoRunWizard();
1798 } else {
1799 breakpointView->clear();
1800 scene->clearScene();
1801 schema->reset();
1802 sl_pasteSample(s);
1803 }
1804 }
1805
getUniquePastedActorIds(const QList<Actor * > & pasted,const QList<Actor * > & origin)1806 static QMap<ActorId, ActorId> getUniquePastedActorIds(const QList<Actor *> &pasted, const QList<Actor *> &origin) {
1807 QMap<ActorId, ActorId> result;
1808 QStringList uniqueIds;
1809 foreach (Actor *a, origin) {
1810 uniqueIds << aid2str(a->getId());
1811 }
1812 foreach (Actor *a, pasted) {
1813 QString uniqId = WorkflowUtils::createUniqueString(aid2str(a->getId()), "-", uniqueIds);
1814 uniqueIds << uniqId;
1815 ActorId newId = str2aid(uniqId);
1816 if (newId != a->getId()) {
1817 result[a->getId()] = newId;
1818 }
1819 }
1820 return result;
1821 }
1822
renamePastedSchemaActors(Schema & pasted,Metadata & meta,Schema * origin)1823 static void renamePastedSchemaActors(Schema &pasted, Metadata &meta, Schema *origin) {
1824 QMap<ActorId, ActorId> mapping = getUniquePastedActorIds(pasted.getProcesses(), origin->getProcesses());
1825 foreach (const ActorId &id, mapping.keys()) {
1826 pasted.renameProcess(id, mapping[id]);
1827 }
1828 meta.renameActors(mapping);
1829 }
1830
sl_pasteItems(const QString & s,bool updateSchemaInfo)1831 void WorkflowView::sl_pasteItems(const QString &s, bool updateSchemaInfo) {
1832 QString tmp = s.isNull() ? QApplication::clipboard()->text() : s;
1833 if (tmp == lastPaste) {
1834 ++pasteCount;
1835 } else {
1836 pasteCount = 0;
1837 lastPaste = tmp;
1838 }
1839 QByteArray lpt = lastPaste.toLatin1();
1840 DocumentFormat *wf = AppContext::getDocumentFormatRegistry()->getFormatById(WorkflowDocFormat::FORMAT_ID);
1841 if (wf->checkRawData(lpt).score != FormatDetection_Matched) {
1842 return;
1843 }
1844 disconnect(scene, SIGNAL(selectionChanged()), this, SLOT(sl_editItem()));
1845 scene->clearSelection();
1846 connect(scene, SIGNAL(selectionChanged()), SLOT(sl_editItem()));
1847
1848 Schema pastedS;
1849 pastedS.setDeepCopyFlag(true);
1850 Metadata pastedM;
1851 QString msg = HRSchemaSerializer::string2Schema(lastPaste, &pastedS, &pastedM);
1852 if (!msg.isEmpty()) {
1853 uiLog.error("Paste issues: " + msg);
1854 return;
1855 }
1856 renamePastedSchemaActors(pastedS, pastedM, schema.get());
1857 if (schema->getProcesses().isEmpty()) {
1858 schema->setWizards(pastedS.takeWizards());
1859 }
1860 schema->merge(pastedS);
1861 updateMeta();
1862 meta.mergeVisual(pastedM);
1863 if (updateSchemaInfo) {
1864 meta.name = pastedM.name;
1865 meta.comment = pastedM.comment;
1866 meta.scalePercent = pastedM.scalePercent;
1867 meta.estimationsCode = pastedM.estimationsCode;
1868 }
1869 pastedS.setDeepCopyFlag(false);
1870 recreateScene();
1871 scene->connectConfigurationEditors();
1872
1873 foreach (QGraphicsItem *it, scene->items()) {
1874 WorkflowProcessItem *proc = qgraphicsitem_cast<WorkflowProcessItem *>(it);
1875 if (nullptr != proc) {
1876 if (nullptr != pastedS.actorById(proc->getProcess()->getId())) {
1877 it->setSelected(true);
1878 }
1879 }
1880 }
1881
1882 int shift = GRID_STEP * (pasteCount);
1883 foreach (QGraphicsItem *it, scene->selectedItems()) {
1884 it->moveBy(shift, shift);
1885 }
1886 }
1887
recreateScene()1888 void WorkflowView::recreateScene() {
1889 sceneRecreation = true;
1890 SceneCreator sc(schema.get(), meta);
1891 sc.recreateScene(scene);
1892 sceneRecreation = false;
1893 }
1894
sl_showEditor()1895 void WorkflowView::sl_showEditor() {
1896 propertyEditor->show();
1897 QList<int> s = splitter->sizes();
1898 if (s.last() == 0) {
1899 s.last() = propertyEditor->sizeHint().width();
1900 splitter->setSizes(s);
1901 }
1902 }
1903
sl_editItem()1904 void WorkflowView::sl_editItem() {
1905 QList<QGraphicsItem *> list = scene->selectedItems();
1906 if (list.size() == 1) {
1907 QGraphicsItem *it = list.at(0);
1908 if (it->type() == WorkflowProcessItemType) {
1909 Actor *a = qgraphicsitem_cast<WorkflowProcessItem *>(it)->getProcess();
1910 propertyEditor->editActor(a);
1911 return;
1912 }
1913 Port *p = nullptr;
1914
1915 if (it->type() == WorkflowBusItemType) {
1916 WorkflowBusItem *busItem = qgraphicsitem_cast<WorkflowBusItem *>(it);
1917
1918 if (debugInfo->isPaused()) {
1919 investigationWidgets->setCurrentInvestigation(busItem->getBus());
1920 }
1921 p = busItem->getInPort()->getPort();
1922 } else if (it->type() == WorkflowPortItemType) {
1923 p = qgraphicsitem_cast<WorkflowPortItem *>(it)->getPort();
1924 }
1925 if (p) {
1926 if (qobject_cast<IntegralBusPort *>(p)) {
1927 BusPortEditor *ed = new BusPortEditor(qobject_cast<IntegralBusPort *>(p));
1928 ed->setParent(p);
1929 p->setEditor(ed);
1930 }
1931 }
1932 propertyEditor->editPort(p);
1933 } else {
1934 propertyEditor->reset();
1935 }
1936 }
1937
sl_onSelectionChanged()1938 void WorkflowView::sl_onSelectionChanged() {
1939 QList<Actor *> actorsSelected = scene->getSelectedActors();
1940 const int actorsCount = actorsSelected.size();
1941 editScriptAction->setEnabled(actorsCount == 1 && actorsSelected.first()->getScript() != nullptr);
1942 editExternalToolAction->setEnabled(actorsCount == 1 && actorsSelected.first()->getProto()->isExternalTool());
1943 toggleBreakpointAction->setEnabled(scene->items().size() != 0);
1944
1945 WorkflowAbstractRunner *runner = scene->getRunner();
1946 if (nullptr != runner && !actorsSelected.isEmpty()) {
1947 QList<Workflow::WorkerState> workerStates = runner->getState(actorsSelected.first());
1948 tickReadyAction->setEnabled(debugInfo->isPaused() && 1 == actorsCount && workerStates.contains(WorkerReady));
1949 } else {
1950 tickReadyAction->setEnabled(false);
1951 }
1952 }
1953
sl_exportScene()1954 void WorkflowView::sl_exportScene() {
1955 propertyEditor->commit();
1956 QString fileName = GUrlUtils::fixFileName(meta.name);
1957 QObjectScopedPointer<ExportImageDialog> dialog = new ExportImageDialog(sceneView->viewport(), ExportImageDialog::WD, fileName, ExportImageDialog::SupportScaling, sceneView->viewport());
1958 dialog->exec();
1959 }
1960
sl_saveScene()1961 void WorkflowView::sl_saveScene() {
1962 if (meta.url.isEmpty()) {
1963 QObjectScopedPointer<WorkflowMetaDialog> md = new WorkflowMetaDialog(this, meta);
1964 const int rc = md->exec();
1965 CHECK(!md.isNull(), );
1966
1967 if (rc != QDialog::Accepted) {
1968 return;
1969 }
1970 meta = md->meta;
1971 sl_updateTitle();
1972 }
1973 propertyEditor->commit();
1974 Task *t = new SaveWorkflowSceneTask(getSchema(), getMeta());
1975 AppContext::getTaskScheduler()->registerTopLevelTask(t);
1976 connect(t, SIGNAL(si_stateChanged()), SLOT(sl_onSceneSaved()));
1977 }
1978
sl_saveSceneAs()1979 void WorkflowView::sl_saveSceneAs() {
1980 QObjectScopedPointer<WorkflowMetaDialog> md = new WorkflowMetaDialog(this, meta);
1981 const int rc = md->exec();
1982 CHECK(!md.isNull(), );
1983
1984 if (rc != QDialog::Accepted) {
1985 return;
1986 }
1987 propertyEditor->commit();
1988 meta = md->meta;
1989 Task *t = new SaveWorkflowSceneTask(getSchema(), getMeta());
1990 AppContext::getTaskScheduler()->registerTopLevelTask(t);
1991 sl_updateTitle();
1992 connect(t, SIGNAL(si_stateChanged()), SLOT(sl_onSceneSaved()));
1993 }
1994
startWizard(Wizard * wizard)1995 void WorkflowView::startWizard(Wizard *wizard) {
1996 auto viewPointer = new QPointer<WorkflowView>(this);
1997 QTimer::singleShot(100, [this, wizard, viewPointer]() {
1998 // Check that the view is not closed/destroyed before running the wizard. */
1999 if (!viewPointer->isNull()) {
2000 runWizardAndHandleResult(wizard);
2001 }
2002 delete viewPointer;
2003 });
2004 }
2005
runWizardAndHandleResult(Wizard * wizard)2006 void WorkflowView::runWizardAndHandleResult(Wizard *wizard) {
2007 WizardController controller(schema, wizard);
2008 QWizard *gui = controller.createGui();
2009 if (gui->exec() && !controller.isBroken()) {
2010 QString result = wizard->getResult(controller.getVariables());
2011 if (!result.isEmpty()) {
2012 controller.applyChanges(meta);
2013 loadWizardResult(result);
2014 return;
2015 }
2016
2017 const bool isSample = meta.isSample();
2018 updateMeta();
2019 meta.setSampleMark(isSample);
2020
2021 WizardController::ApplyResult res = controller.applyChanges(meta);
2022 if (WizardController::ACTORS_REPLACED == res) {
2023 recreateScene();
2024 schema->setWizards(QList<Wizard *>());
2025 }
2026 scene->sl_updateDocs();
2027 scene->setModified();
2028 propertyEditor->update();
2029 if (controller.isRunAfterApply()) {
2030 sl_launch();
2031 }
2032 } else if (schema->getProcesses().isEmpty()) {
2033 sl_newScene();
2034 }
2035 }
2036
loadWizardResult(const QString & result)2037 void WorkflowView::loadWizardResult(const QString &result) {
2038 QString url = QDir::searchPaths(PATH_PREFIX_DATA).first() + "/workflow_samples/" + result;
2039 if (!QFile::exists(url)) {
2040 coreLog.error(tr("File is not found: %1").arg(url));
2041 return;
2042 }
2043 breakpointView->clear();
2044 schema->reset();
2045 meta.reset();
2046 U2OpStatus2Log os;
2047 WorkflowUtils::schemaFromFile(url, schema.get(), &meta, os);
2048 recreateScene();
2049 sl_onSceneLoaded();
2050 if (!schema->getWizards().isEmpty() && !schema->getWizards().first()->isAutoRun()) {
2051 startWizard(schema->getWizards().first());
2052 }
2053 }
2054
procItemAdded()2055 void WorkflowView::procItemAdded() {
2056 currentActor = nullptr;
2057 propertyEditor->setEditable(true);
2058 scene->invalidate(QRectF(), QGraphicsScene::BackgroundLayer);
2059 if (!currentProto) {
2060 return;
2061 }
2062 palette->resetSelection();
2063 currentProto = nullptr;
2064 assert(scene->views().size() == 1);
2065 scene->views().at(0)->unsetCursor();
2066 }
2067
startFirstAutoRunWizard()2068 void WorkflowView::startFirstAutoRunWizard() {
2069 const QList<Wizard *> wizardList = schema->getWizards();
2070 for (Wizard *wizard : qAsConst(wizardList)) {
2071 if (wizard->isAutoRun()) {
2072 startWizard(wizard);
2073 return;
2074 }
2075 }
2076 }
2077
sl_showWizard()2078 void WorkflowView::sl_showWizard() {
2079 if (schema->getWizards().size() > 0) {
2080 startWizard(schema->getWizards().first());
2081 }
2082 }
2083
getToolbarIcon(const QString & srcPath)2084 static QIcon getToolbarIcon(const QString &srcPath) {
2085 QPixmap pm = QPixmap(":workflow_designer/images/" + srcPath).scaled(16, 16);
2086 return QIcon(pm);
2087 }
2088
hideDashboards()2089 void WorkflowView::hideDashboards() {
2090 setDashboardActionDecoration(false);
2091 tabView->setVisible(false);
2092 splitter->setVisible(true);
2093 setupActions();
2094 }
2095
showDashboards()2096 void WorkflowView::showDashboards() {
2097 setDashboardActionDecoration(true);
2098 splitter->setVisible(false);
2099 tabView->setVisible(true);
2100 setupActions();
2101 }
2102
setDashboardActionDecoration(bool isDashboardsViewActive)2103 void WorkflowView::setDashboardActionDecoration(bool isDashboardsViewActive) {
2104 if (isDashboardsViewActive) {
2105 toggleDashboard->setIconText(tr("To Workflow Designer"));
2106 toggleDashboard->setIcon(getToolbarIcon("wd.png"));
2107 toggleDashboard->setToolTip(tr("Show workflow"));
2108 } else {
2109 toggleDashboard->setIconText(tr("Go to Dashboard"));
2110 toggleDashboard->setIcon(getToolbarIcon("dashboard.png"));
2111 toggleDashboard->setToolTip(tr("Show dashboard"));
2112 }
2113 }
2114
setDashboardActionVisible(bool visible)2115 void WorkflowView::setDashboardActionVisible(bool visible) {
2116 toggleDashboard->setVisible(visible);
2117 }
2118
commitWarningsToMonitor(WorkflowAbstractRunner * t)2119 void WorkflowView::commitWarningsToMonitor(WorkflowAbstractRunner *t) {
2120 for (int i = 0; i < infoList->count(); i++) {
2121 QListWidgetItem *warning = infoList->item(i);
2122 foreach (WorkflowMonitor *monitor, t->getMonitors()) {
2123 monitor->addError(warning->data(TEXT_REF).toString(),
2124 warning->data(ACTOR_ID_REF).toString(),
2125 warning->data(TYPE_REF).toString());
2126 }
2127 }
2128 }
2129
sl_toggleDashboard()2130 void WorkflowView::sl_toggleDashboard() {
2131 if (tabView->isVisible()) {
2132 hideDashboards();
2133 } else {
2134 showDashboards();
2135 }
2136 }
2137
sl_dashboardCountChanged()2138 void WorkflowView::sl_dashboardCountChanged() {
2139 setDashboardActionVisible(tabView->hasDashboards());
2140 if (!tabView->hasDashboards()) {
2141 hideDashboards();
2142 }
2143 }
2144
sl_loadScene()2145 void WorkflowView::sl_loadScene() {
2146 if (!confirmModified()) {
2147 return;
2148 }
2149
2150 QString dir = AppContext::getSettings()->getValue(LAST_DIR, QString("")).toString();
2151 QString filter = DesignerUtils::getSchemaFileFilter(true, true);
2152 QString url;
2153 #ifdef Q_OS_DARWIN
2154 if (qgetenv(ENV_GUI_TEST).toInt() == 1 && qgetenv(ENV_USE_NATIVE_DIALOGS).toInt() == 0) {
2155 url = U2FileDialog::getOpenFileName(0, tr("Open workflow file"), dir, filter, 0, QFileDialog::DontUseNativeDialog);
2156 } else
2157 #endif
2158 url = U2FileDialog::getOpenFileName(0, tr("Open workflow file"), dir, filter);
2159 if (!url.isEmpty()) {
2160 AppContext::getSettings()->setValue(LAST_DIR, QFileInfo(url).absoluteDir().absolutePath());
2161 sl_loadScene(url, false);
2162 }
2163 }
2164
sl_loadScene(const QString & url,bool fromDashboard)2165 void WorkflowView::sl_loadScene(const QString &url, bool fromDashboard) {
2166 CHECK(!running, );
2167 if (fromDashboard && !confirmModified()) {
2168 return;
2169 }
2170 loadWorkflowSceneTask = new LoadWorkflowSceneTask(schema, &meta, scene, url, fromDashboard, fromDashboard); // FIXME unsynchronized meta usage
2171 TaskSignalMapper *m = new TaskSignalMapper(loadWorkflowSceneTask.data());
2172 connect(m, SIGNAL(si_taskFinished(Task *)), SLOT(sl_onSceneLoaded()));
2173 if (LoadWorkflowTask::detectFormat(IOAdapterUtils::readFileHeader(url)) == LoadWorkflowTask::XML) {
2174 connect(m, SIGNAL(si_taskFinished(Task *)), SLOT(sl_xmlSchemaLoaded(Task *)));
2175 }
2176 AppContext::getTaskScheduler()->registerTopLevelTask(loadWorkflowSceneTask);
2177 }
2178
sl_xmlSchemaLoaded(Task * t)2179 void WorkflowView::sl_xmlSchemaLoaded(Task *t) {
2180 assert(t != nullptr);
2181 if (!t->hasError()) {
2182 QMessageBox::warning(this, tr("Warning!"), QObject::tr("You opened obsolete workflow in XML format. It is strongly recommended"
2183 " to clear working space and create workflow from scratch."));
2184 } else {
2185 QMessageBox::warning(this, tr("Warning!"), QObject::tr("Sorry! This workflow is obsolete and cannot be opened."));
2186 }
2187 }
2188
sl_newScene()2189 void WorkflowView::sl_newScene() {
2190 if (!confirmModified()) {
2191 return;
2192 }
2193 breakpointView->clear();
2194 bottomTabs->hide();
2195 scene->sl_reset();
2196 meta.reset();
2197 meta.name = tr("New workflow");
2198 schema->reset();
2199 sl_updateTitle();
2200 scene->setModified(false);
2201 rescale();
2202 scene->update();
2203 sl_updateUi();
2204 }
2205
sl_onSceneLoaded()2206 void WorkflowView::sl_onSceneLoaded() {
2207 breakpointView->clear();
2208 sl_updateTitle();
2209 sl_updateUi();
2210 scene->centerView();
2211
2212 scene->setModified(false);
2213 rescale();
2214 sl_refreshActorDocs();
2215 hideDashboards();
2216 tabs->setCurrentIndex(ElementsTab);
2217 startFirstAutoRunWizard();
2218 }
2219
sl_onSceneSaved()2220 void WorkflowView::sl_onSceneSaved() {
2221 Task *t = dynamic_cast<Task *>(sender());
2222 CHECK(nullptr != t, );
2223 if (t->isFinished() && !t->hasError()) {
2224 scene->setModified(false);
2225 }
2226 }
2227
sl_updateTitle()2228 void WorkflowView::sl_updateTitle() {
2229 setWindowTitle(tr("Workflow Designer - %1").arg(meta.name));
2230 }
2231
sl_updateUi()2232 void WorkflowView::sl_updateUi() {
2233 scene->setModified(false);
2234 showWizard->setVisible(!schema->getWizards().isEmpty());
2235 estimateAction->setVisible(!meta.estimationsCode.isEmpty());
2236 }
2237
saveState()2238 void WorkflowView::saveState() {
2239 AppContext::getSettings()->setValue(SPLITTER_STATE, splitter->saveState());
2240 AppContext::getSettings()->setValue(EDITOR_STATE, propertyEditor->saveState());
2241 AppContext::getSettings()->setValue(PALETTE_STATE, palette->saveState());
2242 AppContext::getSettings()->setValue(TABS_STATE, tabs->currentIndex());
2243 }
2244
onCloseEvent()2245 bool WorkflowView::onCloseEvent() {
2246 saveState();
2247 if (!confirmModified()) {
2248 return false;
2249 }
2250 if (go) {
2251 go->setView(nullptr);
2252 }
2253 return true;
2254 }
2255
confirmModified()2256 bool WorkflowView::confirmModified() {
2257 propertyEditor->commit();
2258 if (scene->isModified() && !scene->items().isEmpty()) {
2259 AppContext::getMainWindow()->getMDIManager()->activateWindow(this);
2260 int ret = QMessageBox::question(this, tr("Workflow Designer"), tr("The workflow has been modified.\n"
2261 "Do you want to save changes?"),
2262 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
2263 QMessageBox::Save);
2264 if (QMessageBox::Cancel == ret) {
2265 return false;
2266 } else if (QMessageBox::Discard != ret) {
2267 sl_saveScene();
2268 }
2269 }
2270 return true;
2271 }
2272
newActorLabel(ActorPrototype * proto,const QList<Actor * > & procs)2273 static QString newActorLabel(ActorPrototype *proto, const QList<Actor *> &procs) {
2274 QStringList allLabels;
2275 foreach (Actor *actor, procs) {
2276 allLabels << actor->getLabel();
2277 }
2278 return WorkflowUtils::createUniqueString(proto->getDisplayName(), " ", allLabels);
2279 }
2280
createActor(ActorPrototype * proto,const QVariantMap & params) const2281 Actor *WorkflowView::createActor(ActorPrototype *proto, const QVariantMap ¶ms) const {
2282 assert(nullptr != proto);
2283 QString pId = proto->getId().replace(QRegExp("\\s"), "-");
2284 ActorId id = Schema::uniqueActorId(pId, schema->getProcesses());
2285 Actor *actor = proto->createInstance(id, nullptr, params);
2286 assert(nullptr != actor);
2287
2288 actor->setLabel(newActorLabel(proto, schema->getProcesses()));
2289 return actor;
2290 }
2291
onModified()2292 void WorkflowView::onModified() {
2293 scene->onModified();
2294 }
2295
tryBind(WorkflowPortItem * from,WorkflowPortItem * to)2296 WorkflowBusItem *WorkflowView::tryBind(WorkflowPortItem *from, WorkflowPortItem *to) {
2297 WorkflowBusItem *dit = nullptr;
2298
2299 if (from->getPort()->canBind(to->getPort())) {
2300 Port *src = from->getPort();
2301 Port *dest = to->getPort();
2302 if (src->isInput()) {
2303 src = to->getPort();
2304 dest = from->getPort();
2305 }
2306 if (WorkflowUtils::isPathExist(src, dest)) {
2307 return nullptr;
2308 }
2309
2310 Link *link = new Link(src, dest);
2311 schema->addFlow(link);
2312 dit = scene->addFlow(from, to, link);
2313 removeEstimations();
2314 }
2315 return dit;
2316 }
2317
sl_updateSchema()2318 void WorkflowView::sl_updateSchema() {
2319 schema->update();
2320 }
2321
getSchema() const2322 QSharedPointer<Schema> WorkflowView::getSchema() const {
2323 return schema;
2324 }
2325
getMeta()2326 const Workflow::Metadata &WorkflowView::getMeta() {
2327 return updateMeta();
2328 }
2329
updateMeta()2330 const Workflow::Metadata &WorkflowView::updateMeta() {
2331 meta.setSampleMark(false);
2332 meta.resetVisual();
2333 foreach (QGraphicsItem *it, scene->items()) {
2334 switch (it->type()) {
2335 case WorkflowProcessItemType: {
2336 WorkflowProcessItem *proc = qgraphicsitem_cast<WorkflowProcessItem *>(it);
2337 ActorVisualData visual(proc->getProcess()->getId());
2338 visual.setPos(proc->pos());
2339 ItemViewStyle *style = proc->getStyleById(proc->getStyle());
2340 if (nullptr != style) {
2341 visual.setStyle(style->getId());
2342 if (style->getBgColor() != style->defaultColor()) {
2343 visual.setColor(style->getBgColor());
2344 }
2345 if (style->defaultFont() != QFont()) {
2346 visual.setFont(style->defaultFont());
2347 }
2348 if (ItemStyles::EXTENDED == style->getId()) {
2349 ExtendedProcStyle *eStyle = dynamic_cast<ExtendedProcStyle *>(style);
2350 if (!eStyle->isAutoResized()) {
2351 visual.setRect(eStyle->boundingRect());
2352 }
2353 }
2354 }
2355 foreach (WorkflowPortItem *port, proc->getPortItems()) {
2356 visual.setPortAngle(port->getPort()->getId(), port->getOrientarion());
2357 }
2358 meta.setActorVisualData(visual);
2359 } break;
2360 case WorkflowBusItemType: {
2361 WorkflowBusItem *bus = qgraphicsitem_cast<WorkflowBusItem *>(it);
2362 Port *src = bus->getBus()->source();
2363 Port *dst = bus->getBus()->destination();
2364 QPointF p = bus->getText()->pos();
2365 meta.setTextPos(src->owner()->getId(), src->getId(), dst->owner()->getId(), dst->getId(), p);
2366 } break;
2367 }
2368 }
2369 return meta;
2370 }
2371
getMeta(const QList<WorkflowProcessItem * > & items)2372 Workflow::Metadata WorkflowView::getMeta(const QList<WorkflowProcessItem *> &items) {
2373 const Workflow::Metadata &meta = getMeta();
2374 Workflow::Metadata result;
2375 result.name = meta.name;
2376 result.url = meta.url;
2377 result.comment = meta.comment;
2378
2379 foreach (WorkflowProcessItem *proc, items) {
2380 bool contains = false;
2381 ActorVisualData visual = meta.getActorVisualData(proc->getProcess()->getId(), contains);
2382 assert(contains);
2383 result.setActorVisualData(visual);
2384 foreach (WorkflowPortItem *port1, proc->getPortItems()) {
2385 foreach (WorkflowBusItem *bus, port1->getDataFlows()) {
2386 WorkflowPortItem *port2 = (bus->getInPort() == port1) ? bus->getOutPort() : bus->getInPort();
2387 WorkflowProcessItem *proc2 = port2->getOwner();
2388 if (!items.contains(proc2)) {
2389 continue;
2390 }
2391 Port *src = bus->getBus()->source();
2392 Port *dst = bus->getBus()->destination();
2393 QPointF p = meta.getTextPos(src->owner()->getId(), src->getId(), dst->owner()->getId(), dst->getId(), contains);
2394 if (contains) {
2395 result.setTextPos(src->owner()->getId(), src->getId(), dst->owner()->getId(), dst->getId(), p);
2396 }
2397 }
2398 }
2399 }
2400 return result;
2401 }
2402
getRFS()2403 RunFileSystem *WorkflowView::getRFS() {
2404 RunFileSystem *result = new RunFileSystem(this);
2405 RFSUtils::initRFS(*result, schema->getProcesses(), this);
2406 return result;
2407 }
2408
getAttributeValue(const AttributeInfo & info) const2409 QVariant WorkflowView::getAttributeValue(const AttributeInfo &info) const {
2410 Actor *actor = schema->actorById(info.actorId);
2411 CHECK(nullptr != actor, QVariant());
2412 Attribute *attr = actor->getParameter(info.attrId);
2413 CHECK(nullptr != attr, QVariant());
2414 return attr->getAttributePureValue();
2415 }
2416
setAttributeValue(const AttributeInfo & info,const QVariant & value)2417 void WorkflowView::setAttributeValue(const AttributeInfo &info, const QVariant &value) {
2418 Actor *actor = schema->actorById(info.actorId);
2419 CHECK(nullptr != actor, );
2420 Attribute *attr = actor->getParameter(info.attrId);
2421 CHECK(nullptr != attr, );
2422 attr->setAttributeValue(value);
2423 }
2424
isShowSamplesHint() const2425 bool WorkflowView::isShowSamplesHint() const {
2426 SAFE_POINT(nullptr != samples, "NULL samples widget", false);
2427 SAFE_POINT(nullptr != schema, "NULL schema", false);
2428 const bool emptySchema = (0 == schema->getProcesses().size());
2429 return samples->isVisible() && emptySchema;
2430 }
2431
2432 /********************************
2433 * WorkflowScene
2434 ********************************/
canDrop(const QMimeData * m,QList<ActorPrototype * > & lst)2435 static bool canDrop(const QMimeData *m, QList<ActorPrototype *> &lst) {
2436 if (m->hasFormat(WorkflowPalette::MIME_TYPE)) {
2437 QString id(m->data(WorkflowPalette::MIME_TYPE));
2438 ActorPrototype *proto = WorkflowEnv::getProtoRegistry()->getProto(id);
2439 if (proto) {
2440 lst << proto;
2441 }
2442 } else {
2443 foreach (QList<ActorPrototype *> l, WorkflowEnv::getProtoRegistry()->getProtos().values()) {
2444 foreach (ActorPrototype *proto, l) {
2445 if (proto->isAcceptableDrop(m)) {
2446 lst << proto;
2447 }
2448 }
2449 }
2450 }
2451 return !lst.isEmpty();
2452 }
2453
WorkflowScene(WorkflowView * parent)2454 WorkflowScene::WorkflowScene(WorkflowView *parent)
2455 : QGraphicsScene(parent), controller(parent), modified(false), locked(false), runner(nullptr), hint(0) {
2456 openDocumentsAction = new QAction(tr("Open document(s)"), this);
2457 connect(openDocumentsAction, SIGNAL(triggered()), SLOT(sl_openDocuments()));
2458 }
2459
~WorkflowScene()2460 WorkflowScene::~WorkflowScene() {
2461 sl_reset();
2462 }
2463
sl_deleteItem()2464 void WorkflowScene::sl_deleteItem() {
2465 assert(!locked);
2466 QList<WorkflowProcessItem *> items;
2467 foreach (QGraphicsItem *it, selectedItems()) {
2468 WorkflowProcessItem *proc = qgraphicsitem_cast<WorkflowProcessItem *>(it);
2469 WorkflowBusItem *bus = qgraphicsitem_cast<WorkflowBusItem *>(it);
2470 switch (it->type()) {
2471 case WorkflowProcessItemType:
2472 items << proc;
2473 break;
2474 case WorkflowBusItemType:
2475 controller->removeBusItem(bus);
2476 setModified();
2477 break;
2478 }
2479 }
2480 foreach (WorkflowProcessItem *it, items) {
2481 if (it->getProcess() != nullptr) {
2482 emit si_itemDeleted(it->getProcess()->getId());
2483 }
2484 controller->removeProcessItem(it);
2485 setModified();
2486 }
2487
2488 controller->update();
2489 emit configurationChanged();
2490 update();
2491 }
2492
getSelectedActors() const2493 QList<Actor *> WorkflowScene::getSelectedActors() const {
2494 QList<Actor *> list;
2495 foreach (QGraphicsItem *item, selectedItems()) {
2496 if (item->type() == WorkflowProcessItemType) {
2497 list << static_cast<WorkflowProcessItem *>(item)->getProcess();
2498 }
2499 }
2500 return list;
2501 }
2502
contextMenuEvent(QGraphicsSceneContextMenuEvent * e)2503 void WorkflowScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *e) {
2504 QGraphicsScene::contextMenuEvent(e);
2505 if (!e->isAccepted()) {
2506 QMenu menu;
2507 controller->setupContextMenu(&menu);
2508 e->accept();
2509 menu.exec(e->screenPos());
2510 }
2511 }
2512
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * mouseEvent)2513 void WorkflowScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent) {
2514 if (!mouseEvent->isAccepted() && (mouseEvent->button() == Qt::LeftButton) && !selectedItems().isEmpty()) {
2515 emit processDblClicked();
2516 }
2517 QGraphicsScene::mousePressEvent(mouseEvent);
2518 }
2519
dragEnterEvent(QGraphicsSceneDragDropEvent * event)2520 void WorkflowScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event) {
2521 QList<ActorPrototype *> lst;
2522 if (!locked && canDrop(event->mimeData(), lst)) {
2523 event->acceptProposedAction();
2524 } else {
2525 QGraphicsScene::dragEnterEvent(event);
2526 }
2527 }
2528
dragMoveEvent(QGraphicsSceneDragDropEvent * event)2529 void WorkflowScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event) {
2530 QList<ActorPrototype *> lst;
2531 if (!locked && canDrop(event->mimeData(), lst)) {
2532 event->acceptProposedAction();
2533 } else {
2534 QGraphicsScene::dragMoveEvent(event);
2535 }
2536 }
2537
dropEvent(QGraphicsSceneDragDropEvent * event)2538 void WorkflowScene::dropEvent(QGraphicsSceneDragDropEvent *event) {
2539 QList<ActorPrototype *> lst;
2540 if (!locked && canDrop(event->mimeData(), lst)) {
2541 QList<QGraphicsItem *> targets = items(event->scenePos());
2542 bool done = false;
2543 foreach (QGraphicsItem *it, targets) {
2544 WorkflowProcessItem *target = qgraphicsitem_cast<WorkflowProcessItem *>(it);
2545 if (target && lst.contains(target->getProcess()->getProto())) {
2546 clearSelection();
2547 QVariantMap params;
2548 Actor *a = target->getProcess();
2549 a->getProto()->isAcceptableDrop(event->mimeData(), ¶ms);
2550 QMapIterator<QString, QVariant> cfg(params);
2551 while (cfg.hasNext()) {
2552 cfg.next();
2553 a->setParameter(cfg.key(), cfg.value());
2554 }
2555 target->setSelected(true);
2556 done = true;
2557 break;
2558 }
2559 }
2560 if (!done) {
2561 ActorPrototype *proto = lst.size() > 1 ? ChooseItemDialog(controller).select(lst) : lst.first();
2562 if (proto) {
2563 Actor *a = controller->getActor();
2564 if (a) {
2565 controller->addProcess(a, event->scenePos());
2566 }
2567 event->setDropAction(Qt::CopyAction);
2568 }
2569 }
2570 }
2571 QGraphicsScene::dropEvent(event);
2572 }
2573
keyPressEvent(QKeyEvent * event)2574 void WorkflowScene::keyPressEvent(QKeyEvent *event) {
2575 if (event->key() == Qt::Key_Shift) {
2576 views().at(0)->setDragMode(QGraphicsView::ScrollHandDrag);
2577 }
2578 QGraphicsScene::keyPressEvent(event);
2579 }
2580
keyReleaseEvent(QKeyEvent * event)2581 void WorkflowScene::keyReleaseEvent(QKeyEvent *event) {
2582 QGraphicsView *v = views().at(0);
2583 if (v->dragMode() == QGraphicsView::ScrollHandDrag) {
2584 v->setDragMode(QGraphicsView::RubberBandDrag);
2585 }
2586 QGraphicsScene::keyReleaseEvent(event);
2587 }
2588
clearScene()2589 void WorkflowScene::clearScene() {
2590 sl_reset();
2591 }
2592
setupLinkCtxMenu(const QString & href,Actor * actor,const QPoint & pos)2593 void WorkflowScene::setupLinkCtxMenu(const QString &href, Actor *actor, const QPoint &pos) {
2594 const QString attributeId = WorkflowUtils::getParamIdFromHref(href);
2595 bool isInput = attributeId == BaseAttributes::URL_IN_ATTRIBUTE().getId();
2596 bool isOutput = attributeId == BaseAttributes::URL_OUT_ATTRIBUTE().getId();
2597 if (isInput || isOutput) {
2598 Attribute *attribute = actor->getParameter(attributeId);
2599 QString urlStr;
2600 const QStringList urlList = WorkflowUtils::getAttributeUrls(attribute);
2601
2602 foreach (const QString &url, urlList) {
2603 if (QFileInfo(url).isFile()) {
2604 urlStr.append(url).append(';');
2605 }
2606 }
2607 urlStr = urlStr.left(urlStr.size() - 1);
2608
2609 if (!urlStr.isEmpty()) {
2610 QMenu menu;
2611 openDocumentsAction->setData(urlStr);
2612 menu.addAction(openDocumentsAction);
2613 menu.exec(pos);
2614 }
2615 }
2616 }
2617
sl_openDocuments()2618 void WorkflowScene::sl_openDocuments() {
2619 const QString &urlStr = openDocumentsAction->data().value<QString>();
2620 const QStringList &_urls = WorkflowUtils::expandToUrls(urlStr);
2621 QList<GUrl> urls;
2622 foreach (const QString &url, _urls) {
2623 urls.append(url);
2624 }
2625 Task *t = AppContext::getProjectLoader()->openWithProjectTask(urls);
2626 if (t) {
2627 AppContext::getTaskScheduler()->registerTopLevelTask(t);
2628 } else {
2629 QMessageBox::critical(controller, tr("Workflow Designer"), tr("Unable to open specified documents. Watch log for details."));
2630 }
2631 }
2632
mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent)2633 void WorkflowScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) {
2634 if (!locked && !mouseEvent->isAccepted() && controller->selectedProto() && (mouseEvent->button() == Qt::LeftButton)) {
2635 controller->addProcess(controller->getActor(), mouseEvent->scenePos());
2636 }
2637 lastMousePressPoint = mouseEvent->scenePos();
2638 QGraphicsScene::mousePressEvent(mouseEvent);
2639 }
2640
sl_selectAll()2641 void WorkflowScene::sl_selectAll() {
2642 foreach (QGraphicsItem *it, items()) {
2643 it->setSelected(true);
2644 }
2645 }
2646
sl_deselectAll()2647 void WorkflowScene::sl_deselectAll() {
2648 foreach (QGraphicsItem *it, items()) {
2649 it->setSelected(false);
2650 }
2651 }
2652
sl_reset()2653 void WorkflowScene::sl_reset() {
2654 QList<QGraphicsItem *> list;
2655 QList<QGraphicsItem *> itemss = items();
2656 foreach (QGraphicsItem *it, itemss) {
2657 if (it->type() == WorkflowProcessItemType) {
2658 list << it;
2659 }
2660 }
2661 modified = false;
2662 foreach (QGraphicsItem *it, list) {
2663 removeItem(it);
2664 delete it;
2665 }
2666 }
2667
setModified(bool b)2668 void WorkflowScene::setModified(bool b) {
2669 modified = b;
2670 update();
2671 }
2672
setModified()2673 void WorkflowScene::setModified() {
2674 setModified(true);
2675 }
2676
drawBackground(QPainter * painter,const QRectF & rect)2677 void WorkflowScene::drawBackground(QPainter *painter, const QRectF &rect) {
2678 if (WorkflowSettings::showGrid()) {
2679 int step = GRID_STEP;
2680 painter->setPen(QPen(QColor(200, 200, 255, 125)));
2681 // draw horizontal grid
2682 qreal start = round(rect.top(), step);
2683 if (start > rect.top()) {
2684 start -= step;
2685 }
2686 for (qreal y = start - step; y < rect.bottom();) {
2687 y += step;
2688 painter->drawLine(rect.left(), y, rect.right(), y);
2689 }
2690 // now draw vertical grid
2691 start = round(rect.left(), step);
2692 if (start > rect.left()) {
2693 start -= step;
2694 }
2695 for (qreal x = start - step; x < rect.right();) {
2696 x += step;
2697 painter->drawLine(x, rect.top(), x, rect.bottom());
2698 }
2699 }
2700
2701 if (items().size() == 0) {
2702 // draw a hint on empty scene
2703 painter->setPen(Qt::darkGray);
2704 QFont f = painter->font();
2705 if (hint == SamplesTab) {
2706 } else {
2707 QTransform trans = painter->combinedTransform();
2708 f.setFamily("Courier New");
2709 f.setPointSizeF(f.pointSizeF() * 2. / trans.m11());
2710 painter->setFont(f);
2711 QRectF res;
2712 painter->drawText(sceneRect(), Qt::AlignCenter, tr("Drop an element from the palette here"), &res);
2713 QPixmap pix(":workflow_designer/images/leftarrow.png");
2714 QPointF pos(res.left(), res.center().y());
2715 pos.rx() -= pix.width() + GRID_STEP;
2716 pos.ry() -= pix.height() / 2;
2717 painter->drawPixmap(pos, pix);
2718 }
2719 }
2720 }
2721
onModified()2722 void WorkflowScene::onModified() {
2723 assert(!locked);
2724 modified = true;
2725 emit configurationChanged();
2726 }
2727
centerView()2728 void WorkflowScene::centerView() {
2729 QRectF childRect;
2730 foreach (QGraphicsItem *child, items()) {
2731 QPointF childPos = child->pos();
2732 QTransform matrix = child->transform() * QTransform().translate(childPos.x(), childPos.y());
2733 childRect |= matrix.mapRect(child->boundingRect() | child->childrenBoundingRect());
2734 }
2735 update();
2736 }
2737
addFlow(WorkflowPortItem * from,WorkflowPortItem * to,Link * link)2738 WorkflowBusItem *WorkflowScene::addFlow(WorkflowPortItem *from, WorkflowPortItem *to, Link *link) {
2739 WorkflowBusItem *dit = new WorkflowBusItem(from, to, link);
2740 from->addDataFlow(dit);
2741 to->addDataFlow(dit);
2742
2743 addItem(dit);
2744 dit->updatePos();
2745 setModified(true);
2746 return dit;
2747 }
2748
connectConfigurationEditors()2749 void WorkflowScene::connectConfigurationEditors() {
2750 foreach (QGraphicsItem *i, items()) {
2751 if (i->type() == WorkflowProcessItemType) {
2752 Actor *proc = static_cast<WorkflowProcessItem *>(i)->getProcess();
2753 ConfigurationEditor *editor = proc->getEditor();
2754 if (nullptr != editor) {
2755 connect(editor, SIGNAL(si_configurationChanged()), this, SIGNAL(configurationChanged()));
2756 }
2757 GrouperEditor *g = dynamic_cast<GrouperEditor *>(editor);
2758 MarkerEditor *m = dynamic_cast<MarkerEditor *>(editor);
2759 if (nullptr != g || nullptr != m) {
2760 connect(editor, SIGNAL(si_configurationChanged()), controller, SLOT(sl_updateSchema()));
2761 }
2762 }
2763 }
2764 }
2765
2766 /************************************************************************/
2767 /* SceneCreator */
2768 /************************************************************************/
SceneCreator(Schema * _schema,const Workflow::Metadata & _meta)2769 SceneCreator::SceneCreator(Schema *_schema, const Workflow::Metadata &_meta)
2770 : schema(_schema), meta(_meta), scene(nullptr) {
2771 }
2772
~SceneCreator()2773 SceneCreator::~SceneCreator() {
2774 delete scene;
2775 }
2776
recreateScene(WorkflowScene * _scene)2777 WorkflowScene *SceneCreator::recreateScene(WorkflowScene *_scene) {
2778 scene = _scene;
2779 scene->sl_reset();
2780 return createScene();
2781 }
2782
createScene(WorkflowView * controller)2783 WorkflowScene *SceneCreator::createScene(WorkflowView *controller) {
2784 scene = new WorkflowScene(controller);
2785 scene->setSceneRect(QRectF(-3 * WS, -3 * WS, 5 * WS, 5 * WS));
2786 scene->setItemIndexMethod(QGraphicsScene::NoIndex);
2787 scene->setObjectName("scene");
2788 return createScene();
2789 }
2790
createScene()2791 WorkflowScene *SceneCreator::createScene() {
2792 QMap<Port *, WorkflowPortItem *> ports;
2793 foreach (Actor *actor, schema->getProcesses()) {
2794 WorkflowProcessItem *procItem = createProcess(actor);
2795 scene->addItem(procItem);
2796 foreach (WorkflowPortItem *portItem, procItem->getPortItems()) {
2797 ports[portItem->getPort()] = portItem;
2798 }
2799 }
2800
2801 foreach (Link *link, schema->getFlows()) {
2802 createBus(ports, link);
2803 }
2804
2805 WorkflowScene *result = scene;
2806 scene = nullptr;
2807 return result;
2808 }
2809
createProcess(Actor * actor)2810 WorkflowProcessItem *SceneCreator::createProcess(Actor *actor) {
2811 WorkflowProcessItem *procItem = new WorkflowProcessItem(actor);
2812 bool contains = false;
2813 ActorVisualData visual = meta.getActorVisualData(actor->getId(), contains);
2814 if (!contains) {
2815 return procItem;
2816 }
2817 QPointF p = visual.getPos(contains);
2818 if (contains) {
2819 procItem->setPos(p);
2820 }
2821 QString s = visual.getStyle(contains);
2822 if (contains) {
2823 procItem->setStyle(s);
2824 {
2825 ItemViewStyle *eStyle = procItem->getStyleById(ItemStyles::EXTENDED);
2826 ItemViewStyle *sStyle = procItem->getStyleById(ItemStyles::SIMPLE);
2827 QColor c = visual.getColor(contains);
2828 if (contains) {
2829 eStyle->setBgColor(c);
2830 sStyle->setBgColor(c);
2831 }
2832 QFont f = visual.getFont(contains);
2833 if (contains) {
2834 eStyle->setDefaultFont(f);
2835 sStyle->setDefaultFont(f);
2836 }
2837 QRectF r = visual.getRect(contains);
2838 if (contains) {
2839 qobject_cast<ExtendedProcStyle *>(eStyle)->setFixedBounds(r);
2840 }
2841 }
2842 }
2843 foreach (WorkflowPortItem *portItem, procItem->getPortItems()) {
2844 Port *port = portItem->getPort();
2845 qreal a = visual.getPortAngle(port->getId(), contains);
2846 if (contains) {
2847 portItem->setOrientation(a);
2848 }
2849 }
2850 return procItem;
2851 }
2852
createBus(const QMap<Port *,WorkflowPortItem * > & ports,Link * link)2853 void SceneCreator::createBus(const QMap<Port *, WorkflowPortItem *> &ports, Link *link) {
2854 WorkflowPortItem *src = ports[link->source()];
2855 WorkflowPortItem *dst = ports[link->destination()];
2856 WorkflowBusItem *busItem = scene->addFlow(src, dst, link);
2857 ActorId srcActorId = src->getOwner()->getProcess()->getId();
2858 ActorId dstActorId = dst->getOwner()->getProcess()->getId();
2859
2860 bool contains = false;
2861 QPointF p = meta.getTextPos(srcActorId, link->source()->getId(), dstActorId, link->destination()->getId(), contains);
2862 if (contains) {
2863 busItem->getText()->setPos(p);
2864 }
2865 }
2866
2867 } // namespace U2
2868