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 "ADVSyncViewManager.h"
23
24 #include <U2Core/AnnotationTableObject.h>
25 #include <U2Core/Counter.h>
26 #include <U2Core/DNASequenceSelection.h>
27
28 #include "ADVSequenceObjectContext.h"
29 #include "ADVSingleSequenceWidget.h"
30 #include "AnnotatedDNAView.h"
31 #include "AutoAnnotationUtils.h"
32 #include "PanView.h"
33
34 namespace U2 {
35
ADVSyncViewManager(AnnotatedDNAView * v)36 ADVSyncViewManager::ADVSyncViewManager(AnnotatedDNAView *v)
37 : QObject(v), adv(v) {
38 assert(v->getSequenceContexts().isEmpty());
39
40 recursion = false;
41 selectionRecursion = false;
42
43 lockByStartPosAction = new QAction(tr("Lock scales: visible range start"), this);
44 lockByStartPosAction->setObjectName("Lock scales: visible range start");
45 connect(lockByStartPosAction, SIGNAL(triggered()), SLOT(sl_lock()));
46 lockByStartPosAction->setCheckable(true);
47
48 lockBySeqSelAction = new QAction(tr("Lock scales: selected sequence"), this);
49 lockBySeqSelAction->setObjectName("Lock scales: selected sequence");
50 connect(lockBySeqSelAction, SIGNAL(triggered()), SLOT(sl_lock()));
51 lockBySeqSelAction->setCheckable(true);
52
53 lockByAnnSelAction = new QAction(tr("Lock scales: selected annotation"), this);
54 lockByAnnSelAction->setObjectName("Lock scales: selected annotation");
55 connect(lockByAnnSelAction, SIGNAL(triggered()), SLOT(sl_lock()));
56 lockByAnnSelAction->setCheckable(true);
57
58 lockActionGroup = new QActionGroup(this);
59 lockActionGroup->addAction(lockByStartPosAction);
60 lockActionGroup->addAction(lockBySeqSelAction);
61 lockActionGroup->addAction(lockByAnnSelAction);
62 lockActionGroup->setExclusive(true);
63
64 syncByStartPosAction = new QAction(tr("Adjust scales: visible range start"), this);
65 syncByStartPosAction->setObjectName("Adjust scales: visible range start");
66 connect(syncByStartPosAction, SIGNAL(triggered()), SLOT(sl_sync()));
67
68 syncBySeqSelAction = new QAction(tr("Adjust scales: selected sequence"), this);
69 syncBySeqSelAction->setObjectName("Adjust scales: selected sequence");
70 connect(syncBySeqSelAction, SIGNAL(triggered()), SLOT(sl_sync()));
71
72 syncByAnnSelAction = new QAction(tr("Adjust scales: selected annotation"), this);
73 syncByAnnSelAction->setObjectName("Adjust scales: selected annotation");
74 connect(syncByAnnSelAction, SIGNAL(triggered()), SLOT(sl_sync()));
75
76 lockMenu = new QMenu(tr("Lock scales"));
77 lockMenu->setIcon(QIcon(":core/images/lock_scales.png"));
78 lockMenu->addActions(lockActionGroup->actions());
79
80 syncMenu = new QMenu(tr("Adjust scales"));
81 syncMenu->setIcon(QIcon(":core/images/sync_scales.png"));
82 syncMenu->addAction(syncByStartPosAction);
83 syncMenu->addAction(syncBySeqSelAction);
84 syncMenu->addAction(syncByAnnSelAction);
85
86 lockButton = new QToolButton();
87 lockButton->setObjectName("Lock scales");
88 lockButton->setCheckable(true);
89 connect(lockButton, SIGNAL(clicked()), SLOT(sl_lock()));
90 lockButton->setDefaultAction(lockMenu->menuAction());
91 lockButton->setCheckable(true);
92
93 syncButton = new QToolButton();
94 syncButton->setObjectName("Adjust scales");
95 connect(syncButton, SIGNAL(clicked()), SLOT(sl_sync()));
96 syncButton->setDefaultAction(syncMenu->menuAction());
97
98 lockButtonTBAction = nullptr;
99 syncButtonTBAction = nullptr;
100
101 // auto-annotations highlighting ops
102
103 toggleAutoAnnotationsMenu = new QMenu("Global automatic annotation highlighting");
104 toggleAutoAnnotationsMenu->setIcon(QIcon(":core/images/predefined_annotation_groups.png"));
105 connect(toggleAutoAnnotationsMenu, SIGNAL(aboutToShow()), SLOT(sl_updateAutoAnnotationsMenu()));
106
107 toggleAutoAnnotationsButton = new QToolButton();
108 toggleAutoAnnotationsButton->setObjectName("toggleAutoAnnotationsButton");
109 toggleAutoAnnotationsButton->setDefaultAction(toggleAutoAnnotationsMenu->menuAction());
110 toggleAutoAnnotationsButton->setPopupMode(QToolButton::InstantPopup);
111
112 toggleAutoAnnotationsAction = nullptr;
113
114 // visual mode ops
115 toggleAllAction = new QAction("Toggle All sequence views", this);
116 toggleAllAction->setObjectName("toggleAllSequenceViews");
117 connect(toggleAllAction, SIGNAL(triggered()), SLOT(sl_toggleVisualMode()));
118
119 toggleOveAction = new QAction("Toggle Overview", this);
120 toggleOveAction->setObjectName("toggleOverview");
121 connect(toggleOveAction, SIGNAL(triggered()), SLOT(sl_toggleVisualMode()));
122
123 togglePanAction = new QAction("Toggle Zoom view", this);
124 togglePanAction->setObjectName("toggleZoomView");
125 connect(togglePanAction, SIGNAL(triggered()), SLOT(sl_toggleVisualMode()));
126
127 toggleDetAction = new QAction("Toggle Details view", this);
128 toggleDetAction->setObjectName("toggleDetailsView");
129 connect(toggleDetAction, SIGNAL(triggered()), SLOT(sl_toggleVisualMode()));
130
131 toggleViewButtonAction = nullptr;
132 toggleViewButtonMenu = new QMenu(tr("Toggle views"));
133 toggleViewButtonMenu->setIcon(QIcon(":core/images/adv_widget_menu.png"));
134
135 toggleViewButtonMenu->addAction(toggleAllAction); //-> behavior can be not clear to user
136 toggleViewButtonMenu->addAction(toggleOveAction);
137 toggleViewButtonMenu->addAction(togglePanAction);
138 toggleViewButtonMenu->addAction(toggleDetAction);
139 connect(toggleViewButtonMenu, SIGNAL(aboutToShow()), SLOT(sl_updateVisualMode()));
140
141 toggleViewButton = new QToolButton();
142 toggleViewButton->setObjectName("toggleViewButton");
143 toggleViewButton->setDefaultAction(toggleViewButtonMenu->menuAction());
144 toggleViewButton->setPopupMode(QToolButton::InstantPopup);
145
146 updateEnabledState();
147
148 connect(adv, SIGNAL(si_sequenceWidgetAdded(ADVSequenceWidget *)), SLOT(sl_sequenceWidgetAdded(ADVSequenceWidget *)));
149 connect(adv, SIGNAL(si_sequenceWidgetRemoved(ADVSequenceWidget *)), SLOT(sl_sequenceWidgetRemoved(ADVSequenceWidget *)));
150 }
151
~ADVSyncViewManager()152 ADVSyncViewManager::~ADVSyncViewManager() {
153 delete lockButton;
154 delete syncButton;
155 delete syncMenu;
156 delete lockMenu;
157
158 delete toggleAutoAnnotationsButton;
159 delete toggleAutoAnnotationsMenu;
160
161 delete toggleViewButton;
162 delete toggleViewButtonMenu;
163 }
164
updateToolbar1(QToolBar * tb)165 void ADVSyncViewManager::updateToolbar1(QToolBar *tb) {
166 if (lockButtonTBAction == nullptr) {
167 lockButtonTBAction = tb->addWidget(lockButton);
168 syncButtonTBAction = tb->addWidget(syncButton);
169 } else {
170 tb->addAction(lockButtonTBAction);
171 tb->addAction(syncButtonTBAction);
172 }
173 }
174
updateToolbar2(QToolBar * tb)175 void ADVSyncViewManager::updateToolbar2(QToolBar *tb) {
176 if (toggleAutoAnnotationsAction == nullptr) {
177 updateAutoAnnotationActions();
178 toggleAutoAnnotationsAction = tb->addWidget(toggleAutoAnnotationsButton);
179 } else {
180 tb->addAction(toggleAutoAnnotationsAction);
181 }
182
183 if (toggleViewButtonAction == nullptr) {
184 toggleViewButtonAction = tb->addWidget(toggleViewButton);
185 } else {
186 tb->addAction(toggleViewButtonAction);
187 }
188 }
189
updateEnabledState()190 void ADVSyncViewManager::updateEnabledState() {
191 bool enabled = getViewsFromADV().size() > 1;
192 syncButton->setEnabled(enabled);
193 lockButton->setEnabled(enabled);
194 }
195
sl_sequenceWidgetAdded(ADVSequenceWidget * w)196 void ADVSyncViewManager::sl_sequenceWidgetAdded(ADVSequenceWidget *w) {
197 ADVSingleSequenceWidget *sw = qobject_cast<ADVSingleSequenceWidget *>(w);
198 if (sw == nullptr) {
199 return;
200 }
201 unlock();
202 if (toggleAutoAnnotationsAction != nullptr) {
203 updateAutoAnnotationActions();
204 }
205 }
206
sl_sequenceWidgetRemoved(ADVSequenceWidget * w)207 void ADVSyncViewManager::sl_sequenceWidgetRemoved(ADVSequenceWidget *w) {
208 ADVSingleSequenceWidget *sw = qobject_cast<ADVSingleSequenceWidget *>(w);
209 if (sw == nullptr) {
210 return;
211 }
212 unlock();
213 updateAutoAnnotationActions();
214 }
215
unlock()216 void ADVSyncViewManager::unlock() {
217 foreach (ADVSingleSequenceWidget *sw, views) {
218 sw->getPanView()->disconnect(this);
219 sw->getSequenceSelection()->disconnect(this);
220 }
221 views.clear();
222 updateEnabledState();
223 }
224
getViewsFromADV() const225 QList<ADVSingleSequenceWidget *> ADVSyncViewManager::getViewsFromADV() const {
226 QList<ADVSingleSequenceWidget *> res;
227 foreach (ADVSequenceWidget *w, adv->getSequenceWidgets()) {
228 ADVSingleSequenceWidget *sw = qobject_cast<ADVSingleSequenceWidget *>(w);
229 if (sw != nullptr) {
230 res.append(sw);
231 }
232 }
233 return res;
234 }
235
sl_rangeChanged()236 void ADVSyncViewManager::sl_rangeChanged() {
237 if (recursion) {
238 return;
239 }
240 recursion = true;
241
242 PanView *activePan = qobject_cast<PanView *>(sender());
243 const U2Region &activeRange = activePan->getVisibleRange();
244 int activeOffset = activePan->getSyncOffset();
245 foreach (ADVSingleSequenceWidget *sw, views) {
246 PanView *pan = sw->getPanView();
247 if (pan == activePan) {
248 continue;
249 }
250 int panOffset = pan->getSyncOffset();
251 int resultOffset = panOffset - activeOffset;
252 qint64 seqLen = pan->getSequenceLength();
253 qint64 newStart = qBound(qint64(0), activeRange.startPos + resultOffset, seqLen);
254 qint64 nVisible = qMin(activeRange.length, seqLen);
255 if (newStart + nVisible > seqLen) {
256 newStart = seqLen - nVisible;
257 }
258 assert(newStart >= 0 && newStart + nVisible <= seqLen);
259 pan->setVisibleRange(U2Region(newStart, nVisible));
260 }
261
262 recursion = false;
263 }
264
sl_lock()265 void ADVSyncViewManager::sl_lock() {
266 GCOUNTER(tvar, "SequenceView::SyncViewManager::Lock scales");
267 QObject *s = sender();
268 bool buttonClicked = (s == lockButton);
269
270 SyncMode m = SyncMode_Start;
271 if (lockButton->isChecked()) {
272 unlock();
273 } else {
274 if (s == lockBySeqSelAction) {
275 m = SyncMode_SeqSel;
276 } else if (s == lockByAnnSelAction) {
277 m = SyncMode_AnnSel;
278 } else if (s == lockButton) {
279 m = detectSyncMode();
280 }
281 sync(true, m);
282 }
283
284 if (buttonClicked) {
285 QAction *checkedAction = lockActionGroup->checkedAction();
286 if (nullptr == checkedAction) {
287 toggleCheckedAction(m);
288 } else {
289 checkedAction->toggle();
290 }
291 lockButton->toggle();
292 } else {
293 lockButton->setChecked(lockActionGroup->checkedAction() != nullptr);
294 }
295 }
296
sl_sync()297 void ADVSyncViewManager::sl_sync() {
298 GCOUNTER(tvar, "SequenceView::SyncViewManager::Adjust scales");
299 QObject *s = sender();
300 SyncMode m = SyncMode_Start;
301 if (s == syncBySeqSelAction) {
302 m = SyncMode_SeqSel;
303 } else if (s == syncByAnnSelAction) {
304 m = SyncMode_AnnSel;
305 } else if (s == syncButton) {
306 m = detectSyncMode();
307 }
308 sync(false, m);
309 }
310
sync(bool lock,SyncMode m)311 void ADVSyncViewManager::sync(bool lock, SyncMode m) {
312 ADVSingleSequenceWidget *focusedW = qobject_cast<ADVSingleSequenceWidget *>(adv->getActiveSequenceWidget());
313 if (focusedW == nullptr) {
314 return;
315 }
316
317 QList<ADVSingleSequenceWidget *> seqs = getViewsFromADV();
318 QVector<int> offsets(seqs.size());
319
320 // offset here ==> new panview start pos
321 // dOffset is used to keep focused sequence unchanged
322 U2Region focusedRange;
323 int dOffset = 0;
324 for (int i = 0; i < seqs.size(); i++) {
325 int offset = 0;
326 ADVSingleSequenceWidget *seqW = seqs[i];
327 switch (m) {
328 case SyncMode_Start:
329 offset = seqW->getVisibleRange().startPos;
330 break;
331 case SyncMode_SeqSel:
332 offset = offsetBySeqSel(seqW);
333 break;
334 case SyncMode_AnnSel:
335 offset = offsetByAnnSel(seqW);
336 break;
337 }
338 offsets[i] = offset;
339 if (seqW == focusedW) {
340 focusedRange = focusedW->getVisibleRange();
341 dOffset = offset - focusedRange.startPos;
342 }
343 }
344 assert(!focusedRange.isEmpty());
345 for (int i = 0; i < seqs.size(); i++) {
346 ADVSingleSequenceWidget *seqW = seqs[i];
347 int offset = offsets[i] - dOffset;
348 PanView *pan = seqW->getPanView();
349 if (seqW != focusedW) {
350 pan->setNumBasesVisible(focusedRange.length);
351 pan->setStartPos(offset);
352 }
353 if (lock) {
354 DNASequenceSelection *selection = seqW->getSequenceContext()->getSequenceSelection();
355 connect(selection,
356 SIGNAL(si_selectionChanged(LRegionsSelection *, const QVector<U2Region> &, const QVector<U2Region> &)),
357 SLOT(sl_onSelectionChanged(LRegionsSelection *, const QVector<U2Region> &, const QVector<U2Region> &)));
358 pan->setSyncOffset(offset);
359 connect(pan, SIGNAL(si_visibleRangeChanged()), SLOT(sl_rangeChanged()));
360 views.append(seqW);
361 }
362 }
363 }
364
offsetBySeqSel(ADVSingleSequenceWidget * w) const365 int ADVSyncViewManager::offsetBySeqSel(ADVSingleSequenceWidget *w) const {
366 DNASequenceSelection *seqSel = w->getSequenceContext()->getSequenceSelection();
367 if (seqSel->isEmpty()) {
368 return w->getVisibleRange().startPos;
369 }
370 return seqSel->getSelectedRegions().first().startPos;
371 }
372
offsetByAnnSel(ADVSingleSequenceWidget * w) const373 int ADVSyncViewManager::offsetByAnnSel(ADVSingleSequenceWidget *w) const {
374 int pos = findSelectedAnnotationPos(w);
375 if (pos == -1) {
376 return w->getVisibleRange().startPos;
377 }
378 return pos;
379 }
380
findSelectedAnnotationPos(ADVSingleSequenceWidget * w) const381 int ADVSyncViewManager::findSelectedAnnotationPos(ADVSingleSequenceWidget *w) const {
382 AnnotationSelection *as = w->getSequenceContext()->getAnnotationsSelection();
383 const QSet<AnnotationTableObject *> &objs = w->getSequenceContext()->getAnnotationObjects(true);
384 foreach (const Annotation *annotation, as->getAnnotations()) {
385 AnnotationTableObject *obj = annotation->getGObject();
386 if (objs.contains(obj)) {
387 return annotation->getStrand().isCompementary() ? annotation->getRegions().last().endPos() : annotation->getRegions().first().startPos;
388 }
389 }
390 return -1;
391 }
392
detectSyncMode() const393 ADVSyncViewManager::SyncMode ADVSyncViewManager::detectSyncMode() const {
394 ADVSingleSequenceWidget *focusedW = qobject_cast<ADVSingleSequenceWidget *>(adv->getActiveSequenceWidget());
395 assert(focusedW != nullptr);
396 QList<ADVSingleSequenceWidget *> seqs = getViewsFromADV();
397
398 // if current sequence + any other sequence have annotation selection -> sync by annotation
399 if (findSelectedAnnotationPos(focusedW) != -1) {
400 foreach (ADVSingleSequenceWidget *sw, seqs) {
401 if (sw != focusedW && findSelectedAnnotationPos(sw) != -1) {
402 return SyncMode_AnnSel;
403 }
404 }
405 }
406
407 // if current sequence + any other sequence have sequence selection -> sync by annotation
408 if (!focusedW->getSequenceContext()->getSequenceSelection()->isEmpty()) {
409 foreach (ADVSingleSequenceWidget *sw, seqs) {
410 if (sw != focusedW && !sw->getSequenceContext()->getSequenceSelection()->isEmpty()) {
411 return SyncMode_SeqSel;
412 }
413 }
414 }
415 // else sync by start pos
416 return SyncMode_Start;
417 }
418
sl_updateVisualMode()419 void ADVSyncViewManager::sl_updateVisualMode() {
420 // if have at least 1 visible -> hide all
421 bool haveVisiblePan = false;
422 bool haveVisibleDet = false;
423 bool haveVisibleView = false;
424 bool haveVisibleOve = false;
425 foreach (ADVSingleSequenceWidget *sw, getViewsFromADV()) {
426 haveVisiblePan = haveVisiblePan || !sw->isPanViewCollapsed();
427 haveVisibleDet = haveVisibleDet || !sw->isDetViewCollapsed();
428 haveVisibleView = haveVisibleView || !sw->isViewCollapsed();
429 haveVisibleOve = haveVisibleOve || !sw->isOverviewCollapsed();
430 }
431 toggleAllAction->setText(haveVisibleView ? tr("Hide all sequences") : tr("Show all sequences"));
432 togglePanAction->setText(haveVisiblePan ? tr("Hide all zoom views") : tr("Show all zoom views"));
433 toggleDetAction->setText(haveVisibleDet ? tr("Hide all details") : tr("Show all details"));
434 toggleOveAction->setText(haveVisibleOve ? tr("Hide all overviews") : tr("Show all overviews"));
435 }
436
sl_toggleVisualMode()437 void ADVSyncViewManager::sl_toggleVisualMode() {
438 // if have at least 1 visible -> hide all
439 bool haveVisibleNav = false;
440 bool haveVisiblePan = false;
441 bool haveVisibleDet = false;
442 bool haveVisibleView = false;
443
444 QList<ADVSingleSequenceWidget *> views = getViewsFromADV();
445 foreach (ADVSingleSequenceWidget *sw, views) {
446 haveVisibleDet = haveVisibleDet || !sw->isDetViewCollapsed();
447 haveVisibleView = haveVisibleView || !sw->isViewCollapsed();
448 haveVisiblePan = haveVisiblePan || !sw->isPanViewCollapsed();
449 haveVisibleNav = haveVisibleNav || !sw->isOverviewCollapsed();
450 }
451
452 QObject *s = sender();
453 foreach (ADVSingleSequenceWidget *sw, views) {
454 if (s == toggleOveAction) {
455 sw->setOverviewCollapsed(haveVisibleNav);
456 } else if (s == togglePanAction) {
457 sw->setPanViewCollapsed(haveVisiblePan);
458 } else if (s == toggleDetAction) {
459 sw->setDetViewCollapsed(haveVisibleDet);
460 } else {
461 sw->setViewCollapsed(haveVisibleView);
462 }
463 }
464 }
465
sl_onSelectionChanged(LRegionsSelection * sel,const QVector<U2Region> & added,const QVector<U2Region> &)466 void ADVSyncViewManager::sl_onSelectionChanged(LRegionsSelection *sel, const QVector<U2Region> &added, const QVector<U2Region> &) {
467 Q_UNUSED(sel);
468 if (selectionRecursion) {
469 return;
470 }
471
472 selectionRecursion = true;
473
474 ADVSingleSequenceWidget *focusedW = qobject_cast<ADVSingleSequenceWidget *>(adv->getActiveSequenceWidget());
475 if (focusedW == nullptr) {
476 return;
477 }
478 for (int i = 0; i < views.size(); ++i) {
479 ADVSingleSequenceWidget *w = views[i];
480 if (w == focusedW) {
481 continue;
482 }
483
484 int offset = focusedW->getVisibleRange().startPos - w->getVisibleRange().startPos;
485
486 DNASequenceSelection *selection = w->getSequenceSelection();
487 selection->clear();
488 qint64 seqLen = w->getSequenceLength();
489 foreach (U2Region r, added) {
490 r.startPos -= offset;
491
492 if (r.startPos < 0) {
493 r.startPos = 0;
494 }
495
496 if (r.endPos() > seqLen) {
497 r.length = seqLen - r.startPos;
498 }
499 if (r.length > 0) {
500 selection->addRegion(r);
501 }
502 }
503 }
504
505 selectionRecursion = false;
506 }
507
toggleCheckedAction(SyncMode mode)508 void ADVSyncViewManager::toggleCheckedAction(SyncMode mode) {
509 switch (mode) {
510 case SyncMode_AnnSel:
511 lockByAnnSelAction->toggle();
512 break;
513 case SyncMode_SeqSel:
514 lockBySeqSelAction->toggle();
515 break;
516 default:
517 lockByStartPosAction->toggle();
518 }
519 }
520
updateAutoAnnotationActions()521 void ADVSyncViewManager::updateAutoAnnotationActions() {
522 aaActionMap.clear();
523 toggleAutoAnnotationsMenu->clear();
524
525 foreach (ADVSequenceWidget *w, adv->getSequenceWidgets()) {
526 QList<ADVSequenceWidgetAction *> actions = w->getADVSequenceWidgetActions();
527 bool active = false;
528 foreach (ADVSequenceWidgetAction *action, actions) {
529 AutoAnnotationsADVAction *aaAction = qobject_cast<AutoAnnotationsADVAction *>(action);
530 if (aaAction != nullptr) {
531 QList<QAction *> aaToggleActions = aaAction->getToggleActions();
532 foreach (QAction *toggleAction, aaToggleActions) {
533 if (toggleAction->isEnabled()) {
534 aaActionMap.insertMulti(toggleAction->text(), toggleAction);
535 active = true;
536 }
537 }
538 aaAction->setVisible(active);
539 }
540 }
541 }
542
543 toggleAutoAnnotationsButton->setEnabled(!aaActionMap.isEmpty());
544
545 QSet<QString> actionNames = aaActionMap.keys().toSet();
546
547 foreach (const QString &aName, actionNames) {
548 QAction *action = new QAction(toggleAutoAnnotationsMenu);
549 action->setObjectName(aName);
550 connect(action, SIGNAL(triggered()), SLOT(sl_toggleAutoAnnotationHighlighting()));
551 toggleAutoAnnotationsMenu->addAction(action);
552 }
553 }
554
555 #define HAVE_ENABLED_AUTOANNOTATIONS "have_enabled_autoannotations"
556
sl_toggleAutoAnnotationHighlighting()557 void ADVSyncViewManager::sl_toggleAutoAnnotationHighlighting() {
558 QAction *menuAction = qobject_cast<QAction *>(sender());
559 if (menuAction == nullptr) {
560 return;
561 }
562 QVariant val = menuAction->property(HAVE_ENABLED_AUTOANNOTATIONS);
563 assert(val.isValid());
564 bool haveEnabledAutoAnnotations = val.toBool();
565 QList<QAction *> aaActions = aaActionMap.values(menuAction->objectName());
566 foreach (QAction *aaAction, aaActions) {
567 aaAction->setChecked(!haveEnabledAutoAnnotations);
568 }
569 }
570
sl_updateAutoAnnotationsMenu()571 void ADVSyncViewManager::sl_updateAutoAnnotationsMenu() {
572 QList<QAction *> menuActions = toggleAutoAnnotationsMenu->actions();
573
574 foreach (QAction *menuAction, menuActions) {
575 QString aName = menuAction->objectName();
576 bool haveEnabledAutoAnnotations = false;
577 // if have at least 1 checked -> uncheck all
578 QList<QAction *> aaActions = aaActionMap.values(aName);
579 foreach (QAction *aaAction, aaActions) {
580 if (aaAction->isChecked()) {
581 haveEnabledAutoAnnotations = true;
582 break;
583 }
584 }
585
586 if (haveEnabledAutoAnnotations) {
587 menuAction->setText(tr("Hide %1").arg(aName));
588 } else {
589 menuAction->setText(tr("Show %1").arg(aName));
590 }
591 menuAction->setProperty(HAVE_ENABLED_AUTOANNOTATIONS, haveEnabledAutoAnnotations);
592 }
593 }
594
595 } // namespace U2
596