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 "ADVSingleSequenceWidget.h"
23 
24 #include <QApplication>
25 #include <QDialog>
26 #include <QMessageBox>
27 #include <QToolButton>
28 #include <QWidgetAction>
29 
30 #include <U2Core/AnnotationSelection.h>
31 #include <U2Core/AnnotationTableObject.h>
32 #include <U2Core/DNAAlphabet.h>
33 #include <U2Core/DNASequenceObject.h>
34 #include <U2Core/DNASequenceSelection.h>
35 #include <U2Core/DocumentModel.h>
36 #include <U2Core/GHints.h>
37 #include <U2Core/GObjectRelationRoles.h>
38 #include <U2Core/GUrlUtils.h>
39 #include <U2Core/L10n.h>
40 #include <U2Core/QObjectScopedPointer.h>
41 #include <U2Core/Settings.h>
42 #include <U2Core/U2SafePoints.h>
43 
44 #include <U2Gui/DialogUtils.h>
45 #include <U2Gui/ExportImageDialog.h>
46 #include <U2Gui/GUIUtils.h>
47 #include <U2Gui/OrderedToolbar.h>
48 #include <U2Gui/PositionSelector.h>
49 #include <U2Gui/RangeSelector.h>
50 
51 #include "ADVConstants.h"
52 #include "ADVSequenceObjectContext.h"
53 #include "AnnotatedDNAView.h"
54 #include "CreateRulerDialogController.h"
55 #include "DetView.h"
56 #include "GSequenceGraphView.h"
57 #include "Overview.h"
58 #include "image_export/SingleSequenceImageExportController.h"
59 #include "ov_sequence/codon_table/CodonTable.h"
60 
61 namespace U2 {
62 
63 #define ADV_HEADER_HEIGHT 30
64 #define ADV_HEADER_TOOLBAR_SPACING 6
65 #define ADV_HEADER_TOP_BOTTOM_INDENT 2
66 #define IMAGE_DIR "image"
67 
68 const QString ADVSingleSequenceWidget::SEQUENCE_SETTINGS = "sequenceViewSettings";
69 const QString ADVSingleSequenceWidget::DET_VIEW_COLLAPSED = SEQUENCE_SETTINGS + "/detViewCollapsed";
70 const QString ADVSingleSequenceWidget::ZOOM_VIEW_COLLAPSED = SEQUENCE_SETTINGS + "/zoomViewState";
71 const QString ADVSingleSequenceWidget::OVERVIEW_COLLAPSED = SEQUENCE_SETTINGS + "/overviewState";
72 
ADVSingleSequenceWidget(ADVSequenceObjectContext * seqCtx,AnnotatedDNAView * ctx)73 ADVSingleSequenceWidget::ADVSingleSequenceWidget(ADVSequenceObjectContext *seqCtx, AnnotatedDNAView *ctx)
74     : ADVSequenceWidget(ctx),
75       detView(nullptr),
76       panView(nullptr),
77       overview(nullptr) {
78     seqContexts.append(seqCtx);
79 
80     toggleViewAction = new QAction(this);
81     toggleViewAction->setObjectName("show_hide_all_views");
82     connect(toggleViewAction, SIGNAL(triggered()), SLOT(sl_toggleAllSubViews()));
83 
84     togglePanViewAction = new QAction(this);
85     togglePanViewAction->setCheckable(true);
86     togglePanViewAction->setObjectName("show_hide_zoom_view");
87     togglePanViewAction->setIcon(QIcon(":/core/images/zoom_view.png"));
88     connect(togglePanViewAction, SIGNAL(triggered(bool)), SLOT(sl_togglePanView(bool)));
89 
90     toggleDetViewAction = new QAction(this);
91     toggleDetViewAction->setCheckable(true);
92     toggleDetViewAction->setObjectName("show_hide_details_view");
93     toggleDetViewAction->setIcon(QIcon(":/core/images/details_view.png"));
94     connect(toggleDetViewAction, SIGNAL(triggered(bool)), SLOT(sl_toggleDetView(bool)));
95 
96     toggleOverviewAction = new QAction(this);
97     toggleOverviewAction->setCheckable(true);
98     toggleOverviewAction->setObjectName("show_hide_overview");
99     toggleOverviewAction->setIcon(QIcon(":/core/images/overview.png"));
100     connect(toggleOverviewAction, SIGNAL(triggered(bool)), SLOT(sl_toggleOverview(bool)));
101 
102     connect(seqCtx->getAnnotatedDNAView()->getAnnotationsSelection(),
103             SIGNAL(si_selectionChanged(AnnotationSelection *, const QList<Annotation *> &, const QList<Annotation *> &)),
104             SLOT(sl_onAnnotationSelectionChanged(AnnotationSelection *, const QList<Annotation *> &, const QList<Annotation *> &)));
105 
106     selectRangeAction1 = new QAction(QIcon(":/core/images/select_region.png"), tr("Select sequence region..."), this);
107     selectRangeAction1->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_A));
108     selectRangeAction1->setObjectName("select_range_action");
109     selectRangeAction1->setShortcutContext(Qt::WidgetShortcut);
110     connect(selectRangeAction1, SIGNAL(triggered()), SLOT(sl_onSelectRange()));
111 
112     selectRangeAction2 = new QAction(QIcon(":/core/images/select_region.png"), tr("Sequence region..."), this);
113     selectRangeAction2->setObjectName("Sequence region");
114     connect(selectRangeAction2, SIGNAL(triggered()), SLOT(sl_onSelectRange()));
115 
116     selectInAnnotationRangeAction = new QAction(tr("Sequence between selected annotations"), this);
117     selectInAnnotationRangeAction->setObjectName("Sequence between selected annotations");
118     connect(selectInAnnotationRangeAction, SIGNAL(triggered()), SLOT(sl_onSelectInRange()));
119 
120     selectOutAnnotationRangeAction = new QAction(tr("Sequence around selected annotations"), this);
121     selectOutAnnotationRangeAction->setObjectName("Sequence around selected annotations");
122     connect(selectOutAnnotationRangeAction, SIGNAL(triggered()), SLOT(sl_onSelectOutRange()));
123 
124     zoomToRangeAction = new QAction(QIcon(":/core/images/zoom_reg.png"), tr("Zoom to range..."), this);
125     zoomToRangeAction->setObjectName("zoom_to_range_" + getSequenceObject()->getGObjectName());
126     connect(zoomToRangeAction, SIGNAL(triggered()), SLOT(sl_zoomToRange()));
127 
128     createNewRulerAction = new QAction(tr("Create new ruler..."), this);
129     createNewRulerAction->setObjectName("Create new ruler");
130     connect(createNewRulerAction, SIGNAL(triggered()), SLOT(sl_createCustomRuler()));
131 
132     linesLayout = new QVBoxLayout();
133     linesLayout->setMargin(0);
134     linesLayout->setSpacing(0);
135     linesLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
136 
137     linesSplitter = new QSplitter(Qt::Vertical);
138     linesSplitter->setChildrenCollapsible(false);
139     linesSplitter->setBackgroundRole(QPalette::Window);
140     linesSplitter->setAutoFillBackground(true);
141     linesSplitter->setObjectName("single_sequence_view_splitter");
142 
143     QWidget *linesLayoutWidget = new QWidget();
144     linesLayoutWidget->setObjectName("lines_layout_widget");
145     linesLayoutWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
146     linesLayoutWidget->setLayout(linesLayout);
147 
148     linesSplitter->addWidget(linesLayoutWidget);
149 
150     QVBoxLayout *l = new QVBoxLayout(this);
151     l->setMargin(0);
152     l->setSpacing(0);
153     l->addWidget(linesSplitter);
154     l->setSizeConstraint(QLayout::SetMinAndMaxSize);
155     setLayout(l);
156 
157     headerWidget = new ADVSingleSequenceHeaderWidget(this);
158     headerWidget->installEventFilter(this);
159     headerWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
160     linesLayout->addWidget(headerWidget);
161 
162     init();
163     updateMinMaxHeight();
164     setDetViewCollapsed(AppContext::getSettings()->getValue(DET_VIEW_COLLAPSED, QVariant(false)).toBool());
165     setPanViewCollapsed(AppContext::getSettings()->getValue(ZOOM_VIEW_COLLAPSED, QVariant(false)).toBool());
166     setOverviewCollapsed(AppContext::getSettings()->getValue(OVERVIEW_COLLAPSED, QVariant(false)).toBool());
167 }
168 
init()169 void ADVSingleSequenceWidget::init() {
170     ADVSequenceObjectContext *seqCtx = getSequenceContext();
171     detView = new DetView(this, seqCtx);
172     const QString objName = getSequenceObject()->getGObjectName();
173     detView->setObjectName("det_view_" + objName);
174     detView->setMouseTracking(true);
175     detView->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
176 
177     panView = new PanView(this, seqCtx);
178     panView->setObjectName("pan_view_" + objName);
179     panView->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
180     connect(panView, SIGNAL(si_centerPosition(qint64)), SLOT(sl_onLocalCenteringRequest(qint64)));
181 
182     zoomUseObject.setPanView(panView);
183 
184     addSequenceView(panView);
185     addSequenceView(detView, panView);
186 
187     panView->setFrameView(detView);
188     overview = new Overview(this, seqCtx);
189     overview->setObjectName("overview_" + objName);
190     overview->setMouseTracking(true);
191     overview->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
192     lineViews.append(overview);
193     linesLayout->addWidget(overview);
194 
195     buttonTabOrederedNames = new QList<QString>;
196 
197     QToolBar *hStandardBar = headerWidget->getStandardToolBar();
198     QToolBar *hViewsBar = headerWidget->getViewsToolBar();
199     hViewsBar->addSeparator();
200     addButtonWithActionToToolbar(toggleOverviewAction, hViewsBar);
201     addButtonWithActionToToolbar(togglePanViewAction, hViewsBar);
202     addButtonWithActionToToolbar(toggleDetViewAction, hViewsBar);
203 
204     addButtonWithActionToToolbar(selectRangeAction1, hStandardBar);
205     buttonTabOrederedNames->append(selectRangeAction1->objectName());
206 
207     auto exportImageAction = new QAction(QIcon(":/core/images/cam2.png"), tr("Export image"), this);
208     exportImageAction->setObjectName("export_image");
209     connect(exportImageAction, SIGNAL(triggered()), this, SLOT(sl_saveScreenshot()));
210 
211     addButtonWithActionToToolbar(exportImageAction, hStandardBar);
212     buttonTabOrederedNames->append(exportImageAction->objectName());
213 
214     panView->addActionToLocalToolbar(zoomToRangeAction);
215 
216     toggleDetViewAction->setChecked(true);
217     togglePanViewAction->setChecked(true);
218     toggleOverviewAction->setChecked(true);
219 
220     addButtonWithActionToToolbar(toggleViewAction, hViewsBar);
221     hViewsBar->addSeparator();
222 
223     closeViewAction = new QAction(tr("Remove sequence"), this);
224     closeViewAction->setObjectName("remove_sequence");
225     closeViewAction->setIcon(QIcon(":core/images/close_small.png"));
226     addButtonWithActionToToolbar(closeViewAction, hViewsBar);
227     connect(closeViewAction, SIGNAL(triggered()), SLOT(sl_closeView()));
228 
229     dynamic_cast<OrderedToolbar *>(hStandardBar)->setButtonTabOrderList(buttonTabOrederedNames);
230 
231     updateSelectionActions();
232 
233 #define MIN_SEQUENCE_LEN_TO_USE_FULL_MODE 100
234     if (seqCtx->getSequenceLength() < MIN_SEQUENCE_LEN_TO_USE_FULL_MODE) {
235         // sequence is rather small -> show panview only by default
236         setOverviewCollapsed(true);
237         setDetViewCollapsed(true);
238     }
239 
240     updateViewButtonState();
241     togglePanViewAction->setText(isPanViewCollapsed() ? tr("Show zoom view") : tr("Hide zoom view"));
242     toggleDetViewAction->setText(isDetViewCollapsed() ? tr("Show details view") : tr("Hide details view"));
243     toggleOverviewAction->setText(isOverviewCollapsed() ? tr("Show overview") : tr("Hide overview"));
244 }
245 
~ADVSingleSequenceWidget()246 ADVSingleSequenceWidget::~ADVSingleSequenceWidget() {
247     delete buttonTabOrederedNames;
248 }
249 
addButtonWithActionToToolbar(QAction * buttonAction,QToolBar * toolBar,int position) const250 QToolButton *ADVSingleSequenceWidget::addButtonWithActionToToolbar(QAction *buttonAction, QToolBar *toolBar, int position) const {
251     SAFE_POINT(nullptr != buttonAction, "buttonAction is NULL", nullptr);
252     SAFE_POINT(nullptr != toolBar, "toolBar is NULL", nullptr);
253     SAFE_POINT(!buttonAction->objectName().isEmpty(), "Action's object name is empty", nullptr);
254 
255     if (position == -1) {
256         toolBar->addAction(buttonAction);
257     } else {
258         QAction *before = toolBar->actions().at(position);
259         if (before != nullptr) {
260             toolBar->insertAction(before, buttonAction);
261         } else {
262             toolBar->addAction(buttonAction);
263         }
264     }
265     QToolButton *button = qobject_cast<QToolButton *>(toolBar->widgetForAction(buttonAction));
266     button->setFixedHeight(ADV_HEADER_HEIGHT - ADV_HEADER_TOP_BOTTOM_INDENT);
267 
268     SAFE_POINT(button, QString("ToolButton for %1 is NULL").arg(buttonAction->objectName()), nullptr);
269     button->setObjectName(buttonAction->objectName());
270     if (buttonAction->menu() != nullptr) {
271         button->setPopupMode(QToolButton::InstantPopup);
272     }
273 
274     return button;
275 }
276 
isPanViewCollapsed() const277 bool ADVSingleSequenceWidget::isPanViewCollapsed() const {
278     return panView->isHidden();
279 }
280 
isDetViewCollapsed() const281 bool ADVSingleSequenceWidget::isDetViewCollapsed() const {
282     return detView->isHidden();
283 }
284 
isOverviewCollapsed() const285 bool ADVSingleSequenceWidget::isOverviewCollapsed() const {
286     return overview->isHidden();
287 }
288 
isViewCollapsed() const289 bool ADVSingleSequenceWidget::isViewCollapsed() const {
290     return isPanViewCollapsed() && isDetViewCollapsed() && isOverviewCollapsed();
291 }
292 
setViewCollapsed(bool collapsed)293 void ADVSingleSequenceWidget::setViewCollapsed(bool collapsed) {
294     setOverviewCollapsed(collapsed);
295     setPanViewCollapsed(collapsed);
296     setDetViewCollapsed(collapsed);
297 }
298 
updateViewButtonState()299 void ADVSingleSequenceWidget::updateViewButtonState() {
300     toggleViewAction->setText(isViewCollapsed() ? tr("Show all views") : tr("Hide all views"));
301     toggleViewAction->setIcon(isViewCollapsed() ? QIcon(":core/images/show_all_views.png") : QIcon(":core/images/hide_all_views.png"));
302 }
303 
setPanViewCollapsed(bool collapsed)304 void ADVSingleSequenceWidget::setPanViewCollapsed(bool collapsed) {
305     if (collapsed == panView->isHidden()) {
306         return;
307     }
308 
309     AppContext::getSettings()->setValue(ZOOM_VIEW_COLLAPSED, QVariant(collapsed));
310 
311     panView->setHidden(collapsed);
312     togglePanViewAction->setChecked(!collapsed);
313     togglePanViewAction->setText(collapsed ? tr("Show zoom view") : tr("Hide zoom view"));
314     updateMinMaxHeight();
315 
316     if (isPanViewCollapsed()) {
317         zoomUseObject.releaseZoom();
318     } else {
319         zoomUseObject.useZoom();
320     }
321     zoomToRangeAction->setDisabled(collapsed);
322 
323     updateViewButtonState();
324 }
325 
setDetViewCollapsed(bool collapsed)326 void ADVSingleSequenceWidget::setDetViewCollapsed(bool collapsed) {
327     if (collapsed == detView->isHidden()) {
328         return;
329     }
330 
331     AppContext::getSettings()->setValue(DET_VIEW_COLLAPSED, QVariant(collapsed));
332 
333     detView->setHidden(collapsed);
334     detView->setDisabledDetViewActions(collapsed);
335     toggleDetViewAction->setChecked(!collapsed);
336     toggleDetViewAction->setText(collapsed ? tr("Show details view") : tr("Hide details view"));
337     updateMinMaxHeight();
338     updateViewButtonState();
339 }
340 
setOverviewCollapsed(bool collapsed)341 void ADVSingleSequenceWidget::setOverviewCollapsed(bool collapsed) {
342     if (collapsed == overview->isHidden()) {
343         return;
344     }
345 
346     AppContext::getSettings()->setValue(OVERVIEW_COLLAPSED, QVariant(collapsed));
347 
348     overview->setHidden(collapsed);
349     toggleOverviewAction->setChecked(!collapsed);
350     toggleOverviewAction->setText(collapsed ? tr("Show overview") : tr("Hide overview"));
351     updateMinMaxHeight();
352     updateViewButtonState();
353 }
354 
addSequenceView(GSequenceLineView * v,QWidget * after)355 void ADVSingleSequenceWidget::addSequenceView(GSequenceLineView *v, QWidget *after) {
356     assert(!lineViews.contains(v));
357     lineViews.append(v);
358     if (after == nullptr) {
359         linesSplitter->insertWidget(1, v);
360     } else {
361         int after_ = linesSplitter->indexOf(after);
362         assert(after_ != -1);
363         linesSplitter->insertWidget(after_ + 1, v);
364     }
365     v->setVisible(true);
366     v->installEventFilter(this);
367     updateMinMaxHeight();
368     connect(v, SIGNAL(destroyed(QObject *)), SLOT(sl_onViewDestroyed(QObject *)));
369 }
370 
removeSequenceView(GSequenceLineView * v,bool deleteView)371 void ADVSingleSequenceWidget::removeSequenceView(GSequenceLineView *v, bool deleteView) {
372     assert(lineViews.contains(v));
373     lineViews.removeOne(v);
374     v->setVisible(false);  // making widget invisible removes it from the splitter automatically
375     v->disconnect(this);
376     v->removeEventFilter(this);
377     if (deleteView) {
378         delete v;
379     }
380     updateMinMaxHeight();
381 }
382 
getVisibleRange() const383 U2Region ADVSingleSequenceWidget::getVisibleRange() const {
384     return panView->getVisibleRange();
385 }
386 
setVisibleRange(const U2Region & r)387 void ADVSingleSequenceWidget::setVisibleRange(const U2Region &r) {
388     return panView->setVisibleRange(r);
389 }
390 
getNumBasesVisible() const391 int ADVSingleSequenceWidget::getNumBasesVisible() const {
392     return panView->getVisibleRange().length;
393 }
394 
setNumBasesVisible(qint64 n)395 void ADVSingleSequenceWidget::setNumBasesVisible(qint64 n) {
396     panView->setNumBasesVisible(n);
397 }
398 
sl_onViewDestroyed(QObject * o)399 void ADVSingleSequenceWidget::sl_onViewDestroyed(QObject *o) {
400     GSequenceLineView *v = static_cast<GSequenceLineView *>(o);
401     bool r = lineViews.removeOne(v);
402     assert(r);
403     Q_UNUSED(r);
404     updateMinMaxHeight();
405 }
406 
centerPosition(int pos,QWidget * skipView)407 void ADVSingleSequenceWidget::centerPosition(int pos, QWidget *skipView) {
408     foreach (GSequenceLineView *v, lineViews) {
409         if (v == skipView) {
410             continue;
411         }
412         v->setCenterPos(pos);
413     }
414 }
415 
updateMinMaxHeight()416 void ADVSingleSequenceWidget::updateMinMaxHeight() {
417     if (lineViews.size() == 1 && lineViews.first() == overview) {
418         setMaximumHeight(ADV_HEADER_HEIGHT + lineViews.first()->minimumHeight());
419     } else {
420         setMaximumHeight(QWIDGETSIZE_MAX);
421     }
422 }
423 
addZoomMenu(const QPoint & globalPos,QMenu * m)424 void ADVSingleSequenceWidget::addZoomMenu(const QPoint &globalPos, QMenu *m) {
425     GSequenceLineView *lineView = findSequenceViewByPos(globalPos);
426     if (lineView == nullptr) {
427         return;
428     }
429 
430     QAction *first = m->actions().isEmpty() ? nullptr : m->actions().first();
431 
432     QAction *zoomInAction = lineView->getZoomInAction();
433     QAction *zoomOutAction = lineView->getZoomOutAction();
434     QAction *zoomToSelection = lineView->getZoomToSelectionAction();
435     QAction *zoomToSequence = lineView->getZoomToSequenceAction();
436 
437     if (zoomInAction == nullptr && zoomOutAction == nullptr && zoomToSelection == nullptr && zoomToSequence == nullptr) {
438         return;
439     }
440 
441     QMenu *zm = m->addMenu(tr("Zoom"));
442 
443     if (zoomInAction != nullptr) {
444         zm->insertAction(first, zoomInAction);
445     }
446     if (zoomOutAction != nullptr) {
447         zm->insertAction(first, zoomOutAction);
448     }
449     if (zoomToSelection != nullptr) {
450         zm->insertAction(first, zoomToSelection);
451     }
452     if (lineView == panView || lineView->getConherentRangeView() == panView) {
453         zm->insertAction(first, zoomToRangeAction);
454     }
455     if (zoomToSequence != nullptr) {
456         zm->insertAction(first, zoomToSequence);
457     }
458     zm->menuAction()->setObjectName(ADV_MENU_ZOOM);
459     m->addSeparator();
460 }
461 
findSequenceViewByPos(const QPoint & globalPos) const462 GSequenceLineView *ADVSingleSequenceWidget::findSequenceViewByPos(const QPoint &globalPos) const {
463     Q_UNUSED(globalPos);
464     assert(0);
465     return nullptr;
466 }
467 
getSequenceLength() const468 qint64 ADVSingleSequenceWidget::getSequenceLength() const {
469     return getSequenceContext()->getSequenceLength();
470 }
471 
getComplementTT() const472 DNATranslation *ADVSingleSequenceWidget::getComplementTT() const {
473     ADVSequenceObjectContext *seqCtx = getSequenceContext();
474     return seqCtx->getComplementTT();
475 }
476 
getAminoTT() const477 DNATranslation *ADVSingleSequenceWidget::getAminoTT() const {
478     ADVSequenceObjectContext *seqCtx = getSequenceContext();
479     return seqCtx->getAminoTT();
480 }
481 
getSequenceSelection() const482 DNASequenceSelection *ADVSingleSequenceWidget::getSequenceSelection() const {
483     ADVSequenceObjectContext *seqCtx = getSequenceContext();
484     return seqCtx->getSequenceSelection();
485 }
486 
getSequenceObject() const487 U2SequenceObject *ADVSingleSequenceWidget::getSequenceObject() const {
488     ADVSequenceObjectContext *seqCtx = getSequenceContext();
489     return seqCtx->getSequenceObject();
490 }
491 
getPanGSLView() const492 GSequenceLineView *ADVSingleSequenceWidget::getPanGSLView() const {
493     return panView;
494 }
495 
getDetGSLView() const496 GSequenceLineView *ADVSingleSequenceWidget::getDetGSLView() const {
497     return detView;
498 }
499 
buildPopupMenu(QMenu & m)500 void ADVSingleSequenceWidget::buildPopupMenu(QMenu &m) {
501     m.insertAction(GUIUtils::findActionAfter(m.actions(), ADV_GOTO_ACTION), getAnnotatedDNAView()->getCreateAnnotationAction());
502     m.insertAction(GUIUtils::findActionAfter(m.actions(), ADV_GOTO_ACTION), selectRangeAction1);
503 
504     addSelectMenu(m);
505 
506     if (panView->isVisible()) {
507         addRulersMenu(m);
508     }
509 
510     ADVSequenceWidget::buildPopupMenu(m);
511     foreach (GSequenceLineView *v, lineViews) {
512         v->buildPopupMenu(m);
513     }
514 }
515 
addSelectMenu(QMenu & m)516 void ADVSingleSequenceWidget::addSelectMenu(QMenu &m) {
517     QMenu *selectMenu = new QMenu(tr("Select"), &m);
518     selectMenu->menuAction()->setObjectName("Select");
519 
520     selectMenu->addAction(selectRangeAction2);
521     selectMenu->addAction(selectInAnnotationRangeAction);
522     selectMenu->addAction(selectOutAnnotationRangeAction);
523 
524     QAction *aBefore = GUIUtils::findActionAfter(m.actions(), ADV_MENU_COPY);
525     m.insertMenu(aBefore, selectMenu);
526 }
527 
addRulersMenu(QMenu & m)528 void ADVSingleSequenceWidget::addRulersMenu(QMenu &m) {
529     qDeleteAll(rulerActions.qlist);
530     rulerActions.qlist.clear();
531 
532     QMenu *rulersM = new QMenu(tr("Rulers..."), &m);
533     rulersM->menuAction()->setObjectName("Rulers");
534     rulersM->setIcon(QIcon(":core/images/ruler.png"));
535 
536     rulersM->addAction(createNewRulerAction);
537     rulersM->addSeparator();
538     rulersM->addAction(panView->getToggleMainRulerAction());
539     rulersM->addAction(panView->getToggleCustomRulersAction());
540     rulersM->addSeparator();
541 
542     foreach (const RulerInfo &ri, panView->getCustomRulers()) {
543         QAction *rulerAction = new QAction(tr("Remove '%1'").arg(ri.name), this);
544         rulerAction->setData(ri.name);
545         connect(rulerAction, SIGNAL(triggered()), SLOT(sl_removeCustomRuler()));
546         rulerActions.qlist.append(rulerAction);
547     }
548     rulersM->addActions(rulerActions.qlist);
549 
550     QAction *aBefore = GUIUtils::findActionAfter(m.actions(), ADV_MENU_SECTION2_SEP);
551     m.insertMenu(aBefore, rulersM);
552     m.insertSeparator(aBefore)->setObjectName("SECOND_SEP");
553 }
554 
isWidgetOnlyObject(GObject * o) const555 bool ADVSingleSequenceWidget::isWidgetOnlyObject(GObject *o) const {
556     foreach (GSequenceLineView *v, lineViews) {
557         SequenceObjectContext *ctx = v->getSequenceContext();
558         if (ctx->getSequenceGObject() == o) {
559             return true;
560         }
561     }
562     return false;
563 }
564 
eventFilter(QObject * o,QEvent * e)565 bool ADVSingleSequenceWidget::eventFilter(QObject *o, QEvent *e) {
566     QEvent::Type t = e->type();
567     if (t == QEvent::Resize) {
568         GSequenceLineView *v = qobject_cast<GSequenceLineView *>(o);
569         if (lineViews.contains(v)) {
570             updateMinMaxHeight();
571         }
572     } else if (t == QEvent::FocusIn || t == QEvent::MouseButtonPress || t == QEvent::MouseButtonRelease) {
573         ctx->setActiveSequenceWidget(this);
574     }
575 
576     if (o == headerWidget && t == QEvent::MouseButtonPress) {
577         QMouseEvent *event = dynamic_cast<QMouseEvent *>(e);
578         CHECK(event, false);
579         if (event->buttons() == Qt::LeftButton) {
580             emit si_titleClicked(this);
581         }
582     }
583     return false;
584 }
585 
sl_onLocalCenteringRequest(qint64 pos)586 void ADVSingleSequenceWidget::sl_onLocalCenteringRequest(qint64 pos) {
587     detView->setCenterPos(pos);
588 }
589 
addADVSequenceWidgetAction(ADVSequenceWidgetAction * a)590 void ADVSingleSequenceWidget::addADVSequenceWidgetAction(ADVSequenceWidgetAction *a) {
591     ADVSequenceWidget::addADVSequenceWidgetAction(a);
592     if (a->addToBar) {
593         QToolBar *tb = headerWidget->getStandardToolBar();
594         addButtonWithActionToToolbar(a, tb, 0);
595         buttonTabOrederedNames->prepend(a->objectName());
596     }
597 }
598 
addADVSequenceWidgetActionToViewsToolbar(ADVSequenceWidgetAction * a)599 void ADVSingleSequenceWidget::addADVSequenceWidgetActionToViewsToolbar(ADVSequenceWidgetAction *a) {
600     ADVSequenceWidget::addADVSequenceWidgetAction(a);
601     if (a->addToBar) {
602         QToolBar *tb = headerWidget->getViewsToolBar();
603         addButtonWithActionToToolbar(a, tb, 1);
604     }
605 }
606 
sl_onSelectRange()607 void ADVSingleSequenceWidget::sl_onSelectRange() {
608     ADVSequenceObjectContext *ctx = getSequenceContext();
609     DNASequenceSelection *selection = ctx->getSequenceSelection();
610 
611     const QVector<U2Region> &seqRegions = selection->getSelectedRegions();
612 
613     QObjectScopedPointer<MultipleRangeSelector> mrs = new MultipleRangeSelector(this, seqRegions, ctx->getSequenceLength(), ctx->getSequenceObject()->isCircular());
614     mrs->exec();
615     CHECK(!mrs.isNull(), );
616 
617     if (mrs->result() == QDialog::Accepted) {
618         QVector<U2Region> curRegions = mrs->getSelectedRegions();
619         if (curRegions.isEmpty()) {
620             return;
621         }
622         if (curRegions.size() == 1) {
623             U2Region r = curRegions.first();
624             setSelectedRegion(r);
625             if (!detView->getVisibleRange().intersects(r)) {
626                 detView->setCenterPos(r.startPos);
627             }
628         } else {
629             getSequenceContext()->getSequenceSelection()->setSelectedRegions(curRegions);
630         }
631     }
632 }
633 
getSelectedAnnotationRegions(int max)634 QVector<U2Region> ADVSingleSequenceWidget::getSelectedAnnotationRegions(int max) {
635     ADVSequenceObjectContext *seqCtx = getSequenceContext();
636     const QList<Annotation *> selection = seqCtx->getAnnotatedDNAView()->getAnnotationsSelection()->getAnnotations();
637     const QSet<AnnotationTableObject *> myAnns = seqCtx->getAnnotationObjects(true);
638 
639     QVector<U2Region> res;
640     foreach (const Annotation *annotation, selection) {
641         AnnotationTableObject *aObj = annotation->getGObject();
642         if (myAnns.contains(aObj)) {
643             res << U2Region::containingRegion(annotation->getRegions());
644             if (max > 0 && res.size() >= max) {
645                 break;
646             }
647         }
648     }
649     return res;
650 }
651 
sl_onSelectInRange()652 void ADVSingleSequenceWidget::sl_onSelectInRange() {
653     QVector<U2Region> selRegs = getSelectedAnnotationRegions(3);
654     assert(selRegs.size() == 2);
655 
656     const U2Region &r1 = selRegs.at(0);
657     const U2Region &r2 = selRegs.at(1);
658     assert(!r1.intersects(r2));
659 
660     U2Region r;
661     r.startPos = qMin(r1.endPos(), r2.endPos());
662     r.length = qMax(r1.startPos, r2.startPos) - r.startPos;
663 
664     setSelectedRegion(r);
665 }
666 
sl_onSelectOutRange()667 void ADVSingleSequenceWidget::sl_onSelectOutRange() {
668     QVector<U2Region> selRegs = getSelectedAnnotationRegions(0);
669     assert(!selRegs.isEmpty());
670     U2Region r = U2Region::containingRegion(selRegs);
671 
672     setSelectedRegion(r);
673 }
674 
setSelectedRegion(const U2Region & region)675 void ADVSingleSequenceWidget::setSelectedRegion(const U2Region &region) {
676     getSequenceContext()->getSequenceSelection()->setRegion(region);
677 }
678 
sl_zoomToRange()679 void ADVSingleSequenceWidget::sl_zoomToRange() {
680     DNASequenceSelection *sel = getSequenceSelection();
681     int start = getVisibleRange().startPos + 1;
682     int end = getVisibleRange().endPos();
683     if (!sel->isEmpty()) {
684         const QVector<U2Region> &regions = sel->getSelectedRegions();
685         start = regions.first().startPos + 1;
686         end = regions.first().endPos();
687     }
688 
689     QObjectScopedPointer<QDialog> dlg = new QDialog(this);
690     dlg->setModal(true);
691     dlg->setWindowTitle(tr("Zoom to range"));
692 
693     RangeSelector *rs = new RangeSelector(dlg.data(), start, end, getSequenceLength(), true);
694 
695     const int rc = dlg->exec();
696     CHECK(!dlg.isNull(), );
697 
698     if (rc == QDialog::Accepted) {
699         U2Region r(rs->getStart() - 1, rs->getEnd() - rs->getStart() + 1);
700         panView->setVisibleRange(r);
701         detView->setStartPos(r.startPos);
702     }
703 }
704 
705 #define SPLITTER_STATE_MAP_NAME "ADVSI_MAP"
706 #define PAN_REG_NAME "PAN_REG"
707 #define DET_POS_NAME "DET_POS"
708 #define OVERVIEW_VISIBLE "OVERVIEW_VISIBLE"
709 #define PAN_VISIBLE "PAN_VISIBLE"
710 #define DET_VISIBLE "DET_VISIBLE"
711 #define MAIN_RULER_VISIBLE "MAINR_VISIBLE"
712 #define CUSTOM_RULERS_VISIBLE "CUSTOMR_VISIBLE"
713 #define CUSTOM_R_NAMES "CUSTOMR_NAMES"
714 #define CUSTOM_R_COLORS "CUSTOMR_COLORS"
715 #define CUSTOM_R_OFFSETS "CUSTOMR_OFFSETS"
716 #define SEQUENCE_GRAPH_NAME "GRAPH_NAME"
717 
updateState(const QVariantMap & m)718 void ADVSingleSequenceWidget::updateState(const QVariantMap &m) {
719     QVariantMap map = m.value(SPLITTER_STATE_MAP_NAME).toMap();
720     QString sequenceInProjectId = getActiveSequenceContext()->getSequenceObject()->getGHints()->get(GObjectHint_InProjectId).toString();
721     QVariantMap myData = map.value(sequenceInProjectId).toMap();
722     U2Region panReg = myData.value(PAN_REG_NAME).value<U2Region>();
723     int detPos = myData.value(DET_POS_NAME).toInt();
724 
725     U2Region seqRange(0, getActiveSequenceContext()->getSequenceLength());
726     if (seqRange.contains(detPos)) {
727         detView->setStartPos(detPos);
728     }
729     if (!panReg.isEmpty() && seqRange.contains(panReg)) {
730         panView->setVisibleRange(panReg);
731     }
732 
733     bool overIsVisible = myData.value(OVERVIEW_VISIBLE, true).toBool();
734     setOverviewCollapsed(!overIsVisible);
735 
736     bool panIsVisible = myData.value(PAN_VISIBLE, true).toBool();
737     setPanViewCollapsed(!panIsVisible);
738 
739     bool detIsVisible = myData.value(DET_VISIBLE, true).toBool();
740     setDetViewCollapsed(!detIsVisible);
741 
742     bool mainRulerVisible = myData.value(MAIN_RULER_VISIBLE, true).toBool();
743     panView->getToggleMainRulerAction()->setChecked(mainRulerVisible);
744 
745     bool customRulersVisible = myData.value(CUSTOM_RULERS_VISIBLE, true).toBool();
746     panView->getToggleCustomRulersAction()->setChecked(customRulersVisible);
747 
748     QStringList rnames = myData[CUSTOM_R_NAMES].toStringList();
749     QList<QVariant> rcolors = myData[CUSTOM_R_COLORS].toList();
750     QList<QVariant> roffsets = myData[CUSTOM_R_OFFSETS].toList();
751     if (rnames.count() == rcolors.count() && rnames.count() == roffsets.count()) {
752         panView->removeAllCustomRulers();
753         for (int i = 0; i < rnames.count(); i++) {
754             QString name = rnames[i];
755             int offset = roffsets[i].toInt();
756             QColor color = rcolors[i].value<QColor>();
757             panView->addCustomRuler(RulerInfo(name, offset, color));
758         }
759     }
760     QStringList graphNames = myData[SEQUENCE_GRAPH_NAME].toStringList();
761 
762     emit si_updateGraphView(graphNames, myData);
763 }
764 
saveState(QVariantMap & m)765 void ADVSingleSequenceWidget::saveState(QVariantMap &m) {
766     QVariantMap map = m.value(SPLITTER_STATE_MAP_NAME).toMap();
767 
768     QVariantMap myData;
769     myData[PAN_REG_NAME] = QVariant::fromValue<U2Region>(panView->getVisibleRange());
770     myData[DET_POS_NAME] = QVariant::fromValue<int>(detView->getVisibleRange().startPos);
771     myData[OVERVIEW_VISIBLE] = !isOverviewCollapsed();
772     myData[PAN_VISIBLE] = !isPanViewCollapsed();
773     myData[DET_VISIBLE] = !isDetViewCollapsed();
774     myData[MAIN_RULER_VISIBLE] = panView->getToggleMainRulerAction()->isChecked();
775     myData[CUSTOM_RULERS_VISIBLE] = panView->getToggleCustomRulersAction()->isChecked();
776 
777     QStringList rnames;
778     QList<QVariant> roffsets;
779     QList<QVariant> rcolors;
780     foreach (const RulerInfo &ri, panView->getCustomRulers()) {
781         rnames.append(ri.name);
782         roffsets.append(ri.offset);
783         rcolors.append(ri.color);
784     }
785     myData[CUSTOM_R_NAMES] = rnames;
786     myData[CUSTOM_R_OFFSETS] = roffsets;
787     myData[CUSTOM_R_COLORS] = rcolors;
788 
789     QStringList graphNames;
790     for (GSequenceLineView *view : qAsConst(lineViews)) {
791         if (auto graphView = dynamic_cast<GSequenceGraphView *>(view)) {
792             QList<QVariant> graphLabelPositions;
793             graphNames.append(graphView->getGraphViewName());
794             graphView->getSavedLabelsState(graphLabelPositions);
795             myData[graphView->getGraphViewName()] = graphLabelPositions;
796         }
797     }
798     myData[SEQUENCE_GRAPH_NAME] = graphNames;
799 
800     QString sequenceInProjectId = getActiveSequenceContext()->getSequenceObject()->getGHints()->get(GObjectHint_InProjectId).toString();
801     map[sequenceInProjectId] = myData;
802     m[SPLITTER_STATE_MAP_NAME] = map;
803 }
804 
805 // QT 4.5.0 bug workaround
sl_closeView()806 void ADVSingleSequenceWidget::sl_closeView() {
807     closeView();
808 }
809 
sl_saveScreenshot()810 void ADVSingleSequenceWidget::sl_saveScreenshot() {
811     if (linesLayout->count() + linesSplitter->count() < 2) {
812         return;
813     }
814 
815     SingleSequenceImageExportController controller(this);
816 
817     QString fileName = GUrlUtils::fixFileName(getSequenceObject()->getGObjectName());
818     QWidget *p = (QWidget *)AppContext::getMainWindow()->getQMainWindow();
819     QObjectScopedPointer<ExportImageDialog> dialog = new ExportImageDialog(&controller, ExportImageDialog::SequenceView, fileName, ExportImageDialog::NoScaling, p);
820 
821     dialog->exec();
822 }
823 
closeView()824 void ADVSingleSequenceWidget::closeView() {
825     U2SequenceObject *dnaObj = getSequenceObject();
826     AnnotatedDNAView *v = getAnnotatedDNAView();
827     v->removeObject(dnaObj);
828 }
829 
sl_createCustomRuler()830 void ADVSingleSequenceWidget::sl_createCustomRuler() {
831     QSet<QString> namesToFilter;
832     foreach (const RulerInfo &ri, panView->getCustomRulers()) {
833         namesToFilter.insert(ri.name);
834     }
835 
836     int offset = panView->getVisibleRange().center();
837 
838     AnnotationSelection *annSelection = getDetGSLView()->getSequenceContext()->getAnnotationsSelection();
839     U2SequenceObject *seqObj = getSequenceObject();
840     int annOffset = INT_MAX;
841     foreach (const Annotation *ann, annSelection->getAnnotations()) {
842         AnnotationTableObject *annObj = ann->getGObject();
843         if (!annObj->hasObjectRelation(seqObj, ObjectRole_Sequence)) {
844             continue;
845         }
846 
847         // find minimum of start positions of selected annotations
848         foreach (const U2Region &region, ann->getRegions()) {
849             annOffset = annOffset > region.startPos ? region.startPos : annOffset;
850         }
851     }
852     if (annOffset != INT_MAX) {
853         offset = annOffset;
854     }
855 
856     QVector<U2Region> selection = getSequenceSelection()->getSelectedRegions();
857     if (!selection.isEmpty()) {
858         offset = selection.first().startPos;
859     }
860 
861     QObjectScopedPointer<CreateRulerDialogController> d = new CreateRulerDialogController(namesToFilter, offset);
862     const int rc = d->exec();
863     CHECK(!d.isNull(), );
864 
865     if (rc != QDialog::Accepted) {
866         return;
867     }
868     RulerInfo ri(d->name, d->offset, d->color);
869     panView->addCustomRuler(ri);
870 }
871 
sl_removeCustomRuler()872 void ADVSingleSequenceWidget::sl_removeCustomRuler() {
873     QString rulerName = qobject_cast<QAction *>(sender())->data().toString();
874     panView->removeCustomRuler(rulerName);
875 }
876 
sl_onAnnotationSelectionChanged(AnnotationSelection *,const QList<Annotation * > &,const QList<Annotation * > &)877 void ADVSingleSequenceWidget::sl_onAnnotationSelectionChanged(AnnotationSelection *, const QList<Annotation *> &, const QList<Annotation *> &) {
878     updateSelectionActions();
879 }
880 
updateSelectionActions()881 void ADVSingleSequenceWidget::updateSelectionActions() {
882     QVector<U2Region> selRegs = getSelectedAnnotationRegions(3);
883 
884     selectInAnnotationRangeAction->setEnabled(selRegs.size() == 2 && !selRegs[0].intersects(selRegs[1]));
885     selectOutAnnotationRangeAction->setEnabled(!selRegs.isEmpty());
886 }
887 
sl_toggleAllSubViews()888 void ADVSingleSequenceWidget::sl_toggleAllSubViews() {
889     setViewCollapsed(!isViewCollapsed());
890 }
891 
sl_togglePanView(bool checked)892 void ADVSingleSequenceWidget::sl_togglePanView(bool checked) {
893     setPanViewCollapsed(!checked);
894 }
895 
sl_toggleDetView(bool checked)896 void ADVSingleSequenceWidget::sl_toggleDetView(bool checked) {
897     setDetViewCollapsed(!checked);
898 }
899 
sl_toggleOverview(bool checked)900 void ADVSingleSequenceWidget::sl_toggleOverview(bool checked) {
901     setOverviewCollapsed(!checked);
902 }
903 
onSequenceObjectRenamed(const QString &)904 void ADVSingleSequenceWidget::onSequenceObjectRenamed(const QString &) {
905     headerWidget->updateTitle();
906 }
907 
908 //////////////////////////////////////////////////////////////////////////
909 // header
910 
ADVSingleSequenceHeaderWidget(ADVSingleSequenceWidget * p)911 ADVSingleSequenceHeaderWidget::ADVSingleSequenceHeaderWidget(ADVSingleSequenceWidget *p)
912     : QWidget(p), ctx(p) {
913     setFixedHeight(ADV_HEADER_HEIGHT);
914     setBackgroundRole(QPalette::Window);
915     setAutoFillBackground(true);
916 
917     connect(ctx->getAnnotatedDNAView(), SIGNAL(si_activeSequenceWidgetChanged(ADVSequenceWidget *, ADVSequenceWidget *)), SLOT(sl_onActiveSequenceWidgetChanged(ADVSequenceWidget *, ADVSequenceWidget *)));
918 
919     // TODO: track focus events (mouse clicks) on toolbar in disabled state and on disabled buttons !!!
920 
921     QHBoxLayout *l = new QHBoxLayout();
922     l->setSpacing(4);
923     l->setContentsMargins(5, 1, 0, 2);
924 
925     U2SequenceObject *seqObj = ctx->getSequenceObject();
926     QString objName = seqObj->getGObjectName();
927     pixLabel = new QLabel(this);
928     QFont f = pixLabel->font();
929     if (f.pixelSize() > ADV_HEADER_HEIGHT) {
930         f.setPixelSize(ADV_HEADER_HEIGHT - 8);
931     }
932     QIcon objIcon(":/core/images/gobject.png");
933     QPixmap pix = objIcon.pixmap(QSize(16, 16), QIcon::Active);
934     pixLabel->setPixmap(pix);
935     pixLabel->setFont(f);
936     QString objInfoTip = "<i>" + objName + "</i>" + "<br>" + tr("Alphabet: <b>%1</b>").arg(seqObj->getAlphabet()->getName()) + "<br>" + tr(" Sequence size: <b>%1</b>").arg(seqObj->getSequenceLength()) + "<br>" + tr(" File:&nbsp;<b>%1</b>").arg(seqObj->getDocument()->getURLString());
937     pixLabel->setToolTip(objInfoTip);
938     pixLabel->installEventFilter(this);
939 
940     int labelWidth = 50;
941     QFontMetrics fm(f, this);
942     nameLabel = new QLabel("", this);
943     updateTitle();
944     nameLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
945     nameLabel->setMinimumWidth(labelWidth);
946     nameLabel->setMaximumWidth(fm.width(nameLabel->text()));
947     nameLabel->setFont(f);
948     nameLabel->setToolTip(objInfoTip);
949     nameLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
950     nameLabel->setObjectName("nameLabel");
951 
952     standardToolBar = new OrderedToolbar(this);
953     standardToolBar->setObjectName("tool_bar_" + ctx->getSequenceObject()->getGObjectName());
954     standardToolBar->setMovable(true);
955     standardToolBar->setStyleSheet(QString("QToolBar {spacing: %1px; margin: 0px; }").arg(ADV_HEADER_TOOLBAR_SPACING));
956     standardToolBar->setFixedHeight(ADV_HEADER_HEIGHT);
957 
958     viewsToolBar = new OrderedToolbar(this);
959     viewsToolBar->setObjectName("views_tool_bar_" + ctx->getSequenceObject()->getGObjectName());
960     viewsToolBar->setStyleSheet(QString("QToolBar {spacing: %1px; margin: 0px; }").arg(ADV_HEADER_TOOLBAR_SPACING));
961     viewsToolBar->setFixedHeight(ADV_HEADER_HEIGHT);
962 
963     setLayout(l);
964 
965     l->addWidget(pixLabel);
966     l->addWidget(nameLabel);
967     l->addStretch();
968     l->addWidget(standardToolBar);
969     l->addWidget(viewsToolBar);
970 
971     connect(standardToolBar, SIGNAL(actionTriggered(QAction *)), SLOT(sl_actionTriggered(QAction *)));
972     connect(viewsToolBar, SIGNAL(actionTriggered(QAction *)), SLOT(sl_actionTriggered(QAction *)));
973 
974     updateActiveState();
975 }
976 
updateTitle()977 void ADVSingleSequenceHeaderWidget::updateTitle() {
978     U2SequenceObject *seqObj = ctx->getSequenceObject();
979     QString newTitle = seqObj->getGObjectName() + " [" + getShortAlphabetName(seqObj->getAlphabet()) + "]";
980     setTitle(newTitle);
981 }
982 
sl_actionTriggered(QAction * a)983 void ADVSingleSequenceHeaderWidget::sl_actionTriggered(QAction *a) {
984     Q_UNUSED(a);
985     ctx->getAnnotatedDNAView()->setActiveSequenceWidget(ctx);
986 }
987 
sl_onActiveSequenceWidgetChanged(ADVSequenceWidget * oldActiveWidget,ADVSequenceWidget * newActiveWidget)988 void ADVSingleSequenceHeaderWidget::sl_onActiveSequenceWidgetChanged(ADVSequenceWidget *oldActiveWidget, ADVSequenceWidget *newActiveWidget) {
989     if (oldActiveWidget == ctx || newActiveWidget == ctx) {
990         update();
991         updateActiveState();
992     }
993 }
994 
updateActiveState()995 void ADVSingleSequenceHeaderWidget::updateActiveState() {
996     bool focused = ctx->getAnnotatedDNAView()->getActiveSequenceWidget() == ctx;
997     nameLabel->setEnabled(focused);
998     pixLabel->setEnabled(focused);
999     ctx->getSelectRangeAction()->setShortcutContext(focused ? Qt::WindowShortcut : Qt::WidgetShortcut);
1000     // toolBar->setEnabled(focused); TODO: click on disabled buttons does not switch focus!
1001 }
1002 
mouseDoubleClickEvent(QMouseEvent * e)1003 void ADVSingleSequenceHeaderWidget::mouseDoubleClickEvent(QMouseEvent *e) {
1004     ctx->toggleViewAction->trigger();
1005     QWidget::mouseDoubleClickEvent(e);
1006 }
1007 
paintEvent(QPaintEvent * e)1008 void ADVSingleSequenceHeaderWidget::paintEvent(QPaintEvent *e) {
1009     QWidget::paintEvent(e);
1010 
1011     QPainter p(this);
1012     p.setPen(QApplication::palette().color(QPalette::Dark));
1013     p.drawLine(0, height() - 1, width(), height() - 1);
1014 }
1015 
getShortAlphabetName(const DNAAlphabet * al)1016 QString ADVSingleSequenceHeaderWidget::getShortAlphabetName(const DNAAlphabet *al) {
1017     DNAAlphabetType type = al->getType();
1018     if (type == DNAAlphabet_RAW) {
1019         return tr("raw");
1020     }
1021     if (type == DNAAlphabet_AMINO) {
1022         if (al->getId() == BaseDNAAlphabetIds::AMINO_EXTENDED()) {
1023             return tr("amino ext");
1024         }
1025         return tr("amino");
1026     }
1027     assert(type == DNAAlphabet_NUCL);
1028     QString id = al->getId();
1029     if (id == BaseDNAAlphabetIds::NUCL_DNA_DEFAULT()) {
1030         return tr("dna");
1031     } else if (id == BaseDNAAlphabetIds::NUCL_DNA_EXTENDED()) {
1032         return tr("dna ext");
1033     } else if (id == BaseDNAAlphabetIds::NUCL_RNA_DEFAULT()) {
1034         return tr("rna");
1035     } else if (id == BaseDNAAlphabetIds::NUCL_RNA_EXTENDED()) {
1036         return tr("rna ext");
1037     }
1038     return "?";
1039 }
1040 
1041 }  // namespace U2
1042