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 <limits.h>
23 
24 #include <QLineEdit>
25 #include <QMessageBox>
26 #include <QPushButton>
27 
28 #include "WindowStepSelectorWidget.h"
29 
30 namespace U2 {
31 
32 //////////////////////////////////////////////////////////////////////////
33 // WindowStepSelectorWidget
34 
WindowStepSelectorWidget(QWidget * p,const U2Region & winRange,int win,int step)35 WindowStepSelectorWidget::WindowStepSelectorWidget(QWidget *p, const U2Region &winRange, int win, int step)
36     : QWidget(p) {
37     assert(win >= step);
38 
39     windowEdit = new QSpinBox(this);
40     windowEdit->setRange(winRange.startPos, winRange.endPos());
41     windowEdit->setValue(win);
42     windowEdit->setAlignment(Qt::AlignLeft);
43     windowEdit->setObjectName("windowEdit");
44 
45     stepsPerWindowEdit = new QSpinBox(this);
46     stepsPerWindowEdit->setRange(1, winRange.endPos());
47     stepsPerWindowEdit->setValue(win / step);
48     stepsPerWindowEdit->setAlignment(Qt::AlignLeft);
49     stepsPerWindowEdit->setObjectName("stepsPerWindowEdit");
50 
51     formLayout = new QFormLayout(this);
52     formLayout->setMargin(0);
53     formLayout->addRow(tr("Window"), windowEdit);
54     formLayout->addRow(tr("Steps per window"), stepsPerWindowEdit);
55     setLayout(formLayout);
56 }
57 
getWindow() const58 int WindowStepSelectorWidget::getWindow() const {
59     assert(validate().isEmpty());
60     return windowEdit->value();
61 }
62 
getStep() const63 int WindowStepSelectorWidget::getStep() const {
64     assert(validate().isEmpty());
65     return windowEdit->value() / stepsPerWindowEdit->value();
66 }
67 
validate() const68 QString WindowStepSelectorWidget::validate() const {
69     int win = windowEdit->value();
70     int stepsPerWindow = stepsPerWindowEdit->value();
71     if (win % stepsPerWindow != 0) {
72         stepsPerWindowEdit->setFocus(Qt::NoFocusReason);
73         return tr("Illegal step value");
74     }
75     int step = win / stepsPerWindow;
76     if (step > win) {
77         stepsPerWindowEdit->setFocus(Qt::NoFocusReason);
78         return tr("Invalid step value");
79     }
80     return QString();
81 }
82 //////////////////////////////////////////////////////////////////////////
83 ///
84 
85 class MinMaxDoubleSpinBox : public QDoubleSpinBox {
86 public:
getLineEdit() const87     QLineEdit *getLineEdit() const {
88         return lineEdit();
89     }
90 };
91 
MinMaxSelectorWidget(QWidget * p,double min,double max,bool enabled)92 MinMaxSelectorWidget::MinMaxSelectorWidget(QWidget *p, double min, double max, bool enabled) {
93     Q_UNUSED(p);
94 
95     minmaxGroup = new QGroupBox(QString(tr("Cutoff for minimum and maximum values")), this);
96     minmaxGroup->setCheckable(true);
97     minmaxGroup->setChecked(enabled);
98     minmaxGroup->setObjectName("minmaxGroup");
99 
100     // for range use min max of type
101     minBox = new MinMaxDoubleSpinBox;
102     minBox->setRange(INT_MIN, INT_MAX);
103     minBox->setValue(min);
104     minBox->setDecimals(2);
105     minBox->setAlignment(Qt::AlignLeft);
106     minBox->setObjectName("minBox");
107 
108     maxBox = new MinMaxDoubleSpinBox;
109     maxBox->setRange(INT_MIN, INT_MAX);
110     maxBox->setValue(max);
111     maxBox->setDecimals(2);
112     maxBox->setAlignment(Qt::AlignLeft);
113     maxBox->setObjectName("maxBox");
114 
115     normalPalette = maxBox->palette();
116 
117     QFormLayout *l = new QFormLayout;
118     l->setSizeConstraint(QLayout::SetMinAndMaxSize);
119     l->addRow(tr("Minimum"), minBox);
120     l->addRow(tr("Maximum"), maxBox);
121     minmaxGroup->setLayout(l);
122 
123     QVBoxLayout *mainLayout = new QVBoxLayout;
124     mainLayout->setSizeConstraint(QLayout::SetFixedSize);
125     mainLayout->setMargin(0);
126     mainLayout->addWidget(minmaxGroup);
127     setLayout(mainLayout);
128 
129     connect(minBox, SIGNAL(valueChanged(const QString &)), SLOT(sl_valueChanged(const QString &)));
130     connect(maxBox, SIGNAL(valueChanged(const QString &)), SLOT(sl_valueChanged(const QString &)));
131 }
132 
getMin() const133 double MinMaxSelectorWidget::getMin() const {
134     assert(validate().isEmpty());
135     return minBox->value();
136 }
137 
getMax() const138 double MinMaxSelectorWidget::getMax() const {
139     assert(validate().isEmpty());
140     return maxBox->value();
141 }
142 
getState() const143 bool MinMaxSelectorWidget::getState() const {
144     assert(validate().isEmpty());
145     return minmaxGroup->isChecked();
146 }
147 
sl_valueChanged(const QString &)148 void MinMaxSelectorWidget::sl_valueChanged(const QString &) {
149     double min = minBox->value();
150     double max = maxBox->value();
151     QPalette p = normalPalette;
152     if (min >= max) {
153         p.setColor(QPalette::Base, QColor(255, 200, 200));
154     }
155     ((MinMaxDoubleSpinBox *)minBox)->getLineEdit()->setPalette(p);
156     ((MinMaxDoubleSpinBox *)maxBox)->getLineEdit()->setPalette(p);
157 }
158 
validate() const159 QString MinMaxSelectorWidget::validate() const {
160     if (!minmaxGroup->isChecked())
161         return QString();
162     double min = minBox->value();
163     double max = maxBox->value();
164     if (min >= max) {
165         minBox->setFocus(Qt::NoFocusReason);
166         return tr("Invalid cutoff range");
167     }
168     return QString();
169 }
170 
171 //////////////////////////////////////////////////////////////////////////
172 /// Dialog
173 
WindowStepSelectorDialog(QWidget * p,const U2Region & winRange,int win,int step,double min,double max,bool e)174 WindowStepSelectorDialog::WindowStepSelectorDialog(QWidget *p, const U2Region &winRange, int win, int step, double min, double max, bool e)
175     : QDialog(p) {
176     wss = new WindowStepSelectorWidget(this, winRange, win, step);
177     mms = new MinMaxSelectorWidget(this, min, max, e);
178     QVBoxLayout *l = new QVBoxLayout();
179     QHBoxLayout *buttonsLayout = new QHBoxLayout();
180     buttonsLayout->addStretch(10);
181     QPushButton *cancelButton = new QPushButton(tr("Cancel"), this);
182     QPushButton *okButton = new QPushButton(tr("OK"), this);
183     buttonsLayout->addWidget(okButton);
184     buttonsLayout->addWidget(cancelButton);
185 
186     l->addWidget(wss);
187     l->addWidget(mms);
188     l->addLayout(buttonsLayout);
189 
190     setLayout(l);
191     setWindowTitle(tr("Graph Settings"));
192     setWindowIcon(QIcon(":core/images/graphs.png"));
193 
194     setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
195     setMinimumWidth(400);
196 
197     connect(cancelButton, SIGNAL(clicked(bool)), SLOT(sl_onCancelClicked(bool)));
198     connect(okButton, SIGNAL(clicked(bool)), SLOT(sl_onOkClicked(bool)));
199 
200     okButton->setDefault(true);
201 }
202 
sl_onCancelClicked(bool v)203 void WindowStepSelectorDialog::sl_onCancelClicked(bool v) {
204     Q_UNUSED(v);
205     reject();
206 }
207 
sl_onOkClicked(bool v)208 void WindowStepSelectorDialog::sl_onOkClicked(bool v) {
209     Q_UNUSED(v);
210     QString err = wss->validate();
211     QString mmerr = mms->validate();
212     if (err.isEmpty() && mmerr.isEmpty()) {
213         accept();
214         return;
215     }
216     QMessageBox::critical(this, tr("Error!"), err.append(' ').append(mmerr));
217 }
218 
219 }  // namespace U2
220