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 "AssemblySettingsWidget.h"
23 
24 #include <QAction>
25 #include <QCheckBox>
26 #include <QComboBox>
27 #include <QVBoxLayout>
28 
29 #include <U2Core/U2SafePoints.h>
30 
31 #include <U2Gui/ShowHideSubgroupWidget.h>
32 #include <U2Gui/U2WidgetStateStorage.h>
33 
34 #include "AssemblyBrowser.h"
35 #include "AssemblyConsensusArea.h"
36 #include "AssemblyReadsArea.h"
37 
38 namespace U2 {
39 
40 static const int ITEMS_SPACING = 10;
41 static const int TITLE_SPACING = 5;
42 
initLayout(QWidget * w)43 static inline QVBoxLayout *initLayout(QWidget *w) {
44     QVBoxLayout *layout = new QVBoxLayout;
45     layout->setContentsMargins(0, 0, 0, 0);
46     layout->setSpacing(5);
47 
48     w->setLayout(layout);
49     return layout;
50 }
51 
AssemblySettingsWidget(AssemblyBrowserUi * ui_)52 AssemblySettingsWidget::AssemblySettingsWidget(AssemblyBrowserUi *ui_)
53     : QWidget(ui_), ui(ui_), savableTab(this, GObjectViewUtils::findViewByName(ui_->getWindow()->getName())) {
54     QVBoxLayout *mainLayout = initLayout(this);
55     mainLayout->setSpacing(0);
56 
57     QWidget *readsGroup = new ShowHideSubgroupWidget("READS", tr("Reads Area"), createReadsSettings(), true);
58     mainLayout->addWidget(readsGroup);
59 
60     QWidget *consensusGroup = new ShowHideSubgroupWidget("CONSENSUS", tr("Consensus Area"), createConsensusSettings(), true);
61     mainLayout->addWidget(consensusGroup);
62 
63     QWidget *rulerGroup = new ShowHideSubgroupWidget("RULER", tr("Ruler"), createRulerSettings(), true);
64     mainLayout->addWidget(rulerGroup);
65 
66     U2WidgetStateStorage::restoreWidgetState(savableTab);
67 }
68 
createTwoWayBinding(QCheckBox * checkBox,QAction * action)69 static inline void createTwoWayBinding(QCheckBox *checkBox, QAction *action) {
70     QObject::connect(action, SIGNAL(toggled(bool)), checkBox, SLOT(setChecked(bool)));
71     QObject::connect(checkBox, SIGNAL(toggled(bool)), action, SLOT(setChecked(bool)));
72     checkBox->setChecked(action->isChecked());
73 }
74 
75 // ------- Reads ----------
76 
createReadsSettings()77 QWidget *AssemblySettingsWidget::createReadsSettings() {
78     QWidget *group = new QWidget(this);
79     QVBoxLayout *layout = initLayout(group);
80     AssemblyReadsArea *readsArea = ui->getReadsArea();
81     hint = new QLabel("", group);
82     hint->setObjectName("HINT_HIGHLIGHTNING");
83     hint->setWordWrap(true);
84     hint->setStyleSheet(
85         "color: green;"
86         "font: bold;");
87 
88     layout->addSpacing(TITLE_SPACING);
89 
90     layout->addWidget(new QLabel(tr("Reads highlighting:"), group));
91 
92     readsHighlightCombo = new QComboBox(group);
93     readsHighlightCombo->setObjectName("READS_HIGHLIGHTNING_COMBO");
94     foreach (QAction *a, readsArea->getCellRendererActions()) {
95         readsHighlightCombo->addItem(a->text());
96         connect(a, SIGNAL(triggered()), SLOT(sl_cellRendererChanged()));
97         if (a->isChecked()) {
98             readsHighlightCombo->setCurrentIndex(readsHighlightCombo->count() - 1);
99             AssemblyCellRendererFactory *factory = ui->getWindow()->getCellRendererRegistry()->getFactoryById(AssemblyCellRendererFactory::DIFF_NUCLEOTIDES);
100             if (a->text() == factory->getName()) {
101                 hint->setText(tr("You should add reference  first for correct displaying of this highlighting"));
102                 hint->show();
103             } else {
104                 hint->setText("");
105                 hint->hide();
106             }
107         }
108     }
109     connect(readsHighlightCombo, SIGNAL(currentIndexChanged(int)), SLOT(sl_changeCellRenderer(int)));
110     layout->addWidget(readsHighlightCombo);
111     layout->addWidget(hint);
112 
113     QLabel *aboutScrolling = new QLabel(tr("Scrolling can be optimized by drawing only reads' positions without content while scrolling:"));
114     aboutScrolling->setWordWrap(true);
115     aboutScrolling->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
116     layout->addWidget(aboutScrolling);
117 
118     QCheckBox *optimizeScroll = new QCheckBox(tr("Optimize scrolling"), group);
119     QAction *optimizeAction = readsArea->getOptimizeRenderAction();
120     createTwoWayBinding(optimizeScroll, optimizeAction);
121     layout->addWidget(optimizeScroll);
122 
123     layout->addSpacing(ITEMS_SPACING);
124 
125     QCheckBox *showHint = new QCheckBox(tr("Show pop-up hint"), group);
126     QAction *hintAct = ui->getWindow()->getReadHintEnabledAction();
127     createTwoWayBinding(showHint, hintAct);
128     layout->addWidget(showHint);
129 
130     return group;
131 }
132 
sl_cellRendererChanged()133 void AssemblySettingsWidget::sl_cellRendererChanged() {
134     QAction *action = qobject_cast<QAction *>(sender());
135     int index = ui->getReadsArea()->getCellRendererActions().indexOf(action);
136     SAFE_POINT(index >= 0, "cell renderer action not found", );
137     readsHighlightCombo->setCurrentIndex(index);
138 }
139 
sl_changeCellRenderer(int index)140 void AssemblySettingsWidget::sl_changeCellRenderer(int index) {
141     QList<QAction *> actions = ui->getReadsArea()->getCellRendererActions();
142     CHECK(index >= 0, );
143     SAFE_POINT(index <= actions.count(), "too big cell renderer action index", );
144     QAction *selected = actions.at(index);
145     selected->trigger();
146     AssemblyCellRendererFactory *factory = ui->getWindow()->getCellRendererRegistry()->getFactoryById(AssemblyCellRendererFactory::DIFF_NUCLEOTIDES);
147     if (selected->text() == factory->getName()) {
148         hint->setText(tr("You should add a reference first for correct displaying of selected highlighting"));
149         hint->show();
150     } else {
151         hint->setText("");
152         hint->hide();
153     }
154 }
155 
156 // ------- Consensus ----------
157 
createConsensusSettings()158 QWidget *AssemblySettingsWidget::createConsensusSettings() {
159     QWidget *group = new QWidget(this);
160     QVBoxLayout *layout = initLayout(group);
161     AssemblyConsensusArea *consensusArea = ui->getConsensusArea();
162 
163     layout->addSpacing(TITLE_SPACING);
164 
165     layout->addWidget(new QLabel(tr("Consensus algorithm:")));
166 
167     algorithmCombo = new QComboBox(group);
168     algorithmCombo->setObjectName("consensusAlgorithmCombo");
169     foreach (QAction *a, consensusArea->getAlgorithmActions()) {
170         algorithmCombo->addItem(a->text());
171         connect(a, SIGNAL(triggered()), SLOT(sl_consensusAlgorithmChanged()));
172         if (a->isChecked()) {
173             algorithmCombo->setCurrentIndex(algorithmCombo->count() - 1);
174         }
175     }
176     connect(algorithmCombo, SIGNAL(currentIndexChanged(int)), SLOT(sl_changeConsensusAlgorithm(int)));
177     layout->addWidget(algorithmCombo);
178 
179     layout->addSpacing(ITEMS_SPACING);
180 
181     QCheckBox *showDiff = new QCheckBox(tr("Difference from reference"), group);
182     QAction *diffAct = consensusArea->getDiffAction();
183     createTwoWayBinding(showDiff, diffAct);
184     layout->addWidget(showDiff);
185 
186     return group;
187 }
188 
sl_consensusAlgorithmChanged()189 void AssemblySettingsWidget::sl_consensusAlgorithmChanged() {
190     QAction *action = qobject_cast<QAction *>(sender());
191     int index = ui->getConsensusArea()->getAlgorithmActions().indexOf(action);
192     SAFE_POINT(index >= 0, "consensus algorithm action not found", );
193     algorithmCombo->setCurrentIndex(index);
194 }
195 
sl_changeConsensusAlgorithm(int index)196 void AssemblySettingsWidget::sl_changeConsensusAlgorithm(int index) {
197     QList<QAction *> actions = ui->getConsensusArea()->getAlgorithmActions();
198     CHECK(index >= 0, );
199     SAFE_POINT(index <= actions.count(), "too big consensus algorithm action index", );
200     actions.at(index)->trigger();
201 }
202 
203 // ------- Ruler ----------
204 
createRulerSettings()205 QWidget *AssemblySettingsWidget::createRulerSettings() {
206     QWidget *group = new QWidget(this);
207     QVBoxLayout *layout = initLayout(group);
208     AssemblyBrowser *browser = ui->getWindow();
209 
210     layout->addSpacing(TITLE_SPACING);
211 
212     QCheckBox *showCoords = new QCheckBox(tr("Show coordinates"), group);
213     QAction *coordAct = browser->getCoordsOnRulerAction();
214     createTwoWayBinding(showCoords, coordAct);
215     layout->addWidget(showCoords);
216 
217     layout->addSpacing(ITEMS_SPACING);
218 
219     QCheckBox *showCoverage = new QCheckBox(tr("Show coverage under cursor"), group);
220     QAction *coverageAct = browser->getCoverageOnRulerAction();
221     createTwoWayBinding(showCoverage, coverageAct);
222     layout->addWidget(showCoverage);
223 
224     return group;
225 }
226 
227 //
228 // AssemblySettingsWidgetFactory
229 ////////////////////////////////////
230 const QString AssemblySettingsWidgetFactory::GROUP_ID = "OP_ASS_SETTINGS";
231 const QString AssemblySettingsWidgetFactory::GROUP_ICON_STR = ":core/images/settings2.png";
232 const QString AssemblySettingsWidgetFactory::GROUP_DOC_PAGE = "65929863";
233 
AssemblySettingsWidgetFactory()234 AssemblySettingsWidgetFactory::AssemblySettingsWidgetFactory() {
235     objectViewOfWidget = ObjViewType_AssemblyBrowser;
236 }
237 
createWidget(GObjectView * objView,const QVariantMap &)238 QWidget *AssemblySettingsWidgetFactory::createWidget(GObjectView *objView, const QVariantMap & /*options*/) {
239     SAFE_POINT(objView != nullptr,
240                QString("Internal error: unable to create widget for group '%1', object view is NULL.").arg(GROUP_ID),
241                nullptr);
242 
243     AssemblyBrowser *assemblyBrowser = qobject_cast<AssemblyBrowser *>(objView);
244     SAFE_POINT(assemblyBrowser != nullptr,
245                QString("Internal error: unable to cast object view to Assembly Browser for group '%1'.").arg(GROUP_ID),
246                nullptr);
247 
248     return new AssemblySettingsWidget(assemblyBrowser->getMainWidget());
249 }
250 
getOPGroupParameters()251 OPGroupParameters AssemblySettingsWidgetFactory::getOPGroupParameters() {
252     return OPGroupParameters(GROUP_ID, QPixmap(GROUP_ICON_STR), QObject::tr("Assembly Browser Settings"), GROUP_DOC_PAGE);
253 }
254 
255 }  // namespace U2
256