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 #ifndef _U2_WORKFLOW_ATTR_H_
23 #define _U2_WORKFLOW_ATTR_H_
24
25 #include <cassert>
26
27 #include <QScriptValue>
28 #include <QVariant>
29
30 #include <U2Core/ScriptEngine.h>
31 #include <U2Core/ScriptTask.h>
32 #include <U2Core/Task.h>
33
34 #include <U2Lang/AttributeRelation.h>
35 #include <U2Lang/Datatype.h>
36 #include <U2Lang/Descriptor.h>
37 #include <U2Lang/ScriptLibrary.h>
38 #include <U2Lang/SupportClass.h>
39 #include <U2Lang/WorkflowContext.h>
40 #include <U2Lang/WorkflowScriptEngine.h>
41
42 #include "PortRelation.h"
43 #include "SlotRelation.h"
44
45 namespace U2 {
46
47 typedef QString ActorId;
str2aid(const QString & s)48 inline ActorId str2aid(const QString &s) {
49 return s;
50 }
aid2str(const ActorId & s)51 inline QString aid2str(const ActorId &s) {
52 return s;
53 }
54
55 /**
56 * attribute value can be obtained from script
57 */
58 class U2LANG_EXPORT AttributeScript {
59 public:
60 AttributeScript(const QString &text);
AttributeScript()61 AttributeScript() {
62 }
63
64 bool isEmpty() const;
65
66 void setScriptText(const QString &t);
67 const QString &getScriptText() const;
68
69 void setScriptVar(const Descriptor &desc, const QVariant &val);
70 const QMap<Descriptor, QVariant> &getScriptVars() const;
71 void clearScriptVars();
72
73 bool hasVarWithId(const QString &varName) const;
74 bool hasVarWithDesc(const QString &varName) const;
75 void setVarValueWithId(const QString &varName, const QVariant &value);
76
77 private:
78 QString text;
79 QMap<Descriptor, QVariant> vars; // (desc, val)
80
81 }; // AttributeScript
82
83 /**
84 * Existing types of attributes
85 */
86 enum AttributeGroup {
87 COMMON_GROUP,
88 MARKER_GROUP,
89 GROUPER_SLOT_GROUP
90 };
91
92 /**
93 * Value of certain type that can be identified by (descriptors) id
94 */
95 class U2LANG_EXPORT Attribute : public Descriptor {
96 public:
97 enum Flag {
98 None = 0,
99 CanBeEmpty = 1, // it has meaning only for required attributes, allows the required attribute to be empty
100 NeedValidateEncoding = 2, // it has meaning that the attribute is some string which must be validated against Unicode -> Byte convertion
101 // for example many plugins/external tools accept filenames as char*, but QString -> char* convertion may
102 // produce invalid values if QString's encoding is not the same as system Locale Code Page
103 Required = 4, // values of required attributes cannot be empty, if the appropriate flag is not set
104 Hidden = 8 // Hidden attribute
105 };
106 Q_DECLARE_FLAGS(Flags, Flag)
107
108 Attribute(const Descriptor &descriptor, const DataTypePtr type, const Flags flags = None, const QVariant &defaultValue = QVariant());
109 Attribute(const Descriptor &descriptor, const DataTypePtr type, bool required, const QVariant &defaultValue = QVariant());
110 ~Attribute();
111
112 // getters/setters
113 const DataTypePtr getAttributeType() const;
114 bool isRequiredAttribute() const;
115 bool canBeEmpty() const;
116 bool needValidateEncoding() const;
117 Flags getFlags() const;
118
119 virtual void setAttributeValue(const QVariant &newVal);
120 // attribute value is kept in qvariant
121 // but it can be transformed to value of specific type using scripting or not (see getAttributeValue)
122 virtual const QVariant &getAttributePureValue() const;
123 virtual const QVariant &getDefaultPureValue() const;
124 virtual bool isDefaultValue() const;
125
126 // base realization without scripting. to support scripting for other types: see template realizations
127 template<typename T>
getAttributeValue(Workflow::WorkflowContext *)128 T getAttributeValue(Workflow::WorkflowContext *) const {
129 return getAttributeValueWithoutScript<T>();
130 }
131
132 template<typename T>
getAttributeValueWithoutScript()133 T getAttributeValueWithoutScript() const {
134 return value.value<T>();
135 }
136
137 const AttributeScript &getAttributeScript() const;
138 // used to change script data
139 AttributeScript &getAttributeScript();
140
141 // stores value and script data in variant
142 // used in saving schema to xml
143 QVariant toVariant() const;
144 // reads value and script from variant
145 // used in reading schema from xml
146 bool fromVariant(const QVariant &variant);
147 bool isEmptyString() const;
148 void addRelation(const AttributeRelation *relation);
149 QVector<const AttributeRelation *> &getRelations();
150
151 void addPortRelation(PortRelationDescriptor *relationDesc);
152 const QList<PortRelationDescriptor *> &getPortRelations() const;
153
154 void addSlotRelation(SlotRelationDescriptor *relationDesc);
155 const QList<SlotRelationDescriptor *> &getSlotRelations() const;
156
157 virtual bool isEmpty() const;
158 virtual Attribute *clone();
159 virtual AttributeGroup getGroup();
160
161 /**
162 * Ids of actors in the scheme can be changed (after copy-paste, for example).
163 * It is needed to update all of ids which are used by this attribute
164 */
165 virtual void updateActorIds(const QMap<ActorId, ActorId> &actorIdsMap);
166
167 virtual bool validate(NotificationsList ¬ificationList);
168
169 private:
170 void debugCheckAttributeId() const;
171 void copy(const Attribute &other);
172
173 protected:
174 Attribute(const Attribute &other);
175 Attribute &operator=(const Attribute &other);
176
177 // type of value
178 DataTypePtr type;
179 // Different additional options
180 Flags flags;
181 // pure value and default pure value. if script exists, value should be processed throw it
182 QVariant value;
183 QVariant defaultValue;
184 // script text and variable values for script evaluating
185 // script variables get values only in runtime
186 AttributeScript scriptData;
187
188 QVector<const AttributeRelation *> relations;
189 QList<PortRelationDescriptor *> portRelations;
190 QList<SlotRelationDescriptor *> slotRelations;
191
192 }; // Attribute
193
194 // getAttributeValue function realizations with scripting support
195 template<>
getAttributeValue(Workflow::WorkflowContext * ctx)196 inline QString Attribute::getAttributeValue(Workflow::WorkflowContext *ctx) const {
197 if (scriptData.isEmpty()) {
198 return getAttributeValueWithoutScript<QString>();
199 }
200 // run script
201 WorkflowScriptEngine engine(ctx);
202 QMap<QString, QScriptValue> scriptVars;
203 foreach (const Descriptor &key, scriptData.getScriptVars().uniqueKeys()) {
204 assert(!key.getId().isEmpty());
205 scriptVars[key.getId()] = engine.newVariant(scriptData.getScriptVars().value(key));
206 }
207
208 TaskStateInfo tsi;
209 WorkflowScriptLibrary::initEngine(&engine);
210 QScriptValue scriptResult = ScriptTask::runScript(&engine, scriptVars, scriptData.getScriptText(), tsi);
211
212 // FIXME: report errors!
213 // FIXME: write to log
214 if (tsi.cancelFlag) {
215 if (!tsi.hasError()) {
216 tsi.setError("Script task canceled");
217 }
218 }
219 if (tsi.hasError()) {
220 scriptLog.error(tsi.getError());
221 return QString();
222 }
223 if (scriptResult.isString()) {
224 return scriptResult.toString();
225 }
226
227 return QString();
228 }
229
230 template<>
getAttributeValue(Workflow::WorkflowContext * ctx)231 inline int Attribute::getAttributeValue(Workflow::WorkflowContext *ctx) const {
232 if (scriptData.isEmpty()) {
233 return getAttributeValueWithoutScript<int>();
234 }
235
236 WorkflowScriptEngine engine(ctx);
237 QMap<QString, QScriptValue> scriptVars;
238 foreach (const Descriptor &key, scriptData.getScriptVars().uniqueKeys()) {
239 assert(!key.getId().isEmpty());
240 scriptVars[key.getId()] = engine.newVariant(scriptData.getScriptVars().value(key));
241 }
242
243 TaskStateInfo tsi;
244 WorkflowScriptLibrary::initEngine(&engine);
245 QScriptValue scriptResult = ScriptTask::runScript(&engine, scriptVars, scriptData.getScriptText(), tsi);
246
247 if (tsi.cancelFlag) {
248 if (!tsi.hasError()) {
249 tsi.setError("Script task canceled");
250 }
251 }
252 if (tsi.hasError()) {
253 scriptLog.error(tsi.getError());
254 return 0;
255 }
256 if (scriptResult.isNumber()) {
257 return scriptResult.toInt32();
258 }
259
260 return 0;
261 }
262
263 } // namespace U2
264
265 Q_DECLARE_METATYPE(U2::AttributeScript)
266 Q_DECLARE_OPERATORS_FOR_FLAGS(U2::Attribute::Flags)
267
268 #endif
269