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 "MSAHighlightingTab.h"
23
24 #include <QCheckBox>
25 #include <QComboBox>
26 #include <QDoubleSpinBox>
27 #include <QLabel>
28 #include <QRadioButton>
29 #include <QStandardItemModel>
30 #include <QToolButton>
31 #include <QVBoxLayout>
32
33 #include <U2Algorithm/MsaColorScheme.h>
34 #include <U2Algorithm/MsaHighlightingScheme.h>
35
36 #include <U2Core/AppContext.h>
37 #include <U2Core/DNAAlphabet.h>
38 #include <U2Core/U2SafePoints.h>
39
40 #include <U2Gui/GroupedComboBoxDelegate.h>
41 #include <U2Gui/ShowHideSubgroupWidget.h>
42 #include <U2Gui/U2WidgetStateStorage.h>
43
44 #include <U2View/MSAEditor.h>
45 #include <U2View/MSAEditorSequenceArea.h>
46
47 namespace U2 {
48
49 static const int ITEMS_SPACING = 6;
50 static const int TITLE_SPACING = 1;
51
initVBoxLayout(QWidget * w)52 static inline QVBoxLayout *initVBoxLayout(QWidget *w) {
53 QVBoxLayout *layout = new QVBoxLayout;
54 layout->setContentsMargins(0, 0, 0, 0);
55 layout->setSpacing(5);
56
57 w->setLayout(layout);
58 return layout;
59 }
60
initHBoxLayout(QWidget * w)61 static inline QHBoxLayout *initHBoxLayout(QWidget *w) {
62 QHBoxLayout *layout = new QHBoxLayout;
63 layout->setContentsMargins(0, 0, 0, 0);
64
65 w->setLayout(layout);
66 return layout;
67 }
68
createColorGroup()69 QWidget *MSAHighlightingTab::createColorGroup() {
70 QWidget *group = new QWidget(this);
71
72 QVBoxLayout *layout = initVBoxLayout(group);
73 colorSchemeController = new MsaSchemeComboBoxController<MsaColorSchemeFactory, MsaColorSchemeRegistry>(msa, AppContext::getMsaColorSchemeRegistry(), this);
74 colorSchemeController->getComboBox()->setObjectName("colorScheme");
75 colorSchemeController->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
76
77 colorThresholdLabel = new QLabel(tr("Threshold"));
78
79 colorThresholdSlider = new QSlider(Qt::Horizontal, this);
80 colorThresholdSlider->setMinimum(1);
81 colorThresholdSlider->setMaximum(999);
82 colorThresholdSlider->setValue(500);
83 colorThresholdSlider->setObjectName("colorThresholdSlider");
84
85 colorSpinBox = new QDoubleSpinBox();
86 colorSpinBox->setMinimum(0.1);
87 colorSpinBox->setMaximum(99.9);
88 colorSpinBox->setSingleStep(0.1);
89 colorSpinBox->setValue(50.0);
90 colorSpinBox->setDecimals(1);
91 colorSpinBox->setObjectName("colorSpinBox");
92
93 QHBoxLayout *horizontalLayout = new QHBoxLayout();
94 horizontalLayout->addWidget(colorThresholdSlider);
95 horizontalLayout->addWidget(colorSpinBox);
96 horizontalLayout->setSpacing(10);
97
98 layout->addWidget(colorSchemeController->getComboBox());
99 layout->addSpacing(TITLE_SPACING);
100 layout->addSpacing(TITLE_SPACING);
101 layout->addWidget(colorThresholdLabel);
102 layout->addLayout(horizontalLayout);
103
104 layout->addSpacing(ITEMS_SPACING);
105
106 return group;
107 }
108
createHighlightingGroup()109 QWidget *MSAHighlightingTab::createHighlightingGroup() {
110 QWidget *group = new QWidget(this);
111
112 QVBoxLayout *layout = initVBoxLayout(group);
113 highlightingSchemeController = new MsaSchemeComboBoxController<MsaHighlightingSchemeFactory, MsaHighlightingSchemeRegistry>(msa, AppContext::getMsaHighlightingSchemeRegistry(), this);
114 highlightingSchemeController->getComboBox()->setObjectName("highlightingScheme");
115
116 hint = new QLabel("");
117 hint->setWordWrap(true);
118 hint->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred);
119
120 useDots = new QCheckBox(tr("Use dots"));
121 useDots->setObjectName("useDots");
122
123 exportHighlightning = new QToolButton();
124 exportHighlightning->setText(tr("Export"));
125 exportHighlightning->setObjectName("exportHighlightning");
126 exportHighlightning->setMinimumWidth(198);
127 exportHighlightning->setMinimumHeight(23);
128
129 QWidget *buttonAndSpacer = new QWidget(this);
130 QHBoxLayout *layout2 = initHBoxLayout(buttonAndSpacer);
131 layout2->addWidget(exportHighlightning);
132 // layout2->addSpacerItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
133
134 lessMoreLabel = new QLabel(tr("Highlight characters with conservation level:"));
135 lessMoreLabel->setWordWrap(true);
136
137 thresholdMoreRb = new QRadioButton(QString::fromWCharArray(L"\x2265") + tr(" threshold"));
138 thresholdLessRb = new QRadioButton(QString::fromWCharArray(L"\x2264") + tr(" threshold"));
139 thresholdMoreRb->setObjectName("thresholdMoreRb");
140 thresholdLessRb->setObjectName("thresholdLessRb");
141
142 highlightingThresholdSlider = new QSlider(Qt::Horizontal, this);
143 highlightingThresholdSlider->setMinimum(0);
144 highlightingThresholdSlider->setMaximum(100);
145 highlightingThresholdSlider->setValue(50);
146 highlightingThresholdSlider->setTickPosition(QSlider::TicksRight);
147 highlightingThresholdSlider->setObjectName("thresholdSlider");
148
149 thresholdLabel = new QLabel(tr("Threshold: %1%").arg(highlightingThresholdSlider->value()), this);
150
151 layout->setSpacing(ITEMS_SPACING);
152 layout->addSpacing(TITLE_SPACING);
153 layout->addWidget(highlightingSchemeController->getComboBox());
154 layout->addWidget(thresholdLabel);
155 layout->addWidget(highlightingThresholdSlider);
156 layout->addWidget(lessMoreLabel);
157 layout->addWidget(thresholdLessRb);
158 layout->addWidget(thresholdMoreRb);
159 layout->addWidget(useDots);
160
161 #ifdef Q_OS_DARWIN
162 layout->addSpacerItem(new QSpacerItem(40, 8, QSizePolicy::Expanding, QSizePolicy::Minimum));
163 #endif
164 layout->addWidget(buttonAndSpacer);
165 layout->addWidget(hint);
166
167 return group;
168 }
169
MSAHighlightingTab(MSAEditor * m)170 MSAHighlightingTab::MSAHighlightingTab(MSAEditor *m)
171 : msa(m), savableTab(this, GObjectViewUtils::findViewByName(m->getName())) {
172 setObjectName("HighlightingOptionsPanelWidget");
173 QVBoxLayout *mainLayout = initVBoxLayout(this);
174 mainLayout->setSpacing(0);
175
176 QWidget *colorGroup = new ShowHideSubgroupWidget("COLOR", tr("Color"), createColorGroup(), true);
177 mainLayout->addWidget(colorGroup);
178
179 QWidget *highlightingGroup = new ShowHideSubgroupWidget("HIGHLIGHTING", tr("Highlighting"), createHighlightingGroup(), true);
180 mainLayout->addWidget(highlightingGroup);
181
182 seqArea = msa->getUI()->getSequenceArea();
183
184 savableTab.disableSavingForWidgets(QStringList()
185 << highlightingThresholdSlider->objectName()
186 << highlightingSchemeController->getComboBox()->objectName()
187 << colorSchemeController->getComboBox()->objectName()
188 << colorThresholdSlider->objectName()
189 << colorSpinBox->objectName());
190 U2WidgetStateStorage::restoreWidgetState(savableTab);
191
192 sl_sync();
193
194 connect(colorSchemeController, SIGNAL(si_dataChanged(const QString &)), seqArea, SLOT(sl_changeColorSchemeOutside(const QString &)));
195 connect(highlightingSchemeController, SIGNAL(si_dataChanged(const QString &)), seqArea, SLOT(sl_changeColorSchemeOutside(const QString &)));
196 connect(useDots, SIGNAL(stateChanged(int)), seqArea, SLOT(sl_triggerUseDots()));
197
198 connect(seqArea, SIGNAL(si_highlightingChanged()), SLOT(sl_sync()));
199
200 MsaColorSchemeRegistry *msaColorSchemeRegistry = AppContext::getMsaColorSchemeRegistry();
201 connect(msaColorSchemeRegistry, SIGNAL(si_customSettingsChanged()), SLOT(sl_refreshSchemes()));
202
203 connect(m, SIGNAL(si_referenceSeqChanged(qint64)), SLOT(sl_updateHint()));
204 connect(m->getMaObject(), SIGNAL(si_alphabetChanged(MaModificationInfo, const DNAAlphabet *)), SLOT(sl_refreshSchemes()));
205
206 connect(highlightingSchemeController->getComboBox(), SIGNAL(currentIndexChanged(const QString &)), SLOT(sl_updateHint()));
207 connect(colorSchemeController->getComboBox(), SIGNAL(currentIndexChanged(const QString &)), SLOT(sl_updateColorSchemeWidgets()));
208 connect(exportHighlightning, SIGNAL(clicked()), SLOT(sl_exportHighlightningClicked()));
209
210 connect(colorThresholdSlider, SIGNAL(valueChanged(int)), SLOT(sl_colorParametersChanged()));
211 connect(colorSpinBox, SIGNAL(valueChanged(double)), SLOT(sl_colorParametersChanged()));
212 connect(this, SIGNAL(si_colorSchemeChanged()), seqArea, SLOT(sl_completeRedraw()));
213
214 connect(highlightingThresholdSlider, SIGNAL(valueChanged(int)), SLOT(sl_highlightingParametersChanged()));
215 connect(thresholdMoreRb, SIGNAL(toggled(bool)), SLOT(sl_highlightingParametersChanged()));
216 connect(thresholdLessRb, SIGNAL(toggled(bool)), SLOT(sl_highlightingParametersChanged()));
217
218 sl_updateHint();
219 sl_highlightingParametersChanged();
220 }
221
sl_sync()222 void MSAHighlightingTab::sl_sync() {
223 MsaColorScheme *s = seqArea->getCurrentColorScheme();
224 SAFE_POINT(s != nullptr, "Current scheme is NULL", );
225 SAFE_POINT(s->getFactory() != nullptr, "Current scheme color factory is NULL", );
226
227 colorSchemeController->getComboBox()->blockSignals(true);
228 colorSchemeController->setCurrentItemById(s->getFactory()->getId());
229 colorSchemeController->getComboBox()->blockSignals(false);
230
231 MsaHighlightingScheme *sh = seqArea->getCurrentHighlightingScheme();
232 SAFE_POINT(sh != nullptr, "Current highlighting scheme is NULL!", );
233 SAFE_POINT(sh->getFactory() != nullptr, "Current highlighting scheme factory is NULL!", );
234
235 highlightingSchemeController->getComboBox()->blockSignals(true);
236 highlightingSchemeController->setCurrentItemById(sh->getFactory()->getId());
237 highlightingSchemeController->getComboBox()->blockSignals(false);
238
239 useDots->blockSignals(true);
240 useDots->setChecked(seqArea->getUseDotsCheckedState());
241 useDots->blockSignals(false);
242
243 sl_updateHint();
244 sl_updateColorSchemeWidgets();
245 }
246
sl_updateHint()247 void MSAHighlightingTab::sl_updateHint() {
248 MsaHighlightingScheme *s = seqArea->getCurrentHighlightingScheme();
249 SAFE_POINT(s->getFactory() != nullptr, "Highlighting factory is NULL!", );
250
251 QVariantMap highlightingSettings;
252 if (s->getFactory()->isNeedThreshold()) {
253 thresholdLabel->show();
254 highlightingThresholdSlider->show();
255 thresholdLessRb->show();
256 thresholdMoreRb->show();
257 lessMoreLabel->show();
258 bool ok = false;
259 int thresholdValue = s->getSettings().value(MsaHighlightingScheme::THRESHOLD_PARAMETER_NAME).toInt(&ok);
260 assert(ok);
261 highlightingThresholdSlider->setValue(thresholdValue);
262 bool lessThenThreshold = s->getSettings().value(MsaHighlightingScheme::LESS_THAN_THRESHOLD_PARAMETER_NAME, thresholdLessRb->isChecked()).toBool();
263 thresholdLessRb->setChecked(lessThenThreshold);
264 thresholdMoreRb->setChecked(!lessThenThreshold);
265 highlightingSettings.insert(MsaHighlightingScheme::THRESHOLD_PARAMETER_NAME, thresholdValue);
266 highlightingSettings.insert(MsaHighlightingScheme::LESS_THAN_THRESHOLD_PARAMETER_NAME, lessThenThreshold);
267 } else {
268 thresholdLabel->hide();
269 highlightingThresholdSlider->hide();
270 thresholdLessRb->hide();
271 thresholdMoreRb->hide();
272 lessMoreLabel->hide();
273 }
274 if (U2MsaRow::INVALID_ROW_ID == msa->getReferenceRowId() && !seqArea->getCurrentHighlightingScheme()->getFactory()->isRefFree()) {
275 hint->setText(tr("Info: set a reference sequence."));
276 hint->setStyleSheet(
277 "color: green;"
278 "font: bold;");
279 exportHighlightning->setDisabled(true);
280 return;
281 }
282 hint->setText("");
283 if (s->getFactory()->isRefFree()) {
284 hint->setText(tr("Info: export is not available for the selected highlighting."));
285 hint->setStyleSheet(
286 "color: green;"
287 "font: bold;");
288 exportHighlightning->setDisabled(true);
289 } else {
290 exportHighlightning->setEnabled(true);
291 }
292 s->applySettings(highlightingSettings);
293 }
294
sl_updateColorSchemeWidgets()295 void MSAHighlightingTab::sl_updateColorSchemeWidgets() {
296 MsaColorScheme *currentColorScheme = seqArea->getCurrentColorScheme();
297 SAFE_POINT(currentColorScheme != nullptr, "Current Color Scheme is NULL!", );
298
299 const MsaColorSchemeFactory *factory = currentColorScheme->getFactory();
300 SAFE_POINT(factory != nullptr, "Current Color Scheme factory is NULL!", );
301
302 if (factory->isThresholdNeeded()) {
303 colorThresholdLabel->show();
304 colorThresholdSlider->show();
305 colorSpinBox->show();
306 } else {
307 colorThresholdLabel->hide();
308 colorThresholdSlider->hide();
309 colorSpinBox->hide();
310 }
311 }
312
sl_exportHighlightningClicked()313 void MSAHighlightingTab::sl_exportHighlightningClicked() {
314 msa->exportHighlighted();
315 }
316
sl_colorParametersChanged()317 void MSAHighlightingTab::sl_colorParametersChanged() {
318 QSignalBlocker thresholdBlocker(colorThresholdSlider);
319 Q_UNUSED(thresholdBlocker);
320 QSignalBlocker spinBoxBlocker(colorSpinBox);
321 Q_UNUSED(spinBoxBlocker);
322
323 double thresholdValue = colorSpinBox->value();
324 if (sender() == colorThresholdSlider) {
325 int sliderValue = colorThresholdSlider->value();
326 thresholdValue = double(sliderValue) / 10;
327 colorSpinBox->setValue(thresholdValue);
328 } else if (sender() == colorSpinBox) {
329 int sliderNewValue = int(thresholdValue * 10);
330 colorThresholdSlider->setValue(sliderNewValue);
331 }
332 MsaColorScheme *currentColorScheme = seqArea->getCurrentColorScheme();
333 SAFE_POINT(currentColorScheme != nullptr, "Current Color Scheme is NULL!", );
334
335 QVariantMap settings;
336 settings.insert(MsaColorScheme::THRESHOLD_PARAMETER_NAME, thresholdValue);
337 currentColorScheme->applySettings(settings);
338 emit si_colorSchemeChanged();
339 }
340
sl_highlightingParametersChanged()341 void MSAHighlightingTab::sl_highlightingParametersChanged() {
342 QVariantMap highlightingSettings;
343 thresholdLabel->setText(tr("Threshold: %1%").arg(highlightingThresholdSlider->value()));
344 MsaHighlightingScheme *s = seqArea->getCurrentHighlightingScheme();
345 highlightingSettings.insert(MsaHighlightingScheme::THRESHOLD_PARAMETER_NAME, highlightingThresholdSlider->value());
346 highlightingSettings.insert(MsaHighlightingScheme::LESS_THAN_THRESHOLD_PARAMETER_NAME, thresholdLessRb->isChecked());
347 s->applySettings(highlightingSettings);
348 seqArea->sl_changeColorSchemeOutside(colorSchemeController->getComboBox()->currentData().toString());
349 }
350
sl_refreshSchemes()351 void MSAHighlightingTab::sl_refreshSchemes() {
352 colorSchemeController->init();
353 highlightingSchemeController->init();
354 sl_sync();
355 }
356
357 } // namespace U2
358