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 ®ion) {
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> ®ions = 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 ®ion, 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: <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