21 #include "ui_mainwindow.h"
22 #include "../core/messages/message.h"
23 #include "../core/messages/messagehandler.h"
24 #include "../core/messages/messagemodechanged.h"
25 #include "../core/messages/messageprojectfile.h"
26 #include "../core/messages/messagekeyselectionchanged.h"
27 #include "../core/messages/messagerecorderenergychanged.h"
28 #include "../core/messages/messagefinalkey.h"
29 #include "../core/messages/messagecaluclationprogress.h"
30 #include "../core/messages/messagenewfftcalculated.h"
31 #include "../core/system/version.h"
32 #include "../core/system/serverinfo.h"
34 #include <QCloseEvent>
36 #include <QMessageBox>
37 #include <QFileDialog>
38 #include <QToolButton>
40 #include <QButtonGroup>
43 #include <QGuiApplication>
47 #include <QDesktopServices>
50 #include <QTextBrowser>
52 #include <QDialogButtonBox>
68 mIconPostfix((QApplication::primaryScreen()->devicePixelRatio() > 1.5) ?
"@2x" :
""),
73 ui->graphSplitter->setSizes(QList<int>() << 200 << 200);
76 qreal maxDisplaySize = std::max(QGuiApplication::primaryScreen()->physicalSize().width(),
77 QGuiApplication::primaryScreen()->physicalSize().height());
83 ui->controlLayout->addWidget(mVolumeControlGroup, 1);
85 QObject::connect(mVolumeControlGroup, SIGNAL(refreshInputLevels()),
this, SLOT(
onResetNoiseLevel()));
86 QObject::connect(mVolumeControlGroup, SIGNAL(muteMicroToggled(
bool)),
this, SLOT(
onToggleMicroMute(
bool)));
87 QObject::connect(mVolumeControlGroup, SIGNAL(muteSpeakerToggled(
bool)),
this, SLOT(
onToggleSpeakerMute(
bool)));
102 int iconSize =
ui->modeToolBar->fontMetrics().height();
103 QSize modeIconSize = QSize(iconSize, iconSize) * 2;
104 ui->modeToolBar->setObjectName(
"modeToolBar");
105 ui->modeToolBar->setIconSize(QSize(iconSize, iconSize) * 2);
108 QScrollArea *modeScrollArea =
new QScrollArea;
109 ui->modeToolBar->addWidget(modeScrollArea);
110 modeScrollArea->setWidgetResizable(
true);
111 modeScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
112 modeScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
113 modeScrollArea->setStyleSheet(
"\
114 QScrollArea { background: transparent; } \
115 QScrollArea > QWidget > QWidget { background: transparent; } \
117 modeScrollArea->setFrameShape(QFrame::NoFrame);
118 QScroller::grabGesture(modeScrollArea->viewport(), QScroller::LeftMouseButtonGesture);
119 QWidget *modeScrollContents =
new QWidget;
120 modeScrollArea->setWidget(modeScrollContents);
121 modeScrollContents->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
122 QVBoxLayout *modeScrollLayout =
new QVBoxLayout;
123 modeScrollLayout->setMargin(0);
124 modeScrollLayout->setSpacing(0);
125 modeScrollContents->setLayout(modeScrollLayout);
127 QButtonGroup *group =
new QButtonGroup(
this);
129 auto createModeToolButton = [
this, modeIconSize, group, modeScrollLayout]() {
130 QToolButton *b =
new QToolButton(
this);
132 b->setAutoRaise(
true);
133 b->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
134 b->setCheckable(
true);
135 b->setIconSize(modeIconSize);
136 b->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
138 modeScrollLayout->addWidget(b);
142 QToolButton *idleButton = createModeToolButton();
143 idleButton->setText(tr(
"Idle"));
144 idleButton->setIcon(QIcon(
":/media/icons/system-idle.png"));
145 idleButton->setWhatsThis(tr(
"Press this button to switch to the idle mode."));
146 connect(idleButton, SIGNAL(toggled(
bool)),
this, SLOT(
onModeIdle(
bool)));
148 QToolButton *recordingButton = createModeToolButton();
149 recordingButton->setText(tr(
"Record"));
150 recordingButton->setIcon(QIcon::fromTheme(
"audio-input-microphone", QIcon(
":/media/icons/audio-input-microphone.png")));
151 recordingButton->setWhatsThis(tr(
"Press this button to switch to the recording mode."));
152 connect(recordingButton, SIGNAL(toggled(
bool)),
this, SLOT(
onModeRecord(
bool)));
154 QToolButton *calculatingButton = createModeToolButton();
155 calculatingButton->setText(tr(
"Calculate"));
156 calculatingButton->setIcon(QIcon(
":/media/icons/note.png"));
157 calculatingButton->setWhatsThis(tr(
"Press this button to switch to the calculation mode."));
158 connect(calculatingButton, SIGNAL(toggled(
bool)),
this, SLOT(
onModeCalculate(
bool)));
160 QToolButton *tuningButton = createModeToolButton();
161 tuningButton->setText(tr(
"Tune"));
162 tuningButton->setIcon(QIcon(
":/media/icons/wrest.png"));
163 tuningButton->setWhatsThis(tr(
"Press this button to switch to the tuning mode."));
164 connect(tuningButton, SIGNAL(toggled(
bool)),
this, SLOT(
onModeTune(
bool)));
166 idleButton->setChecked(
true);
168 modeScrollLayout->addStretch();
176 auto iconFromTheme = [](
const QString &s) {
return QIcon::fromTheme(s, QIcon(
":/media/icons/" + s +
".png"));};
182 mFileToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::LeftToolBarArea);
184 mFileToolBar->setIconSize(QSize(iconSize, iconSize) * 1.5);
192 mFileToolBar->addAction(iconFromTheme(
"preferences-system"), tr(
"Options"),
this, SLOT(
onOptions()));
193 mFileToolBar->addAction(QIcon(
":/media/icons/mathematical_plot.png"), tr(
"Graphs"),
this, SLOT(
onOpenPlots()));
195 QToolBar *helpToolBar =
new QToolBar(tr(
"Help"));
196 helpToolBar->setObjectName(
"helpToolBar");
197 addToolBar(Qt::TopToolBarArea, helpToolBar);
198 helpToolBar->setMovable(
false);
199 helpToolBar->setFloatable(
false);
200 helpToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::LeftToolBarArea);
203 QWidget *tbStretch =
new QWidget;
204 helpToolBar->addWidget(tbStretch);
205 tbStretch->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
206 tbStretch->setVisible(
true);
208 helpToolBar->addAction(iconFromTheme(
"help-contents"), tr(
"Tutorial"),
this, SLOT(
onTutorial()));
210 helpToolBar->addAction(iconFromTheme(
"help-about"), tr(
"About"),
this, SLOT(
onAbout()));
214 #if CONFIG_MENU_ICONS
215 ui->action_New->setIcon(iconFromTheme(
"document-new"));
216 ui->actionOpen->setIcon(iconFromTheme(
"document-open"));
217 ui->actionSave->setIcon(iconFromTheme(
"document-save"));
218 ui->actionSave_As->setIcon(iconFromTheme(
"document-save-as"));
219 ui->actionExit->setIcon(iconFromTheme(
"application-exit"));
220 ui->actionEdit_piano_data_sheet->setIcon(iconFromTheme(
"accessories-text-editor"));
221 ui->actionClear_pitches->setIcon(iconFromTheme(
"edit-clear"));
222 ui->actionOptions->setIcon(iconFromTheme(
"preferences-system"));
223 ui->actionTutorial->setIcon(iconFromTheme(
"help-contents"));
224 ui->actionView_log->setIcon(iconFromTheme(
"accessories-text-editor"));
225 ui->actionAbout->setIcon(iconFromTheme(
"help-about"));
230 QAction *exportAction =
new QAction(tr(
"Export"),
ui->menuFile);
231 QObject::connect(exportAction, SIGNAL(triggered(
bool)),
this, SLOT(
onExport()));
232 ui->menuFile->insertAction(
ui->actionShare, exportAction);
233 ui->menuFile->insertSeparator(exportAction);
237 # if defined(TARGET_IPHONE_SIMULATOR) || defined(TARGET_OS_IPHONE)
238 ui->menuBar->setVisible(
false);
244 ui->actionShare->setVisible(
true);
245 #endif // __ANDROID__
247 #if EPT_WHATS_THIS_ENABLED
248 QAction *whatsThisAction = QWhatsThis::createAction(
this);
249 whatsThisAction->setIcon(QIcon(
":/media/icons/help-context.png"));
250 whatsThisAction->setCheckable(
true);
251 ui->menuHelp->addAction(whatsThisAction);
252 helpToolBar->addAction(whatsThisAction);
253 #endif // EPT_WHATS_THIS_ENABLED
263 ui->action_New->setShortcut(QKeySequence::New);
264 ui->actionOpen->setShortcut(QKeySequence::Open);
265 ui->actionSave->setShortcut(QKeySequence::Save);
266 ui->actionSave_As->setShortcut(QKeySequence::SaveAs);
267 ui->actionExit->setShortcut(QKeySequence::Quit);
268 ui->actionOptions->setShortcut(QKeySequence::Preferences);
269 ui->actionTutorial->setShortcut(QKeySequence::HelpContents);
270 ui->actionEdit_piano_data_sheet->setShortcut(QKeySequence(Qt::Key_F9));
276 QBoxLayout *mainLayout = qobject_cast<QBoxLayout*>(centralWidget()->layout());
277 mainLayout->setStretch(0, 0);
278 mainLayout->setStretch(1, 1);
279 mainLayout->setStretch(3, 1);
281 #if CONFIG_DIALOG_SIZE == 1
284 restoreGeometry(settings.value(
"geometry/mainwindow").toByteArray());
285 restoreState(settings.value(
"windowState/mainwindow").toByteArray());
287 for (QVariant v : settings.value(
"splitterSizes/graphSplitter").toList()) {
288 sizes.push_back(v.toInt());
290 if (sizes.size() > 0) {
291 ui->graphSplitter->setSizes(sizes);
296 #endif // CONFIG_DIALOG_SIZE
309 qDebug() <<
"Display size: " << QGuiApplication::primaryScreen()->physicalSize();
315 ui->fourierSpectrumGraphics->setVisible(
false);
318 statusBar()->setHidden(
true);
340 #if CONFIG_DIALOG_SIZE == 1
342 settings.setValue(
"geometry/mainwindow", saveGeometry());
343 settings.setValue(
"windowState/mainwindow", saveState());
345 for (
int s :
ui->graphSplitter->sizes()) {
346 sizes.push_back(QVariant(s));
348 settings.setValue(
"splitterSizes/graphSplitter", sizes);
352 QMainWindow::closeEvent(event);
359 switch (m->getType()) {
361 auto mpf(std::static_pointer_cast<MessageProjectFile>(m));
362 switch (mpf->getFileMessageType()) {
364 statusBar()->showMessage(tr(
"File created"));
367 statusBar()->showMessage(tr(
"File edited"));
370 statusBar()->showMessage(tr(
"File opened"));
373 statusBar()->showMessage(tr(
"File saved"));
376 LogW(
"MessagePojectFile::Type Not implemented");
383 auto mmc(std::static_pointer_cast<MessageModeChanged>(m));
397 ui->fourierSpectrumGraphics->setVisible(
false);
402 ui->fourierSpectrumGraphics->setVisible(
true);
409 int missingKeyRecordings = 0;
410 int missingComputedFrequencies = 0;
413 if (!key.isRecorded()) {
414 missingKeyRecordings++;
416 if (key.getComputedFrequency() <= 0) {
417 missingComputedFrequencies++;
429 }
else if (missingComputedFrequencies > 0) {
439 statusBar()->showMessage(tr(
"Recording keystroke"));
441 ui->tuningCurveGraphicsView->setVisible(
false);
442 ui->fourierSpectrumGraphics->setVisible(
true);
447 statusBar()->showMessage(tr(
"Signal analysis started"));
450 statusBar()->showMessage(tr(
"Signal analysis ended"));
452 ui->fourierSpectrumGraphics->setVisible(
false);
453 ui->tuningCurveGraphicsView->setVisible(
true);
457 auto mksc(std::static_pointer_cast<MessageKeySelectionChanged>(m));
462 auto mrec(std::static_pointer_cast<MessageRecorderEnergyChanged>(m));
470 auto message(std::static_pointer_cast<MessageFinalKey>(m));
471 auto keyptr = message->getFinalKey();
476 auto mcp(std::static_pointer_cast<MessageCaluclationProgress>(m));
477 switch (mcp->getCalculationType()) {
479 statusBar()->showMessage(tr(
"Calculation failed"));
482 statusBar()->showMessage(tr(
"Calculation ended"));
485 statusBar()->showMessage(tr(
"Calculation started"));
504 text.replace(
"#",
"<sup>#</sup>");
530 QList<QPair<QString, QStringList> > programNames;
532 programNames.append(qMakePair(QString(
"pavucontrol"), QStringList()));
533 programNames.append(qMakePair(QString(
"gnome-control-center"), QStringList() <<
"sound"));
536 programNames.append(qMakePair(QString(
"open"), QStringList() <<
"/System/Library/PreferencePanes/Sound.prefPane/"));
539 programNames.append(qMakePair(QString(
"control"), QStringList() <<
"mmsys.cpl" <<
"sounds"));
545 QProcess *process =
new QProcess(
this);
546 for (
auto &program : programNames) {
547 process->start(program.first, program.second);
548 if (process->waitForStarted()) {
549 LogI(
"Sound control program '%s' started", program.first.toStdString().c_str());
555 QMessageBox::warning(
this, tr(
"Warning"), tr(
"Unable to find a supported sound control."));
563 # if TARGET_IPHONE_SIMULATOR
565 # elif TARGET_OS_IPHONE
603 QMessageBox::information(
this, tr(
"Canceled"), tr(
"You need to save the file before you can share it."));
628 QDialog helpDialog(
this, Qt::Window);
631 QRect mwRect(this->geometry());
632 helpDialog.setGeometry(mwRect.x() + mwRect.width() / 4, mwRect.y() + mwRect.height() / 4,
633 mwRect.width() / 2, mwRect.height() / 2);
636 QVBoxLayout *mainLayout =
new QVBoxLayout;
637 helpDialog.setLayout(mainLayout);
638 QTextBrowser *edit =
new QTextBrowser;
639 mainLayout->addWidget(edit);
640 edit->setOpenExternalLinks(
true);
641 edit->setReadOnly(
true);
642 QString languageStr(QLocale().name());
643 languageStr = languageStr.left(languageStr.indexOf(
"_"));
644 QFile manual(
":/tutorial/tutorial_" + languageStr +
".html");
647 auto readAllFromFile = [](QFile &f) {
654 if (!manual.open(QFile::ReadOnly | QFile::Text)) {
655 LogW(
"Manual not found for language %s. Using english as fallback.",
656 languageStr.toStdString().c_str());
659 QFile enManual(
":/tutorial/tutorial_en.html");
660 if (!enManual.open(QFile::ReadOnly | QFile::Text)) {
661 LogE(
"Engish manual not found. Maybe the location of the manual changed?");
662 text =
"No manual found. Please use the online manual instead.";
664 text = readAllFromFile(enManual);
667 text = readAllFromFile(manual);
671 text.replace(QRegExp(
"SRC=\"([^\"]*)\""),
"SRC=\":/tutorial/\\1\"");
673 edit->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard);
675 QDialogButtonBox *buttons =
new QDialogButtonBox(QDialogButtonBox::Close);
676 mainLayout->addWidget(buttons);
678 QObject::connect(buttons, SIGNAL(rejected()), &helpDialog, SLOT(reject()));
680 QScroller::grabGesture(edit);
683 helpDialog.showMaximized();
737 if (this->windowState() & Qt::WindowFullScreen) {
758 mb.setText(tr(
"A new update is available!"));
759 mb.setInformativeText(tr(
"The online app version is %1. Do you want to install this update?").arg(information.
mAppVersion));
760 mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
761 if (mb.exec() == QMessageBox::Yes) {
765 LogW(
"Online installer file for mac could not be found.");
771 # ifdef QT_NO_PROCESS
775 if (QProcess::startDetached(
"maintenancetool", QStringList() <<
"--updater") ==
false) {
776 LogW(
"Maintenace tool could not be started.");
777 QMessageBox::warning(
this, tr(
"Warning"), tr(
"The maintenance tool could not be started automatically. To update the program you have to start the maintenance tool manually."));
782 # endif // QT_NO_PROCESS
double getRecordedFrequency() const
Get recorded frequency.
void setMuted(bool muted)
Mute the audio player.
PianoManager * getPianoManager()
std::shared_ptr< Message > MessagePtr
Global type of a shared message pointer.
void changesInFileUpdated(bool b) overridefinal
Called if changed in file are made to update the window title.
void updateVolumeBar()
This will update the positions of the labels in the volume bar.
const Key * getSelectedKey() const
void updateWindowTitle()
Update the window title.
TuningIndicatorView * getTunincIndicatorView()
void onOptions()
Slot to open the options.
OperationMode
Operation mode of the tuner.
void setCallback(FileChangesCallback *cb)
Set a callback function for file changes.
void toggleSpectralAndStroboscopeMode()
Toggle between spectral and stroboscopic operation mode.
void setMuted(bool muted)
Set and reset the muting flag.
void updateFrequency(const Key *key)
Update the frequency label.
void onOpenPlots()
Slot to open the mathematical plots dialog.
void onOpenSoundControl()
Slot to open the sound control.
void onFileSaveAs()
Slot to save the current file as a new file.
bool hasChangesInFile() const
static const double LEVEL_TRIGGER
Level above which the recorder starts to operate.
void onResetRecording()
Slot to reset the recording.
virtual ~MainWindow()
Destructor.
OperationMode mCurrentMode
void onSelectNextMode()
Slot to select the next mode.
void onManual()
Slot to open the manual.
Message that a change was made with the current project file.
Class describing a single piano key.
void onViewLog()
Slot to open the log viewer.
std::string getManualFileAddress(const std::string &langCode)
The tuning curve has to be recalculated.
CalculationProgressGroup * mCalculationProgressGroup
Pointer to the CalculationProgressGroup.
Message that the operation mode has changed.
void onModeTune(bool)
Slot to switch to tuning mode.
void onAbout()
Slot to open the about dialog.
void updateNoteName(int key)
Update the note name.
std::string getDownloadsFileAddress(const std::string &filename)
void resetPitches()
Reset all recorded keys and send a message to redraw all elements.
void onFileSave()
Slot to save the current file.
QToolButton * mModeToolButtons[OperationMode::MODE_COUNT]
Tool buttons for all modes.
Mode where the entropy optimization is carried out.
Mode for recording the piano keys.
Message that a key has been selected.
AudioPlayerAdapter * getAudioPlayer()
void onExport()
Slot to open the export dialog.
void onSelectPreviousMode()
Slot to select the previous mode.
void setFrequency(QString f)
Visible QGroupBox to handle the calculation.
const Keyboard & getKeyboard() const
recording input level has changed
void start()
Starts the main window.
analysis of the signal started
std::string getNoteName(int keynumber) const
Get the name of the key as a string.
Ui::MainWindow * ui
Ui of the Mainwindow.
double getStopLevel() const
Results onNewFile()
New-file menu response.
ProjectManagerAdapter * getProjectManager()
Not all keys have been recorded.
void init(Core *core)
Initialize the project management adapter.
Core * mCore
Pointer to the Core.
void resetInputLevelControl()
Reset input level control.
MainWindow(QWidget *parent=nullptr)
Constructor.
Message that progress of any kind was made by the calculator.
void modeChanged(OperationMode mode)
void updateLevels(double stopLevel, double onLevel)
Mode for manually tuning the piano.
void setMode(OperationMode m)
Set operation mode.
KeyboardGraphicsView * mKeyboardGraphicsView
const QString mIconPostfix
void onToggleFullscreen()
Slot to toggle full screen of the MainWindow.
void onFileShare()
Slot to store the current file.
final key information after recording
void onModeCalculate(bool)
Slot to switch to calculation mode.
CORE : Class managing the core.
void onFileOpen()
Slot to open a new file.
void onToggleSpeakerMute(bool checked)
Toggle the mute button.
static int show(Type type, const QString text, QWidget *parent=nullptr)
Show a message box if the user didnt check the QCheckBox.
The tuning curve has not been calculated.
bool isSoundControlSupported()
VolumeControlGroupBox * mVolumeControlGroup
Pointer to the VolumeControlGroupBox.
void onToggleTuningIndictator()
Slot to toggle between the two tuning indicator modes.
void onVersionUpdate(VersionInformation information)
static bool doNotShowAgain(Type type)
void onToggleMicroMute(bool checked)
Toggle the mute button.
void onModeIdle(bool)
Slot to switch to idle mode.
SignalAnalyzerGroupBox * mSignalAnalyzerGroup
Pointer to the SignalAnalyzerGroupBox.
void init(Core *core)
Initialised the window using the given Core.
void onFileNew()
Slot called for creating a new file.
static const std::string SERVER_ADDRESS
void onEditPianoDataSheet()
Slot to edit the current piano data sheet.
static const std::unique_ptr< DisplaySizeDefines > & getSingleton()
void onModeRecord(bool)
Slot to switch to recording mode.
int getNumberOfKeys() const
const std::string & getName() const
double getTunedFrequency() const
Get tuned frequency.
analysis of the signal ended
static SettingsForQt & getSingleton()
Getter function for the singleton.
TuningIndicatorGroupBox * mTuningIndicatorGroup
Pointer to the TuningIndicatorGroupBox.
void handleMessage(MessagePtr m) override
Message handling.
void onResetNoiseLevel()
Slot to reset the noise level.
keystroke recognized and recording started
void closeEvent(QCloseEvent *event) override
Reimplementation of the close event.
static const std::string MAC_X86_64_DMG
AudioRecorderAdapter * getAudioRecorder()