Entropy Piano Tuner  1.1.3 (documentation not yet complete)
An open-source experimental software for piano tuning by entropy minimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
algorithmdialog.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * Copyright 2015 Haye Hinrichsen, Christoph Wick
3  *
4  * This file is part of Entropy Piano Tuner.
5  *
6  * Entropy Piano Tuner is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * Entropy Piano Tuner is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * Entropy Piano Tuner. If not, see http://www.gnu.org/licenses/.
18  *****************************************************************************/
19 
20 #include "algorithmdialog.h"
21 
22 #include <QVBoxLayout>
23 #include <QHBoxLayout>
24 #include <QFormLayout>
25 #include <QDialogButtonBox>
26 #include <QScrollArea>
27 #include <QComboBox>
28 #include <QLabel>
29 #include <QGroupBox>
30 #include <QDoubleSpinBox>
31 #include <QScroller>
32 #include <QDebug>
33 #include "doubleslider.h"
34 
35 #include "qtconfig.h"
36 #include "core/config.h"
40 
42 
43 AlgorithmDialog::AlgorithmDialog(std::shared_ptr<const AlgorithmInformation> currentAlgorithm, QWidget *parent) :
44  QDialog(parent)
45 {
46  EptAssert(currentAlgorithm, "Current algorithm has to exist.");
47 
48  QRect pr(parent->contentsRect());
49  setGeometry(pr.center().x() - pr.width() / 4, pr.center().y() - pr.height() / 4,
50  pr.width() / 2, pr.height() / 2);
51 
52 
53 
54  // load all algorithms on first launch to get the names
55  if (mAlgorithmNames.size() == 0) {
56  for (auto &desc : CalculationManager::getSingleton().getAlgorithms()) {
57  const std::string &name = desc.first;
58  try {
59  auto info(std::move(CalculationManager::getSingleton().loadAlgorithmInformation(name)));
60  mAlgorithmNames.push_back(qMakePair(QString::fromStdString(name), QString::fromStdString(info->getName())));
61  } catch (...) {
62  LogW("Error during loading and adding the algorithm '%s'. Skipping...", name.c_str());
63  }
64  }
65  }
66 
67  // create default layout,
68  QVBoxLayout *mainLayout = new QVBoxLayout;
69  setLayout(mainLayout);
70 
71  // title
72  QHBoxLayout *titleLayout = new QHBoxLayout;
73  mainLayout->addLayout(titleLayout);
74  titleLayout->addWidget(new QLabel(tr("Algorithm:")));
75 
76  QComboBox *comboBox = new QComboBox;
77  mAlgorithmSelection = comboBox;
78  for (const auto &alg : mAlgorithmNames) {
79  comboBox->addItem(alg.second, alg.first);
80  }
81  titleLayout->addWidget(comboBox);
82  // select current algorithm
83  comboBox->setCurrentIndex(comboBox->findData(QString::fromStdString(currentAlgorithm->getId())));
84  EptAssert(comboBox->currentIndex() >= 0, "The default algotihm doesnt exist!");
85 
86  QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(algorithmSelectionChanged(int)));
87 
88  // scroll area
89  mAlgorithmDescriptionScrollArea = new QScrollArea;
90  mainLayout->addWidget(mAlgorithmDescriptionScrollArea);
91  //mAlgorithmDescriptionScrollArea->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
92  mAlgorithmDescriptionScrollArea->setWidgetResizable(true);
93  //mAlgorithmDescriptionScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
94  //mAlgorithmDescriptionScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
95 
96  QScroller::grabGesture(mAlgorithmDescriptionScrollArea->viewport(), QScroller::LeftMouseButtonGesture);
97 
98 
99 
100  // button box
101  QDialogButtonBox *buttons = new QDialogButtonBox;
102  mainLayout->addWidget(buttons);
103  buttons->setStandardButtons(QDialogButtonBox::Ok);
104 
105  QObject::connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
106  QObject::connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
107 
108  algorithmSelectionChanged(comboBox->currentIndex());
109 
110  SHOW_DIALOG(this);
111 }
112 
115  // nothin selected
116  return;
117  }
118 
119  // update the parameters
120  for (auto &paramWidget : mAlgorithmWidgetConnectionList) {
121  const AlgorithmParameter &param = mCurrentAlgorithmInformation->getParameter(paramWidget.first);
122  const QWidget *widget = paramWidget.second;
123 
124  if (param.getType() == AlgorithmParameter::TYPE_DOUBLE) {
125  const QDoubleSpinBox *sb = dynamic_cast<const QDoubleSpinBox*>(widget);
126  EptAssert(sb, "This parameter is described by a QDoubleSpinBox");
127  mCurrentFactoryDescription->setDoubleParameter(paramWidget.first, sb->value());
128  } else if (param.getType() == AlgorithmParameter::TYPE_INT) {
129  const QSpinBox *sb = dynamic_cast<const QSpinBox*>(widget);
130  EptAssert(sb, "This parameter is described by a QSpinBox");
131  mCurrentFactoryDescription->setIntParameter(paramWidget.first, sb->value());
132  } else if (param.getType() == AlgorithmParameter::TYPE_LIST) {
133  const QComboBox *cb = qobject_cast<const QComboBox*>(widget);
134  mCurrentFactoryDescription->setStringParameter(paramWidget.first, cb->currentData().toString().toStdString());
135  } else {
136  EPT_EXCEPT(EptException::ERR_NOT_IMPLEMENTED, "Parameter type not implemented");
137  }
138  }
139 
140 }
141 
143  // cleanup and save old
144  acceptCurrent();
145  if (mAlgorithmDescriptionScrollArea->widget()) {delete mAlgorithmDescriptionScrollArea->widget();}
147 
148  // load new
149  QString algId = mAlgorithmSelection->itemData(index).toString();
151  mCurrentFactoryDescription = &description;
154 
155  setWindowTitle(tr("Info of algorithm: %1").arg(QString::fromStdString(info.getName())));
156 
157  QWidget *scrollContentWidget = new QWidget;
158  scrollContentWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
159  mAlgorithmDescriptionScrollArea->setWidget(scrollContentWidget);
160  QVBoxLayout *scrollLayout = new QVBoxLayout;
161  scrollContentWidget->setLayout(scrollLayout);
162 
163  QGroupBox *infoGroupBox = new QGroupBox(tr("Info"));
164  scrollLayout->addWidget(infoGroupBox);
165 
166  QFormLayout *layout = new QFormLayout;
167  infoGroupBox->setLayout(layout);
168 
169  layout->addRow(new QLabel(tr("Name:")), new QLabel(QString::fromStdString(info.getName())));
170  layout->addRow(new QLabel(tr("Author:")), new QLabel(QString::fromStdString(info.getAuthor())));
171  layout->addRow(new QLabel(tr("Year:")), new QLabel(QString("%1").arg(info.getYear())));
172 
173  QLabel *descriptionLabel = new QLabel(QString::fromStdString(info.getDescription()));
174  descriptionLabel->setWordWrap(true);
175  descriptionLabel->setAlignment(Qt::AlignTop);
176  layout->addRow(new QLabel(tr("Description:")), descriptionLabel);
177 
178 
179  // add parameters
180  if (info.getParameters().size() > 0) {
181  QGroupBox *paramsBox = new QGroupBox(tr("Parameters"));
182  scrollLayout->addWidget(paramsBox);
183  QFormLayout *paramsBoxLayout = new QFormLayout;
184  paramsBox->setLayout(paramsBoxLayout);
185  for (const AlgorithmParameter &param : info.getParameters()) {
186  QWidget *dataWidget = nullptr;
187  QLayout *dataLayout = nullptr;
188 
189  if (param.getType() == AlgorithmParameter::TYPE_DOUBLE) {
190  QHBoxLayout *valueLayout = new QHBoxLayout;
191  dataLayout = valueLayout;
192 
193  QDoubleSpinBox *sb = new QDoubleSpinBox();
194 #ifdef __ANDROID__
195  // HACK: fix spin box size on android
196  sb->setMinimumWidth(sb->fontInfo().pointSizeF() * 15);
197 #endif
198  sb->setRange(param.getDoubleMinValue(), param.getDoubleMaxValue());
199  if (description.hasDoubleParameter(param.getID())) {
200  sb->setValue(description.getDoubleParameter(param.getID()));
201  } else {
202  sb->setValue(param.getDoubleDefaultValue());
203  }
204 
205  if (param.getDoublePrecision() >= 0) {
206  // add a slider aswell
207  DoubleSlider *slider = new DoubleSlider(param.getDoubleMinValue(), param.getDoubleMaxValue(), param.getDoublePrecision());
208  slider->setOrientation(Qt::Horizontal);
209  slider->setValue(sb->value());
210  valueLayout->addWidget(slider);
211 
212  QObject::connect(slider, SIGNAL(valueChanged(double)), sb, SLOT(setValue(double)));
213  QObject::connect(sb, SIGNAL(valueChanged(double)), slider, SLOT(setValue(double)));
214 
215  sb->setDecimals(param.getDoublePrecision());
216  }
217 
218  valueLayout->addWidget(sb);
219 
220  dataWidget = sb;
221  } else if (param.getType() == AlgorithmParameter::TYPE_INT) {
222  QHBoxLayout *valueLayout = new QHBoxLayout;
223  dataLayout = valueLayout;
224 
225  QSpinBox *sb = new QSpinBox();
226 #ifdef __ANDROID__
227  // HACK: fix spin box size on android
228  sb->setMinimumWidth(sb->fontInfo().pointSizeF() * 15);
229 #endif
230  sb->setRange(param.getIntMinValue(), param.getIntMaxValue());
231  if (description.hasIntParameter(param.getID())) {
232  sb->setValue(description.getIntParameter(param.getID()));
233  } else {
234  sb->setValue(param.getIntDefaultValue());
235  }
236 
237  // add a slider aswell
238  QSlider *slider = new QSlider(Qt::Horizontal);
239  slider->setMinimum(param.getIntMinValue());
240  slider->setMaximum(param.getIntMaxValue());
241  slider->setValue(sb->value());
242  valueLayout->addWidget(slider);
243 
244  QObject::connect(slider, SIGNAL(valueChanged(int)), sb, SLOT(setValue(int)));
245  QObject::connect(sb, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)));
246 
247  valueLayout->addWidget(sb);
248 
249  dataWidget = sb;
250  } else if (param.getType() == AlgorithmParameter::TYPE_LIST) {
251  QComboBox *cb = new QComboBox;
252  for (const auto &p : param.getStringList()) {
253  cb->addItem(QString::fromStdString(p.second), QString::fromStdString(p.first));
254  }
255  int defaultIndex = cb->findData(QString::fromStdString(param.getStringDefaultValue()));
256  if (description.hasStringParameter(param.getID())) {
257  defaultIndex = cb->findData(QString::fromStdString(description.getStringParameter(param.getID())));
258  }
259  cb->setCurrentIndex(defaultIndex);
260 
261  dataWidget = cb;
262  } else {
263  EPT_EXCEPT(EptException::ERR_NOT_IMPLEMENTED, "Parameter type not implemented.");
264  }
265 
266  EptAssert(dataWidget, "A data widget has to exist.");
267 
268  dataWidget->setWhatsThis(QString::fromStdString(param.getDescription()));
269 
270  if (dataLayout) {
271  paramsBoxLayout->addRow(new QLabel(QString::fromStdString(param.getLabel())), dataLayout);
272  } else if (dataWidget) {
273  paramsBoxLayout->addRow(new QLabel(QString::fromStdString(param.getLabel())), dataWidget);
274  } else {
275  EPT_EXCEPT(EptException::ERR_NOT_IMPLEMENTED, "the parameter has to create a data layout or a data widget. Maybe it is not implemented at all");
276  }
277 
278  mAlgorithmWidgetConnectionList.append(qMakePair(param.getID(), dataWidget));
279  }
280  }
281 
282 
283  //layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding));
284 }
285 
287  QDialog::accept();
288 
289  acceptCurrent();
290 }
void accept() override
static CalculationManager & getSingleton()
QComboBox * mAlgorithmSelection
void setDoubleParameter(const std::string &s, double p)
bool hasDoubleParameter(const std::string &s) const
#define LogW(...)
Definition: log.h:56
const std::string & getAlgorithmName() const
bool hasIntParameter(const std::string &s) const
AlgorithmDialog(std::shared_ptr< const AlgorithmInformation > currentAlgorithm, QWidget *parent)
std::shared_ptr< const AlgorithmInformation > mCurrentAlgorithmInformation
#define SHOW_DIALOG(d)
Definition: qtconfig.h:41
static AlgorithmIdList mAlgorithmNames
AlgorithmWidgetConnectionList mAlgorithmWidgetConnectionList
double getDoubleParameter(const std::string &s) const
#define EPT_EXCEPT(num, desc)
Definition: eptexception.h:119
QList< QPair< QString, QString >> AlgorithmIdList
AlgorithmFactoryDescription * mCurrentFactoryDescription
int getIntParameter(const std::string &s) const
void setStringParameter(const std::string &id, const std::string &s)
QScrollArea * mAlgorithmDescriptionScrollArea
std::shared_ptr< const AlgorithmInformation > loadAlgorithmInformation(const std::string &algorithmName) const
AlgorithmFactoryDescription & getAlgorithmDescription(const std::string &algorithmName) const
void algorithmSelectionChanged(int index)
#define EptAssert(a, b)
Definition: eptexception.h:47
const std::string & getStringParameter(const std::string &id) const
void setIntParameter(const std::string &s, int i)
void setValue(double)
const std::map< std::string, AlgorithmFactoryBase * > & getAlgorithms() const
bool hasStringParameter(const std::string &id) const