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 "Schema.h"
23
24 #include <U2Core/U2OpStatusUtils.h>
25 #include <U2Core/U2SafePoints.h>
26
27 #include <U2Lang/ActorModel.h>
28 #include <U2Lang/IntegralBusType.h>
29 #include <U2Lang/Wizard.h>
30 #include <U2Lang/WorkflowEnv.h>
31 #include <U2Lang/WorkflowUtils.h>
32
33 namespace U2 {
34 namespace Workflow {
35
36 /**************************
37 * Schema
38 **************************/
Schema()39 Schema::Schema()
40 : deepCopy(false) {
41 }
42
~Schema()43 Schema::~Schema() {
44 reset();
45 }
46
Schema(const Schema & other)47 Schema::Schema(const Schema &other) {
48 *this = other;
49 }
50
operator =(const Schema & other)51 Schema &Schema::operator=(const Schema &other) {
52 procs = other.procs;
53 domain = other.domain;
54 graph = ActorBindingsGraph(other.graph);
55 deepCopy = false;
56 portAliases = other.portAliases;
57 includedTypeName = other.includedTypeName;
58 return *this;
59 }
60
reset()61 void Schema::reset() {
62 if (deepCopy) {
63 qDeleteAll(procs);
64 procs.clear();
65 }
66 graph.clear();
67 qDeleteAll(wizards);
68 wizards.clear();
69 }
70
applyConfiguration(const QMap<ActorId,QVariantMap> & cfg)71 void Schema::applyConfiguration(const QMap<ActorId, QVariantMap> &cfg) {
72 foreach (Actor *a, procs) {
73 if (cfg.contains(a->getId())) {
74 a->setParameters(cfg[a->getId()]);
75 }
76 }
77 }
78
actorById(ActorId id) const79 Actor *Schema::actorById(ActorId id) const {
80 return WorkflowUtils::actorById(procs, id);
81 }
82
actorsByOwnerId(ActorId id) const83 QList<Actor *> Schema::actorsByOwnerId(ActorId id) const {
84 QList<Actor *> res;
85 foreach (Actor *proc, procs) {
86 if (proc->getOwner() == id) {
87 res.append(proc);
88 }
89 }
90 return res;
91 }
92
getDomain() const93 QString Schema::getDomain() const {
94 return domain;
95 }
96
setDomain(const QString & d)97 void Schema::setDomain(const QString &d) {
98 domain = d;
99 }
100
getActorBindingsGraph() const101 const ActorBindingsGraph &Schema::getActorBindingsGraph() const {
102 return graph;
103 }
104
getProcesses() const105 const QList<Actor *> &Schema::getProcesses() const {
106 return procs;
107 }
108
addProcess(Actor * a)109 void Schema::addProcess(Actor *a) {
110 assert(a != nullptr);
111 procs.append(a);
112 }
113
getFlows() const114 QList<Link *> Schema::getFlows() const {
115 return graph.getFlows();
116 }
117
addFlow(Link * l)118 void Schema::addFlow(Link *l) {
119 assert(l != nullptr);
120 graph.addBinding(l->source(), l->destination());
121 }
122
setDeepCopyFlag(bool flag)123 void Schema::setDeepCopyFlag(bool flag) {
124 deepCopy = flag;
125 }
126
hasParamAliases() const127 bool Schema::hasParamAliases() const {
128 foreach (Actor *actor, procs) {
129 if (actor->hasParamAliases()) {
130 return true;
131 }
132 }
133 return false;
134 }
135
hasAliasHelp() const136 bool Schema::hasAliasHelp() const {
137 foreach (Actor *a, procs) {
138 if (a->hasAliasHelp()) {
139 return true;
140 }
141 }
142 return false;
143 }
144
hasPortAliases() const145 bool Schema::hasPortAliases() const {
146 return !portAliases.isEmpty();
147 }
148
getPortAliases() const149 const QList<PortAlias> &Schema::getPortAliases() const {
150 return portAliases;
151 }
152
addPortAlias(const PortAlias & newAlias)153 bool Schema::addPortAlias(const PortAlias &newAlias) {
154 foreach (const PortAlias &alias, portAliases) {
155 if (alias.getAlias() == newAlias.getAlias()) {
156 return false;
157 }
158 if (alias.getSourcePort() == newAlias.getSourcePort()) {
159 return false;
160 }
161 }
162
163 portAliases.append(newAlias);
164 return true;
165 }
166
setPortAliases(const QList<PortAlias> & aliases)167 void Schema::setPortAliases(const QList<PortAlias> &aliases) {
168 portAliases = aliases;
169 }
170
getTypeName() const171 QString Schema::getTypeName() const {
172 return includedTypeName;
173 }
174
setTypeName(const QString & typeName)175 void Schema::setTypeName(const QString &typeName) {
176 this->includedTypeName = typeName;
177 }
178
179 using namespace std;
180
recursiveExpand(QList<QString> & schemaIds)181 bool Schema::recursiveExpand(QList<QString> &schemaIds) {
182 QMap<Actor *, Schema *> subSchemas;
183
184 // Expand all processes
185 foreach (Actor *proc, procs) {
186 ActorPrototype *proto = proc->getProto();
187 if (!proto->isSchemaFlagSet()) {
188 continue;
189 }
190
191 if (schemaIds.contains(proto->getId())) {
192 return false;
193 }
194
195 Schema *schema = WorkflowEnv::getSchemaActorsRegistry()->getSchema(proto->getId());
196 if (nullptr == schema) {
197 return false;
198 }
199
200 QList<QString> newIdList(schemaIds);
201 newIdList.append(proto->getId());
202 bool res = schema->recursiveExpand(newIdList);
203 if (!res) {
204 return false;
205 }
206
207 subSchemas.insert(proc, schema);
208 }
209
210 // Everything is all right after expanding. So replace expanded processes
211 for (Actor *proc : qAsConst(procs)) {
212 if (!proc->getProto()->isSchemaFlagSet()) {
213 continue;
214 }
215 Schema *schema = subSchemas.value(proc);
216
217 // set owner
218 foreach (Actor *subProc, schema->getProcesses()) {
219 subProc->setOwner(proc->getId());
220 }
221
222 // replace parameters
223 foreach (Actor *subProc, schema->getProcesses()) {
224 if (subProc->hasParamAliases()) {
225 setAliasedAttributes(proc, subProc);
226 }
227 }
228
229 // replace ports and slots
230 foreach (const PortAlias &subPortAlias, schema->getPortAliases()) {
231 if (subPortAlias.isInput()) {
232 replaceInLinksAndSlots(proc, subPortAlias);
233 } else {
234 replaceOutLinks(proc, subPortAlias);
235 replaceOutSlots(proc, subPortAlias);
236 }
237
238 if (this->hasPortAliases()) {
239 replacePortAliases(subPortAlias);
240 }
241 }
242
243 graph.getBindings().unite(schema->graph.getBindings());
244
245 // replace procs
246 procs.removeOne(proc);
247 procs.append(schema->getProcesses());
248 }
249
250 return true;
251 }
252
expand()253 bool Schema::expand() {
254 QList<QString> emptyList;
255 return this->recursiveExpand(emptyList);
256 }
257
setAliasedAttributes(Actor * proc,Actor * subProc)258 void Schema::setAliasedAttributes(Actor *proc, Actor *subProc) {
259 QMap<QString, QString> newParamAliases;
260
261 foreach (QString subAttrId, subProc->getParamAliases().keys()) {
262 QString alias = subProc->getParamAliases().value(subAttrId);
263
264 QVariant value = proc->getParameter(alias)->getAttributePureValue();
265 subProc->getParameter(subAttrId)->setAttributeValue(value);
266 AttributeScript script = proc->getParameter(alias)->getAttributeScript();
267 subProc->getParameter(subAttrId)->getAttributeScript() = script;
268
269 if (proc->getParamAliases().keys().contains(alias)) {
270 newParamAliases.insert(subAttrId, proc->getParamAliases().value(alias));
271 }
272 }
273 subProc->getParamAliases() = newParamAliases;
274 }
275
276 typedef QPair<QString, QString> SlotPair;
277
replaceInLinksAndSlots(Actor * proc,const PortAlias & portAlias)278 void Schema::replaceInLinksAndSlots(Actor *proc, const PortAlias &portAlias) {
279 Port *port = proc->getPort(portAlias.getAlias());
280 Actor *subProc = portAlias.getSourcePort()->owner();
281 Port *subPort = subProc->getPort(portAlias.getSourcePort()->getId());
282
283 const QList<Link *> &links = this->getFlows();
284 for (Link *link: qAsConst(links)) {
285 if (link->destination() == port) {
286 // replace ports link
287 removeFlow(link);
288 link->connect(link->source(), subPort);
289 addFlow(link);
290
291 // replace slots links and paths
292 Attribute *busMapAttr = port->getParameter(IntegralBusPort::BUS_MAP_ATTR_ID);
293 Attribute *pathsAttr = port->getParameter(IntegralBusPort::PATHS_ATTR_ID);
294 StrStrMap busMap = busMapAttr->getAttributeValueWithoutScript<StrStrMap>();
295 SlotPathMap pathMap = pathsAttr->getAttributeValueWithoutScript<SlotPathMap>();
296 StrStrMap subBusMap;
297 SlotPathMap subPathMap;
298
299 QList<SlotAlias> portSlotAliases = portAlias.getSlotAliases();
300 for (const SlotAlias &slotAlias : qAsConst(portSlotAliases)) {
301 subBusMap[slotAlias.getSourceSlotId()] = busMap[slotAlias.getAlias()];
302
303 QList<SlotPair> pathMapKeys = pathMap.keys();
304 for (const SlotPair &slotPair : qAsConst(pathMapKeys)) {
305 if (slotAlias.getAlias() == slotPair.first) {
306 SlotPair subPair(slotAlias.getSourceSlotId(), slotPair.second);
307 foreach (const QStringList &p, pathMap.values(slotPair)) {
308 subPathMap.insertMulti(subPair, p);
309 }
310 }
311 }
312 }
313 subPort->getParameter(IntegralBusPort::BUS_MAP_ATTR_ID)->setAttributeValue(qVariantFromValue(subBusMap));
314 subPort->getParameter(IntegralBusPort::PATHS_ATTR_ID)->setAttributeValue(qVariantFromValue(subPathMap));
315 }
316 }
317 }
318
replaceOutLinks(Actor * origProc,const PortAlias & portAlias)319 void Schema::replaceOutLinks(Actor *origProc, const PortAlias &portAlias) {
320 Port *port = origProc->getPort(portAlias.getAlias());
321 Actor *subProc = portAlias.getSourcePort()->owner();
322 Port *subPort = subProc->getPort(portAlias.getSourcePort()->getId());
323
324 foreach (Link *link, this->getFlows()) {
325 if (link->source() == port) {
326 // replace only ports link
327 removeFlow(link);
328 link->connect(subPort, link->destination());
329 addFlow(link);
330 }
331 }
332 }
333
replaceOutSlots(Actor * origProc,const PortAlias & portAlias)334 void Schema::replaceOutSlots(Actor *origProc, const PortAlias &portAlias) {
335 // replace slots links
336 foreach (Actor *proc, procs) {
337 foreach (Port *p, proc->getInputPorts()) {
338 Attribute *a = p->getParameter(IntegralBusPort::BUS_MAP_ATTR_ID);
339 StrStrMap busMap = a->getAttributeValueWithoutScript<StrStrMap>();
340 StrStrMap newMap;
341
342 QMapIterator<QString, QString> it(busMap);
343 while (it.hasNext()) {
344 it.next();
345 // replace ids at slots' values
346 QString value = it.value();
347 foreach (const SlotAlias &slotAlias, portAlias.getSlotAliases()) {
348 QString origSlotId = slotAlias.getAlias();
349 QString subSlotId = slotAlias.getSourceSlotId();
350
351 QString slotString = origProc->getId() + ":" + origSlotId;
352 int idPos = value.indexOf(slotString);
353 while (idPos >= 0) {
354 Actor *subProc = slotAlias.getSourcePort()->owner();
355 value.remove(idPos, slotString.length());
356 value.insert(idPos, subProc->getId() + ":" + subSlotId);
357 idPos = value.indexOf(slotString);
358 }
359 }
360 newMap.insert(it.key(), value);
361 }
362
363 a->setAttributeValue(qVariantFromValue(newMap));
364 }
365 }
366 }
367
replacePortAliases(const PortAlias & subPortAlias)368 void Schema::replacePortAliases(const PortAlias &subPortAlias) {
369 // replace port aliases
370 QList<PortAlias> newPortAliases;
371 foreach (PortAlias origPortAlias, this->portAliases) {
372 if (origPortAlias.getSourcePort()->getId() == subPortAlias.getAlias()) {
373 origPortAlias.setNewSourcePort(subPortAlias.getSourcePort());
374 }
375
376 // replace slot aliases
377 QList<SlotAlias> newSlotAliases;
378 foreach (const SlotAlias &origSlotAlias, origPortAlias.getSlotAliases()) {
379 if (origSlotAlias.getSourcePort()->getId() == subPortAlias.getAlias()) {
380 foreach (const SlotAlias &subSlotAlias, subPortAlias.getSlotAliases()) {
381 if (subSlotAlias.getAlias() == origSlotAlias.getSourceSlotId()) {
382 SlotAlias newSlotAlias(subSlotAlias.getSourcePort(), subSlotAlias.getSourceSlotId(), origSlotAlias.getAlias());
383 newSlotAliases.append(newSlotAlias);
384 break;
385 }
386 }
387 } else {
388 newSlotAliases.append(origSlotAlias);
389 }
390 }
391 origPortAlias.setNewSlotAliases(newSlotAliases);
392 newPortAliases.append(origPortAlias);
393 }
394 this->portAliases = newPortAliases;
395 }
396
getWizards() const397 const QList<Wizard *> &Schema::getWizards() const {
398 return wizards;
399 }
400
setWizards(const QList<Wizard * > & value)401 void Schema::setWizards(const QList<Wizard *> &value) {
402 qDeleteAll(wizards);
403 wizards = value;
404 }
405
takeWizards()406 QList<Wizard *> Schema::takeWizards() {
407 QList<Wizard *> result = wizards;
408 wizards.clear();
409 return result;
410 }
411
removeProcess(Actor * actor)412 void Schema::removeProcess(Actor *actor) {
413 // remove actors flows
414 foreach (Port *p, actor->getPorts()) {
415 foreach (Link *l, p->getLinks()) {
416 removeFlow(l);
417 }
418 }
419
420 // remove actor from port aliases
421 QList<Port *> ports = actor->getPorts();
422 QList<PortAlias>::iterator i = portAliases.begin();
423 while (i != portAliases.end()) {
424 Port *p = const_cast<Port *>(i->getSourcePort());
425 if (ports.contains(p)) {
426 i = portAliases.erase(i);
427 } else {
428 ++i;
429 }
430 }
431
432 procs.removeOne(actor);
433 update();
434 }
435
update()436 void Schema::update() {
437 update(QMap<ActorId, ActorId>());
438 }
439
update(const QMap<ActorId,ActorId> & actorsMapping)440 void Schema::update(const QMap<ActorId, ActorId> &actorsMapping) {
441 // update actors from the first level of the graph to the last one
442 QMap<int, QList<Actor *>> top = graph.getTopologicalSortedGraph(procs);
443 int beginLevel = top.size() - 1;
444 for (int level = beginLevel; level >= 0; level--) {
445 foreach (Actor *a, top[level]) {
446 a->update(actorsMapping);
447 }
448 }
449 }
450
removeFlow(Link * l)451 void Schema::removeFlow(Link *l) {
452 if (graph.contains(l->source(), l->destination())) {
453 graph.removeBinding(l->source(), l->destination());
454 l->disconnect();
455 // TODO: delete l;
456 }
457 }
458
uniqueActorId(const QString & id,const QList<Actor * > & procs)459 ActorId Schema::uniqueActorId(const QString &id, const QList<Actor *> &procs) {
460 QStringList uniqueIds;
461 foreach (Actor *a, procs) {
462 uniqueIds << aid2str(a->getId());
463 }
464 QString result = WorkflowUtils::createUniqueString(id, "-", uniqueIds);
465 return str2aid(result);
466 }
467
renameProcess(const ActorId & oldId,const ActorId & newId)468 void Schema::renameProcess(const ActorId &oldId, const ActorId &newId) {
469 Actor *actor = actorById(oldId);
470 CHECK(nullptr != actor, );
471
472 actor->setId(newId);
473 QMap<ActorId, ActorId> m;
474 m[oldId] = newId;
475 foreach (Port *p, actor->getPorts()) {
476 p->remap(m);
477 }
478 update(m);
479 }
480
481 namespace {
removeAliasesDupliucates(const QList<Actor * > & actors,Actor * newActor)482 QStringList removeAliasesDupliucates(const QList<Actor *> &actors, Actor *newActor) {
483 QStringList removed;
484 QStringList allAliases;
485 foreach (Actor *actor, actors) {
486 allAliases << actor->getParamAliases().values();
487 }
488 QMap<QString, QString> newAliases = newActor->getParamAliases();
489 foreach (const QString &key, newAliases.keys()) {
490 QString alias = newAliases.value(key);
491 if (allAliases.contains(alias)) {
492 newActor->getParamAliases().remove(key);
493 newActor->getAliasHelp().remove(alias);
494 removed << alias;
495 }
496 }
497 return removed;
498 }
499 } // namespace
500
merge(Schema & other)501 void Schema::merge(Schema &other) {
502 foreach (Actor *newActor, other.procs) {
503 QStringList removed = removeAliasesDupliucates(procs, newActor);
504 foreach (const QString &alias, removed) {
505 coreLog.error(QObject::tr("Duplicate alias '%1'. It has been removed").arg(alias));
506 }
507 procs << newActor;
508 }
509 graph.getBindings().unite(other.graph.getBindings());
510 portAliases << other.portAliases;
511 }
512
replaceProcess(Actor * oldActor,Actor * newActor,const QList<PortMapping> & mappings)513 void Schema::replaceProcess(Actor *oldActor, Actor *newActor, const QList<PortMapping> &mappings) {
514 CHECK(procs.contains(oldActor), );
515 CHECK(!procs.contains(newActor), );
516 QMap<int, QList<Actor *>> top = graph.getTopologicalSortedGraph(procs);
517
518 // replace actors flows
519 foreach (Port *p, oldActor->getPorts()) {
520 U2OpStatus2Log os;
521 PortMapping pm = PortMapping::getMappingBySrcPort(p->getId(), mappings, os);
522 if (os.hasError()) {
523 continue;
524 }
525 foreach (Link *l, p->getLinks()) {
526 Port *p1 = l->source() == p ? l->destination() : l->source();
527 Port *p2 = newActor->getPort(pm.getDstId());
528 removeFlow(l);
529 Link *newLink = new Link(p1, p2);
530 addFlow(newLink);
531 if (p2->isInput()) {
532 IntegralBusPort *oldPort = dynamic_cast<IntegralBusPort *>(p);
533 IntegralBusPort *newPort = dynamic_cast<IntegralBusPort *>(p2);
534 newPort->copyInput(oldPort, pm);
535 }
536 }
537 }
538
539 int beginLevel = top.size() - 1;
540 for (int level = beginLevel; level >= 0; level--) {
541 foreach (Actor *a, top[level]) {
542 if (a != oldActor) {
543 a->replaceActor(oldActor, newActor, mappings);
544 }
545 }
546 }
547
548 procs.removeOne(oldActor);
549 procs.append(newActor);
550 }
551
552 /************************************************************************/
553 /* ActorVisualData */
554 /************************************************************************/
ActorVisualData()555 ActorVisualData::ActorVisualData() {
556 initialize();
557 }
558
ActorVisualData(const ActorId & _actorId)559 ActorVisualData::ActorVisualData(const ActorId &_actorId)
560 : actorId(_actorId) {
561 initialize();
562 }
563
initialize()564 void ActorVisualData::initialize() {
565 posInited = false;
566 styleInited = false;
567 colorInited = false;
568 fontInited = false;
569 rectInited = false;
570 }
571
getActorId() const572 ActorId ActorVisualData::getActorId() const {
573 return actorId;
574 }
575
setActorId(const ActorId & value)576 void ActorVisualData::setActorId(const ActorId &value) {
577 actorId = value;
578 }
579
getPos(bool & contains) const580 QPointF ActorVisualData::getPos(bool &contains) const {
581 contains = posInited;
582 return pos;
583 }
584
getStyle(bool & contains) const585 QString ActorVisualData::getStyle(bool &contains) const {
586 contains = styleInited;
587 return styleId;
588 }
589
getColor(bool & contains) const590 QColor ActorVisualData::getColor(bool &contains) const {
591 contains = colorInited;
592 return color;
593 }
594
getFont(bool & contains) const595 QFont ActorVisualData::getFont(bool &contains) const {
596 contains = fontInited;
597 return font;
598 }
599
getRect(bool & contains) const600 QRectF ActorVisualData::getRect(bool &contains) const {
601 contains = rectInited;
602 return rect;
603 }
604
getPortAngle(const QString & portId,bool & contains) const605 qreal ActorVisualData::getPortAngle(const QString &portId, bool &contains) const {
606 contains = angleMap.contains(portId);
607 return angleMap.value(portId, 0.0);
608 }
609
setPos(const QPointF & value)610 void ActorVisualData::setPos(const QPointF &value) {
611 posInited = true;
612 pos = value;
613 }
614
setStyle(const QString & value)615 void ActorVisualData::setStyle(const QString &value) {
616 styleInited = true;
617 styleId = value;
618 }
619
setColor(const QColor & value)620 void ActorVisualData::setColor(const QColor &value) {
621 colorInited = true;
622 color = value;
623 }
624
setFont(const QFont & value)625 void ActorVisualData::setFont(const QFont &value) {
626 fontInited = true;
627 font = value;
628 }
629
setRect(const QRectF & value)630 void ActorVisualData::setRect(const QRectF &value) {
631 rectInited = true;
632 rect = value;
633 }
634
setPortAngle(const QString & portId,qreal value)635 void ActorVisualData::setPortAngle(const QString &portId, qreal value) {
636 angleMap[portId] = value;
637 }
638
getAngleMap() const639 QMap<QString, qreal> ActorVisualData::getAngleMap() const {
640 return angleMap;
641 }
642
643 /**************************
644 * Metadata
645 **************************/
Metadata()646 Metadata::Metadata() {
647 reset();
648 }
649
reset()650 void Metadata::reset() {
651 name = QString();
652 comment = QString();
653 url = QString();
654 scalePercent = 100;
655 isSampleWorkflow = false;
656 estimationsCode.clear();
657
658 resetVisual();
659 }
660
resetVisual()661 void Metadata::resetVisual() {
662 actorVisual.clear();
663 textPosMap.clear();
664 }
665
getActorVisualData(const ActorId & actorId,bool & contains) const666 ActorVisualData Metadata::getActorVisualData(const ActorId &actorId, bool &contains) const {
667 contains = actorVisual.contains(actorId);
668 return actorVisual.value(actorId, ActorVisualData());
669 }
670
setActorVisualData(const ActorVisualData & data)671 void Metadata::setActorVisualData(const ActorVisualData &data) {
672 actorVisual[data.getActorId()] = data;
673 }
674
getTextPos(const ActorId & srcActorId,const QString & srcPortId,const ActorId & dstActorId,const QString & dstPortId,bool & contains) const675 QPointF Metadata::getTextPos(const ActorId &srcActorId, const QString &srcPortId, const ActorId &dstActorId, const QString &dstPortId, bool &contains) const {
676 QString linkStr = getLinkString(srcActorId, srcPortId, dstActorId, dstPortId);
677 contains = textPosMap.contains(linkStr);
678 return textPosMap.value(linkStr, QPointF());
679 }
680
setTextPos(const ActorId & srcActorId,const QString & srcPortId,const ActorId & dstActorId,const QString & dstPortId,const QPointF & value)681 void Metadata::setTextPos(const ActorId &srcActorId, const QString &srcPortId, const ActorId &dstActorId, const QString &dstPortId, const QPointF &value) {
682 QString linkStr = getLinkString(srcActorId, srcPortId, dstActorId, dstPortId);
683 textPosMap[linkStr] = value;
684 }
685
removeActorMeta(const ActorId & actorId)686 void Metadata::removeActorMeta(const ActorId &actorId) {
687 actorVisual.remove(actorId);
688
689 foreach (const QString &linkStr, textPosMap.keys()) {
690 if (isActorLinked(actorId, linkStr)) {
691 textPosMap.remove(linkStr);
692 }
693 }
694 }
695
getPortString(const ActorId & actorId,const QString & portId) const696 QString Metadata::getPortString(const ActorId &actorId, const QString &portId) const {
697 return actorId + "." + portId;
698 }
699
getActorId(const QString & portStr) const700 ActorId Metadata::getActorId(const QString &portStr) const {
701 QStringList tokens = portStr.split(".");
702 CHECK(2 == tokens.size(), ActorId(""));
703 return tokens[0];
704 }
705
getLinkString(const ActorId & srcActorId,const QString & srcPortId,const ActorId & dstActorId,const QString & dstPortId) const706 QString Metadata::getLinkString(const ActorId &srcActorId, const QString &srcPortId, const ActorId &dstActorId, const QString &dstPortId) const {
707 return getPortString(srcActorId, srcPortId) + "->" +
708 getPortString(dstActorId, dstPortId);
709 }
710
isActorLinked(const ActorId & actorId,const QString & linkStr) const711 bool Metadata::isActorLinked(const ActorId &actorId, const QString &linkStr) const {
712 QStringList tokens = linkStr.split("->");
713 CHECK(2 == tokens.size(), false);
714
715 QStringList srcTokens = tokens[0].split(".");
716 CHECK(2 == srcTokens.size(), false);
717 QStringList dstTokens = tokens[1].split(".");
718 CHECK(2 == dstTokens.size(), false);
719
720 return (srcTokens[0] == actorId) || (dstTokens[0] == actorId);
721 }
722
getActorsVisual() const723 QList<ActorVisualData> Metadata::getActorsVisual() const {
724 return actorVisual.values();
725 }
726
getTextPosMap() const727 QMap<QString, QPointF> Metadata::getTextPosMap() const {
728 return textPosMap;
729 }
730
setSampleMark(bool isSample)731 void Metadata::setSampleMark(bool isSample) {
732 isSampleWorkflow = isSample;
733 }
734
isSample() const735 bool Metadata::isSample() const {
736 return isSampleWorkflow;
737 }
738
renameActors(const QMap<ActorId,ActorId> & actorsMapping)739 void Metadata::renameActors(const QMap<ActorId, ActorId> &actorsMapping) {
740 foreach (const ActorId &oldId, actorsMapping.keys()) {
741 if (actorVisual.contains(oldId)) {
742 ActorId newId = actorsMapping[oldId];
743 ActorVisualData visual = actorVisual.take(oldId);
744 visual.setActorId(newId);
745 actorVisual[newId] = visual;
746 }
747 }
748
749 foreach (const QString &oldLinkStr, textPosMap.keys()) {
750 QString newLinkStr = renameLink(oldLinkStr, actorsMapping);
751 if (newLinkStr != oldLinkStr) {
752 textPosMap[newLinkStr] = textPosMap[oldLinkStr];
753 textPosMap.remove(oldLinkStr);
754 }
755 }
756 }
757
renameLink(const QString & linkStr,const QMap<ActorId,ActorId> & actorsMapping) const758 QString Metadata::renameLink(const QString &linkStr, const QMap<ActorId, ActorId> &actorsMapping) const {
759 QStringList tokens = linkStr.split("->");
760 CHECK(2 == tokens.size(), linkStr);
761
762 QStringList srcTokens = tokens[0].split(".");
763 CHECK(2 == srcTokens.size(), linkStr);
764 QStringList dstTokens = tokens[1].split(".");
765 CHECK(2 == dstTokens.size(), linkStr);
766
767 foreach (const ActorId &oldId, actorsMapping.keys()) {
768 if (srcTokens[0] == oldId) {
769 srcTokens[0] = actorsMapping[oldId];
770 }
771 if (dstTokens[0] == oldId) {
772 dstTokens[0] = actorsMapping[oldId];
773 }
774 }
775 return getLinkString(srcTokens[0], srcTokens[1], dstTokens[0], dstTokens[1]);
776 }
777
renameLink(const QString & linkStr,const ActorId & oldId,const ActorId & newId,const QList<PortMapping> & mappings) const778 QString Metadata::renameLink(const QString &linkStr, const ActorId &oldId, const ActorId &newId, const QList<PortMapping> &mappings) const {
779 QStringList tokens = linkStr.split("->");
780 CHECK(2 == tokens.size(), linkStr);
781
782 QStringList srcTokens = tokens[0].split(".");
783 CHECK(2 == srcTokens.size(), linkStr);
784 QStringList dstTokens = tokens[1].split(".");
785 CHECK(2 == dstTokens.size(), linkStr);
786
787 if (srcTokens[0] == oldId) {
788 U2OpStatus2Log os;
789 PortMapping m = PortMapping::getMappingBySrcPort(srcTokens[1], mappings, os);
790 srcTokens[0] = newId;
791 srcTokens[1] = m.getDstId();
792 }
793 if (dstTokens[0] == oldId) {
794 U2OpStatus2Log os;
795 PortMapping m = PortMapping::getMappingBySrcPort(dstTokens[1], mappings, os);
796 dstTokens[0] = newId;
797 dstTokens[1] = m.getDstId();
798 }
799 return getLinkString(srcTokens[0], srcTokens[1], dstTokens[0], dstTokens[1]);
800 }
801
mergeVisual(const Metadata & other)802 void Metadata::mergeVisual(const Metadata &other) {
803 actorVisual.unite(other.actorVisual);
804 textPosMap.unite(other.textPosMap);
805 }
806
replaceProcess(const ActorId & oldId,const ActorId & newId,const QList<PortMapping> & mappings)807 void Metadata::replaceProcess(const ActorId &oldId, const ActorId &newId, const QList<PortMapping> &mappings) {
808 bool contains = false;
809 if (actorVisual.contains(oldId)) {
810 ActorVisualData oldV = actorVisual[oldId];
811 ActorVisualData newV(newId);
812 QPointF p = oldV.getPos(contains);
813 if (contains) {
814 newV.setPos(p);
815 }
816 QString s = oldV.getStyle(contains);
817 if (contains) {
818 newV.setStyle(s);
819 }
820 QColor c = oldV.getColor(contains);
821 if (contains) {
822 newV.setColor(c);
823 }
824 QFont f = oldV.getFont(contains);
825 if (contains) {
826 newV.setFont(f);
827 }
828 QRectF r = oldV.getRect(contains);
829 if (contains) {
830 newV.setRect(r);
831 }
832 actorVisual.remove(oldId);
833 actorVisual[newId] = newV;
834 }
835 foreach (const QString &linkStr, textPosMap.keys()) {
836 QString newLinkStr = renameLink(linkStr, oldId, newId, mappings);
837 if (newLinkStr != linkStr) {
838 textPosMap[newLinkStr] = textPosMap[linkStr];
839 textPosMap.remove(linkStr);
840 }
841 }
842 }
843
844 /**************************
845 * ActorBindingGraph
846 **************************/
validateGraph(QString &) const847 bool ActorBindingsGraph::validateGraph(QString &) const {
848 return true;
849 }
850
addBinding(Port * source,Port * dest)851 bool ActorBindingsGraph::addBinding(Port *source, Port *dest) {
852 QList<Port *> ports;
853 if (bindings.contains(source)) {
854 ports = bindings.value(source);
855 if (ports.contains(dest)) {
856 return false;
857 }
858 }
859 ports.append(dest);
860 bindings.insert(source, ports);
861 return true;
862 }
863
contains(Port * source,Port * dest) const864 bool ActorBindingsGraph::contains(Port *source, Port *dest) const {
865 if (bindings.contains(source)) {
866 const QList<Port *> &ports = bindings[source];
867 return ports.contains(dest);
868 }
869 return false;
870 }
871
removeBinding(Port * source,Port * dest)872 void ActorBindingsGraph::removeBinding(Port *source, Port *dest) {
873 if (bindings.contains(source)) {
874 QList<Port *> &ports = bindings[source];
875 ports.removeOne(dest);
876 if (ports.isEmpty()) {
877 bindings.remove(source);
878 }
879 }
880 }
881
getBindings() const882 const QMap<Port *, QList<Port *>> &ActorBindingsGraph::getBindings() const {
883 return bindings;
884 }
885
getBindings()886 QMap<Port *, QList<Port *>> &ActorBindingsGraph::getBindings() {
887 return bindings;
888 }
889
getTopologicalSortedGraph(QList<Actor * > actors) const890 QMap<int, QList<Actor *>> ActorBindingsGraph::getTopologicalSortedGraph(QList<Actor *> actors) const {
891 QMap<Actor *, QList<Port *>> graph;
892 foreach (Port *source, bindings.keys()) {
893 if (graph.contains(source->owner())) {
894 graph[source->owner()].append(bindings.value(source));
895 } else {
896 graph.insert(source->owner(), bindings.value(source));
897 }
898 }
899 QMap<int, QList<Actor *>> result;
900
901 int vertexLabel = 0;
902 while (!graph.isEmpty()) {
903 QList<Actor *> endVertexes;
904 {
905 foreach (Actor *a, actors) {
906 if (!graph.keys().contains(a)) { // so, there is no arcs from this actor
907 endVertexes.append(a);
908 }
909 }
910 }
911 result.insert(vertexLabel, endVertexes);
912
913 foreach (Actor *a, graph.keys()) {
914 QList<Port *> ports = graph.value(a);
915 foreach (Port *p, ports) {
916 if (endVertexes.contains(p->owner())) {
917 ports.removeOne(p);
918 }
919 }
920 if (ports.isEmpty()) {
921 graph.remove(a);
922 } else {
923 graph.insert(a, ports);
924 }
925 }
926
927 foreach (Actor *a, endVertexes) {
928 actors.removeOne(a);
929 }
930 vertexLabel++;
931 }
932 result.insert(vertexLabel, actors);
933
934 return result;
935 }
936
clear()937 void ActorBindingsGraph::clear() {
938 bindings.clear();
939 }
940
isEmpty() const941 bool ActorBindingsGraph::isEmpty() const {
942 return bindings.isEmpty();
943 }
944
getFlows() const945 QList<Link *> ActorBindingsGraph::getFlows() const {
946 QList<Link *> result;
947 foreach (Port *src, bindings.keys()) {
948 foreach (Link *l, src->getLinks()) {
949 SAFE_POINT(l->source() == src, "Link's source port mismatch", result);
950 Port *dst = l->destination();
951 SAFE_POINT(bindings[src].contains(dst), "Link's destination port mismatch", result);
952 result << l;
953 }
954 }
955 return result;
956 }
957
958 } // namespace Workflow
959
960 } // namespace U2
961