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 "QDScheme.h"
23 
24 #include <U2Core/DNASequenceObject.h>
25 #include <U2Core/Log.h>
26 
27 #include <U2Lang/SupportClass.h>
28 
29 #include "ConfigurationEditor.h"
30 #include "QDConstraint.h"
31 
32 namespace U2 {
33 
setParameter(const QString & name,const QVariant & val)34 void QDParameters::setParameter(const QString &name, const QVariant &val) {
35     Configuration::setParameter(name, val);
36     emit si_modified();
37 }
38 
39 // QDActor
40 //////////////////////////////////////////////////////////////////////////
41 const int QDActor::DEFAULT_MAX_RESULT_LENGTH(10000);
42 
QDActor(QDActorPrototype const * _proto)43 QDActor::QDActor(QDActorPrototype const *_proto)
44     : scheme(nullptr), proto(_proto), strand(QDStrand_Both), simmetric(false) {
45     cfg = new QDActorParameters;
46     foreach (Attribute *a, proto->getParameters()) {
47         cfg->addParameter(a->getId(), a->clone());
48     }
49     ConfigurationEditor *ed = proto->getEditor();
50 
51     if (ed) {
52         cfg->setEditor(ed);
53     }
54 
55     const QMap<QString, Attribute *> &attrs = cfg->getParameters();
56     QMapIterator<QString, Attribute *> it(attrs);
57     while (it.hasNext()) {
58         it.next();
59         defaultCfg[it.key()] = it.value()->getAttributePureValue();
60     }
61 }
62 
~QDActor()63 QDActor::~QDActor() {
64     qDeleteAll(paramConstraints);
65     delete cfg;
66 }
67 
reset()68 void QDActor::reset() {
69     const QMap<QString, Attribute *> &attrs = cfg->getParameters();
70     foreach (const QString &key, attrs.keys()) {
71         Attribute *a = attrs[key];
72         a->setAttributeValue(defaultCfg.value(key));
73     }
74 }
75 
contains(const QDResultUnit & res,const QVector<U2Region> & location)76 bool contains(const QDResultUnit &res, const QVector<U2Region> &location) {
77     foreach (const U2Region &r, location) {
78         if (r.contains(res->region)) {
79             return true;
80         }
81     }
82     return false;
83 }
84 
filterResults(const QVector<U2Region> &)85 void QDActor::filterResults(const QVector<U2Region> &) {
86     /*QList<QDResultGroup*> res = results;
87     foreach(QDResultGroup* grp, res) {
88         foreach(const QDResultUnit& ru, grp->getResultsList()) {
89             if (!contains(ru, location)) {
90                 results.removeOne(grp);
91                 break;
92             }
93         }
94     }*/
95 }
96 
popResults()97 QList<QDResultGroup *> QDActor::popResults() {
98     QList<QDResultGroup *> res = results;
99     results.clear();
100     return res;
101 }
102 
103 static const QString KEY_ATTR = "key";
104 
saveConfiguration() const105 QList<QPair<QString, QString>> QDActor::saveConfiguration() const {
106     QList<QPair<QString, QString>> res;
107     QMapIterator<QString, Attribute *> it(cfg->getParameters());
108     QString annKey = cfg->getAnnotationKey();
109     if (annKey.contains(' ')) {
110         annKey = "\"" + annKey + "\"";
111     }
112     res.append(qMakePair(KEY_ATTR, annKey));
113     while (it.hasNext()) {
114         it.next();
115         Attribute *a = it.value();
116         if (a->getAttributePureValue() == defaultCfg.value(it.key())) {
117             continue;
118         }
119         // QString displayName = QDAttributeNameConverter::convertAttrName(a->getDisplayName());
120         QString displayName = a->getId();
121         QPair<QString, QString> newAttr = qMakePair(displayName, a->getAttributePureValue().toString());
122         res.append(newAttr);
123     }
124     return res;
125 }
126 
loadConfiguration(const QList<QPair<QString,QString>> & strMap)127 void QDActor::loadConfiguration(const QList<QPair<QString, QString>> &strMap) {
128     foreach (const StringAttribute &attr, strMap) {
129         if (attr.first == KEY_ATTR) {
130             cfg->setAnnotationKey(attr.second);
131         }
132         QMapIterator<QString, Attribute *> paramsIterator(cfg->getParameters());
133         while (paramsIterator.hasNext()) {
134             paramsIterator.next();
135             Attribute *a = paramsIterator.value();
136             if (QDAttributeNameConverter::convertAttrName(a->getId()) == attr.first) {
137                 QVariant val = QDAttributeValueMapper::stringToAttributeValue(attr.second);
138                 cfg->setParameter(a->getId(), val);
139                 break;
140             }
141         }
142     }
143 }
144 
getStrandToRun() const145 QDStrandOption QDActor::getStrandToRun() const {
146     QDStrandOption schemaStrand = scheme->getStrand();
147     QDStrandOption strand2run = QDStrand_Both;
148     if (schemaStrand != QDStrand_Both) {
149         if (schemaStrand == QDStrand_DirectOnly) {
150             strand2run = strand;
151         }
152         if (schemaStrand == QDStrand_ComplementOnly) {
153             if (strand == QDStrand_DirectOnly) {
154                 strand2run = QDStrand_ComplementOnly;
155             }
156             if (strand == QDStrand_ComplementOnly) {
157                 strand2run = QDStrand_DirectOnly;
158             }
159         }
160     }
161     return strand2run;
162 }
163 
getStrand() const164 QDStrandOption QDActor::getStrand() const {
165     if (hasStrand()) {
166         return strand;
167     }
168     // return QDStrand_DirectOnly;
169     return QDStrand_Both;
170 }
171 
setStrand(QDStrandOption stOp)172 void QDActor::setStrand(QDStrandOption stOp) {
173     strand = stOp;
174     emit si_strandChanged(strand);
175 }
176 
getConstraints() const177 QList<QDConstraint *> QDActor::getConstraints() const {
178     QList<QDConstraint *> res;
179     foreach (QDSchemeUnit *su, units) {
180         res << su->getConstraints();
181     }
182     return res;
183 }
184 
getDistanceConstraints() const185 QList<QDDistanceConstraint *> QDSchemeUnit::getDistanceConstraints() const {
186     QList<QDDistanceConstraint *> res;
187     foreach (QDConstraint *c, schemeConstraints) {
188         QDDistanceConstraint *dc = static_cast<QDDistanceConstraint *>(c);
189         if (dc) {
190             res.append(dc);
191         }
192     }
193     return res;
194 }
195 
196 // QDScheme
197 //////////////////////////////////////////////////////////////////////////
~QDScheme()198 QDScheme::~QDScheme() {
199     foreach (QDActor *a, actors) {
200         removeActor(a);
201     }
202 }
203 
addActor(QDActor * a)204 void QDScheme::addActor(QDActor *a) {
205     assert(!actors.contains(a));
206     assert(a->scheme == nullptr);
207     foreach (QDSchemeUnit *su, a->getSchemeUnits()) {
208         assert(su->getConstraints().isEmpty());
209         Q_UNUSED(su);
210     }
211     a->scheme = this;
212     actors.append(a);
213     emit si_schemeChanged();
214 }
215 
removeActor(QDActor * a)216 bool QDScheme::removeActor(QDActor *a) {
217     if (actors.contains(a)) {
218         QList<QDSchemeUnit *> schemaUnits = a->getSchemeUnits();
219         for (QDSchemeUnit *schemaUnit : qAsConst(schemaUnits)) {
220             QList<QDConstraint *> constraints = schemaUnit->getConstraints();
221             for (QDConstraint *c : qAsConst(constraints)) {
222                 removeConstraint(c);
223             }
224         }
225         actors.removeOne(a);
226         const QString &ag = getActorGroup(a);
227         if (!ag.isEmpty()) {
228             actorGroups[ag].removeOne(a);
229         }
230         delete a;
231         emit si_schemeChanged();
232         return true;
233     }
234     return false;
235 }
236 
addConstraint(QDConstraint * constraint)237 void QDScheme::addConstraint(QDConstraint *constraint) {
238     foreach (QDSchemeUnit *su, constraint->getSchemeUnits()) {
239         assert(actors.contains(su->getActor()));
240         su->schemeConstraints.append(constraint);
241     }
242     emit si_schemeChanged();
243 }
244 
removeConstraint(QDConstraint * constraint)245 void QDScheme::removeConstraint(QDConstraint *constraint) {
246     const QList<QDSchemeUnit *> &constraintUnits = constraint->getSchemeUnits();
247     foreach (QDSchemeUnit *su, constraintUnits) {
248         QDActor *actor = su->getActor();
249         Q_UNUSED(actor);
250         assert(actors.contains(actor));
251         assert(su->getConstraints().contains(constraint));
252         su->schemeConstraints.removeOne(constraint);
253     }
254     delete constraint;
255     emit si_schemeChanged();
256 }
257 
getConstraints() const258 QList<QDConstraint *> QDScheme::getConstraints() const {
259     QList<QDConstraint *> res;
260     for (QDActor *actor : qAsConst(actors)) {
261         QList<QDSchemeUnit *> schemeUnits = actor->getSchemeUnits();
262         for (QDSchemeUnit *su : qAsConst(schemeUnits)) {
263             const QList<QDConstraint *> &constraints = su->getConstraints();
264             for (QDConstraint *c : qAsConst(constraints)) {
265                 if (!res.contains(c)) {
266                     res.append(c);
267                 }
268             }
269         }
270     }
271     return res;
272 }
273 
274 QList<QDConstraint *>
getConstraints(QDSchemeUnit const * su1,QDSchemeUnit const * su2) const275     QDScheme::getConstraints(QDSchemeUnit const *su1, QDSchemeUnit const *su2) const {
276     QList<QDConstraint *> sharedConstraints;
277     const QList<QDConstraint *> &su1Cons = su1->getConstraints();
278     const QList<QDConstraint *> &su2Cons = su2->getConstraints();
279     for (QDConstraint *con : qAsConst(su1Cons)) {
280         if (su2Cons.contains(con)) {
281             sharedConstraints.append(con);
282         }
283     }
284     return sharedConstraints;
285 }
286 
clear()287 void QDScheme::clear() {
288     // delete dna;
289     dna = DNASequence();
290     QList<QDActor *> actorsCopy = actors;
291     for (QDActor *a : qAsConst(actorsCopy)) {
292         removeActor(a);
293     }
294     actorGroups.clear();
295     emit si_schemeChanged();
296 }
297 
findPaths(QDSchemeUnit * src,QDSchemeUnit * dst)298 QList<QDPath *> QDScheme::findPaths(QDSchemeUnit *src, QDSchemeUnit *dst) {
299     QList<QDSchemeUnit *> currentRoute = {src};
300     QList<QList<QDSchemeUnit *>> routes;
301     findRoute(src, dst, currentRoute, routes);
302     QList<QDPath *> res;
303     for (const QList<QDSchemeUnit *> &route : qAsConst(routes)) {
304         QList<QDPath *> paths;
305         for (int routeIndex = 0, m = route.size() - 1; routeIndex < m; routeIndex++) {
306             QDSchemeUnit *routeSrc = route.at(routeIndex);
307             QDSchemeUnit *routeDst = route.at(routeIndex + 1);
308             QList<QDConstraint *> joint = getConstraints(routeSrc, routeDst);
309 
310             // include "parameter" constraints
311             foreach (QDConstraint *con, routeSrc->getActor()->getParamConstraints()) {
312                 if (con->getSchemeUnits().contains(routeSrc) && con->getSchemeUnits().contains(routeDst)) {
313                     joint.append(con);
314                 }
315             }
316             QList<QDDistanceConstraint *> jointCons;
317             for (QDConstraint *con : qAsConst(joint)) {
318                 if (auto dc = static_cast<QDDistanceConstraint *>(con)) {
319                     jointCons.append(dc);
320                 }
321             }
322             assert(!jointCons.isEmpty());
323 
324             if (paths.isEmpty()) {
325                 for (QDDistanceConstraint *dc : qAsConst(jointCons)) {
326                     QDPath *newPath = new QDPath;
327                     bool ok = newPath->addConstraint(dc);
328                     assert(ok);
329                     Q_UNUSED(ok);
330                     paths << newPath;
331                 }
332             } else {
333                 QList<QDPath *> newPaths;
334                 for (int jointConstraintIndex = 1, n = jointCons.size(); jointConstraintIndex < n; jointConstraintIndex++) {
335                     for (QDPath *path : qAsConst(paths)) {
336                         QDPath *newPath = path->clone();
337                         bool ok = newPath->addConstraint(jointCons.at(jointConstraintIndex));
338                         assert(ok);
339                         Q_UNUSED(ok);
340                         newPaths.append(newPath);
341                     }
342                 }
343                 for (QDPath *path : qAsConst(paths)) {
344                     bool ok = path->addConstraint(jointCons.at(0));
345                     assert(ok);
346                     Q_UNUSED(ok);
347                 }
348                 paths << newPaths;
349             }
350         }
351         res.append(paths);
352     }
353     currentRoute.clear();
354     routes.clear();
355     return res;
356 }
357 
findRoute(QDSchemeUnit * curSu,QDSchemeUnit * routeDst,QList<QDSchemeUnit * > & currentRoute,QList<QList<QDSchemeUnit * >> routes)358 void QDScheme::findRoute(QDSchemeUnit *curSu, QDSchemeUnit *routeDst, QList<QDSchemeUnit *> &currentRoute, QList<QList<QDSchemeUnit *>> routes) {
359     if (curSu == routeDst) {
360         routes.append(currentRoute);
361     } else {
362         // build list of adjacent vertexes
363         QList<QDSchemeUnit *> adjacentList;
364         QList<QDDistanceConstraint *> dcList = curSu->getDistanceConstraints();
365         // include "parameter" constraints
366         foreach (QDConstraint *con, curSu->getActor()->getParamConstraints()) {
367             if (con->constraintType() == QDConstraintTypes::DISTANCE) {
368                 QDDistanceConstraint *dc = static_cast<QDDistanceConstraint *>(con);
369                 if (dc->getSchemeUnits().contains(curSu)) {
370                     dcList.append(dc);
371                 }
372             }
373         }
374 
375         for (QDDistanceConstraint *dc : qAsConst(dcList)) {
376             QDSchemeUnit *dcSrc = dc->getSource();
377             QDSchemeUnit *dcDst = dc->getDestination();
378             QDSchemeUnit *adj;
379             if (curSu == dcSrc) {
380                 adj = dcDst;
381             } else {
382                 assert(curSu == dcDst);
383                 adj = dcSrc;
384             }
385             if (!adjacentList.contains(adj)) {
386                 adjacentList.append(adj);
387             }
388         }
389         for (QDSchemeUnit *adj : qAsConst(adjacentList)) {
390             if (!currentRoute.contains(adj)) {
391                 currentRoute.append(adj);
392                 findRoute(adj, routeDst, currentRoute, routes);
393                 currentRoute.removeOne(adj);
394             }
395         }
396     }
397 }
398 
399 // QDPath
400 //////////////////////////////////////////////////////////////////////////
~QDPath()401 QDPath::~QDPath() {
402     delete overallConstraint;
403 }
404 
clone() const405 QDPath *QDPath::clone() const {
406     QDPath *cln = new QDPath;
407     cln->constraints = constraints;
408     cln->pathSrc = pathSrc;
409     cln->pathDst = pathDst;
410     return cln;
411 }
412 
addConstraint(QDDistanceConstraint * dc)413 bool QDPath::addConstraint(QDDistanceConstraint *dc) {
414     assert(!constraints.contains(dc));
415     QDSchemeUnit *dcSrc = dc->getSource();
416     QDSchemeUnit *dcDst = dc->getDestination();
417     if (!pathSrc) {
418         assert(!pathDst);
419         pathSrc = dcSrc;
420         pathDst = dcDst;
421         constraints.append(dc);
422         schemeUnits << pathSrc << pathDst;
423     } else if (pathDst == dcSrc) {
424         pathDst = dcDst;
425         constraints.append(dc);
426         schemeUnits << pathDst;
427     } else if (pathDst == dcDst) {
428         pathDst = dcSrc;
429         constraints.append(dc);
430         schemeUnits << pathDst;
431     } else if (pathSrc == dcSrc) {
432         pathSrc = dcDst;
433         constraints.prepend(dc);
434         schemeUnits << pathSrc;
435     } else if (pathSrc == dcDst) {
436         pathSrc = dcSrc;
437         constraints.prepend(dc);
438         schemeUnits << pathSrc;
439     } else {
440         return false;
441     }
442     return true;
443 }
444 
toConstraint()445 QDDistanceConstraint *QDPath::toConstraint() {
446     if (constraints.isEmpty()) {
447         return nullptr;
448     }
449     delete overallConstraint;
450     int minDist = 0, maxDist = 0;
451     QDSchemeUnit *curSu = pathSrc;
452     for (int i = 0, n = constraints.size(); i < n; i++) {
453         QDDistanceConstraint *curDc = constraints.at(i);
454         QDDistanceConstraint *nextDc = nullptr;
455         if (i + 1 < n) {
456             nextDc = constraints.at(i + 1);
457         }
458         QDSchemeUnit *curDcSrc = curDc->getSource();
459         QDSchemeUnit *curDcDst = curDc->getDestination();
460 
461         if (curSu == curDcSrc) {
462             curSu = curDcDst;
463             minDist += curDc->getMin();
464             maxDist += curDc->getMax();
465             if (!nextDc) {
466                 continue;
467             }
468             QDSchemeUnit *nextDcSrc = nextDc->getSource();
469             QDSchemeUnit *nextDcDst = nextDc->getDestination();
470 
471             if (nextDcSrc == curSu) {
472                 if (curDc->distanceType() == S2S || curDc->distanceType() == E2S) {
473                     if (nextDc->distanceType() == E2S || nextDc->distanceType() == E2E) {
474                         minDist += curSu->getActor()->getMinResultLen();
475                         maxDist += curSu->getActor()->getMaxResultLen();
476                     }
477                 } else {  // S2E || E2E
478                     if (nextDc->distanceType() == S2S || nextDc->distanceType() == S2E) {
479                         minDist -= curSu->getActor()->getMaxResultLen();
480                         maxDist -= curSu->getActor()->getMinResultLen();
481                     }
482                 }
483             } else {
484                 assert(nextDcDst == curSu);
485                 Q_UNUSED(nextDcDst);
486                 if (curDc->distanceType() == E2S || curDc->distanceType() == S2S) {
487                     if (nextDc->distanceType() == S2E || nextDc->distanceType() == E2E) {
488                         minDist += curSu->getActor()->getMinResultLen();
489                         maxDist += curSu->getActor()->getMaxResultLen();
490                     }
491                 } else {  // S2E || E2E
492                     if (nextDc->distanceType() == S2S || nextDc->distanceType() == E2S) {
493                         minDist -= curSu->getActor()->getMaxResultLen();
494                         maxDist -= curSu->getActor()->getMinResultLen();
495                     }
496                 }
497             }
498         } else {
499             assert(curSu == curDcDst);
500             curSu = curDcSrc;
501             minDist -= curDc->getMax();
502             maxDist -= curDc->getMin();
503             if (!nextDc) {
504                 continue;
505             }
506             QDSchemeUnit *nextDcSrc = nextDc->getSource();
507             QDSchemeUnit *nextDcDst = nextDc->getDestination();
508 
509             if (nextDcSrc == curSu) {
510                 if (curDc->distanceType() == S2S || curDc->distanceType() == S2E) {
511                     if (nextDc->distanceType() == E2S || nextDc->distanceType() == E2E) {
512                         minDist += curSu->getActor()->getMinResultLen();
513                         maxDist += curSu->getActor()->getMaxResultLen();
514                     }
515                 } else {  // E2S || E2E
516                     if (nextDc->distanceType() == S2S || nextDc->distanceType() == S2E) {
517                         minDist -= curSu->getActor()->getMaxResultLen();
518                         maxDist -= curSu->getActor()->getMinResultLen();
519                     }
520                 }
521             } else {
522                 assert(nextDcDst == curSu);
523                 Q_UNUSED(nextDcDst);
524                 if (curDc->distanceType() == E2S || curDc->distanceType() == E2E) {
525                     if (nextDc->distanceType() == S2S || nextDc->distanceType() == E2S) {
526                         minDist -= curSu->getActor()->getMaxResultLen();
527                         maxDist -= curSu->getActor()->getMinResultLen();
528                     }
529                 } else {  // S2E || S2S
530                     if (nextDc->distanceType() == S2E || nextDc->distanceType() == E2E) {
531                         minDist += curSu->getActor()->getMinResultLen();
532                         maxDist += curSu->getActor()->getMaxResultLen();
533                     }
534                 }
535             }
536         }
537     }
538 
539     if (maxDist < minDist) {
540         return nullptr;
541     }
542 
543     QDDistanceConstraint *firstDc = constraints.first();
544     QDDistanceConstraint *lastDc = constraints.last();
545     QList<QDSchemeUnit *> units;
546     units << pathSrc << pathDst;
547 
548     QDDistanceType distType;
549     if (pathSrc == firstDc->getSource()) {
550         if (pathDst == lastDc->getSource()) {
551             if (firstDc->distanceType() == S2S || firstDc->distanceType() == S2E) {
552                 if (lastDc->distanceType() == S2S || lastDc->distanceType() == S2E) {
553                     distType = S2S;
554                 } else {  // E2S || E2E
555                     distType = S2E;
556                 }
557             } else {  // E2S || E2E
558                 if (lastDc->distanceType() == S2S || lastDc->distanceType() == S2E) {
559                     distType = E2S;
560                 } else {  // E2S || E2E
561                     distType = E2E;
562                 }
563             }
564         } else {
565             assert(pathDst == lastDc->getDestination());
566             if (firstDc->distanceType() == S2S || firstDc->distanceType() == S2E) {
567                 if (lastDc->distanceType() == S2S || lastDc->distanceType() == E2S) {
568                     distType = S2S;
569                 } else {  // S2E || E2E
570                     distType = S2E;
571                 }
572             } else {  // E2S || E2E
573                 if (lastDc->distanceType() == S2S || lastDc->distanceType() == E2S) {
574                     distType = E2S;
575                 } else {  // S2E || E2E
576                     distType = E2E;
577                 }
578             }
579         }
580     } else {
581         assert(pathSrc == firstDc->getDestination());
582         if (pathDst == lastDc->getSource()) {
583             if (firstDc->distanceType() == S2S || firstDc->distanceType() == E2S) {
584                 if (lastDc->distanceType() == S2S || lastDc->distanceType() == S2E) {
585                     distType = S2S;
586                 } else {  // E2S || E2E
587                     distType = S2E;
588                 }
589             } else {  // S2E || E2E
590                 if (lastDc->distanceType() == E2S || lastDc->distanceType() == E2E) {
591                     distType = E2E;
592                 } else {  // S2S || S2E
593                     distType = E2S;
594                 }
595             }
596         } else {
597             assert(pathDst == lastDc->getDestination());
598             if (firstDc->distanceType() == S2S || firstDc->distanceType() == E2S) {
599                 if (lastDc->distanceType() == S2S || lastDc->distanceType() == E2S) {
600                     distType = S2S;
601                 } else {  // S2E || E2E
602                     distType = S2E;
603                 }
604             } else {  // S2E || E2E
605                 if (lastDc->distanceType() == S2S || lastDc->distanceType() == E2S) {
606                     distType = E2S;
607                 } else {  // S2E || E2E
608                     distType = E2E;
609                 }
610             }
611         }
612     }
613     overallConstraint = new QDDistanceConstraint(units, distType, minDist, maxDist);
614     return overallConstraint;
615 }
616 
setOrder(QDActor * a,int serialNum)617 void QDScheme::setOrder(QDActor *a, int serialNum) {
618     assert(actors.contains(a));
619     int aIdx = actors.indexOf(a);
620     if (serialNum < 0) {
621         actors.move(aIdx, 0);
622         return;
623     }
624     if (serialNum >= actors.size()) {
625         actors.move(aIdx, actors.size() - 1);
626         return;
627     }
628     actors.move(aIdx, serialNum);
629 }
630 
isValid() const631 bool QDScheme::isValid() const {
632     bool res = true;
633     foreach (QDActor *actor, getActors()) {
634         QDActorParameters *cfg = actor->getParameters();
635         NotificationsList notificationList;
636         if (!cfg->validate(notificationList)) {
637             res = false;
638             for (const WorkflowNotification &notification : qAsConst(notificationList)) {
639                 coreLog.error(QObject::tr("%1. %2").arg(cfg->getLabel()).arg(notification.message));
640             }
641         }
642     }
643     foreach (QDConstraint *con, getConstraints()) {
644         if (con->constraintType() == QDConstraintTypes::DISTANCE) {
645             QDDistanceConstraint *dc = static_cast<QDDistanceConstraint *>(con);
646             if (dc->getMin() > dc->getMax()) {
647                 coreLog.error(QObject::tr("Invalid distance values"));
648                 res = false;
649             }
650             QDActor *src = dc->getSource()->getActor();
651             QDActor *dst = dc->getDestination()->getActor();
652             QString group = getActorGroup(src);
653             if (!group.isEmpty() && getActors(group).contains(dst)) {
654                 coreLog.error(QObject::tr("Constraints can not be placed between elements of the same group"));
655                 res = false;
656             }
657         }
658     }
659     return res;
660 }
661 
getActorByLabel(const QString & label) const662 QDActor *QDScheme::getActorByLabel(const QString &label) const {
663     foreach (QDActor *a, actors) {
664         if (a->getParameters()->getLabel() == label) {
665             return a;
666         }
667     }
668     return nullptr;
669 }
670 
addActorToGroup(QDActor * a,const QString & group)671 void QDScheme::addActorToGroup(QDActor *a, const QString &group) {
672     assert(actors.contains(a));
673     assert(getActorGroup(a).isEmpty());
674     assert(actorGroups.keys().contains(group));
675     actorGroups[group].append(a);
676     emit si_schemeChanged();
677 }
678 
removeActorFromGroup(QDActor * a)679 bool QDScheme::removeActorFromGroup(QDActor *a) {
680     const QString &group = getActorGroup(a);
681     if (!group.isEmpty()) {
682         bool res = actorGroups[group].removeOne(a);
683         if (res) {
684             emit si_schemeChanged();
685         }
686     }
687     return false;
688 }
689 
createActorGroup(const QString & name)690 void QDScheme::createActorGroup(const QString &name) {
691     assert(validateGroupName(name));
692     assert(!actorGroups.keys().contains(name));
693     actorGroups.insert(name, QList<QDActor *>());
694     actorGroupReqNum[name] = 1;
695     emit si_schemeChanged();
696 }
697 
removeActorGroup(const QString & name)698 bool QDScheme::removeActorGroup(const QString &name) {
699     bool res = actorGroups.remove(name);
700     emit si_schemeChanged();
701     return res;
702 }
703 
getActorGroup(QDActor * a) const704 QString QDScheme::getActorGroup(QDActor *a) const {
705     QMapIterator<QString, QList<QDActor *>> i(actorGroups);
706     while (i.hasNext()) {
707         i.next();
708         if (i.value().contains(a)) {
709             return i.key();
710         }
711     }
712     return QString();
713 }
714 
validateGroupName(const QString & name) const715 bool QDScheme::validateGroupName(const QString &name) const {
716     if (name.isEmpty()) {
717         return false;
718     }
719     return true;
720 }
721 
setRequiredNum(const QString & group,int num)722 void QDScheme::setRequiredNum(const QString &group, int num) {
723     assert(actorGroups.keys().contains(group));
724     const QList<QDActor *> &grpMembrs = actorGroups.value(group);
725     Q_UNUSED(grpMembrs);
726     assert(num <= grpMembrs.size());
727     actorGroupReqNum[group] = num;
728     emit si_schemeChanged();
729 }
730 
adaptActorsOrder()731 void QDScheme::adaptActorsOrder() {
732     QList<QDActor *> actorsQueue;
733     foreach (QDActor *a, actors) {
734         QString group = getActorGroup(a);
735         if (group.isEmpty()) {
736             assert(!actorsQueue.contains(a));
737             actorsQueue.append(a);
738         } else if (!actorsQueue.contains(a)) {
739             const QList<QDActor *> &groupActors = getActors(group);
740             actorsQueue.append(groupActors);
741         }
742     }
743     actors = actorsQueue;
744 }
745 
746 // QDResultGroup
747 //////////////////////////////////////////////////////////////////////////
add(const QDResultUnit & res)748 void QDResultGroup::add(const QDResultUnit &res) {
749     if (results.isEmpty()) {
750         startPos = res->region.startPos;
751         endPos = res->region.endPos();
752     } else {
753         if (res->region.startPos < startPos) {
754             startPos = res->region.startPos;
755         }
756         if (res->region.endPos() > endPos) {
757             endPos = res->region.endPos();
758         }
759     }
760     results.append(res);
761 }
762 
add(const QList<QDResultUnit> & res)763 void QDResultGroup::add(const QList<QDResultUnit> &res) {
764     foreach (const QDResultUnit &r, res) {
765         add(r);
766     }
767 }
768 
buildGroupFromSingleResult(const QDResultUnit & ru,QList<QDResultGroup * > & results)769 void QDResultGroup::buildGroupFromSingleResult(const QDResultUnit &ru, QList<QDResultGroup *> &results) {
770     QDStrandOption groupStrand = ru->strand == U2Strand::Direct ? QDStrand_DirectOnly : QDStrand_ComplementOnly;
771     QDResultGroup *g = new QDResultGroup(groupStrand);
772     g->add(ru);
773     results.append(g);
774 }
775 
776 // AttributeValueMapper
777 //////////////////////////////////////////////////////////////////////////
778 
779 const QMap<QString, bool> QDAttributeValueMapper::BOOLEAN_MAP = initBooleanMap();
780 
initBooleanMap()781 QMap<QString, bool> QDAttributeValueMapper::initBooleanMap() {
782     QMap<QString, bool> map;
783     map.insertMulti("true", true);
784     map.insertMulti("yes", true);
785     map.insertMulti("1", true);
786     map.insertMulti("false", false);
787     map.insertMulti("no", false);
788     map.insertMulti("0", false);
789     return map;
790 }
791 
stringToAttributeValue(const QString & str)792 QVariant QDAttributeValueMapper::stringToAttributeValue(const QString &str) {
793     if (getType(str) == BOOLEAN_TYPE) {
794         return qVariantFromValue(BOOLEAN_MAP.value(str));
795     }
796     return qVariantFromValue(str);
797 }
798 
getType(const QString & val)799 QDAttributeValueMapper::ValueType QDAttributeValueMapper::getType(const QString &val) {
800     if (BOOLEAN_MAP.keys().contains(val)) {
801         return BOOLEAN_TYPE;
802     } else {
803         return UNKNOWN_TYPE;
804     }
805 }
806 
~QDActorPrototype()807 QDActorPrototype::~QDActorPrototype() {
808     qDeleteAll(attributes);
809     delete editor;
810 }
811 
812 }  // namespace U2
813