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 *> ¤tRoute, 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 ¬ification : 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