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 "MaConsensusMismatchController.h"
23
24 #include <U2Algorithm/MSAConsensusAlgorithm.h>
25
26 #include <U2Core/AppContext.h>
27 #include <U2Core/Counter.h>
28 #include <U2Core/DNASequenceSelection.h>
29
30 #include <U2Gui/GUIUtils.h>
31 #include <U2Gui/Notification.h>
32
33 #include "MSAEditorConsensusCache.h"
34 #include "McaEditor.h"
35 #include "McaEditorSequenceArea.h"
36 #include "ov_msa/view_rendering/MaEditorSequenceArea.h"
37 #include "ov_sequence/SequenceObjectContext.h"
38
39 namespace U2 {
40
MaConsensusMismatchController(QObject * p,const QSharedPointer<MSAEditorConsensusCache> & consCache,MaEditor * editor)41 MaConsensusMismatchController::MaConsensusMismatchController(QObject *p,
42 const QSharedPointer<MSAEditorConsensusCache> &consCache,
43 MaEditor *editor)
44 : QObject(p),
45 consCache(consCache),
46 editor(editor),
47 nextMismatch(nullptr),
48 prevMismatch(nullptr) {
49 mismatchCache = QBitArray(editor->getAlignmentLen(), false);
50 connect(consCache.data(), SIGNAL(si_cachedItemUpdated(int, char)), SLOT(sl_updateItem(int, char)));
51 connect(consCache.data(), SIGNAL(si_cacheResized(int)), SLOT(sl_resize(int)));
52
53 nextMismatch = new QAction(QIcon(":core/images/mismatch-forward.png"), tr("Jump to next variation"), this);
54 nextMismatch->setObjectName("next_mismatch");
55 nextMismatch->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_V);
56 GUIUtils::updateActionToolTip(nextMismatch);
57 connect(nextMismatch, SIGNAL(triggered(bool)), SLOT(sl_next()));
58
59 prevMismatch = new QAction(QIcon(":core/images/mismatch-backward.png"), tr("Jump to previous variation"), this);
60 prevMismatch->setShortcut(Qt::CTRL + Qt::ALT + Qt::SHIFT + Qt::Key_V);
61 prevMismatch->setObjectName("prev_mismatch");
62 GUIUtils::updateActionToolTip(prevMismatch);
63 connect(prevMismatch, SIGNAL(triggered(bool)), SLOT(sl_prev()));
64 }
65
isMismatch(int pos) const66 bool MaConsensusMismatchController::isMismatch(int pos) const {
67 SAFE_POINT(0 <= pos && pos < mismatchCache.size(), "Invalid pos", false);
68 return mismatchCache[pos];
69 }
70
getPrevMismatchAction() const71 QAction *MaConsensusMismatchController::getPrevMismatchAction() const {
72 return prevMismatch;
73 }
74
getNextMismatchAction() const75 QAction *MaConsensusMismatchController::getNextMismatchAction() const {
76 return nextMismatch;
77 }
78
sl_updateItem(int pos,char c)79 void MaConsensusMismatchController::sl_updateItem(int pos, char c) {
80 SAFE_POINT(0 <= pos && pos < mismatchCache.size(), "Invalid pos", );
81 mismatchCache[pos] = c != MSAConsensusAlgorithm::INVALID_CONS_CHAR && editor->getReferenceCharAt(pos) != c;
82 }
83
sl_resize(int newSize)84 void MaConsensusMismatchController::sl_resize(int newSize) {
85 mismatchCache.resize(newSize);
86 mismatchCache.fill(false);
87 }
88
sl_next()89 void MaConsensusMismatchController::sl_next() {
90 GCounter::increment("Jump to next variation", editor->getFactoryId());
91 selectNextMismatch(Forward);
92 }
93
sl_prev()94 void MaConsensusMismatchController::sl_prev() {
95 GCounter::increment("Jump to previous variation", editor->getFactoryId());
96 selectNextMismatch(Backward);
97 }
98
selectNextMismatch(NavigationDirection direction)99 void MaConsensusMismatchController::selectNextMismatch(NavigationDirection direction) {
100 McaEditor *mcaEditor = qobject_cast<McaEditor *>(editor);
101 CHECK(mcaEditor != nullptr, );
102
103 SequenceObjectContext *ctx = mcaEditor->getReferenceContext();
104 int initialPos = -1;
105
106 if (ctx->getSequenceSelection()->isEmpty()) {
107 // find next/prev from visible range
108 MaEditorSequenceArea *seqArea = mcaEditor->getUI()->getSequenceArea();
109 initialPos = seqArea->getFirstVisibleBase() != 0 ? seqArea->getFirstVisibleBase() - 1 : mismatchCache.size() - 1;
110 } else {
111 // find next/prev from referenece selection
112 DNASequenceSelection *selection = ctx->getSequenceSelection();
113 initialPos = selection->getSelectedRegions().first().startPos;
114 }
115
116 int pos = initialPos;
117 do {
118 switch (direction) {
119 case Forward:
120 pos++;
121 if (pos == mismatchCache.size()) {
122 pos = 0;
123 }
124 break;
125 default:
126 pos--;
127 if (pos == -1) {
128 pos = mismatchCache.size() - 1;
129 }
130 break;
131 }
132 consCache->updateCacheItem(pos);
133 if (mismatchCache[pos] == true) {
134 emit si_selectMismatch(pos);
135 return;
136 }
137 } while (pos != initialPos);
138 NotificationStack::addNotification(tr("There are no variations in the consensus sequence."), Info_Not);
139 }
140
141 } // namespace U2
142