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 "AutoAnnotationUtils.h"
23
24 #include <U2Core/AnnotationTableObject.h>
25 #include <U2Core/AppContext.h>
26 #include <U2Core/AutoAnnotationsSupport.h>
27 #include <U2Core/DNASequenceObject.h>
28 #include <U2Core/U1AnnotationUtils.h>
29 #include <U2Core/U2SafePoints.h>
30
31 #include <U2Gui/MainWindow.h>
32 #include <U2Gui/ObjectViewModel.h>
33
34 #include <U2View/ADVAnnotationCreation.h>
35
36 #include "ADVSequenceObjectContext.h"
37 #include "AnnotatedDNAView.h"
38
39 namespace U2 {
40
41 const QString AutoAnnotationsADVAction::ACTION_NAME("AutoAnnotationUpdateAction");
42
43 #define AUTO_ANNOTATION_GROUP_NAME "AutoAnnotatationGroupName"
44
AutoAnnotationsADVAction(ADVSequenceWidget * v,AutoAnnotationObject * obj)45 AutoAnnotationsADVAction::AutoAnnotationsADVAction(ADVSequenceWidget *v,
46 AutoAnnotationObject *obj)
47 : ADVSequenceWidgetAction(ACTION_NAME, tr("Automatic annotations highlighting")), aaObj(obj), updatesCount(0) {
48 seqWidget = v;
49 addToBar = true;
50
51 menu = new QMenu();
52 setIcon(QIcon(":core/images/predefined_annotation_groups.png"));
53 setMenu(menu);
54
55 connect(aaObj, SIGNAL(si_updateStarted()), SLOT(sl_autoAnnotationUpdateStarted()));
56 connect(aaObj, SIGNAL(si_updateFinished()), SLOT(sl_autoAnnotationUpdateFinished()));
57
58 selectAllAction = new QAction(tr("Select all"), this);
59 connect(selectAllAction, SIGNAL(triggered()), SLOT(sl_onSelectAll()));
60
61 deselectAllAction = new QAction(tr("Deselect all"), this);
62 connect(deselectAllAction, SIGNAL(triggered()), SLOT(sl_onDeselectAll()));
63
64 updateMenu();
65
66 aaObj->updateAll();
67 }
68
69 #define MAX_SEQ_SIZE_TO_ENABLE_AUTO_ANNOTATIONS 10000
70
updateMenu()71 void AutoAnnotationsADVAction::updateMenu() {
72 AutoAnnotationConstraints constraints;
73 if (seqWidget->getSequenceContexts().count() > 0) {
74 constraints.alphabet = seqWidget->getSequenceContexts().first()->getAlphabet();
75 }
76
77 // Auto annotations should not be enabled by default for very large sequences
78 // or when there are many small sequences. This flag controls such behavior.
79 bool largeSequence = false;
80
81 if (seqWidget->getSequenceObjects().count() > 0) {
82 constraints.hints = seqWidget->getSequenceObjects().first()->getGHints();
83
84 int totalLen = 0;
85
86 AnnotatedDNAView *view = seqWidget->getAnnotatedDNAView();
87 if (view != nullptr) {
88 const QList<ADVSequenceObjectContext *> &ctxList = view->getSequenceContexts();
89 foreach (const ADVSequenceObjectContext *ctx, ctxList) {
90 totalLen += ctx->getSequenceLength();
91 }
92 }
93 largeSequence = totalLen > MAX_SEQ_SIZE_TO_ENABLE_AUTO_ANNOTATIONS;
94 }
95
96 QList<AutoAnnotationsUpdater *> updaters = AppContext::getAutoAnnotationsSupport()->getAutoAnnotationUpdaters();
97 if (updaters.count() == 0) {
98 setEnabled(false);
99 return;
100 }
101 foreach (AutoAnnotationsUpdater *updater, updaters) {
102 QAction *toggleAction = new QAction(updater->getName(), this);
103 toggleAction->setObjectName(updater->getName());
104 toggleAction->setProperty(AUTO_ANNOTATION_GROUP_NAME, updater->getGroupName());
105 bool enabled = updater->checkConstraints(constraints);
106 toggleAction->setEnabled(enabled);
107 toggleAction->setCheckable(true);
108 bool checked = updater->isEnabledByDefault() && !largeSequence;
109 toggleAction->setChecked(checked);
110 aaObj->setGroupEnabled(updater->getGroupName(), checked);
111 connect(toggleAction, SIGNAL(toggled(bool)), SLOT(sl_toggle(bool)));
112 menu->addAction(toggleAction);
113 }
114
115 menu->update();
116 }
117
sl_toggle(bool toggled)118 void AutoAnnotationsADVAction::sl_toggle(bool toggled) {
119 QAction *action = qobject_cast<QAction *>(sender());
120 if (action == nullptr) {
121 return;
122 }
123 AutoAnnotationsUpdater *updater = AppContext::getAutoAnnotationsSupport()->findUpdaterByName(action->text());
124 if (updater != nullptr) {
125 QString groupName = updater->getGroupName();
126 aaObj->setGroupEnabled(groupName, toggled);
127 aaObj->updateGroup(groupName);
128 updater->setEnabledByDefault(toggled);
129 }
130 }
131
sl_onSelectAll()132 void AutoAnnotationsADVAction::sl_onSelectAll() {
133 QList<QAction *> actions = getToggleActions();
134 foreach (QAction *action, actions) {
135 if (!action->isChecked()) {
136 action->trigger();
137 }
138 }
139 }
140
sl_onDeselectAll()141 void AutoAnnotationsADVAction::sl_onDeselectAll() {
142 QList<QAction *> actions = getToggleActions();
143 foreach (QAction *action, actions) {
144 if (action->isChecked()) {
145 action->trigger();
146 }
147 }
148 }
149
~AutoAnnotationsADVAction()150 AutoAnnotationsADVAction::~AutoAnnotationsADVAction() {
151 menu->clear();
152 delete menu;
153 menu = nullptr;
154 }
155
getToggleActions()156 QList<QAction *> AutoAnnotationsADVAction::getToggleActions() {
157 return menu->actions();
158 }
159
findToggleAction(const QString & groupName)160 QAction *AutoAnnotationsADVAction::findToggleAction(const QString &groupName) {
161 QList<QAction *> toggleActions = menu->actions();
162 foreach (QAction *tAction, toggleActions) {
163 if (tAction->property(AUTO_ANNOTATION_GROUP_NAME) == groupName) {
164 return tAction;
165 }
166 }
167 return nullptr;
168 }
169
addUpdaterToMenu(AutoAnnotationsUpdater * updater)170 void AutoAnnotationsADVAction::addUpdaterToMenu(AutoAnnotationsUpdater *updater) {
171 AutoAnnotationConstraints constraints;
172 if (seqWidget->getSequenceContexts().count() > 0) {
173 constraints.alphabet = seqWidget->getSequenceContexts().first()->getAlphabet();
174 }
175 if (seqWidget->getSequenceObjects().count() > 0) {
176 constraints.hints = seqWidget->getSequenceObjects().first()->getGHints();
177 }
178
179 QAction *toggleAction = new QAction(updater->getName(), this);
180 toggleAction->setProperty(AUTO_ANNOTATION_GROUP_NAME, updater->getGroupName());
181 bool enabled = updater->checkConstraints(constraints);
182 toggleAction->setEnabled(enabled);
183 toggleAction->setCheckable(true);
184 bool checked = updater->isEnabledByDefault();
185 toggleAction->setChecked(checked);
186 aaObj->setGroupEnabled(updater->getGroupName(), checked);
187 connect(toggleAction, SIGNAL(toggled(bool)), SLOT(sl_toggle(bool)));
188 menu->addAction(toggleAction);
189
190 menu->update();
191 }
192
sl_autoAnnotationUpdateStarted()193 void AutoAnnotationsADVAction::sl_autoAnnotationUpdateStarted() {
194 setEnabled(false);
195 updatesCount++;
196 }
197
sl_autoAnnotationUpdateFinished()198 void AutoAnnotationsADVAction::sl_autoAnnotationUpdateFinished() {
199 updatesCount--;
200 if (updatesCount == 0) {
201 setEnabled(true);
202 }
203 }
204
205 //////////////////////////////////////////////////////////////////////////
206
findAutoAnnotationsToggleAction(ADVSequenceObjectContext * ctx,const QString & groupName)207 QAction *AutoAnnotationUtils::findAutoAnnotationsToggleAction(ADVSequenceObjectContext *ctx, const QString &groupName) {
208 foreach (ADVSequenceWidget *w, ctx->getSequenceWidgets()) {
209 ADVSequenceWidgetAction *advAction = w->getADVSequenceWidgetAction(AutoAnnotationsADVAction::ACTION_NAME);
210 if (advAction == nullptr) {
211 continue;
212 }
213 AutoAnnotationsADVAction *aaAction = qobject_cast<AutoAnnotationsADVAction *>(advAction);
214 assert(aaAction != nullptr);
215 QList<QAction *> toggleActions = aaAction->getToggleActions();
216 foreach (QAction *tAction, toggleActions) {
217 if (tAction->property(AUTO_ANNOTATION_GROUP_NAME) == groupName) {
218 return tAction;
219 }
220 }
221 }
222
223 return nullptr;
224 }
225
triggerAutoAnnotationsUpdate(ADVSequenceObjectContext * ctx,const QString & aaGroupName)226 void AutoAnnotationUtils::triggerAutoAnnotationsUpdate(ADVSequenceObjectContext *ctx, const QString &aaGroupName) {
227 AutoAnnotationsADVAction *aaAction = findAutoAnnotationADVAction(ctx);
228
229 if (aaAction != nullptr && !aaAction->isEnabled()) {
230 return;
231 }
232
233 assert(aaAction != nullptr);
234 if (aaAction) {
235 QAction *updateAction = aaAction->findToggleAction(aaGroupName);
236 assert(updateAction != nullptr);
237
238 if (!updateAction) {
239 return;
240 }
241
242 if (!updateAction->isChecked()) {
243 updateAction->trigger();
244 } else {
245 AutoAnnotationsUpdater *updater = AppContext::getAutoAnnotationsSupport()->findUpdaterByGroupName(aaGroupName);
246 if (updater != nullptr) {
247 aaAction->getAAObj()->updateGroup(aaGroupName);
248 }
249 }
250 }
251 }
252
findAutoAnnotationADVAction(ADVSequenceObjectContext * ctx)253 AutoAnnotationsADVAction *AutoAnnotationUtils::findAutoAnnotationADVAction(ADVSequenceObjectContext *ctx) {
254 foreach (ADVSequenceWidget *w, ctx->getSequenceWidgets()) {
255 ADVSequenceWidgetAction *advAction = w->getADVSequenceWidgetAction(AutoAnnotationsADVAction::ACTION_NAME);
256 if (advAction == nullptr) {
257 continue;
258 } else {
259 return qobject_cast<AutoAnnotationsADVAction *>(advAction);
260 }
261 }
262
263 return nullptr;
264 }
265
getAutoAnnotationToggleActions(ADVSequenceObjectContext * ctx)266 QList<QAction *> AutoAnnotationUtils::getAutoAnnotationToggleActions(ADVSequenceObjectContext *ctx) {
267 QList<QAction *> res;
268
269 foreach (ADVSequenceWidget *w, ctx->getSequenceWidgets()) {
270 ADVSequenceWidgetAction *advAction = w->getADVSequenceWidgetAction(AutoAnnotationsADVAction::ACTION_NAME);
271 if (advAction == nullptr) {
272 continue;
273 }
274 AutoAnnotationsADVAction *aaAction = qobject_cast<AutoAnnotationsADVAction *>(advAction);
275 assert(aaAction != nullptr);
276 res = aaAction->getToggleActions();
277
278 int selectedCount = 0;
279 foreach (QAction *a, res) {
280 if (a->isChecked()) {
281 selectedCount += 1;
282 }
283 }
284
285 if (selectedCount == res.size()) {
286 res.append(aaAction->getDeselectAllAction());
287 } else {
288 res.append(aaAction->getSelectAllAction());
289 }
290 }
291
292 return res;
293 }
294
295 //////////////////////////////////////////////////////////////////////////
296
ExportAutoAnnotationsGroupTask(AnnotationGroup * ag,GObjectReference & ref,ADVSequenceObjectContext * ctx,const QString & annDescription)297 ExportAutoAnnotationsGroupTask::ExportAutoAnnotationsGroupTask(AnnotationGroup *ag,
298 GObjectReference &ref,
299 ADVSequenceObjectContext *ctx,
300 const QString &annDescription)
301 : Task("ExportAutoAnnotationsGroupTask", TaskFlags_NR_FOSCOE),
302 aGroup(ag),
303 aRef(ref),
304 seqCtx(ctx),
305 createTask(nullptr),
306 annDescription(annDescription) {
307 SAFE_POINT_EXT(nullptr != ag, stateInfo.setError(tr("Invalid annotation group provided")), );
308 }
309
prepare()310 void ExportAutoAnnotationsGroupTask::prepare() {
311 QList<Annotation *> annotationList;
312 aGroup->findAllAnnotationsInGroupSubTree(annotationList);
313
314 QList<SharedAnnotationData> newAnnotationDataList;
315 for (const Annotation *annotation : qAsConst(annotationList)) {
316 SharedAnnotationData data(new AnnotationData(*(annotation->getData())));
317 U1AnnotationUtils::addDescriptionQualifier(data, annDescription);
318 newAnnotationDataList.append(data);
319 }
320
321 CHECK(!newAnnotationDataList.isEmpty(), );
322
323 bool selectNewAnnotations = newAnnotationDataList.size() < 100;
324 createTask = new ADVCreateAnnotationsTask(seqCtx->getAnnotatedDNAView(), aRef, aGroup->getName(), newAnnotationDataList, selectNewAnnotations);
325 addSubTask(createTask);
326 }
327
onSubTaskFinished(Task * subTask)328 QList<Task *> ExportAutoAnnotationsGroupTask::onSubTaskFinished(Task *subTask) {
329 QList<Task *> res;
330
331 if (!subTask->isFinished() || subTask->hasError() || subTask->isCanceled()) {
332 return res;
333 }
334
335 if (subTask == createTask) {
336 QAction *toggleAction = AutoAnnotationUtils::findAutoAnnotationsToggleAction(seqCtx, aGroup->getName());
337 if (toggleAction != nullptr && toggleAction->isChecked()) {
338 toggleAction->trigger();
339 }
340 }
341
342 return res;
343 }
344
345 } // namespace U2
346