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 "HRWizardSerializer.h"
23 
24 #include <U2Core/U2SafePoints.h>
25 
26 #include <U2Lang/HRSchemaSerializer.h>
27 
28 namespace U2 {
29 namespace WorkflowSerialize {
30 
31 const QString HRWizardParser::WIZARD("wizard");
32 const QString HRWizardParser::NAME("name");
33 const QString HRWizardParser::AUTORUN("auto-run");
34 const QString HRWizardParser::PAGE("page");
35 const QString HRWizardParser::ID("id");
36 const QString HRWizardParser::NEXT("next");
37 const QString HRWizardParser::TITLE("title");
38 const QString HRWizardParser::TEMPLATE("template");
39 const QString HRWizardParser::TYPE("type");
40 const QString HRWizardParser::LOGO_PATH("logo-path");
41 const QString HRWizardParser::DEFAULT("default");
42 const QString HRWizardParser::HIDEABLE("hideable");
43 const QString HRWizardParser::LABEL("label");
44 const QString HRWizardParser::LABEL_SIZE("label-size");
45 const QString HRWizardParser::ELEMENT_ID("element-id");
46 const QString HRWizardParser::PROTOTYPE("prototype");
47 const QString HRWizardParser::VALUE("value");
48 const QString HRWizardParser::PORT_MAPPING("port-mapping");
49 const QString HRWizardParser::SLOTS_MAPPRING("slots-mapping");
50 const QString HRWizardParser::SRC_PORT("src-port");
51 const QString HRWizardParser::DST_PORT("dst-port");
52 const QString HRWizardParser::RESULT("result");
53 const QString HRWizardParser::FINISH_LABEL("finish-label");
54 const QString HRWizardParser::TOOLTIP("tooltip");
55 const QString HRWizardParser::HAS_RUN_BUTTON("has-run-button");
56 const QString HRWizardParser::HAS_DEFAULTS_BUTTON("has-defaults-button");
57 const QString HRWizardParser::DATASETS_PROVIDER("datasets-provider");
58 const QString HRWizardParser::TEXT("text");
59 const QString HRWizardParser::TEXT_COLOR("text-color");
60 const QString HRWizardParser::BACKGROUND_COLOR("background-color");
61 const QString HRWizardParser::HELP_PAGE_ID("help-page-id");
62 
HRWizardParser(Tokenizer & tokenizer,const QMap<QString,Actor * > & _actorMap)63 HRWizardParser::HRWizardParser(Tokenizer &tokenizer, const QMap<QString, Actor *> &_actorMap)
64     : tokenizer(tokenizer), actorMap(_actorMap), wizardName(Wizard::DEFAULT_NAME) {
65 }
66 
~HRWizardParser()67 HRWizardParser::~HRWizardParser() {
68     qDeleteAll(pagesMap);
69 }
70 
takeResult()71 Wizard *HRWizardParser::takeResult() {
72     QList<WizardPage *> retPages = pages;
73     pages.clear();
74     pagesMap.clear();
75 
76     Wizard *wizard = new Wizard(wizardName, retPages, helpPageId);
77     foreach (const QString &name, vars.keys()) {
78         wizard->addVariable(vars[name]);
79     }
80     foreach (const QString &result, results.keys()) {
81         wizard->addResult(results[result], result);
82     }
83     wizard->setFinishLabel(finishLabel);
84     return wizard;
85 }
86 
parseWizard(U2OpStatus & os)87 Wizard *HRWizardParser::parseWizard(U2OpStatus &os) {
88     bool autoRun = false;
89     bool hasRunButton = true;
90     bool hasDefaultsButton = true;
91     while (tokenizer.look() != Constants::BLOCK_END) {
92         QString tok = tokenizer.take();
93         if (PAGE == tok) {
94             tokenizer.assertToken(Constants::BLOCK_START);
95             parsePage(os);
96             CHECK_OP(os, nullptr);
97             tokenizer.assertToken(Constants::BLOCK_END);
98         } else if (NAME == tok) {
99             tokenizer.assertToken(Constants::EQUALS_SIGN);
100             wizardName = tokenizer.take();
101         } else if (HELP_PAGE_ID == tok) {
102             tokenizer.assertToken(Constants::EQUALS_SIGN);
103             helpPageId = tokenizer.take();
104         } else if (AUTORUN == tok) {
105             tokenizer.assertToken(Constants::EQUALS_SIGN);
106             autoRun = ("true" == tokenizer.take());
107         } else if (HAS_RUN_BUTTON == tok) {
108             tokenizer.assertToken(Constants::EQUALS_SIGN);
109             hasRunButton = ("false" != tokenizer.take());
110         } else if (HAS_DEFAULTS_BUTTON == tok) {
111             tokenizer.assertToken(Constants::EQUALS_SIGN);
112             hasDefaultsButton = ("false" != tokenizer.take());
113         } else if (RESULT == tok) {
114             tokenizer.assertToken(Constants::BLOCK_START);
115             parseResult(os);
116             CHECK_OP(os, nullptr);
117             tokenizer.assertToken(Constants::BLOCK_END);
118         } else if (FINISH_LABEL == tok) {
119             tokenizer.assertToken(Constants::EQUALS_SIGN);
120             finishLabel = tokenizer.take();
121         }
122     }
123 
124     finilizePagesOrder(os);
125     CHECK_OP(os, nullptr);
126 
127     Wizard *result = takeResult();
128     CHECK(nullptr != result, nullptr);
129     result->setAutoRun(autoRun);
130     result->setHasRunButton(hasRunButton);
131     result->setHasDefaultsButton(hasDefaultsButton);
132     return result;
133 }
134 
parsePage(U2OpStatus & os)135 void HRWizardParser::parsePage(U2OpStatus &os) {
136     ParsedPairs pairs(tokenizer);
137 
138     QString title = pairs.equalPairs.value(TITLE, "");
139     if (!pairs.equalPairs.contains(ID)) {
140         os.setError(tr("Wizard page %1 does not contain id").arg(title));
141         return;
142     }
143     QString id = pairs.equalPairs.take(ID);
144     if (nextIds.keys().contains(id)) {
145         os.setError(tr("Several wizard pages have equal ids: %1").arg(id));
146         return;
147     }
148 
149     QString templateId = pairs.equalPairs.value(TEMPLATE, DefaultPageContent::ID);
150     QScopedPointer<TemplatedPageContent> content(PageContentFactory::createContent(templateId, os));
151     CHECK_OP(os, );
152     PageContentParser pcp(pairs, actorMap, vars, os);
153     content->accept(&pcp);
154     CHECK_OP(os, );
155 
156     QScopedPointer<WizardPage> page(new WizardPage(id, title));
157     parseNextIds(pairs, page.data(), os);
158     CHECK_OP(os, );
159     page->setContent(content.take());
160     pagesMap[id] = page.take();
161 }
162 
parseResult(U2OpStatus & os)163 void HRWizardParser::parseResult(U2OpStatus &os) {
164     ParsedPairs pairs(tokenizer);
165     foreach (const QString &result, pairs.equalPairs.keys()) {
166         QList<Predicate> preds;
167         QStringList tokens = pairs.equalPairs[result].split(" ");
168         for (const QString &predStr : qAsConst(tokens)) {
169             preds << Predicate::fromString(predStr, os);
170             CHECK_OP(os, );
171         }
172         results[result] = preds;
173     }
174 }
175 
finilizePagesOrder(U2OpStatus & os)176 void HRWizardParser::finilizePagesOrder(U2OpStatus &os) {
177     // TODO: UGENE-1322
178     Q_UNUSED(os);
179     pages = pagesMap.values();
180     // QString lastId;
181     // QList<QString> ids = nextIds.keys();
182     //// Check loops, first page id and last page id
183     // foreach (const QString &id, nextIds.keys()) {
184     //     if (nextIds[id].isEmpty()) {
185     //         if (!lastId.isEmpty()) {
186     //             os.setError(tr("Two pages of the wizard are defined as last: %1, %2").arg(lastId).arg(id));
187     //             return;
188     //         }
189     //         lastId = id;
190     //     } else {
191     //         if (!nextIds.keys().contains(nextIds[id])) {
192     //             os.setError(tr("Unknown next page id: %1").arg(nextIds[id]));
193     //             return;
194     //         }
195     //         if (!ids.contains(nextIds[id])) {
196     //             os.setError(tr("Two pages of the wizard have equal next page ids: %1").arg(nextIds[id]));
197     //             return;
198     //         }
199     //         ids.removeOne(nextIds[id]);
200     //     }
201     // }
202     // if (ids.isEmpty()) {
203     //     os.setError(tr("Some pages of the widget are looped"));
204     //     return;
205     // } else if (ids.size() > 1) {
206     //     os.setError(tr("Several pages of the wizard are defined as first: %1, %2, ...").arg(ids[0]).arg(ids[1]));
207     //     return;
208     // }
209 
210     //// Create pages list saving order
211     // QString currentId = ids.first();
212     // while ("" != currentId) {
213     //     QString nextId = nextIds[currentId];
214 
215     //    WizardPage *page = pagesMap[currentId];
216     //    if (!nextId.isEmpty()) {
217     //        page->setNext(pagesMap[nextId]->getId());
218     //    }
219     //    pages << page;
220     //    currentId = nextId;
221     //}
222 }
223 
parseNextIds(ParsedPairs & pairs,WizardPage * page,U2OpStatus & os)224 void HRWizardParser::parseNextIds(ParsedPairs &pairs, WizardPage *page, U2OpStatus &os) {
225     if (pairs.equalPairs.contains(NEXT)) {
226         QString nextId = pairs.equalPairs.value(NEXT);
227         if (page->getId() == nextId) {
228             os.setError(tr("Page's id and next id are equal: %1").arg(nextId));
229             return;
230         }
231         if (pairs.blockPairs.contains(NEXT)) {
232             os.setError(HRWizardParser::tr("Double definition of next id in the page with id: %1").arg(page->getId()));
233             return;
234         }
235         page->setNext(nextId);
236         return;
237     }
238     if (pairs.blockPairs.contains(NEXT)) {
239         ParsedPairs predPairs(pairs.blockPairs[NEXT]);
240         foreach (const QString &id, predPairs.equalPairs.keys()) {
241             Predicate p = Predicate::fromString(predPairs.equalPairs[id], os);
242             CHECK_OP(os, );
243             page->setNext(id, p, os);
244             CHECK_OP(os, );
245         }
246     }
247 }
248 
249 /************************************************************************/
250 /* WizardWidgetParser */
251 /************************************************************************/
WizardWidgetParser(const QString & _title,const QString & _data,const QMap<QString,Actor * > & _actorMap,QMap<QString,Variable> & _vars,U2OpStatus & _os)252 WizardWidgetParser::WizardWidgetParser(const QString &_title,
253                                        const QString &_data,
254                                        const QMap<QString, Actor *> &_actorMap,
255                                        QMap<QString, Variable> &_vars,
256                                        U2OpStatus &_os)
257     : title(_title), data(_data), actorMap(_actorMap), vars(_vars), os(_os) {
258 }
259 
visit(AttributeWidget * aw)260 void WizardWidgetParser::visit(AttributeWidget *aw) {
261     AttributeInfo info = parseInfo(title, data);
262     CHECK_OP(os, );
263     aw->setInfo(info);
264 }
265 
visit(WidgetsArea * wa)266 void WizardWidgetParser::visit(WidgetsArea *wa) {
267     pairs = ParsedPairs(data, 0);
268 
269     getTitle(wa);
270     getLabelSize(wa);
271 
272     foreach (const StrStrPair &pair, pairs.blockPairsList) {
273         WizardWidgetParser wParser(pair.first, pair.second, actorMap, vars, os);
274         QScopedPointer<WizardWidget> w(createWidget(pair.first));
275         CHECK_OP(os, );
276         w->accept(&wParser);
277         CHECK_OP(os, );
278         wa->addWidget(w.take());
279     }
280 }
281 
visit(LogoWidget * lw)282 void WizardWidgetParser::visit(LogoWidget *lw) {
283     pairs = ParsedPairs(data, 0);
284     if (pairs.equalPairs.contains(HRWizardParser::LOGO_PATH)) {
285         lw->setLogoPath(pairs.equalPairs.value(HRWizardParser::LOGO_PATH));
286     }
287 }
288 
visit(GroupWidget * gw)289 void WizardWidgetParser::visit(GroupWidget *gw) {
290     visit((WidgetsArea *)gw);
291     CHECK_OP(os, );
292 
293     QString typeStr = pairs.equalPairs.value(HRWizardParser::TYPE, HRWizardParser::DEFAULT);
294     if (HRWizardParser::DEFAULT == typeStr) {
295         gw->setType(GroupWidget::DEFAULT);
296     } else if (HRWizardParser::HIDEABLE == typeStr) {
297         gw->setType(GroupWidget::HIDEABLE);
298     }
299 }
300 
visit(ElementSelectorWidget * esw)301 void WizardWidgetParser::visit(ElementSelectorWidget *esw) {
302     pairs = ParsedPairs(data, 0);
303     if (!pairs.equalPairs.contains(HRWizardParser::ELEMENT_ID)) {
304         os.setError(HRWizardParser::tr("Element id is undefined in the element selector"));
305         return;
306     }
307     QString actorId = pairs.equalPairs[HRWizardParser::ELEMENT_ID];
308     if (!actorMap.contains(actorId)) {
309         os.setError(HRWizardParser::tr("Undefined actor id: %1").arg(actorId));
310         return;
311     }
312     esw->setActorId(actorId);
313     if (pairs.equalPairs.contains(AttributeInfo::LABEL)) {
314         esw->setLabel(pairs.equalPairs[AttributeInfo::LABEL]);
315     }
316     ActorPrototype *srcProto = actorMap[actorId]->getProto();
317     foreach (const StrStrPair &pair, pairs.blockPairsList) {
318         if (pair.first != HRWizardParser::VALUE) {
319             os.setError(HRWizardParser::tr("Unknown block name in element selector definition: %1").arg(pair.first));
320             return;
321         }
322         SelectorValue value = parseSelectorValue(srcProto, pair.second);
323         CHECK_OP(os, );
324         esw->addValue(value);
325     }
326     addVariable(Variable(actorId));
327     CHECK_OP(os, );
328 }
329 
visit(PairedReadsWidget * dsw)330 void WizardWidgetParser::visit(PairedReadsWidget *dsw) {
331     pairs = ParsedPairs(data, 0);
332     foreach (const StrStrPair &p, pairs.blockPairsList) {
333         dsw->addInfo(parseInfo(p.first, p.second));
334         CHECK_OP(os, );
335     }
336 }
337 
visit(UrlAndDatasetWidget * ldsw)338 void WizardWidgetParser::visit(UrlAndDatasetWidget *ldsw) {
339     pairs = ParsedPairs(data, 0);
340     foreach (const StrStrPair &p, pairs.blockPairsList) {
341         ldsw->addInfo(parseInfo(p.first, p.second));
342         CHECK_OP(os, );
343     }
344 }
345 
parseValue(const QString & valueDef,U2OpStatus & os)346 static RadioWidget::Value parseValue(const QString &valueDef, U2OpStatus &os) {
347     ParsedPairs pairs(valueDef, 0);
348     if (!pairs.equalPairs.contains(HRWizardParser::ID)) {
349         os.setError("No id of radio value");
350         return RadioWidget::Value("", "");
351     }
352     QString id = pairs.equalPairs[HRWizardParser::ID];
353     QString label = pairs.equalPairs.value(HRWizardParser::LABEL, id);
354     RadioWidget::Value result(id, label);
355 
356     result.tooltip = pairs.equalPairs.value(HRWizardParser::TOOLTIP, "");
357     return result;
358 }
359 
serializeValue(const RadioWidget::Value & value,int depth)360 static QString serializeValue(const RadioWidget::Value &value, int depth) {
361     QString vData;
362     vData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::ID, value.id, depth + 1);
363     if (!value.label.isEmpty()) {
364         vData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::LABEL, value.label, depth + 1);
365     }
366     if (!value.tooltip.isEmpty()) {
367         vData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::TOOLTIP, value.tooltip, depth + 1);
368     }
369 
370     return HRSchemaSerializer::makeBlock(HRWizardParser::VALUE, Constants::NO_NAME, vData, depth);
371 }
372 
visit(RadioWidget * rw)373 void WizardWidgetParser::visit(RadioWidget *rw) {
374     pairs = ParsedPairs(data, 0);
375     if (!pairs.equalPairs.contains(HRWizardParser::ID)) {
376         os.setError("No id of radio");
377         return;
378     }
379 
380     rw->setVar(pairs.equalPairs[HRWizardParser::ID]);
381     Variable v(rw->var());
382     foreach (const StrStrPair &p, pairs.blockPairsList) {
383         if (p.first == HRWizardParser::VALUE) {
384             RadioWidget::Value value = parseValue(p.second, os);
385             CHECK_OP(os, );
386             rw->add(value);
387             if (!v.isAssigned()) {
388                 v.setValue(value.id);
389             }
390         }
391     }
392 
393     addVariable(v);
394     CHECK_OP(os, );
395 }
396 
visit(SettingsWidget * sw)397 void WizardWidgetParser::visit(SettingsWidget *sw) {
398     pairs = ParsedPairs(data, 0);
399     if (!pairs.equalPairs.contains(HRWizardParser::ID)) {
400         os.setError("No id of settings-widget");
401         return;
402     }
403 
404     sw->setVar(SettingsWidget::SETTING_PREFIX + pairs.equalPairs[HRWizardParser::ID]);
405     sw->setType(pairs.equalPairs[HRWizardParser::TYPE]);
406     sw->setLabel(pairs.equalPairs[HRWizardParser::LABEL]);
407     Variable v(sw->var());
408 
409     addVariable(v);
410     CHECK_OP(os, );
411 }
412 
visit(BowtieWidget * bw)413 void WizardWidgetParser::visit(BowtieWidget *bw) {
414     pairs = ParsedPairs(data, 0);
415     if (pairs.blockPairsList.size() != 2) {
416         os.setError("Not enough attributes for Bowtie index widget");
417         return;
418     }
419     bw->idxDir = parseInfo(pairs.blockPairsList[0].first, pairs.blockPairsList[0].second);
420     CHECK_OP(os, );
421     bw->idxName = parseInfo(pairs.blockPairsList[1].first, pairs.blockPairsList[1].second);
422     CHECK_OP(os, );
423 }
424 
visit(TophatSamplesWidget * tsw)425 void WizardWidgetParser::visit(TophatSamplesWidget *tsw) {
426     pairs = ParsedPairs(data, 0);
427     if (!pairs.equalPairs.contains(HRWizardParser::DATASETS_PROVIDER)) {
428         os.setError(HRWizardParser::tr("Not enough attributes for Tophat samples widget"));
429         return;
430     }
431     if (1 != pairs.blockPairsList.size()) {
432         os.setError(HRWizardParser::tr("Not enough attributes for Tophat samples widget"));
433         return;
434     }
435     tsw->datasetsProvider = pairs.equalPairs[HRWizardParser::DATASETS_PROVIDER];
436     tsw->samplesAttr = parseInfo(pairs.blockPairsList[0].first, pairs.blockPairsList[0].second);
437 }
438 
visit(LabelWidget * lw)439 void WizardWidgetParser::visit(LabelWidget *lw) {
440     pairs = ParsedPairs(data, 0);
441     if (!pairs.equalPairs.contains(HRWizardParser::TEXT)) {
442         os.setError(HRWizardParser::tr("Not enough attributes for the label widget"));
443         return;
444     }
445     lw->text = pairs.equalPairs[HRWizardParser::TEXT];
446 
447     if (pairs.equalPairs.contains(HRWizardParser::TEXT_COLOR)) {
448         lw->textColor = pairs.equalPairs[HRWizardParser::TEXT_COLOR];
449     }
450     if (pairs.equalPairs.contains(HRWizardParser::BACKGROUND_COLOR)) {
451         lw->backgroundColor = pairs.equalPairs[HRWizardParser::BACKGROUND_COLOR];
452     }
453 }
454 
parseSelectorValue(ActorPrototype * srcProto,const QString & valueDef)455 SelectorValue WizardWidgetParser::parseSelectorValue(ActorPrototype *srcProto, const QString &valueDef) {
456     ParsedPairs pairs(valueDef, 0);
457     if (!pairs.equalPairs.contains(HRWizardParser::ID)) {
458         os.setError(HRWizardParser::tr("Id is undefined in some selector value definition"));
459         return SelectorValue("", "");
460     }
461     QString id = pairs.equalPairs[HRWizardParser::ID];
462     if (!pairs.equalPairs.contains(HRWizardParser::PROTOTYPE)) {
463         os.setError(HRWizardParser::tr("Prototype is undefined in the selector value definition: %1").arg(id));
464         return SelectorValue("", "");
465     }
466     QString protoId = pairs.equalPairs[HRWizardParser::PROTOTYPE];
467     SelectorValue result(id, protoId);
468     result.setName(pairs.equalPairs[HRWizardParser::NAME]);
469     if (srcProto->getId() == protoId) {
470         if (!pairs.blockPairsList.isEmpty()) {
471             os.setError(HRWizardParser::tr("The same prototype could not be mapped: %1").arg(protoId));
472         }
473         return result;
474     }
475     foreach (const StrStrPair &pair, pairs.blockPairsList) {
476         if (pair.first != HRWizardParser::PORT_MAPPING) {
477             os.setError(HRWizardParser::tr("Unknown block name in selector value definition: %1").arg(pair.first));
478             return result;
479         }
480         PortMapping mapping = parsePortMapping(pair.second);
481         CHECK_OP(os, result);
482         result.addPortMapping(mapping);
483     }
484     return result;
485 }
486 
parsePortMapping(const QString & mappingDef)487 PortMapping WizardWidgetParser::parsePortMapping(const QString &mappingDef) {
488     ParsedPairs pairs(mappingDef, 0);
489     if (!pairs.equalPairs.contains(HRWizardParser::SRC_PORT)) {
490         os.setError(HRWizardParser::tr("Undefined source port id for some port mapping"));
491         return PortMapping("", "");
492     }
493     if (!pairs.equalPairs.contains(HRWizardParser::DST_PORT)) {
494         os.setError(HRWizardParser::tr("Undefined destination port id for some port mapping"));
495         return PortMapping("", "");
496     }
497     QString srcPortId = pairs.equalPairs[HRWizardParser::SRC_PORT];
498     QString dstPortId = pairs.equalPairs[HRWizardParser::DST_PORT];
499     PortMapping result(srcPortId, dstPortId);
500     foreach (const StrStrPair &pair, pairs.blockPairsList) {
501         if (pair.first != HRWizardParser::SLOTS_MAPPRING) {
502             os.setError(HRWizardParser::tr("Unknown block name in port mapping definition: %1").arg(pair.first));
503             return result;
504         }
505         parseSlotsMapping(result, pair.second);
506         CHECK_OP(os, result);
507     }
508     return result;
509 }
510 
parseSlotsMapping(PortMapping & pm,const QString & mappingDef)511 void WizardWidgetParser::parseSlotsMapping(PortMapping &pm, const QString &mappingDef) {
512     ParsedPairs pairs(mappingDef, 0);
513     foreach (const StrStrPair &pair, pairs.equalPairsList) {
514         QString srcSlotId = pair.first;
515         QString dstSlotId = pair.second;
516         pm.addSlotMapping(SlotMapping(srcSlotId, dstSlotId));
517     }
518 }
519 
getLabelSize(WidgetsArea * wa)520 void WizardWidgetParser::getLabelSize(WidgetsArea *wa) {
521     if (pairs.equalPairs.contains(HRWizardParser::LABEL_SIZE)) {
522         QString &sizeStr = pairs.equalPairs[HRWizardParser::LABEL_SIZE];
523         bool ok = true;
524         int size = sizeStr.toInt(&ok);
525         if (!ok) {
526             os.setError(QObject::tr("Wrong label size value: %1").arg(sizeStr));
527             return;
528         }
529         wa->setLabelSize(size);
530     }
531 }
532 
getTitle(WidgetsArea * wa)533 void WizardWidgetParser::getTitle(WidgetsArea *wa) {
534     if (pairs.equalPairs.contains(HRWizardParser::TITLE)) {
535         wa->setTitle(pairs.equalPairs[HRWizardParser::TITLE]);
536     }
537 }
538 
createWidget(const QString & id)539 WizardWidget *WizardWidgetParser::createWidget(const QString &id) {
540     if (LogoWidget::ID == id) {
541         return new LogoWidget();
542     } else if (GroupWidget::ID == id) {
543         return new GroupWidget();
544     } else if (ElementSelectorWidget::ID == id) {
545         return new ElementSelectorWidget();
546     } else if (PairedReadsWidget::ID == id) {
547         return new PairedReadsWidget();
548     } else if (UrlAndDatasetWidget::ID == id) {
549         return new UrlAndDatasetWidget();
550     } else if (RadioWidget::ID == id) {
551         return new RadioWidget();
552     } else if (SettingsWidget::ID == id) {
553         return new SettingsWidget();
554     } else if (BowtieWidget::ID == id) {
555         return new BowtieWidget();
556     } else if (TophatSamplesWidget::ID == id) {
557         return new TophatSamplesWidget();
558     } else if (LabelWidget::ID == id) {
559         return new LabelWidget();
560     } else {
561         return new AttributeWidget();
562     }
563 }
564 
addVariable(const Variable & v)565 void WizardWidgetParser::addVariable(const Variable &v) {
566     if (vars.contains(v.getName())) {
567         os.setError(QObject::tr("The variable is already defined: %1").arg(v.getName()));
568         return;
569     }
570     vars[v.getName()] = v;
571 }
572 
parseInfo(const QString & attrStr,const QString & body)573 AttributeInfo WizardWidgetParser::parseInfo(const QString &attrStr, const QString &body) {
574     QStringList vals = attrStr.split(Constants::DOT, QString::SkipEmptyParts);
575     if (2 != vals.size()) {
576         os.setError(HRWizardParser::tr("Unknown widget name: %1").arg(attrStr));
577         return AttributeInfo("", "");
578     }
579 
580     ParsedPairs pairs = ParsedPairs(body, 0);
581     QVariantMap hints;
582     foreach (const QString &id, pairs.equalPairs.keys()) {
583         hints[id] = pairs.equalPairs[id];
584     }
585 
586     return AttributeInfo(vals[0], vals[1], hints);
587 }
588 
589 /************************************************************************/
590 /* PageContentParser */
591 /************************************************************************/
PageContentParser(ParsedPairs & pairs,const QMap<QString,Actor * > & actorMap,QMap<QString,Variable> & vars,U2OpStatus & os)592 PageContentParser::PageContentParser(ParsedPairs &pairs,
593                                      const QMap<QString, Actor *> &actorMap,
594                                      QMap<QString, Variable> &vars,
595                                      U2OpStatus &os)
596     : pairs(pairs), actorMap(actorMap), vars(vars), os(os) {
597 }
598 
visit(DefaultPageContent * content)599 void PageContentParser::visit(DefaultPageContent *content) {
600     foreach (const StrStrPair &pair, pairs.blockPairsList) {
601         WizardWidgetParser wParser(pair.first, pair.second, actorMap, vars, os);
602         if (LogoWidget::ID == pair.first) {
603             content->getLogoArea()->accept(&wParser);
604         } else if (DefaultPageContent::PARAMETERS == pair.first) {
605             content->getParamsArea()->accept(&wParser);
606         }
607         CHECK_OP(os, );
608     }
609 }
610 
611 /************************************************************************/
612 /* HRWizardSerializer */
613 /************************************************************************/
serialize(Wizard * wizard,int depth)614 QString HRWizardSerializer::serialize(Wizard *wizard, int depth) {
615     QString wizardData;
616 
617     if (Wizard::DEFAULT_NAME != wizard->getName()) {
618         wizardData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::NAME,
619                                                          wizard->getName(),
620                                                          depth + 1);
621     }
622 
623     if (wizard->isAutoRun()) {
624         wizardData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::AUTORUN, "true", depth + 1);
625     }
626 
627     if (!wizard->hasRunButton()) {
628         wizardData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::HAS_RUN_BUTTON, "false", depth + 1);
629     }
630     if (!wizard->hasDefaultsButton()) {
631         wizardData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::HAS_DEFAULTS_BUTTON, "false", depth + 1);
632     }
633 
634     if (!wizard->getResults().isEmpty()) {
635         wizardData += serializeResults(wizard->getResults(), depth + 1);
636     }
637 
638     foreach (WizardPage *page, wizard->getPages()) {
639         wizardData += serializePage(page, depth + 1);
640     }
641 
642     return HRSchemaSerializer::makeBlock(HRWizardParser::WIZARD,
643                                          Constants::NO_NAME,
644                                          wizardData,
645                                          depth);
646 }
647 
serializePage(WizardPage * page,int depth)648 QString HRWizardSerializer::serializePage(WizardPage *page, int depth) {
649     QString pageData;
650 
651     pageData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::ID, page->getId(), depth + 1);
652     pageData += HRWizardSerializer::serializeNextId(page, depth + 1);
653     if (!page->getTitle().isEmpty()) {
654         pageData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::TITLE,
655                                                        page->getTitle(),
656                                                        depth + 1);
657     }
658     if (DefaultPageContent::ID != page->getContent()->getTemplateId()) {
659         pageData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::TEMPLATE,
660                                                        page->getContent()->getTemplateId(),
661                                                        depth + 1);
662     }
663 
664     PageContentSerializer cs(depth + 1);
665     page->getContent()->accept(&cs);
666     pageData += cs.getResult();
667 
668     return HRSchemaSerializer::makeBlock(HRWizardParser::PAGE,
669                                          Constants::NO_NAME,
670                                          pageData,
671                                          depth);
672 }
673 
serializeResults(const QMap<QString,QList<Predicate>> results,int depth)674 QString HRWizardSerializer::serializeResults(const QMap<QString, QList<Predicate>> results, int depth) {
675     QString rData;
676 
677     foreach (const QString &result, results.keys()) {
678         QStringList preds;
679         const QList<Predicate> &predicates = results[result];
680         for (const Predicate &p : qAsConst(predicates)) {
681             preds << p.toString();
682         }
683         QString predsStr = preds.join(" ");
684         rData += HRSchemaSerializer::makeEqualsPair(result, predsStr, depth + 1);
685     }
686 
687     return HRSchemaSerializer::makeBlock(HRWizardParser::RESULT,
688                                          Constants::NO_NAME,
689                                          rData,
690                                          depth);
691 }
692 
serializeNextId(WizardPage * page,int depth)693 QString HRWizardSerializer::serializeNextId(WizardPage *page, int depth) {
694     if (page->nextIdMap().isEmpty()) {
695         if (page->plainNextId().isEmpty()) {
696             return "";
697         }
698         return HRSchemaSerializer::makeEqualsPair(HRWizardParser::NEXT, page->plainNextId(), depth);
699     }
700     QString nextData;
701     foreach (const Predicate &p, page->nextIdMap().keys()) {
702         QString id = page->nextIdMap()[p];
703         nextData += HRSchemaSerializer::makeEqualsPair(id, p.toString(), depth + 1);
704     }
705     return HRSchemaSerializer::makeBlock(HRWizardParser::NEXT,
706                                          Constants::NO_NAME,
707                                          nextData,
708                                          depth);
709 }
710 
711 /************************************************************************/
712 /* WizardWidgetSerializer */
713 /************************************************************************/
WizardWidgetSerializer(int _depth)714 WizardWidgetSerializer::WizardWidgetSerializer(int _depth)
715     : depth(_depth) {
716 }
717 
visit(AttributeWidget * aw)718 void WizardWidgetSerializer::visit(AttributeWidget *aw) {
719     result = serializeInfo(aw->getInfo(), depth);
720 }
721 
visit(WidgetsArea * wa)722 void WizardWidgetSerializer::visit(WidgetsArea *wa) {
723     QString wData;
724     // write title
725     if (!wa->getTitle().isEmpty()) {
726         wData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::TITLE,
727                                                     wa->getTitle(),
728                                                     depth + 1);
729     }
730     // write label size
731     if (wa->hasLabelSize()) {
732         wData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::LABEL_SIZE,
733                                                     QString::number(wa->getLabelSize()),
734                                                     depth + 1);
735     }
736     // write additional info
737     wData += addInfo;
738     // write widgets
739     foreach (WizardWidget *w, wa->getWidgets()) {
740         WizardWidgetSerializer ws(depth + 1);
741         w->accept(&ws);
742         wData += ws.getResult();
743     }
744 
745     result = HRSchemaSerializer::makeBlock(wa->getName(),
746                                            Constants::NO_NAME,
747                                            wData,
748                                            depth);
749 }
750 
visit(GroupWidget * gw)751 void WizardWidgetSerializer::visit(GroupWidget *gw) {
752     if (GroupWidget::HIDEABLE == gw->getType()) {
753         addInfo = HRSchemaSerializer::makeEqualsPair(HRWizardParser::TYPE,
754                                                      HRWizardParser::HIDEABLE,
755                                                      depth + 1);
756     }
757     visit((WidgetsArea *)gw);
758 }
759 
visit(LogoWidget * lw)760 void WizardWidgetSerializer::visit(LogoWidget *lw) {
761     QString wData;
762     if (!lw->isDefault()) {
763         wData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::LOGO_PATH,
764                                                     lw->getLogoPath(),
765                                                     depth + 1);
766     }
767     result = HRSchemaSerializer::makeBlock(LogoWidget::ID,
768                                            Constants::NO_NAME,
769                                            wData,
770                                            depth);
771 }
772 
visit(ElementSelectorWidget * esw)773 void WizardWidgetSerializer::visit(ElementSelectorWidget *esw) {
774     QString wData;
775     wData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::ELEMENT_ID,
776                                                 esw->getActorId(),
777                                                 depth + 1);
778     if (!esw->getLabel().isEmpty()) {
779         wData += HRSchemaSerializer::makeEqualsPair(AttributeInfo::LABEL,
780                                                     esw->getLabel(),
781                                                     depth + 1);
782     }
783     foreach (const SelectorValue &value, esw->getValues()) {
784         wData += serializeSelectorValue(value, depth + 1);
785     }
786     result = HRSchemaSerializer::makeBlock(ElementSelectorWidget::ID,
787                                            Constants::NO_NAME,
788                                            wData,
789                                            depth);
790 }
791 
visit(PairedReadsWidget * dsw)792 void WizardWidgetSerializer::visit(PairedReadsWidget *dsw) {
793     QString dData;
794     foreach (const AttributeInfo &info, dsw->getInfos()) {
795         dData += serializeInfo(info, depth + 1);
796     }
797     result = HRSchemaSerializer::makeBlock(PairedReadsWidget::ID,
798                                            Constants::NO_NAME,
799                                            dData,
800                                            depth);
801 }
802 
visit(UrlAndDatasetWidget * ldsw)803 void WizardWidgetSerializer::visit(UrlAndDatasetWidget *ldsw) {
804     QString dData;
805     foreach (const AttributeInfo &info, ldsw->getInfos()) {
806         dData += serializeInfo(info, depth + 1);
807     }
808     result = HRSchemaSerializer::makeBlock(UrlAndDatasetWidget::ID,
809                                            Constants::NO_NAME,
810                                            dData,
811                                            depth);
812 }
813 
visit(RadioWidget * rw)814 void WizardWidgetSerializer::visit(RadioWidget *rw) {
815     QString rData;
816     rData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::ID, rw->var(), depth + 1);
817     foreach (const RadioWidget::Value &value, rw->values()) {
818         rData += serializeValue(value, depth + 1);
819     }
820     result = HRSchemaSerializer::makeBlock(RadioWidget::ID,
821                                            Constants::NO_NAME,
822                                            rData,
823                                            depth);
824 }
825 
visit(SettingsWidget * sw)826 void WizardWidgetSerializer::visit(SettingsWidget *sw) {
827     QString rData;
828     QString var = sw->var();
829     if (var.startsWith(SettingsWidget::SETTING_PREFIX)) {
830         var.remove(0, SettingsWidget::SETTING_PREFIX.length());
831     }
832 
833     rData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::ID, var, depth + 1);
834     rData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::TYPE, sw->type(), depth + 1);
835     rData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::LABEL, sw->label(), depth + 1);
836     result = HRSchemaSerializer::makeBlock(SettingsWidget::ID,
837                                            Constants::NO_NAME,
838                                            rData,
839                                            depth);
840 }
841 
visit(BowtieWidget * bw)842 void WizardWidgetSerializer::visit(BowtieWidget *bw) {
843     QString bData;
844     bData += serializeInfo(bw->idxDir, depth + 1);
845     bData += serializeInfo(bw->idxName, depth + 1);
846     result = HRSchemaSerializer::makeBlock(BowtieWidget::ID,
847                                            Constants::NO_NAME,
848                                            bData,
849                                            depth);
850 }
851 
visit(TophatSamplesWidget * tsw)852 void WizardWidgetSerializer::visit(TophatSamplesWidget *tsw) {
853     QString tsData;
854     tsData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::DATASETS_PROVIDER,
855                                                  tsw->datasetsProvider,
856                                                  depth + 1);
857     tsData += serializeInfo(tsw->samplesAttr, depth + 1);
858 
859     result = HRSchemaSerializer::makeBlock(TophatSamplesWidget::ID,
860                                            Constants::NO_NAME,
861                                            tsData,
862                                            depth);
863 }
864 
visit(LabelWidget * lw)865 void WizardWidgetSerializer::visit(LabelWidget *lw) {
866     QString lData;
867     lData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::TEXT, lw->text, depth + 1);
868     if (lw->backgroundColor != LabelWidget::DEFAULT_BG_COLOR) {
869         lData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::BACKGROUND_COLOR, lw->backgroundColor, depth + 1);
870     }
871     if (lw->textColor != LabelWidget::DEFAULT_TEXT_COLOR) {
872         lData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::TEXT_COLOR, lw->textColor, depth + 1);
873     }
874     result = HRSchemaSerializer::makeBlock(LabelWidget::ID, Constants::NO_NAME, lData, depth);
875 }
876 
serializeSlotsMapping(const QList<SlotMapping> & mappings,int depth) const877 QString WizardWidgetSerializer::serializeSlotsMapping(const QList<SlotMapping> &mappings, int depth) const {
878     QString smData;
879     foreach (const SlotMapping &mapping, mappings) {
880         smData += HRSchemaSerializer::makeEqualsPair(mapping.getSrcId(),
881                                                      mapping.getDstId(),
882                                                      depth + 1);
883     }
884     return HRSchemaSerializer::makeBlock(HRWizardParser::SLOTS_MAPPRING,
885                                          Constants::NO_NAME,
886                                          smData,
887                                          depth);
888 }
889 
serializePortMapping(const PortMapping & mapping,int depth) const890 QString WizardWidgetSerializer::serializePortMapping(const PortMapping &mapping, int depth) const {
891     QString pmData;
892     pmData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::SRC_PORT,
893                                                  mapping.getSrcId(),
894                                                  depth + 1);
895     pmData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::DST_PORT,
896                                                  mapping.getDstId(),
897                                                  depth + 1);
898     pmData += serializeSlotsMapping(mapping.getMappings(), depth + 1);
899     return HRSchemaSerializer::makeBlock(HRWizardParser::PORT_MAPPING,
900                                          Constants::NO_NAME,
901                                          pmData,
902                                          depth);
903 }
904 
serializeSelectorValue(const SelectorValue & value,int depth) const905 QString WizardWidgetSerializer::serializeSelectorValue(const SelectorValue &value, int depth) const {
906     QString vData;
907     vData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::ID,
908                                                 value.getValue(),
909                                                 depth + 1);
910     vData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::PROTOTYPE,
911                                                 value.getProtoId(),
912                                                 depth + 1);
913     if (!value.getName().isEmpty()) {
914         vData += HRSchemaSerializer::makeEqualsPair(HRWizardParser::NAME,
915                                                     value.getName(),
916                                                     depth + 1);
917     }
918     foreach (const PortMapping &mapping, value.getMappings()) {
919         vData += serializePortMapping(mapping, depth + 1);
920     }
921     return HRSchemaSerializer::makeBlock(HRWizardParser::VALUE,
922                                          Constants::NO_NAME,
923                                          vData,
924                                          depth);
925 }
926 
serializeInfo(const AttributeInfo & info,int depth) const927 QString WizardWidgetSerializer::serializeInfo(const AttributeInfo &info, int depth) const {
928     QString iData;
929 
930     foreach (const QString &id, info.hints.keys()) {
931         QString value = info.hints[id].toString();
932         if (!value.isEmpty()) {
933             iData += HRSchemaSerializer::makeEqualsPair(id, value, depth + 1);
934         }
935     }
936 
937     QString name = info.actorId + Constants::DOT + info.attrId;
938     return HRSchemaSerializer::makeBlock(name, Constants::NO_NAME, iData, depth);
939 }
940 
getResult()941 const QString &WizardWidgetSerializer::getResult() {
942     return result;
943 }
944 
945 /************************************************************************/
946 /* PageContentSerializer */
947 /************************************************************************/
PageContentSerializer(int _depth)948 PageContentSerializer::PageContentSerializer(int _depth)
949     : depth(_depth) {
950 }
951 
visit(DefaultPageContent * content)952 void PageContentSerializer::visit(DefaultPageContent *content) {
953     WizardWidgetSerializer pws(depth);
954     content->getParamsArea()->accept(&pws);
955     result += pws.getResult();
956 
957     if (!content->getLogoArea()->isDefault()) {
958         WizardWidgetSerializer lws(depth);
959         content->getLogoArea()->accept(&lws);
960         result += lws.getResult();
961     }
962 }
963 
getResult() const964 const QString &PageContentSerializer::getResult() const {
965     return result;
966 }
967 
968 }  // namespace WorkflowSerialize
969 }  // namespace U2
970