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 "FilterAnnotationsByQualifierWorker.h"
23 
24 #include <U2Core/AnnotationTableObject.h>
25 #include <U2Core/TaskSignalMapper.h>
26 
27 #include <U2Designer/DelegateEditors.h>
28 
29 #include <U2Gui/DialogUtils.h>
30 
31 #include <U2Lang/ActorPrototypeRegistry.h>
32 #include <U2Lang/BaseActorCategories.h>
33 #include <U2Lang/BasePorts.h>
34 #include <U2Lang/BaseSlots.h>
35 #include <U2Lang/BaseTypes.h>
36 #include <U2Lang/ConfigurationEditor.h>
37 #include <U2Lang/CoreLibConstants.h>
38 #include <U2Lang/WorkflowEnv.h>
39 
40 namespace U2 {
41 namespace LocalWorkflow {
42 
43 const QString FilterAnnotationsByQualifierWorkerFactory::ACTOR_ID("filter-annotations-by-qualifier");
44 
45 const static QString QUALIFER_NAME_ATTR("qualifier-name");
46 const static QString QUALIFER_VALUE_ATTR("qualifier-value");
47 const static QString WHICH_FILTER_ATTR("accept-or-filter");
48 
composeRichDoc()49 QString FilterAnnotationsByQualifierPrompter::composeRichDoc() {
50     QString unsetStr = "<font color='red'>" + tr("unset") + "</font>";
51     QString annName = getProducers(BasePorts::IN_ANNOTATIONS_PORT_ID(), BaseSlots::ANNOTATION_TABLE_SLOT().getId());
52     annName = annName.isEmpty() ? unsetStr : annName;
53     return tr("Filter annotations from <u>%1</u> by given qualifier name and value.").arg(annName);
54 }
55 
init()56 void FilterAnnotationsByQualifierWorker::init() {
57     input = ports.value(BasePorts::IN_ANNOTATIONS_PORT_ID());
58     output = ports.value(BasePorts::OUT_ANNOTATIONS_PORT_ID());
59 }
60 
tick()61 Task *FilterAnnotationsByQualifierWorker::tick() {
62     if (input->hasMessage()) {
63         Message inputMessage = getMessageAndSetupScriptValues(input);
64         if (inputMessage.isEmpty()) {
65             output->transit();
66             return nullptr;
67         }
68 
69         QVariantMap qm = inputMessage.getData().toMap();
70         const QVariant annsVar = qm[BaseSlots::ANNOTATION_TABLE_SLOT().getId()];
71         inputAnns = StorageUtils::getAnnotationTable(context->getDataStorage(), annsVar);
72 
73         bool accept = actor->getParameter(WHICH_FILTER_ATTR)->getAttributeValue<bool>(context);
74         QString qualName = actor->getParameter(QUALIFER_NAME_ATTR)->getAttributeValue<QString>(context);
75         QString qualValue = actor->getParameter(QUALIFER_VALUE_ATTR)->getAttributeValue<QString>(context);
76 
77         Task *t = new FilterAnnotationsByQualifierTask(inputAnns, qualName, qualValue, accept);
78         connect(new TaskSignalMapper(t), SIGNAL(si_taskFinished(Task *)), SLOT(sl_taskFinished(Task *)));
79         return t;
80     } else if (input->isEnded()) {
81         setDone();
82         output->setEnded();
83     }
84     return nullptr;
85 }
86 
sl_taskFinished(Task * t)87 void FilterAnnotationsByQualifierWorker::sl_taskFinished(Task *t) {
88     if (t->isCanceled() || t->hasError()) {
89         return;
90     }
91     const SharedDbiDataHandler tableId = context->getDataStorage()->putAnnotationTable(inputAnns);
92     output->put(Message(BaseTypes::ANNOTATION_TABLE_TYPE(),
93                         qVariantFromValue<SharedDbiDataHandler>(tableId)));
94 }
95 
cleanup()96 void FilterAnnotationsByQualifierWorker::cleanup() {
97 }
98 
init()99 void FilterAnnotationsByQualifierWorkerFactory::init() {
100     QList<PortDescriptor *> portDescs;
101     QList<Attribute *> attribs;
102 
103     // accept sequence and annotated regions as input
104     QMap<Descriptor, DataTypePtr> inputMap;
105     inputMap[BaseSlots::ANNOTATION_TABLE_SLOT()] = BaseTypes::ANNOTATION_TABLE_TYPE();
106 
107     {  // Create input port descriptors
108         Descriptor inDesc(BasePorts::IN_ANNOTATIONS_PORT_ID(), FilterAnnotationsByQualifierWorker::tr("Input annotations"), FilterAnnotationsByQualifierWorker::tr("Annotations to be filtered by name."));
109         Descriptor outDesc(BasePorts::OUT_ANNOTATIONS_PORT_ID(), FilterAnnotationsByQualifierWorker::tr("Result annotations"), FilterAnnotationsByQualifierWorker::tr("Resulted annotations, filtered by name."));
110 
111         portDescs << new PortDescriptor(inDesc, DataTypePtr(new MapDataType("filter.anns", inputMap)), /*input*/ true);
112         portDescs << new PortDescriptor(outDesc, DataTypePtr(new MapDataType("filter.anns", inputMap)), /*input*/ false, /*multi*/ true);
113     }
114 
115     {  // Create attributes descriptors
116         Descriptor qualifierNameDesc(QUALIFER_NAME_ATTR,
117                                      FilterAnnotationsByQualifierWorker::tr("Qualifier name"),
118                                      FilterAnnotationsByQualifierWorker::tr("Name of the qualifier to use for filtering."));
119         Descriptor qualifierValDesc(QUALIFER_VALUE_ATTR,
120                                     FilterAnnotationsByQualifierWorker::tr("Qualifier value"),
121                                     FilterAnnotationsByQualifierWorker::tr("Text value of the qualifier to apply as filtering criteria"));
122         Descriptor whichFilterDesc(WHICH_FILTER_ATTR,
123                                    FilterAnnotationsByQualifierWorker::tr("Accept or filter"),
124                                    FilterAnnotationsByQualifierWorker::tr("Selects the name filter: accept specified names or accept all except specified."));
125 
126         attribs << new Attribute(qualifierNameDesc, BaseTypes::STRING_TYPE(), /*required*/ true);
127         attribs << new Attribute(qualifierValDesc, BaseTypes::STRING_TYPE(), /*required*/ true);
128         attribs << new Attribute(whichFilterDesc, BaseTypes::BOOL_TYPE(), /*required*/ false, QVariant(true));
129     }
130 
131     Descriptor desc(FilterAnnotationsByQualifierWorkerFactory::ACTOR_ID,
132                     FilterAnnotationsByQualifierWorker::tr("Filter Annotations by Qualifier"),
133                     FilterAnnotationsByQualifierWorker::tr("Filters annotations by Qualifier."));
134     ActorPrototype *proto = new IntegralBusActorPrototype(desc, portDescs, attribs);
135 
136     proto->setPrompter(new FilterAnnotationsByQualifierPrompter());
137 
138     WorkflowEnv::getProtoRegistry()->registerProto(BaseActorCategories::CATEGORY_BASIC(), proto);
139     DomainFactory *localDomain = WorkflowEnv::getDomainRegistry()->getById(LocalDomainFactory::ID);
140     localDomain->registerEntry(new FilterAnnotationsByQualifierWorkerFactory());
141 }
142 
run()143 void FilterAnnotationsByQualifierTask::run() {
144     // TODO: add reg exp option and tests!
145 
146     QMutableListIterator<SharedAnnotationData> i(anns);
147 
148     while (i.hasNext()) {
149         SharedAnnotationData &ad = i.next();
150         QVector<U2Qualifier> quals;
151         ad->findQualifiers(qualName, quals);
152 
153         bool matchFound = false;
154         foreach (const U2Qualifier &qual, quals) {
155             if (qual.value == qualFilterVal) {
156                 matchFound = true;
157                 break;
158             }
159         }
160 
161         if (accept) {
162             if (!matchFound) {
163                 i.remove();
164             }
165         } else {
166             if (matchFound) {
167                 i.remove();
168             }
169         }
170     }
171 }
172 
173 }  // namespace LocalWorkflow
174 }  // namespace U2
175