From 66585a6cdabbd7a6775e289a19b4bb142dded3a1 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 18 Mar 2020 23:17:00 +0100 Subject: [PATCH 01/55] controllers/controllermanager: Make use of the getPresetPaths() function --- src/controllers/controllermanager.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index ec74976f7f5..51ded8c0669 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -119,11 +119,8 @@ void ControllerManager::slotInitialize() { // Initialize preset info parsers. This object is only for use in the main // thread. Do not touch it from within ControllerManager. - QStringList presetSearchPaths; - presetSearchPaths << userPresetsPath(m_pConfig) - << resourcePresetsPath(m_pConfig); m_pMainThreadPresetEnumerator = QSharedPointer( - new PresetInfoEnumerator(presetSearchPaths)); + new PresetInfoEnumerator(getPresetPaths(m_pConfig))); // Instantiate all enumerators. Enumerators can take a long time to // construct since they interact with host MIDI APIs. From 05f7ce4998ec0db221cd7bddab8ac72760abcc78 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 18 Mar 2020 23:20:39 +0100 Subject: [PATCH 02/55] controllers/controllermanager: Rename function to sanitizeString --- src/controllers/controllermanager.cpp | 17 ++++++++--------- src/controllers/controllermanager.h | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 51ded8c0669..b9fa4373523 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -218,7 +218,7 @@ void ControllerManager::slotSetUpDevices() { } // The filename for this device name. - QString presetBaseName = presetFilenameFromName(name); + QString presetBaseName = sanitizeString(name); // The first unique filename for this device (appends numbers at the end // if we have already seen a controller by this name on this run of @@ -347,8 +347,8 @@ void ControllerManager::openController(Controller* pController) { pController->applyPreset(getPresetPaths(m_pConfig), true); // Update configuration to reflect controller is enabled. - m_pConfig->setValue(ConfigKey( - "[Controller]", presetFilenameFromName(pController->getName())), 1); + m_pConfig->setValue( + ConfigKey("[Controller]", sanitizeString(pController->getName())), 1); } } @@ -359,8 +359,8 @@ void ControllerManager::closeController(Controller* pController) { pController->close(); maybeStartOrStopPolling(); // Update configuration to reflect controller is disabled. - m_pConfig->setValue(ConfigKey( - "[Controller]", presetFilenameFromName(pController->getName())), 0); + m_pConfig->setValue( + ConfigKey("[Controller]", sanitizeString(pController->getName())), 0); } bool ControllerManager::loadPreset(Controller* pController, @@ -372,9 +372,8 @@ bool ControllerManager::loadPreset(Controller* pController, // Save the file path/name in the config so it can be auto-loaded at // startup next time m_pConfig->set( - ConfigKey("[ControllerPreset]", - presetFilenameFromName(pController->getName())), - preset->filePath()); + ConfigKey("[ControllerPreset]", sanitizeString(pController->getName())), + preset->filePath()); return true; } @@ -391,7 +390,7 @@ void ControllerManager::slotSavePresets(bool onlyActive) { } QString name = pController->getName(); QString filename = firstAvailableFilename( - filenames, presetFilenameFromName(name)); + filenames, sanitizeString(name)); QString presetPath = userPresetsPath(m_pConfig) + filename + pController->presetExtension(); if (!pController->savePreset(presetPath)) { diff --git a/src/controllers/controllermanager.h b/src/controllers/controllermanager.h index 1fa873ba4bc..0f2c45d1265 100644 --- a/src/controllers/controllermanager.h +++ b/src/controllers/controllermanager.h @@ -85,7 +85,7 @@ class ControllerManager : public QObject { void stopPolling(); void maybeStartOrStopPolling(); - static QString presetFilenameFromName(QString name) { + static QString sanitizeString(QString name) { return name.replace(" ", "_").replace("/", "_").replace("\\", "_"); } From d7269cf75641da4aac415350a3591578114c8484 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 18 Mar 2020 23:24:50 +0100 Subject: [PATCH 03/55] controllers/controllermanager: Rework device setup code --- src/controllers/controllermanager.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index b9fa4373523..9a997652866 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -218,24 +218,24 @@ void ControllerManager::slotSetUpDevices() { } // The filename for this device name. - QString presetBaseName = sanitizeString(name); + QString deviceName = sanitizeString(name); - // The first unique filename for this device (appends numbers at the end - // if we have already seen a controller by this name on this run of - // Mixxx. - presetBaseName = firstAvailableFilename(filenames, presetBaseName); - - ControllerPresetPointer pPreset = - ControllerPresetFileHandler::loadPreset( - presetBaseName + pController->presetExtension(), - getPresetPaths(m_pConfig)); + if (m_pConfig->getValueString(ConfigKey("[Controller]", deviceName)) != "1") { + continue; + } - if (!loadPreset(pController, pPreset)) { - // TODO(XXX) : auto load midi preset here. + QString presetFile = m_pConfig->getValueString( + ConfigKey("[ControllerPreset]", deviceName)); + if (presetFile.isEmpty()) { continue; } - if (m_pConfig->getValueString(ConfigKey("[Controller]", presetBaseName)) != "1") { + ControllerPresetPointer pPreset = ControllerPresetFileHandler::loadPreset( + presetFile, + getPresetPaths(m_pConfig)); + + if (!loadPreset(pController, pPreset)) { + // TODO(XXX) : auto load midi preset here. continue; } From 88132126a85c433e031420857fc643556454af47 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 19 Mar 2020 09:23:34 +0100 Subject: [PATCH 04/55] controllers: Preselect configured mapping in preferences if available --- src/controllers/controllermanager.cpp | 8 +++++--- src/controllers/controllermanager.h | 1 + src/controllers/dlgprefcontroller.cpp | 18 ++++++++++++------ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 9a997652866..8b89af3e5a3 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -202,6 +202,10 @@ QList ControllerManager::getControllerList(bool bOutputDevices, boo return filteredDeviceList; } +QString ControllerManager::getConfiguredPresetFileForDevice(QString name) { + return m_pConfig->getValueString(ConfigKey("[ControllerPreset]", sanitizeString(name))); +} + void ControllerManager::slotSetUpDevices() { qDebug() << "ControllerManager: Setting up devices"; @@ -219,13 +223,11 @@ void ControllerManager::slotSetUpDevices() { // The filename for this device name. QString deviceName = sanitizeString(name); - if (m_pConfig->getValueString(ConfigKey("[Controller]", deviceName)) != "1") { continue; } - QString presetFile = m_pConfig->getValueString( - ConfigKey("[ControllerPreset]", deviceName)); + QString presetFile = getConfiguredPresetFileForDevice(deviceName); if (presetFile.isEmpty()) { continue; } diff --git a/src/controllers/controllermanager.h b/src/controllers/controllermanager.h index 0f2c45d1265..03275338946 100644 --- a/src/controllers/controllermanager.h +++ b/src/controllers/controllermanager.h @@ -36,6 +36,7 @@ class ControllerManager : public QObject { QSharedPointer getMainThreadPresetEnumerator() { return m_pMainThreadPresetEnumerator; } + QString getConfiguredPresetFileForDevice(QString name); // Prevent other parts of Mixxx from having to manually connect to our slots void setUpDevices() { emit requestSetUpDevices(); }; diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 6217a12f13a..729e041447e 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -261,12 +261,18 @@ void DlgPrefController::enumeratePresets() { } } - // Jump to matching device in list if it was found. - if (match.isValid()) { - int index = m_ui.comboBoxPreset->findText(match.getName()); - if (index != -1) { - m_ui.comboBoxPreset->setCurrentIndex(index); - } + QString configuredPresetFile = m_pControllerManager->getConfiguredPresetFileForDevice( + m_pController->getName()); + + // Preselect configured or matching preset + int index = -1; + if (!configuredPresetFile.isEmpty()) { + index = m_ui.comboBoxPreset->findData(configuredPresetFile); + } else if (match.isValid()) { + index = m_ui.comboBoxPreset->findText(match.getName()); + } + if (index != -1) { + m_ui.comboBoxPreset->setCurrentIndex(index); } } From 29b1df889991d63772c9a5c4d8627d66cd05bbdd Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 19 Mar 2020 15:00:50 +0100 Subject: [PATCH 05/55] controllers/dlgprefcontroller: Fix reset of combobox item on apply --- src/controllers/dlgprefcontroller.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 729e041447e..1ea7ad97ba0 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -340,9 +340,6 @@ void DlgPrefController::slotApply() { // the same preset. emit loadPreset(m_pController, m_pPreset); - //Select the "..." item again in the combobox. - m_ui.comboBoxPreset->setCurrentIndex(0); - bool wantEnabled = m_ui.chkEnabledDevice->isChecked(); bool enabled = m_pController->isOpen(); if (wantEnabled && !enabled) { From 2e314f547ded3074db6be443bed35c5ade585cfb Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 19 Mar 2020 13:50:45 +0100 Subject: [PATCH 06/55] controllers/controllerpresetinfo: Remove unused header file --- src/controllers/controllerpresetinfo.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/controllerpresetinfo.cpp b/src/controllers/controllerpresetinfo.cpp index 3e8c1d581f4..bf0051209af 100644 --- a/src/controllers/controllerpresetinfo.cpp +++ b/src/controllers/controllerpresetinfo.cpp @@ -10,7 +10,6 @@ */ #include "controllers/controllerpresetinfo.h" -#include "controllers/controllerpresetinfoenumerator.h" #include "controllers/defs_controllers.h" #include "util/xml.h" From bc92e0ddb172f9eca3f4a1327424dddcaac8dd2e Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 19 Mar 2020 13:51:12 +0100 Subject: [PATCH 07/55] controllers/dlgprefcontroller: Separate user and system presets --- src/controllers/controllermanager.cpp | 6 ++-- src/controllers/controllermanager.h | 10 ++++-- src/controllers/dlgprefcontroller.cpp | 50 +++++++++++++++++++-------- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 8b89af3e5a3..499798a690f 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -119,8 +119,10 @@ void ControllerManager::slotInitialize() { // Initialize preset info parsers. This object is only for use in the main // thread. Do not touch it from within ControllerManager. - m_pMainThreadPresetEnumerator = QSharedPointer( - new PresetInfoEnumerator(getPresetPaths(m_pConfig))); + m_pMainThreadUserPresetEnumerator = QSharedPointer( + new PresetInfoEnumerator(QStringList{userPresetsPath(m_pConfig)})); + m_pMainThreadSystemPresetEnumerator = QSharedPointer( + new PresetInfoEnumerator(QStringList{resourcePresetsPath(m_pConfig)})); // Instantiate all enumerators. Enumerators can take a long time to // construct since they interact with host MIDI APIs. diff --git a/src/controllers/controllermanager.h b/src/controllers/controllermanager.h index 03275338946..e291327dd2e 100644 --- a/src/controllers/controllermanager.h +++ b/src/controllers/controllermanager.h @@ -33,8 +33,11 @@ class ControllerManager : public QObject { QList getControllers() const; QList getControllerList(bool outputDevices=true, bool inputDevices=true); ControllerLearningEventFilter* getControllerLearningEventFilter() const; - QSharedPointer getMainThreadPresetEnumerator() { - return m_pMainThreadPresetEnumerator; + QSharedPointer getMainThreadUserPresetEnumerator() { + return m_pMainThreadUserPresetEnumerator; + } + QSharedPointer getMainThreadSystemPresetEnumerator() { + return m_pMainThreadSystemPresetEnumerator; } QString getConfiguredPresetFileForDevice(QString name); @@ -98,7 +101,8 @@ class ControllerManager : public QObject { QList m_enumerators; QList m_controllers; QThread* m_pThread; - QSharedPointer m_pMainThreadPresetEnumerator; + QSharedPointer m_pMainThreadUserPresetEnumerator; + QSharedPointer m_pMainThreadSystemPresetEnumerator; bool m_skipPoll; }; diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 1ea7ad97ba0..0e35ebd95a6 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -239,25 +239,45 @@ void DlgPrefController::enumeratePresets() { // user has their controller plugged in) m_ui.comboBoxPreset->addItem("..."); - // Ask the controller manager for a list of applicable presets - QSharedPointer pie = - m_pControllerManager->getMainThreadPresetEnumerator(); + QList presets; + PresetInfo match; - // Not ready yet. Should be rare. We will re-enumerate on the next open of - // the preferences. - if (pie.isNull()) { - return; + // Ask the controller manager for a list of applicable user presets + QSharedPointer userPresetEnumerator = + m_pControllerManager->getMainThreadUserPresetEnumerator(); + // Check if enumerator is ready. Should be rare. We will re-enumerate on + // the next open of the preferences. + if (!userPresetEnumerator.isNull()) { + // Making the list of presets in the alphabetical order + QList userPresets = userPresetEnumerator->getPresetsByExtension( + m_pController->presetExtension()); + + for (const PresetInfo& preset : userPresets) { + m_ui.comboBoxPreset->addItem(preset.getName(), preset.getPath()); + if (m_pController->matchPreset(preset)) { + match = preset; + } + } } - // Making the list of presets in the alphabetical order - QList presets = pie->getPresetsByExtension( - m_pController->presetExtension()); + // Insert a separator between user presets (+ dummy item) and system presets + m_ui.comboBoxPreset->insertSeparator(m_ui.comboBoxPreset->count()); - PresetInfo match; - for (const PresetInfo& preset : presets) { - m_ui.comboBoxPreset->addItem(preset.getName(), preset.getPath()); - if (m_pController->matchPreset(preset)) { - match = preset; + // Ask the controller manager for a list of applicable system presets + QSharedPointer systemPresetEnumerator = + m_pControllerManager->getMainThreadSystemPresetEnumerator(); + // Check if enumerator is ready. Should be rare. We will re-enumerate on + // the next open of the preferences. + if (!systemPresetEnumerator.isNull()) { + // Making the list of presets in the alphabetical order + QList systemPresets = systemPresetEnumerator->getPresetsByExtension( + m_pController->presetExtension()); + + for (const PresetInfo& preset : systemPresets) { + m_ui.comboBoxPreset->addItem(preset.getName(), preset.getPath()); + if (m_pController->matchPreset(preset)) { + match = preset; + } } } From 2730b6abc3ca1e4a20c57b55cb6d61ba445ec86f Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 19 Mar 2020 15:49:57 +0100 Subject: [PATCH 08/55] controllers/controllermanager: Always write preset to config on exit --- src/controllers/controllermanager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 499798a690f..2843f5371a8 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -392,15 +392,15 @@ void ControllerManager::slotSavePresets(bool onlyActive) { if (onlyActive && !pController->isOpen()) { continue; } - QString name = pController->getName(); - QString filename = firstAvailableFilename( - filenames, sanitizeString(name)); + QString deviceName = sanitizeString(pController->getName()); + QString filename = firstAvailableFilename(filenames, deviceName); QString presetPath = userPresetsPath(m_pConfig) + filename + pController->presetExtension(); if (!pController->savePreset(presetPath)) { qWarning() << "Failed to write preset for device" - << name << "to" << presetPath; + << deviceName << "to" << presetPath; } + m_pConfig->set(ConfigKey("[ControllerPreset]", deviceName), presetPath); } } From 8b46ef0a008911fbce83951fc51fb72e927e00e2 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 19 Mar 2020 16:53:35 +0100 Subject: [PATCH 09/55] controllers/midi: Make MidiControllerPreset's mappings private --- .../controllerinputmappingtablemodel.cpp | 11 ++--- .../controlleroutputmappingtablemodel.cpp | 11 ++--- src/controllers/midi/midicontroller.cpp | 26 ++++++----- src/controllers/midi/midicontrollerpreset.h | 43 ++++++++++++++++++- .../midi/midicontrollerpresetfilehandler.cpp | 18 ++++---- src/test/midicontrollertest.cpp | 2 +- 6 files changed, 79 insertions(+), 32 deletions(-) diff --git a/src/controllers/controllerinputmappingtablemodel.cpp b/src/controllers/controllerinputmappingtablemodel.cpp index 456e0556307..237cda87745 100644 --- a/src/controllers/controllerinputmappingtablemodel.cpp +++ b/src/controllers/controllerinputmappingtablemodel.cpp @@ -18,12 +18,13 @@ void ControllerInputMappingTableModel::apply() { if (m_pMidiPreset != NULL) { // Clear existing input mappings and insert all the input mappings in // the table into the preset. - m_pMidiPreset->inputMappings.clear(); + QHash mappings; foreach (const MidiInputMapping& mapping, m_midiInputMappings) { // Use insertMulti because we support multiple inputs mappings for // the same input MidiKey. - m_pMidiPreset->inputMappings.insertMulti(mapping.key.key, mapping); + mappings.insertMulti(mapping.key.key, mapping); } + m_pMidiPreset->setInputMappings(mappings); } } @@ -39,9 +40,9 @@ void ControllerInputMappingTableModel::onPresetLoaded() { setHeaderData(MIDI_COLUMN_ACTION, Qt::Horizontal, tr("Action")); setHeaderData(MIDI_COLUMN_COMMENT, Qt::Horizontal, tr("Comment")); - if (!m_pMidiPreset->inputMappings.isEmpty()) { - beginInsertRows(QModelIndex(), 0, m_pMidiPreset->inputMappings.size() - 1); - m_midiInputMappings = m_pMidiPreset->inputMappings.values(); + if (!m_pMidiPreset->getInputMappings().isEmpty()) { + beginInsertRows(QModelIndex(), 0, m_pMidiPreset->getInputMappings().size() - 1); + m_midiInputMappings = m_pMidiPreset->getInputMappings().values(); endInsertRows(); } } diff --git a/src/controllers/controlleroutputmappingtablemodel.cpp b/src/controllers/controlleroutputmappingtablemodel.cpp index 7dc3756e414..253aa412d6d 100644 --- a/src/controllers/controlleroutputmappingtablemodel.cpp +++ b/src/controllers/controlleroutputmappingtablemodel.cpp @@ -18,12 +18,13 @@ void ControllerOutputMappingTableModel::apply() { if (m_pMidiPreset != NULL) { // Clear existing output mappings and insert all the output mappings in // the table into the preset. - m_pMidiPreset->outputMappings.clear(); + QHash mappings; foreach (const MidiOutputMapping& mapping, m_midiOutputMappings) { // Use insertMulti because we support multiple outputs from the same // control. - m_pMidiPreset->outputMappings.insertMulti(mapping.controlKey, mapping); + mappings.insertMulti(mapping.controlKey, mapping); } + m_pMidiPreset->setOutputMappings(mappings); } } @@ -42,9 +43,9 @@ void ControllerOutputMappingTableModel::onPresetLoaded() { setHeaderData(MIDI_COLUMN_MAX, Qt::Horizontal, tr("On Range Max")); setHeaderData(MIDI_COLUMN_COMMENT, Qt::Horizontal, tr("Comment")); - if (!m_pMidiPreset->outputMappings.isEmpty()) { - beginInsertRows(QModelIndex(), 0, m_pMidiPreset->outputMappings.size() - 1); - m_midiOutputMappings = m_pMidiPreset->outputMappings.values(); + if (!m_pMidiPreset->getOutputMappings().isEmpty()) { + beginInsertRows(QModelIndex(), 0, m_pMidiPreset->getOutputMappings().size() - 1); + m_midiOutputMappings = m_pMidiPreset->getOutputMappings().values(); endInsertRows(); } } diff --git a/src/controllers/midi/midicontroller.cpp b/src/controllers/midi/midicontroller.cpp index 877897f00f1..2f613c954ba 100644 --- a/src/controllers/midi/midicontroller.cpp +++ b/src/controllers/midi/midicontroller.cpp @@ -75,11 +75,11 @@ bool MidiController::applyPreset(QList scriptPaths, bool initializeScri } void MidiController::createOutputHandlers() { - if (m_preset.outputMappings.isEmpty()) { + if (m_preset.getOutputMappings().isEmpty()) { return; } - QHashIterator outIt(m_preset.outputMappings); + QHashIterator outIt(m_preset.getOutputMappings()); QStringList failures; while (outIt.hasNext()) { outIt.next(); @@ -185,15 +185,19 @@ void MidiController::clearTemporaryInputMappings() { void MidiController::commitTemporaryInputMappings() { // We want to replace duplicates that exist in m_preset but allow duplicates // in m_temporaryInputMappings. To do this, we first remove every key in - // m_temporaryInputMappings from m_preset.inputMappings. + // m_temporaryInputMappings from m_preset's input mappings. for (auto it = m_temporaryInputMappings.constBegin(); it != m_temporaryInputMappings.constEnd(); ++it) { - m_preset.inputMappings.remove(it.key()); + m_preset.removeInputMapping(it.key()); } - // Now, we can just use unite since we manually removed the duplicates in - // the original set. - m_preset.inputMappings.unite(m_temporaryInputMappings); + // Now, we can just use add all mappings from m_temporaryInputMappings + // since we removed the duplicates in the original set. + for (auto it = m_temporaryInputMappings.constBegin(); + it != m_temporaryInputMappings.constEnd(); + ++it) { + m_preset.addInputMapping(it.key(), it.value()); + } m_temporaryInputMappings.clear(); } @@ -219,8 +223,8 @@ void MidiController::receive(unsigned char status, unsigned char control, } } - auto it = m_preset.inputMappings.constFind(mappingKey.key); - for (; it != m_preset.inputMappings.constEnd() && it.key() == mappingKey.key; ++it) { + auto it = m_preset.getInputMappings().constFind(mappingKey.key); + for (; it != m_preset.getInputMappings().constEnd() && it.key() == mappingKey.key; ++it) { processInputMapping(it.value(), status, control, value, timestamp); } } @@ -470,8 +474,8 @@ void MidiController::receive(QByteArray data, mixxx::Duration timestamp) { } } - auto it = m_preset.inputMappings.constFind(mappingKey.key); - for (; it != m_preset.inputMappings.constEnd() && it.key() == mappingKey.key; ++it) { + auto it = m_preset.getInputMappings().constFind(mappingKey.key); + for (; it != m_preset.getInputMappings().constEnd() && it.key() == mappingKey.key; ++it) { processInputMapping(it.value(), data, timestamp); } } diff --git a/src/controllers/midi/midicontrollerpreset.h b/src/controllers/midi/midicontrollerpreset.h index 12ef6f0a13d..4bc131daba7 100644 --- a/src/controllers/midi/midicontrollerpreset.h +++ b/src/controllers/midi/midicontrollerpreset.h @@ -39,9 +39,48 @@ class MidiControllerPreset : public ControllerPreset { return true; } + void addInputMapping(uint16_t key, MidiInputMapping mapping) { + m_inputMappings.insertMulti(key, mapping); + } + + void removeInputMapping(uint16_t key) { + m_inputMappings.remove(key); + } + + const QHash& getInputMappings() const { + return m_inputMappings; + } + + void setInputMappings(const QHash& mappings) { + if (m_inputMappings != mappings) { + m_inputMappings.clear(); + m_inputMappings.unite(mappings); + } + } + + void addOutputMapping(ConfigKey key, MidiOutputMapping mapping) { + m_outputMappings.insertMulti(key, mapping); + } + + void removeOutputMapping(ConfigKey key) { + m_outputMappings.remove(key); + } + + const QHash& getOutputMappings() const { + return m_outputMappings; + } + + void setOutputMappings(const QHash& mappings) { + if (m_outputMappings != mappings) { + m_outputMappings.clear(); + m_outputMappings.unite(mappings); + } + } + + private: // MIDI input and output mappings. - QHash inputMappings; - QHash outputMappings; + QHash m_inputMappings; + QHash m_outputMappings; }; #endif diff --git a/src/controllers/midi/midicontrollerpresetfilehandler.cpp b/src/controllers/midi/midicontrollerpresetfilehandler.cpp index 32e01244768..dc90812b8f6 100644 --- a/src/controllers/midi/midicontrollerpresetfilehandler.cpp +++ b/src/controllers/midi/midicontrollerpresetfilehandler.cpp @@ -101,7 +101,7 @@ ControllerPresetPointer MidiControllerPresetFileHandler::load(const QDomElement // Use insertMulti because we support multiple inputs mappings for the // same input MidiKey. - preset->inputMappings.insertMulti(mapping.key.key, mapping); + preset->addInputMapping(mapping.key.key, mapping); control = control.nextSiblingElement("control"); } @@ -181,7 +181,7 @@ ControllerPresetPointer MidiControllerPresetFileHandler::load(const QDomElement // Use insertMulti because we support multiple outputs from the same // control. - preset->outputMappings.insertMulti(mapping.controlKey, mapping); + preset->addOutputMapping(mapping.controlKey, mapping); output = output.nextSiblingElement("output"); } @@ -209,11 +209,12 @@ void MidiControllerPresetFileHandler::addControlsToDocument(const MidiController QDomElement controls = doc->createElement("controls"); // We will iterate over all of the values that have the same keys, so we need // to remove duplicate keys or else we'll duplicate those values. - auto sortedInputKeys = preset.inputMappings.uniqueKeys(); + auto sortedInputKeys = preset.getInputMappings().uniqueKeys(); std::sort(sortedInputKeys.begin(), sortedInputKeys.end()); for (const auto& key : sortedInputKeys) { - for (auto it = preset.inputMappings.constFind(key); - it != preset.inputMappings.constEnd() && it.key() == key; ++it) { + for (auto it = preset.getInputMappings().constFind(key); + it != preset.getInputMappings().constEnd() && it.key() == key; + ++it) { QDomElement controlNode = inputMappingToXML(doc, it.value()); controls.appendChild(controlNode); } @@ -223,11 +224,12 @@ void MidiControllerPresetFileHandler::addControlsToDocument(const MidiController // Repeat the process for the output mappings. QDomElement outputs = doc->createElement("outputs"); - auto sortedOutputKeys = preset.outputMappings.uniqueKeys(); + auto sortedOutputKeys = preset.getOutputMappings().uniqueKeys(); std::sort(sortedOutputKeys.begin(), sortedOutputKeys.end()); for (const auto& key : sortedOutputKeys) { - for (auto it = preset.outputMappings.constFind(key); - it != preset.outputMappings.constEnd() && it.key() == key; ++it) { + for (auto it = preset.getOutputMappings().constFind(key); + it != preset.getOutputMappings().constEnd() && it.key() == key; + ++it) { QDomElement outputNode = outputMappingToXML(doc, it.value()); outputs.appendChild(outputNode); } diff --git a/src/test/midicontrollertest.cpp b/src/test/midicontrollertest.cpp index ac520908638..1e44a89e850 100644 --- a/src/test/midicontrollertest.cpp +++ b/src/test/midicontrollertest.cpp @@ -33,7 +33,7 @@ class MidiControllerTest : public MixxxTest { } void addMapping(MidiInputMapping mapping) { - m_preset.inputMappings.insertMulti(mapping.key.key, mapping); + m_preset.addInputMapping(mapping.key.key, mapping); } void loadPreset(const MidiControllerPreset& preset) { From 436cd8809a58e8327885c2663478327b9ca407b0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 19 Mar 2020 17:15:57 +0100 Subject: [PATCH 10/55] controllers: Only write preset to user directory if it's dirty --- src/controllers/controllermanager.cpp | 10 ++++++++ src/controllers/controllerpreset.h | 25 ++++++++++++++++++- .../controllerpresetfilehandler.cpp | 8 +++--- src/controllers/midi/midicontrollerpreset.h | 6 +++++ 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 2843f5371a8..2d2f594e188 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -392,7 +392,17 @@ void ControllerManager::slotSavePresets(bool onlyActive) { if (onlyActive && !pController->isOpen()) { continue; } + ControllerPresetPointer pPreset = pController->getPreset(); + DEBUG_ASSERT(!pPreset); + QString deviceName = sanitizeString(pController->getName()); + if (!pPreset->isDirty()) { + qWarning() + << "Preset for device" << deviceName + << "is not dirty, no need to save it to the user presets."; + continue; + } + QString filename = firstAvailableFilename(filenames, deviceName); QString presetPath = userPresetsPath(m_pConfig) + filename + pController->presetExtension(); diff --git a/src/controllers/controllerpreset.h b/src/controllers/controllerpreset.h index ad4019632e1..19fcfefad9e 100644 --- a/src/controllers/controllerpreset.h +++ b/src/controllers/controllerpreset.h @@ -21,7 +21,9 @@ class ConstControllerPresetVisitor; class ControllerPreset { public: - ControllerPreset() {} + ControllerPreset() + : m_bDirty(false) { + } virtual ~ControllerPreset() {} struct ScriptFileInfo { @@ -47,10 +49,20 @@ class ControllerPreset { info.functionPrefix = functionprefix; info.builtin = builtin; scripts.append(info); + setDirty(true); + } + + inline void setDirty(bool bDirty) { + m_bDirty = bDirty; + } + + inline bool isDirty() const { + return m_bDirty; } inline void setDeviceId(const QString id) { m_deviceId = id; + setDirty(true); } inline QString deviceId() const { @@ -59,6 +71,7 @@ class ControllerPreset { inline void setFilePath(const QString filePath) { m_filePath = filePath; + setDirty(true); } inline QString filePath() const { @@ -67,6 +80,7 @@ class ControllerPreset { inline void setName(const QString name) { m_name = name; + setDirty(true); } inline QString name() const { @@ -75,6 +89,7 @@ class ControllerPreset { inline void setAuthor(const QString author) { m_author = author; + setDirty(true); } inline QString author() const { @@ -83,6 +98,7 @@ class ControllerPreset { inline void setDescription(const QString description) { m_description = description; + setDirty(true); } inline QString description() const { @@ -91,6 +107,7 @@ class ControllerPreset { inline void setForumLink(const QString forumlink) { m_forumlink = forumlink; + setDirty(true); } inline QString forumlink() const { @@ -99,6 +116,7 @@ class ControllerPreset { inline void setWikiLink(const QString wikilink) { m_wikilink = wikilink; + setDirty(true); } inline QString wikilink() const { @@ -107,6 +125,7 @@ class ControllerPreset { inline void setSchemaVersion(const QString schemaVersion) { m_schemaVersion = schemaVersion; + setDirty(true); } inline QString schemaVersion() const { @@ -115,6 +134,7 @@ class ControllerPreset { inline void setMixxxVersion(const QString mixxxVersion) { m_mixxxVersion = mixxxVersion; + setDirty(true); } inline QString mixxxVersion() const { @@ -123,6 +143,7 @@ class ControllerPreset { inline void addProductMatch(QHash match) { m_productMatches.append(match); + setDirty(true); } virtual void accept(ControllerPresetVisitor* visitor) = 0; @@ -134,6 +155,8 @@ class ControllerPreset { QList< QHash > m_productMatches; private: + bool m_bDirty; + QString m_deviceId; QString m_filePath; QString m_name; diff --git a/src/controllers/controllerpresetfilehandler.cpp b/src/controllers/controllerpresetfilehandler.cpp index f50b8bd1b23..22e045bef52 100644 --- a/src/controllers/controllerpresetfilehandler.cpp +++ b/src/controllers/controllerpresetfilehandler.cpp @@ -45,9 +45,11 @@ ControllerPresetPointer ControllerPresetFileHandler::loadPreset(const QString& p return ControllerPresetPointer(); } - // NOTE(rryan): We don't provide a device name. It's unused currently. - // TODO(rryan): Delete pHandler. - return pHandler->load(scriptPath, QString()); + ControllerPresetPointer pPreset = pHandler->load(scriptPath, QString()); + if (pPreset) { + pPreset->setDirty(false); + } + return pPreset; } ControllerPresetPointer ControllerPresetFileHandler::load(const QString path, diff --git a/src/controllers/midi/midicontrollerpreset.h b/src/controllers/midi/midicontrollerpreset.h index 4bc131daba7..1c25659059b 100644 --- a/src/controllers/midi/midicontrollerpreset.h +++ b/src/controllers/midi/midicontrollerpreset.h @@ -41,10 +41,12 @@ class MidiControllerPreset : public ControllerPreset { void addInputMapping(uint16_t key, MidiInputMapping mapping) { m_inputMappings.insertMulti(key, mapping); + setDirty(true); } void removeInputMapping(uint16_t key) { m_inputMappings.remove(key); + setDirty(true); } const QHash& getInputMappings() const { @@ -55,15 +57,18 @@ class MidiControllerPreset : public ControllerPreset { if (m_inputMappings != mappings) { m_inputMappings.clear(); m_inputMappings.unite(mappings); + setDirty(true); } } void addOutputMapping(ConfigKey key, MidiOutputMapping mapping) { m_outputMappings.insertMulti(key, mapping); + setDirty(true); } void removeOutputMapping(ConfigKey key) { m_outputMappings.remove(key); + setDirty(true); } const QHash& getOutputMappings() const { @@ -74,6 +79,7 @@ class MidiControllerPreset : public ControllerPreset { if (m_outputMappings != mappings) { m_outputMappings.clear(); m_outputMappings.unite(mappings); + setDirty(true); } } From 7f08658ad8170afbbed91abd649417fd4486c739 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 19 Mar 2020 17:31:22 +0100 Subject: [PATCH 11/55] controllers/dlgprefcontroller: Don't import scripts into user directory --- src/controllers/dlgprefcontroller.cpp | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 0e35ebd95a6..92882863964 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -394,27 +394,6 @@ void DlgPrefController::slotLoadPreset(int chosenIndex) { return; } - // Import the preset scripts to the user scripts folder. - for (QList::iterator it = - pPreset->scripts.begin(); it != pPreset->scripts.end(); ++it) { - // No need to import builtin scripts. - if (it->builtin) { - continue; - } - - QString scriptPath = ControllerManager::getAbsolutePath( - it->name, presetDirs); - - - QString importedScriptFileName; - // If a conflict exists then importScript will provide a new filename to - // use. If importing fails then load the preset anyway without the - // import. - if (m_pControllerManager->importScript(scriptPath, &importedScriptFileName)) { - it->name = importedScriptFileName; - } - } - // TODO(rryan): We really should not load the preset here. We should load it // into the preferences GUI and then load it to the actual controller once // the user hits apply. From d94a183f79c93f7604692ce9f5f0f1e8cf63e1d4 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Apr 2020 15:13:55 +0200 Subject: [PATCH 12/55] controllers/controllermanager: Rename sanitizeString and move to anon NS --- src/controllers/controllermanager.cpp | 19 +++++++++++++------ src/controllers/controllermanager.h | 4 ---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 2d2f594e188..a6ff633c0b2 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -39,6 +39,12 @@ const int kPollIntervalMillis = 5; const int kPollIntervalMillis = 1; #endif +// Strip slashes and spaces from device name, so that it can be used as config +// key or a filename. +QString sanitizeDeviceName(QString name) { + return name.replace(" ", "_").replace("/", "_").replace("\\", "_"); +} + } // anonymous namespace QString firstAvailableFilename(QSet& filenames, @@ -205,7 +211,7 @@ QList ControllerManager::getControllerList(bool bOutputDevices, boo } QString ControllerManager::getConfiguredPresetFileForDevice(QString name) { - return m_pConfig->getValueString(ConfigKey("[ControllerPreset]", sanitizeString(name))); + return m_pConfig->getValueString(ConfigKey("[ControllerPreset]", sanitizeDeviceName(name))); } void ControllerManager::slotSetUpDevices() { @@ -224,7 +230,7 @@ void ControllerManager::slotSetUpDevices() { } // The filename for this device name. - QString deviceName = sanitizeString(name); + QString deviceName = sanitizeDeviceName(name); if (m_pConfig->getValueString(ConfigKey("[Controller]", deviceName)) != "1") { continue; } @@ -352,7 +358,7 @@ void ControllerManager::openController(Controller* pController) { // Update configuration to reflect controller is enabled. m_pConfig->setValue( - ConfigKey("[Controller]", sanitizeString(pController->getName())), 1); + ConfigKey("[Controller]", sanitizeDeviceName(pController->getName())), 1); } } @@ -364,7 +370,7 @@ void ControllerManager::closeController(Controller* pController) { maybeStartOrStopPolling(); // Update configuration to reflect controller is disabled. m_pConfig->setValue( - ConfigKey("[Controller]", sanitizeString(pController->getName())), 0); + ConfigKey("[Controller]", sanitizeDeviceName(pController->getName())), 0); } bool ControllerManager::loadPreset(Controller* pController, @@ -376,7 +382,7 @@ bool ControllerManager::loadPreset(Controller* pController, // Save the file path/name in the config so it can be auto-loaded at // startup next time m_pConfig->set( - ConfigKey("[ControllerPreset]", sanitizeString(pController->getName())), + ConfigKey("[ControllerPreset]", sanitizeDeviceName(pController->getName())), preset->filePath()); return true; } @@ -392,10 +398,11 @@ void ControllerManager::slotSavePresets(bool onlyActive) { if (onlyActive && !pController->isOpen()) { continue; } + ControllerPresetPointer pPreset = pController->getPreset(); DEBUG_ASSERT(!pPreset); - QString deviceName = sanitizeString(pController->getName()); + QString deviceName = sanitizeDeviceName(pController->getName()); if (!pPreset->isDirty()) { qWarning() << "Preset for device" << deviceName diff --git a/src/controllers/controllermanager.h b/src/controllers/controllermanager.h index e291327dd2e..dae740ee713 100644 --- a/src/controllers/controllermanager.h +++ b/src/controllers/controllermanager.h @@ -89,10 +89,6 @@ class ControllerManager : public QObject { void stopPolling(); void maybeStartOrStopPolling(); - static QString sanitizeString(QString name) { - return name.replace(" ", "_").replace("/", "_").replace("\\", "_"); - } - private: UserSettingsPointer m_pConfig; ControllerLearningEventFilter* m_pControllerLearningEventFilter; From 3e0729ad7eb8edc1d139fe903a7e24ed1af2b456 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Apr 2020 18:55:32 +0200 Subject: [PATCH 13/55] controllers/controllermanager: Fix assertion if no preset is configured --- src/controllers/controllermanager.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index a6ff633c0b2..f965eae2152 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -399,10 +399,14 @@ void ControllerManager::slotSavePresets(bool onlyActive) { continue; } + QString deviceName = sanitizeDeviceName(pController->getName()); + ControllerPresetPointer pPreset = pController->getPreset(); - DEBUG_ASSERT(!pPreset); + if (!pPreset) { + qDebug() << "Device" << deviceName << "has no configurated preset"; + continue; + } - QString deviceName = sanitizeDeviceName(pController->getName()); if (!pPreset->isDirty()) { qWarning() << "Preset for device" << deviceName From 8a30f3a5214ebdaac5996db5fa96bbf38d79ea85 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Apr 2020 18:56:34 +0200 Subject: [PATCH 14/55] controllers/controllermanager: Use qDebug() instead of qWarning() --- src/controllers/controllermanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index f965eae2152..eaa860089f3 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -408,7 +408,7 @@ void ControllerManager::slotSavePresets(bool onlyActive) { } if (!pPreset->isDirty()) { - qWarning() + qDebug() << "Preset for device" << deviceName << "is not dirty, no need to save it to the user presets."; continue; From 5277c500e8a724263c0e9ef82fb4328f972abc24 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Apr 2020 19:25:01 +0200 Subject: [PATCH 15/55] controllers/dlgprefcontroller: Move shared enumeration code to method --- src/controllers/dlgprefcontroller.cpp | 66 +++++++++++++-------------- src/controllers/dlgprefcontroller.h | 3 ++ 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 92882863964..e939147cbc7 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -239,46 +239,22 @@ void DlgPrefController::enumeratePresets() { // user has their controller plugged in) m_ui.comboBoxPreset->addItem("..."); - QList presets; PresetInfo match; - - // Ask the controller manager for a list of applicable user presets - QSharedPointer userPresetEnumerator = - m_pControllerManager->getMainThreadUserPresetEnumerator(); - // Check if enumerator is ready. Should be rare. We will re-enumerate on - // the next open of the preferences. - if (!userPresetEnumerator.isNull()) { - // Making the list of presets in the alphabetical order - QList userPresets = userPresetEnumerator->getPresetsByExtension( - m_pController->presetExtension()); - - for (const PresetInfo& preset : userPresets) { - m_ui.comboBoxPreset->addItem(preset.getName(), preset.getPath()); - if (m_pController->matchPreset(preset)) { - match = preset; - } - } + // Enumerate user presets + PresetInfo userPresetsMatch = enumeratePresetsFromEnumerator( + m_pControllerManager->getMainThreadUserPresetEnumerator()); + if (userPresetsMatch.isValid()) { + match = userPresetsMatch; } // Insert a separator between user presets (+ dummy item) and system presets m_ui.comboBoxPreset->insertSeparator(m_ui.comboBoxPreset->count()); - // Ask the controller manager for a list of applicable system presets - QSharedPointer systemPresetEnumerator = - m_pControllerManager->getMainThreadSystemPresetEnumerator(); - // Check if enumerator is ready. Should be rare. We will re-enumerate on - // the next open of the preferences. - if (!systemPresetEnumerator.isNull()) { - // Making the list of presets in the alphabetical order - QList systemPresets = systemPresetEnumerator->getPresetsByExtension( - m_pController->presetExtension()); - - for (const PresetInfo& preset : systemPresets) { - m_ui.comboBoxPreset->addItem(preset.getName(), preset.getPath()); - if (m_pController->matchPreset(preset)) { - match = preset; - } - } + // Enumerate system presets + PresetInfo systemPresetsMatch = enumeratePresetsFromEnumerator( + m_pControllerManager->getMainThreadSystemPresetEnumerator()); + if (systemPresetsMatch.isValid()) { + match = systemPresetsMatch; } QString configuredPresetFile = m_pControllerManager->getConfiguredPresetFileForDevice( @@ -296,6 +272,28 @@ void DlgPrefController::enumeratePresets() { } } +PresetInfo DlgPrefController::enumeratePresetsFromEnumerator( + QSharedPointer pPresetEnumerator) { + PresetInfo match; + + // Check if enumerator is ready. Should be rare. We will re-enumerate on + // the next open of the preferences. + if (!pPresetEnumerator.isNull()) { + // Making the list of presets in the alphabetical order + QList systemPresets = pPresetEnumerator->getPresetsByExtension( + m_pController->presetExtension()); + + for (const PresetInfo& preset : systemPresets) { + m_ui.comboBoxPreset->addItem(preset.getName(), preset.getPath()); + if (m_pController->matchPreset(preset)) { + match = preset; + } + } + } + + return match; +} + void DlgPrefController::slotUpdate() { enumeratePresets(); diff --git a/src/controllers/dlgprefcontroller.h b/src/controllers/dlgprefcontroller.h index e0cb88ed5aa..973478c398b 100644 --- a/src/controllers/dlgprefcontroller.h +++ b/src/controllers/dlgprefcontroller.h @@ -23,6 +23,7 @@ // Forward declarations class Controller; class ControllerManager; +class PresetInfoEnumerator; class DlgPrefController : public DlgPreferencePage { Q_OBJECT @@ -88,6 +89,8 @@ class DlgPrefController : public DlgPreferencePage { // Reload the mappings in the dropdown dialog void enumeratePresets(); + PresetInfo enumeratePresetsFromEnumerator( + QSharedPointer pPresetEnumerator); void enableDevice(); void disableDevice(); From 6367448993658ebacd7963b57c4503cbd75086b0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Apr 2020 19:29:08 +0200 Subject: [PATCH 16/55] controllers/dlgprefcontroller: Improve some comments --- src/controllers/dlgprefcontroller.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index e939147cbc7..f39deaa508e 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -276,10 +276,10 @@ PresetInfo DlgPrefController::enumeratePresetsFromEnumerator( QSharedPointer pPresetEnumerator) { PresetInfo match; - // Check if enumerator is ready. Should be rare. We will re-enumerate on - // the next open of the preferences. + // Check if enumerator is ready. Should be rare that it isn't. We will + // re-enumerate on the next open of the preferences. if (!pPresetEnumerator.isNull()) { - // Making the list of presets in the alphabetical order + // Get a list of presets in alphabetical order QList systemPresets = pPresetEnumerator->getPresetsByExtension( m_pController->presetExtension()); From c2e2db69d5ef68d1cc4355bef2f3cd3a3259831c Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Apr 2020 19:52:35 +0200 Subject: [PATCH 17/55] controllers/controllermanager: Improve device setup code --- src/controllers/controllermanager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index eaa860089f3..a1e0ab63800 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -231,10 +231,13 @@ void ControllerManager::slotSetUpDevices() { // The filename for this device name. QString deviceName = sanitizeDeviceName(name); - if (m_pConfig->getValueString(ConfigKey("[Controller]", deviceName)) != "1") { + + // Check if device is enabled + if (!m_pConfig->getValue(ConfigKey("[Controller]", deviceName), 0)) { continue; } + // Check if device has a configured preset QString presetFile = getConfiguredPresetFileForDevice(deviceName); if (presetFile.isEmpty()) { continue; From 08d52d93b4d04e2588aebcf5ef437b28446a3ff0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Apr 2020 19:53:16 +0200 Subject: [PATCH 18/55] controllers/controllermanager: Remove unused variable --- src/controllers/controllermanager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index a1e0ab63800..dfccefee22e 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -220,8 +220,6 @@ void ControllerManager::slotSetUpDevices() { updateControllerList(); QList deviceList = getControllerList(false, true); - QSet filenames; - foreach (Controller* pController, deviceList) { QString name = pController->getName(); From fb1573c2640e81ab563a1badf30ce5a789d07572 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Apr 2020 22:30:02 +0200 Subject: [PATCH 19/55] controllers/dlgprefcontroller: Add icon to user controller presets --- res/images/ic_custom.svg | 67 +++++++++++++++++++++++++++ res/mixxx.qrc | 1 + src/controllers/dlgprefcontroller.cpp | 7 +-- src/controllers/dlgprefcontroller.h | 3 +- 4 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 res/images/ic_custom.svg diff --git a/res/images/ic_custom.svg b/res/images/ic_custom.svg new file mode 100644 index 00000000000..44a0fe3f680 --- /dev/null +++ b/res/images/ic_custom.svg @@ -0,0 +1,67 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/res/mixxx.qrc b/res/mixxx.qrc index 545cba1feac..9d8a939ce80 100644 --- a/res/mixxx.qrc +++ b/res/mixxx.qrc @@ -33,6 +33,7 @@ images/mixxx-icon-logo-symbolic.svg images/skin_preview_placeholder.png images/ic_checkmark.svg + images/ic_custom.svg images/ic_delete.svg images/preferences/ic_preferences_autodj.svg images/preferences/ic_preferences_bpmdetect.svg diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index f39deaa508e..b24fa335499 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -241,8 +241,9 @@ void DlgPrefController::enumeratePresets() { PresetInfo match; // Enumerate user presets + QIcon icon(":/images/ic_custom.svg"); PresetInfo userPresetsMatch = enumeratePresetsFromEnumerator( - m_pControllerManager->getMainThreadUserPresetEnumerator()); + m_pControllerManager->getMainThreadUserPresetEnumerator(), icon); if (userPresetsMatch.isValid()) { match = userPresetsMatch; } @@ -273,7 +274,7 @@ void DlgPrefController::enumeratePresets() { } PresetInfo DlgPrefController::enumeratePresetsFromEnumerator( - QSharedPointer pPresetEnumerator) { + QSharedPointer pPresetEnumerator, QIcon icon) { PresetInfo match; // Check if enumerator is ready. Should be rare that it isn't. We will @@ -284,7 +285,7 @@ PresetInfo DlgPrefController::enumeratePresetsFromEnumerator( m_pController->presetExtension()); for (const PresetInfo& preset : systemPresets) { - m_ui.comboBoxPreset->addItem(preset.getName(), preset.getPath()); + m_ui.comboBoxPreset->addItem(icon, preset.getName(), preset.getPath()); if (m_pController->matchPreset(preset)) { match = preset; } diff --git a/src/controllers/dlgprefcontroller.h b/src/controllers/dlgprefcontroller.h index 973478c398b..92fc9086616 100644 --- a/src/controllers/dlgprefcontroller.h +++ b/src/controllers/dlgprefcontroller.h @@ -90,7 +90,8 @@ class DlgPrefController : public DlgPreferencePage { // Reload the mappings in the dropdown dialog void enumeratePresets(); PresetInfo enumeratePresetsFromEnumerator( - QSharedPointer pPresetEnumerator); + QSharedPointer pPresetEnumerator, + QIcon icon = QIcon()); void enableDevice(); void disableDevice(); From d25942171c3bfe397dabfc15bc5319c1303f5a6a Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Apr 2020 23:37:25 +0200 Subject: [PATCH 20/55] controllers/controllerpresetinfoenumerator: Add constructor for single path --- src/controllers/controllermanager.cpp | 4 ++-- src/controllers/controllerpresetinfoenumerator.cpp | 4 ++++ src/controllers/controllerpresetinfoenumerator.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index dfccefee22e..06864bd8398 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -126,9 +126,9 @@ void ControllerManager::slotInitialize() { // Initialize preset info parsers. This object is only for use in the main // thread. Do not touch it from within ControllerManager. m_pMainThreadUserPresetEnumerator = QSharedPointer( - new PresetInfoEnumerator(QStringList{userPresetsPath(m_pConfig)})); + new PresetInfoEnumerator(userPresetsPath(m_pConfig))); m_pMainThreadSystemPresetEnumerator = QSharedPointer( - new PresetInfoEnumerator(QStringList{resourcePresetsPath(m_pConfig)})); + new PresetInfoEnumerator(resourcePresetsPath(m_pConfig))); // Instantiate all enumerators. Enumerators can take a long time to // construct since they interact with host MIDI APIs. diff --git a/src/controllers/controllerpresetinfoenumerator.cpp b/src/controllers/controllerpresetinfoenumerator.cpp index 60e5d6e0408..14f43a247eb 100644 --- a/src/controllers/controllerpresetinfoenumerator.cpp +++ b/src/controllers/controllerpresetinfoenumerator.cpp @@ -29,6 +29,10 @@ bool presetInfoNameComparator(const PresetInfo &a, const PresetInfo &b) { } } +PresetInfoEnumerator::PresetInfoEnumerator(const QString& searchPath) + : PresetInfoEnumerator(QList{searchPath}) { +} + PresetInfoEnumerator::PresetInfoEnumerator(const QStringList& searchPaths) : m_controllerDirPaths(searchPaths) { loadSupportedPresets(); diff --git a/src/controllers/controllerpresetinfoenumerator.h b/src/controllers/controllerpresetinfoenumerator.h index d948aadfb61..24b5a7be4db 100644 --- a/src/controllers/controllerpresetinfoenumerator.h +++ b/src/controllers/controllerpresetinfoenumerator.h @@ -15,6 +15,7 @@ class PresetInfoEnumerator { public: + PresetInfoEnumerator(const QString& searchPath); PresetInfoEnumerator(const QStringList& searchPaths); // Return cached list of presets for this extension From 302155ee5b88631c26c8ae642d073d5dc75074c1 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Apr 2020 23:43:52 +0200 Subject: [PATCH 21/55] controllers/dlgprefcontroller: Show Mixxx icon for system presets --- res/images/ic_mixxx_symbolic.svg | 1308 +++++++++++++++++++++++++ res/mixxx.qrc | 1 + src/controllers/dlgprefcontroller.cpp | 7 +- 3 files changed, 1313 insertions(+), 3 deletions(-) create mode 100644 res/images/ic_mixxx_symbolic.svg diff --git a/res/images/ic_mixxx_symbolic.svg b/res/images/ic_mixxx_symbolic.svg new file mode 100644 index 00000000000..c51004a4556 --- /dev/null +++ b/res/images/ic_mixxx_symbolic.svg @@ -0,0 +1,1308 @@ + + + + + + + + image/svg+xml + + Mixxx application icon + + + + + + + Mixxx application icon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/mixxx.qrc b/res/mixxx.qrc index 9d8a939ce80..33381991f02 100644 --- a/res/mixxx.qrc +++ b/res/mixxx.qrc @@ -35,6 +35,7 @@ images/ic_checkmark.svg images/ic_custom.svg images/ic_delete.svg + images/ic_mixxx_symbolic.svg images/preferences/ic_preferences_autodj.svg images/preferences/ic_preferences_bpmdetect.svg images/preferences/ic_preferences_broadcast.svg diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index b24fa335499..5bdf9e084c7 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -241,9 +241,9 @@ void DlgPrefController::enumeratePresets() { PresetInfo match; // Enumerate user presets - QIcon icon(":/images/ic_custom.svg"); + QIcon userPresetIcon(":/images/ic_custom.svg"); PresetInfo userPresetsMatch = enumeratePresetsFromEnumerator( - m_pControllerManager->getMainThreadUserPresetEnumerator(), icon); + m_pControllerManager->getMainThreadUserPresetEnumerator(), userPresetIcon); if (userPresetsMatch.isValid()) { match = userPresetsMatch; } @@ -252,8 +252,9 @@ void DlgPrefController::enumeratePresets() { m_ui.comboBoxPreset->insertSeparator(m_ui.comboBoxPreset->count()); // Enumerate system presets + QIcon systemPresetIcon(":/images/ic_mixxx_symbolic.svg"); PresetInfo systemPresetsMatch = enumeratePresetsFromEnumerator( - m_pControllerManager->getMainThreadSystemPresetEnumerator()); + m_pControllerManager->getMainThreadSystemPresetEnumerator(), systemPresetIcon); if (systemPresetsMatch.isValid()) { match = systemPresetsMatch; } From 6f5ce05132bd33793ba0acba9db7df5d029b7759 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Apr 2020 00:15:13 +0200 Subject: [PATCH 22/55] controllers/dlgprefcontroller: Disable checkbox if no preset selected --- src/controllers/dlgprefcontroller.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 5bdf9e084c7..8581ec30c98 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -269,8 +269,11 @@ void DlgPrefController::enumeratePresets() { } else if (match.isValid()) { index = m_ui.comboBoxPreset->findText(match.getName()); } - if (index != -1) { + if (index == -1) { + m_ui.chkEnabledDevice->setEnabled(false); + } else { m_ui.comboBoxPreset->setCurrentIndex(index); + m_ui.chkEnabledDevice->setEnabled(true); } } @@ -375,8 +378,10 @@ void DlgPrefController::slotApply() { void DlgPrefController::slotLoadPreset(int chosenIndex) { if (chosenIndex == 0) { // User picked ... + m_ui.chkEnabledDevice->setEnabled(false); return; } + m_ui.chkEnabledDevice->setEnabled(true); const QString presetPath = m_ui.comboBoxPreset->itemData(chosenIndex).toString(); // When loading the preset, we only want to load from the same dir as the From cd14e38ca6186787cfb6972ee827d317cec11185 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Apr 2020 00:26:38 +0200 Subject: [PATCH 23/55] controllers/dlgprefcontroller: Rename "..." to "No Preset" and add icon --- res/images/ic_none.svg | 77 +++++++++++++++++++++++++++ res/mixxx.qrc | 1 + src/controllers/dlgprefcontroller.cpp | 7 +-- 3 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 res/images/ic_none.svg diff --git a/res/images/ic_none.svg b/res/images/ic_none.svg new file mode 100644 index 00000000000..1d4ae648d3a --- /dev/null +++ b/res/images/ic_none.svg @@ -0,0 +1,77 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/res/mixxx.qrc b/res/mixxx.qrc index 33381991f02..6e4684376e4 100644 --- a/res/mixxx.qrc +++ b/res/mixxx.qrc @@ -36,6 +36,7 @@ images/ic_custom.svg images/ic_delete.svg images/ic_mixxx_symbolic.svg + images/ic_none.svg images/preferences/ic_preferences_autodj.svg images/preferences/ic_preferences_bpmdetect.svg images/preferences/ic_preferences_broadcast.svg diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 8581ec30c98..dcdcfbd80aa 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -234,10 +234,11 @@ void DlgPrefController::enumeratePresets() { // qDebug() << "Enumerating presets for controller" << m_pController->getName(); - // Insert a dummy "..." item at the top to try to make it less confusing. + // Insert a dummy item at the top to try to make it less confusing. // (We don't want the first found file showing up as the default item when a // user has their controller plugged in) - m_ui.comboBoxPreset->addItem("..."); + QIcon noPresetIcon(":/images/ic_none.svg"); + m_ui.comboBoxPreset->addItem(noPresetIcon, "No Preset"); PresetInfo match; // Enumerate user presets @@ -377,7 +378,7 @@ void DlgPrefController::slotApply() { void DlgPrefController::slotLoadPreset(int chosenIndex) { if (chosenIndex == 0) { - // User picked ... + // User picked no preset m_ui.chkEnabledDevice->setEnabled(false); return; } From 00b625f47a8199d9efa5de63be41a2180738de42 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Apr 2020 00:33:23 +0200 Subject: [PATCH 24/55] controllers/controllermanager: Fix typo in debug message --- src/controllers/controllermanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 06864bd8398..3131fc2ca69 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -404,7 +404,7 @@ void ControllerManager::slotSavePresets(bool onlyActive) { ControllerPresetPointer pPreset = pController->getPreset(); if (!pPreset) { - qDebug() << "Device" << deviceName << "has no configurated preset"; + qDebug() << "Device" << deviceName << "has no configured preset"; continue; } From 12f083eaabcb749dedd3dd9e17561bb2dfe55fbc Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Apr 2020 11:43:41 +0200 Subject: [PATCH 25/55] controllers/midi/midimessage: Use desc in MidiInputMapping == operator --- src/controllers/midi/midimessage.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/controllers/midi/midimessage.h b/src/controllers/midi/midimessage.h index 5e04d07ef3e..6349f446730 100644 --- a/src/controllers/midi/midimessage.h +++ b/src/controllers/midi/midimessage.h @@ -160,11 +160,9 @@ struct MidiInputMapping { control(control) { } - // Don't use descriptions in operator== since we only use equality testing - // for unit tests. bool operator==(const MidiInputMapping& other) const { return key == other.key && options == other.options && - control == other.control; + control == other.control && description == other.description; } MidiKey key; From 5ee9c9bb0061fb8b5a7da946690d099033f4436e Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Apr 2020 12:35:32 +0200 Subject: [PATCH 26/55] controllers/midi/midimessage: Fix MidiInputMapping == operator --- src/controllers/midi/midimessage.h | 10 ++ src/test/learningutilstest.cpp | 182 ++++++++++++++++++++--------- 2 files changed, 134 insertions(+), 58 deletions(-) diff --git a/src/controllers/midi/midimessage.h b/src/controllers/midi/midimessage.h index 6349f446730..8223dea32e8 100644 --- a/src/controllers/midi/midimessage.h +++ b/src/controllers/midi/midimessage.h @@ -160,6 +160,16 @@ struct MidiInputMapping { control(control) { } + MidiInputMapping(MidiKey key, + MidiOptions options, + const ConfigKey& control, + QString description) + : key(key), + options(options), + control(control), + description(description) { + } + bool operator==(const MidiInputMapping& other) const { return key == other.key && options == other.options && control == other.control && description == other.description; diff --git a/src/test/learningutilstest.cpp b/src/test/learningutilstest.cpp index 664c88a8275..07ca3c995b2 100644 --- a/src/test/learningutilstest.cpp +++ b/src/test/learningutilstest.cpp @@ -15,6 +15,21 @@ class LearningUtilsTest : public MixxxTest { m_messages.append(qMakePair(MidiKey(status, control), value)); } + /** Check if mapping in present in mapping list. + * Similar to MidiInputMappings::contains(const MidiInputMapping&), but + * does not compare the description. + */ + bool containsMapping(const MidiInputMappings& haystack, const MidiInputMapping& needle) { + for (const MidiInputMapping& mapping : haystack) { + if (mapping.key == needle.key && + mapping.options == needle.options && + mapping.control == needle.control) { + return true; + } + } + return false; + } + QList > m_messages; }; @@ -29,8 +44,10 @@ TEST_F(LearningUtilsTest, NoteOnButton) { ASSERT_EQ(1, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_NOTE_ON | 0x01, 0x10), - MidiOptions(), control), - mappings.first()); + MidiOptions(), + control, + mappings.first().description), + mappings.first()); } TEST_F(LearningUtilsTest, NoteOnNoteOffButton) { @@ -44,11 +61,15 @@ TEST_F(LearningUtilsTest, NoteOnNoteOffButton) { ASSERT_EQ(2, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_NOTE_ON | 0x01, 0x10), - MidiOptions(), control), - mappings.at(0)); + MidiOptions(), + control, + mappings.at(0).description), + mappings.at(0)); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_NOTE_OFF | 0x01, 0x10), - MidiOptions(), control), - mappings.at(1)); + MidiOptions(), + control, + mappings.at(1).description), + mappings.at(1)); } TEST_F(LearningUtilsTest, CC7BitKnob) { @@ -69,8 +90,10 @@ TEST_F(LearningUtilsTest, CC7BitKnob) { ASSERT_EQ(1, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - MidiOptions(), control), - mappings.at(0)); + MidiOptions(), + control, + mappings.first().description), + mappings.first()); } TEST_F(LearningUtilsTest, CC7BitKnob_CenterPointButton_NoteOn) { @@ -103,10 +126,13 @@ TEST_F(LearningUtilsTest, CC7BitKnob_CenterPointButton_NoteOn) { LearningUtils::guessMidiInputMappings(control, m_messages); ASSERT_EQ(2, mappings.size()); - EXPECT_TRUE(mappings.contains(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - MidiOptions(), control))); - EXPECT_TRUE(mappings.contains(MidiInputMapping(MidiKey(MIDI_NOTE_ON | 0x01, 0xE0), - MidiOptions(), resetControl))); + EXPECT_TRUE(containsMapping(mappings, + MidiInputMapping( + MidiKey(MIDI_CC | 0x01, 0x10), MidiOptions(), control))); + EXPECT_TRUE(containsMapping(mappings, + MidiInputMapping(MidiKey(MIDI_NOTE_ON | 0x01, 0xE0), + MidiOptions(), + resetControl))); m_messages.clear(); @@ -124,10 +150,13 @@ TEST_F(LearningUtilsTest, CC7BitKnob_CenterPointButton_NoteOn) { addMessage(MIDI_CC | 0x01, 0x10, 0x00); ASSERT_EQ(2, mappings.size()); - EXPECT_TRUE(mappings.contains(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - MidiOptions(), control))); - EXPECT_TRUE(mappings.contains(MidiInputMapping(MidiKey(MIDI_NOTE_ON | 0x01, 0xE0), - MidiOptions(), resetControl))); + EXPECT_TRUE(containsMapping(mappings, + MidiInputMapping( + MidiKey(MIDI_CC | 0x01, 0x10), MidiOptions(), control))); + EXPECT_TRUE(containsMapping(mappings, + MidiInputMapping(MidiKey(MIDI_NOTE_ON | 0x01, 0xE0), + MidiOptions(), + resetControl))); } TEST_F(LearningUtilsTest, CC14BitKnob_MSBFirst) { @@ -167,12 +196,14 @@ TEST_F(LearningUtilsTest, CC14BitKnob_MSBFirst) { ASSERT_EQ(2, mappings.size()); MidiOptions lsb_option; lsb_option.fourteen_bit_lsb = true; - EXPECT_TRUE(mappings.contains(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - lsb_option, control))); + EXPECT_TRUE(containsMapping(mappings, + MidiInputMapping( + MidiKey(MIDI_CC | 0x01, 0x10), lsb_option, control))); MidiOptions msb_option; msb_option.fourteen_bit_msb = true; - EXPECT_TRUE(mappings.contains(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x11), - msb_option, control))); + EXPECT_TRUE(containsMapping(mappings, + MidiInputMapping( + MidiKey(MIDI_CC | 0x01, 0x11), msb_option, control))); } TEST_F(LearningUtilsTest, CC14BitKnob_LSBFirst) { @@ -212,12 +243,14 @@ TEST_F(LearningUtilsTest, CC14BitKnob_LSBFirst) { ASSERT_EQ(2, mappings.size()); MidiOptions lsb_option; lsb_option.fourteen_bit_lsb = true; - EXPECT_TRUE(mappings.contains(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - lsb_option, control))); + EXPECT_TRUE(containsMapping(mappings, + MidiInputMapping( + MidiKey(MIDI_CC | 0x01, 0x10), lsb_option, control))); MidiOptions msb_option; msb_option.fourteen_bit_msb = true; - EXPECT_TRUE(mappings.contains(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x11), - msb_option, control))); + EXPECT_TRUE(containsMapping(mappings, + MidiInputMapping( + MidiKey(MIDI_CC | 0x01, 0x11), msb_option, control))); } TEST_F(LearningUtilsTest, CC7BitKnob_ConfusableForCC7BitTicker_Zeroes) { @@ -236,8 +269,11 @@ TEST_F(LearningUtilsTest, CC7BitKnob_ConfusableForCC7BitTicker_Zeroes) { MidiOptions options; options.selectknob = true; ASSERT_EQ(1, mappings.size()); - EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), options, control), - mappings.at(0)); + EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), + options, + control, + mappings.first().description), + mappings.first()); m_messages.clear(); @@ -252,8 +288,10 @@ TEST_F(LearningUtilsTest, CC7BitKnob_ConfusableForCC7BitTicker_Zeroes) { ASSERT_EQ(1, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - MidiOptions(), control), - mappings.at(0)); + MidiOptions(), + control, + mappings.first().description), + mappings.first()); } TEST_F(LearningUtilsTest, CC7BitKnob_ConfusableForCC7BitTicker_ZeroIncluded) { @@ -285,8 +323,10 @@ TEST_F(LearningUtilsTest, CC7BitKnob_ConfusableForCC7BitTicker_ZeroIncluded) { ASSERT_EQ(1, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - MidiOptions(), control), - mappings.at(0)); + MidiOptions(), + control, + mappings.first().description), + mappings.first()); } TEST_F(LearningUtilsTest, CC7BitKnob_ConfusableForCC7BitTicker) { @@ -312,11 +352,14 @@ TEST_F(LearningUtilsTest, CC7BitKnob_ConfusableForCC7BitTicker) { ASSERT_EQ(1, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - MidiOptions(), control), - mappings.at(0)); + MidiOptions(), + control, + mappings.first().description), + mappings.first()); } -TEST_F(LearningUtilsTest, CC7BitKnob_ConfusableForSpread64Ticker_StartAndStopOn41) { +TEST_F(LearningUtilsTest, + CC7BitKnob_ConfusableForSpread64Ticker_StartAndStopOn41) { // Moving a CC knob through its range multiple times is confusable for // Spread64 select knobs when a 0x41 or 0x3F is repeated. If we start and // stop on 0x41 (and don't pass through 0x40) then this can set off Spread64 @@ -342,8 +385,10 @@ TEST_F(LearningUtilsTest, CC7BitKnob_ConfusableForSpread64Ticker_StartAndStopOn4 ASSERT_EQ(1, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - MidiOptions(), control), - mappings.at(0)); + MidiOptions(), + control, + mappings.first().description), + mappings.first()); } TEST_F(LearningUtilsTest, CC7BitKnob_ConfusableForSpread64Ticker_0x40Included) { @@ -375,8 +420,10 @@ TEST_F(LearningUtilsTest, CC7BitKnob_ConfusableForSpread64Ticker_0x40Included) { ASSERT_EQ(1, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - MidiOptions(), control), - mappings.at(0)); + MidiOptions(), + control, + mappings.first().description), + mappings.first()); } TEST_F(LearningUtilsTest, CC7BitTicker) { @@ -401,8 +448,10 @@ TEST_F(LearningUtilsTest, CC7BitTicker) { MidiOptions options; options.selectknob = true; EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - options, control), - mappings.at(0)); + options, + control, + mappings.first().description), + mappings.first()); } TEST_F(LearningUtilsTest, Spread64Ticker) { @@ -425,8 +474,10 @@ TEST_F(LearningUtilsTest, Spread64Ticker) { MidiOptions options; options.spread64 = true; EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - options, control), - mappings.at(0)); + options, + control, + mappings.first().description), + mappings.first()); } TEST_F(LearningUtilsTest, CC7BitTicker_SingleDirection) { @@ -452,8 +503,10 @@ TEST_F(LearningUtilsTest, CC7BitTicker_SingleDirection) { LearningUtils::guessMidiInputMappings(control, m_messages); ASSERT_EQ(1, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - options, control), - mappings.at(0)); + options, + control, + mappings.first().description), + mappings.first()); m_messages.clear(); @@ -466,8 +519,10 @@ TEST_F(LearningUtilsTest, CC7BitTicker_SingleDirection) { mappings = LearningUtils::guessMidiInputMappings(control, m_messages); ASSERT_EQ(1, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - options, control), - mappings.at(0)); + options, + control, + mappings.first().description), + mappings.first()); } TEST_F(LearningUtilsTest, SingleMessageSwitchMode_NoteOn) { @@ -485,8 +540,10 @@ TEST_F(LearningUtilsTest, SingleMessageSwitchMode_NoteOn) { MidiOptions options; options.sw = true; EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_NOTE_ON | 0x01, 0x10), - options, control), - mappings.at(0)); + options, + control, + mappings.first().description), + mappings.first()); m_messages.clear(); @@ -497,8 +554,10 @@ TEST_F(LearningUtilsTest, SingleMessageSwitchMode_NoteOn) { ASSERT_EQ(1, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_NOTE_ON | 0x01, 0x10), - options, control), - mappings.at(0)); + options, + control, + mappings.first().description), + mappings.first()); } TEST_F(LearningUtilsTest, SingleMessageSwitchMode_CC) { @@ -516,8 +575,10 @@ TEST_F(LearningUtilsTest, SingleMessageSwitchMode_CC) { MidiOptions options; options.sw = true; EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - options, control), - mappings.at(0)); + options, + control, + mappings.first().description), + mappings.first()); m_messages.clear(); @@ -528,11 +589,12 @@ TEST_F(LearningUtilsTest, SingleMessageSwitchMode_CC) { ASSERT_EQ(1, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_CC | 0x01, 0x10), - options, control), - mappings.at(0)); + options, + control, + mappings.first().description), + mappings.first()); } - TEST_F(LearningUtilsTest, MultipleControlsUnrecognized_BindsFirst) { // Status 0x91, Control 0x10 addMessage(MIDI_NOTE_ON | 0x01, 0x10, 0x7F); @@ -547,8 +609,10 @@ TEST_F(LearningUtilsTest, MultipleControlsUnrecognized_BindsFirst) { LearningUtils::guessMidiInputMappings(control, m_messages); ASSERT_EQ(1, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_NOTE_ON | 0x01, 0x10), - MidiOptions(), control), - mappings.first()); + MidiOptions(), + control, + mappings.first().description), + mappings.first()); } TEST_F(LearningUtilsTest, MultipleChannelsUnrecognized_BindsFirst) { @@ -565,6 +629,8 @@ TEST_F(LearningUtilsTest, MultipleChannelsUnrecognized_BindsFirst) { LearningUtils::guessMidiInputMappings(control, m_messages); ASSERT_EQ(1, mappings.size()); EXPECT_EQ(MidiInputMapping(MidiKey(MIDI_NOTE_ON | 0x01, 0x10), - MidiOptions(), control), - mappings.first()); + MidiOptions(), + control, + mappings.first().description), + mappings.first()); } From fc97ef7c33eb25144aca8007da644a5a0c4ab620 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Apr 2020 13:05:32 +0200 Subject: [PATCH 27/55] controllers/controllermanager: Add "(edited)" suffix to changed presets --- src/controllers/controllermanager.cpp | 6 ++++++ src/controllers/midi/midicontrollerpresetfilehandler.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 3131fc2ca69..2b5ea1b5b98 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -415,6 +415,12 @@ void ControllerManager::slotSavePresets(bool onlyActive) { continue; } + if (pPreset->filePath().startsWith(resourcePresetsPath(m_pConfig))) { + pPreset->setName(QString(tr("%1 (edited)")).arg(pPreset->name())); + pController->setPreset(*pPreset); + qDebug() << "Renamed preset to " << pPreset->name(); + } + QString filename = firstAvailableFilename(filenames, deviceName); QString presetPath = userPresetsPath(m_pConfig) + filename + pController->presetExtension(); diff --git a/src/controllers/midi/midicontrollerpresetfilehandler.cpp b/src/controllers/midi/midicontrollerpresetfilehandler.cpp index dc90812b8f6..beafe38b753 100644 --- a/src/controllers/midi/midicontrollerpresetfilehandler.cpp +++ b/src/controllers/midi/midicontrollerpresetfilehandler.cpp @@ -194,7 +194,7 @@ ControllerPresetPointer MidiControllerPresetFileHandler::load(const QDomElement bool MidiControllerPresetFileHandler::save(const MidiControllerPreset& preset, const QString deviceName, const QString fileName) const { - qDebug() << "Saving preset for" << deviceName << "to" << fileName; + qDebug() << "Saving preset" << preset.name() << "for" << deviceName << "to" << fileName; QDomDocument doc = buildRootWithScripts(preset, deviceName); addControlsToDocument(preset, &doc); return writeDocument(doc, fileName); From 390d3ddd331430eadac6c478c15ba8f385cf4f31 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Apr 2020 13:18:31 +0200 Subject: [PATCH 28/55] controllers: Add some comments to undocumented classes --- src/controllers/controllerinputmappingtablemodel.h | 4 ++++ src/controllers/controlleroutputmappingtablemodel.h | 4 ++++ src/controllers/dlgprefcontroller.h | 2 +- src/controllers/dlgprefcontrollers.h | 10 ++++++---- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/controllers/controllerinputmappingtablemodel.h b/src/controllers/controllerinputmappingtablemodel.h index 96b6134f2a7..6abaa5ed6d0 100644 --- a/src/controllers/controllerinputmappingtablemodel.h +++ b/src/controllers/controllerinputmappingtablemodel.h @@ -9,6 +9,10 @@ #include "controllers/controllermappingtablemodel.h" #include "controllers/midi/midimessage.h" +/** Table Model for the "Inputs" table view in the preferences dialog. + * + * This allows editing the input mappings for a MIDI preset. + */ class ControllerInputMappingTableModel : public ControllerMappingTableModel { Q_OBJECT public: diff --git a/src/controllers/controlleroutputmappingtablemodel.h b/src/controllers/controlleroutputmappingtablemodel.h index 781338c0e7a..317837b7fef 100644 --- a/src/controllers/controlleroutputmappingtablemodel.h +++ b/src/controllers/controlleroutputmappingtablemodel.h @@ -9,6 +9,10 @@ #include "controllers/controllermappingtablemodel.h" #include "controllers/midi/midimessage.h" +/** Table Model for the "Outputs" table view in the preferences dialog. + * + * This allows editing the output mappings for a MIDI preset. + */ class ControllerOutputMappingTableModel : public ControllerMappingTableModel { Q_OBJECT public: diff --git a/src/controllers/dlgprefcontroller.h b/src/controllers/dlgprefcontroller.h index a344011a543..30c354de9b6 100644 --- a/src/controllers/dlgprefcontroller.h +++ b/src/controllers/dlgprefcontroller.h @@ -2,7 +2,7 @@ * @file dlgprefcontroller.h * @author Sean M. Pappalardo spappalardo@mixxx.org * @date Mon May 2 2011 -* @brief Configuration dialog for a DJ controller +* @brief Configuration dialog for a single DJ controller */ #ifndef DLGPREFCONTROLLER_H diff --git a/src/controllers/dlgprefcontrollers.h b/src/controllers/dlgprefcontrollers.h index 9fbef1bc47e..66be4651cf8 100644 --- a/src/controllers/dlgprefcontrollers.h +++ b/src/controllers/dlgprefcontrollers.h @@ -1,5 +1,4 @@ -#ifndef DLGPREFCONTROLLERS_H -#define DLGPREFCONTROLLERS_H +#pragma once #include @@ -11,6 +10,11 @@ class DlgPreferences; class DlgPrefController; class ControllerManager; +/** Controllers Overview in the preferences + * + * This dialog allows selecting controllers for configuration. + */ + class DlgPrefControllers : public DlgPreferencePage, public Ui::DlgPrefControllersDlg { Q_OBJECT public: @@ -43,5 +47,3 @@ class DlgPrefControllers : public DlgPreferencePage, public Ui::DlgPrefControlle QList m_controllerWindows; QList m_controllerTreeItems; }; - -#endif /* DLGPREFCONTROLLERS_H */ From 02ee5c447347326466c9accf6eaefd68895d7e88 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Apr 2020 13:51:21 +0200 Subject: [PATCH 29/55] controllers/controllermanager: Remove obsolete importScript method --- src/controllers/controllermanager.cpp | 68 --------------------------- src/controllers/controllermanager.h | 1 - 2 files changed, 69 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 2b5ea1b5b98..59e59dc0c65 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -479,71 +479,3 @@ QString ControllerManager::getAbsolutePath(const QString& pathOrFilename, return QString(); } - -bool ControllerManager::importScript(const QString& scriptPath, - QString* newScriptFileName) { - QDir userPresets(userPresetsPath(m_pConfig)); - - qDebug() << "ControllerManager::importScript importing script" << scriptPath - << "to" << userPresets.absolutePath(); - - QFile scriptFile(scriptPath); - QFileInfo script(scriptFile); - - if (!script.exists() || !script.isReadable()) { - qWarning() << "ControllerManager::importScript script does not exist" - << "or is unreadable:" << scriptPath; - return false; - } - - // Not fatal if we can't checksum but still warn about it. - quint16 scriptChecksum = 0; - bool scriptChecksumGood = checksumFile(scriptPath, &scriptChecksum); - if (!scriptChecksumGood) { - qWarning() << "ControllerManager::importScript could not checksum file:" - << scriptPath; - } - - // The name we will save this file as in our local script mixxxdb. The - // conflict resolution logic below will mutate this variable if the name is - // already taken. - QString scriptFileName = script.fileName(); - - // For a file like "myfile.foo.bar.js", scriptBaseName is "myfile.foo.bar" - // and scriptSuffix is "js". - QString scriptBaseName = script.completeBaseName(); - QString scriptSuffix = script.suffix(); - int conflictNumber = 1; - - // This script exists. - while (userPresets.exists(scriptFileName)) { - // If the two files are identical. We're done. - quint16 localScriptChecksum = 0; - if (checksumFile(userPresets.filePath(scriptFileName), &localScriptChecksum) && - scriptChecksumGood && scriptChecksum == localScriptChecksum) { - *newScriptFileName = scriptFileName; - qDebug() << "ControllerManager::importScript" << scriptFileName - << "had identical checksum to a file of the same name." - << "Skipping import."; - return true; - } - - // Otherwise, we need to rename the file to a non-conflicting - // name. Insert a .X where X is a counter that we count up until we find - // a filename that does not exist. - scriptFileName = QString("%1.%2.%3").arg( - scriptBaseName, - QString::number(conflictNumber++), - scriptSuffix); - } - - QString destinationPath = userPresets.filePath(scriptFileName); - if (!scriptFile.copy(destinationPath)) { - qDebug() << "ControllerManager::importScript could not copy script to" - << "local preset path:" << destinationPath; - return false; - } - - *newScriptFileName = scriptFileName; - return true; -} diff --git a/src/controllers/controllermanager.h b/src/controllers/controllermanager.h index dae740ee713..e1047f09d7d 100644 --- a/src/controllers/controllermanager.h +++ b/src/controllers/controllermanager.h @@ -53,7 +53,6 @@ class ControllerManager : public QObject { static QString getAbsolutePath(const QString& pathOrFilename, const QStringList& presetPaths); - bool importScript(const QString& scriptPath, QString* newScriptFileName); static bool checksumFile(const QString& filename, quint16* pChecksum); signals: From 98d50b00cc93e84e253662d136f0e8d0082ded44 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Apr 2020 14:37:28 +0200 Subject: [PATCH 30/55] controllers: Always load scripts from mapping dir (with system as fallback) --- src/controllers/controller.cpp | 11 ++++++++++- src/controllers/controller.h | 2 +- src/controllers/controllermanager.cpp | 4 ++-- src/controllers/controllerpreset.h | 7 ++++++- src/controllers/midi/midicontroller.cpp | 4 ++-- src/controllers/midi/midicontroller.h | 2 +- src/test/controller_preset_validation_test.cpp | 14 +++++++------- 7 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/controllers/controller.cpp b/src/controllers/controller.cpp index 15a1e1dd5ec..f1ac6dc8f48 100644 --- a/src/controllers/controller.cpp +++ b/src/controllers/controller.cpp @@ -50,7 +50,7 @@ void Controller::stopEngine() { m_pEngine = NULL; } -bool Controller::applyPreset(QList scriptPaths, bool initializeScripts) { +bool Controller::applyPreset(const QString& fallbackScriptPath, bool initializeScripts) { qDebug() << "Applying controller preset..."; const ControllerPreset* pPreset = preset(); @@ -66,6 +66,15 @@ bool Controller::applyPreset(QList scriptPaths, bool initializeScripts) return true; } + // Always prefer script from the mapping's directory + QList scriptPaths = {pPreset->dirPath().absolutePath()}; + + // Additional fallback path if a script file is not present in the + // mapping's directory + if (!scriptPaths.contains(fallbackScriptPath)) { + scriptPaths << fallbackScriptPath; + } + bool success = m_pEngine->loadScriptFiles(scriptPaths, pPreset->scripts); if (initializeScripts) { m_pEngine->initializeScripts(pPreset->scripts); diff --git a/src/controllers/controller.h b/src/controllers/controller.h index 09a20d8181b..f5deeb87ba7 100644 --- a/src/controllers/controller.h +++ b/src/controllers/controller.h @@ -83,7 +83,7 @@ class Controller : public QObject, ConstControllerPresetVisitor { virtual void receive(const QByteArray data, mixxx::Duration timestamp); // Initializes the controller engine and returns whether it was successful. - virtual bool applyPreset(QList scriptPaths, bool initializeScripts); + virtual bool applyPreset(const QString& fallbackScriptPath, bool initializeScripts); // Puts the controller in and out of learning mode. void startLearning(); diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 59e59dc0c65..0f90618fce9 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -263,7 +263,7 @@ void ControllerManager::slotSetUpDevices() { qWarning() << "There was a problem opening" << name; continue; } - pController->applyPreset(getPresetPaths(m_pConfig), true); + pController->applyPreset(resourcePresetsPath(m_pConfig), true); } maybeStartOrStopPolling(); @@ -355,7 +355,7 @@ void ControllerManager::openController(Controller* pController) { // If successfully opened the device, apply the preset and save the // preference setting. if (result == 0) { - pController->applyPreset(getPresetPaths(m_pConfig), true); + pController->applyPreset(resourcePresetsPath(m_pConfig), true); // Update configuration to reflect controller is enabled. m_pConfig->setValue( diff --git a/src/controllers/controllerpreset.h b/src/controllers/controllerpreset.h index 19fcfefad9e..b8acab95765 100644 --- a/src/controllers/controllerpreset.h +++ b/src/controllers/controllerpreset.h @@ -11,10 +11,11 @@ #ifndef CONTROLLERPRESET_H #define CONTROLLERPRESET_H +#include #include +#include #include #include -#include class ControllerPresetVisitor; class ConstControllerPresetVisitor; @@ -78,6 +79,10 @@ class ControllerPreset { return m_filePath; } + inline QDir dirPath() const { + return QFileInfo(filePath()).absoluteDir(); + } + inline void setName(const QString name) { m_name = name; setDirty(true); diff --git a/src/controllers/midi/midicontroller.cpp b/src/controllers/midi/midicontroller.cpp index 2f613c954ba..a9554c30cda 100644 --- a/src/controllers/midi/midicontroller.cpp +++ b/src/controllers/midi/midicontroller.cpp @@ -59,9 +59,9 @@ bool MidiController::savePreset(const QString fileName) const { return handler.save(m_preset, getName(), fileName); } -bool MidiController::applyPreset(QList scriptPaths, bool initializeScripts) { +bool MidiController::applyPreset(const QString& fallbackScriptPath, bool initializeScripts) { // Handles the engine - bool result = Controller::applyPreset(scriptPaths, initializeScripts); + bool result = Controller::applyPreset(fallbackScriptPath, initializeScripts); // Only execute this code if this is an output device if (isOutputDevice()) { diff --git a/src/controllers/midi/midicontroller.h b/src/controllers/midi/midicontroller.h index a81ff7d680c..ee173ee2914 100644 --- a/src/controllers/midi/midicontroller.h +++ b/src/controllers/midi/midicontroller.h @@ -76,7 +76,7 @@ class MidiController : public Controller { private slots: // Initializes the engine and static output mappings. - bool applyPreset(QList scriptPaths, bool initializeScripts) override; + bool applyPreset(const QString& fallbackScriptPath, bool initializeScripts) override; void learnTemporaryInputMappings(const MidiInputMappings& mappings); void clearTemporaryInputMappings(); diff --git a/src/test/controller_preset_validation_test.cpp b/src/test/controller_preset_validation_test.cpp index a1a65f4015f..5ce0cb64dfe 100644 --- a/src/test/controller_preset_validation_test.cpp +++ b/src/test/controller_preset_validation_test.cpp @@ -122,14 +122,15 @@ FakeController::~FakeController() { class ControllerPresetValidationTest : public MixxxTest { protected: void SetUp() override { - m_presetPaths << QDir::currentPath() + "/res/controllers"; - m_pEnumerator.reset(new PresetInfoEnumerator(m_presetPaths)); + m_presetPath = QDir::currentPath() + "/res/controllers"; + m_pEnumerator.reset(new PresetInfoEnumerator(QList{m_presetPath})); } bool testLoadPreset(const PresetInfo& preset) { ControllerPresetPointer pPreset = - ControllerPresetFileHandler::loadPreset(preset.getPath(), - m_presetPaths); + ControllerPresetFileHandler::loadPreset( + preset.getPath(), + QList{m_presetPath}); if (pPreset.isNull()) { return false; } @@ -139,13 +140,12 @@ class ControllerPresetValidationTest : public MixxxTest { controller.startEngine(); controller.setPreset(*pPreset); // Do not initialize the scripts. - bool result = controller.applyPreset(m_presetPaths, false); + bool result = controller.applyPreset(m_presetPath, false); controller.stopEngine(); return result; } - - QStringList m_presetPaths; + QString m_presetPath; QScopedPointer m_pEnumerator; }; From cb12d22ea4bddd682ac482173387e26f9fe146c2 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Apr 2020 14:39:45 +0200 Subject: [PATCH 31/55] controllers/dlgprefcontroller: Add "(built-in)" to system scripts --- src/controllers/dlgprefcontroller.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index bd1487aa177..c945029f0f5 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -224,16 +224,27 @@ QString DlgPrefController::presetScriptFileLinks(const ControllerPresetPointer p QString scriptFileLinks; if (pPreset) { - QList presetDirs; - presetDirs.append(userPresetsPath(m_pConfig)); - presetDirs.append(resourcePresetsPath(m_pConfig)); + // Always prefer script from the mapping's directory + QList scriptPaths = {pPreset->dirPath().absolutePath()}; + + QString systemPresetPath = resourcePresetsPath(m_pConfig); + if (!scriptPaths.contains(systemPresetPath)) { + scriptPaths << systemPresetPath; + } + QStringList linkList; for (QList::iterator it = pPreset->scripts.begin(); it != pPreset->scripts.end(); ++it) { QString name = it->name; QString path = ControllerManager::getAbsolutePath( - name, presetDirs); + name, scriptPaths); QString scriptFileLink = "" + name + ""; + + qDebug() << "path" << path << systemPresetPath; + if (path.startsWith(systemPresetPath)) { + scriptFileLink = QString(tr("%1 (built-in)")).arg(scriptFileLink); + } + linkList << scriptFileLink; } scriptFileLinks = linkList.join("
"); From 148a4e684600931695746809394e1e909517bfa0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Apr 2020 19:58:51 +0200 Subject: [PATCH 32/55] controllers: Move script file search code into ControllerPreset class --- src/controllers/controller.cpp | 17 ++----- src/controllers/controllerengine.cpp | 50 ++++++------------- src/controllers/controllerengine.h | 7 ++- src/controllers/controllerpreset.h | 32 ++++++++++-- .../controllerpresetfilehandler.cpp | 8 ++- src/controllers/controllerpresetfilehandler.h | 4 +- src/controllers/dlgprefcontroller.cpp | 39 ++++++--------- .../hid/hidcontrollerpresetfilehandler.cpp | 4 +- .../hid/hidcontrollerpresetfilehandler.h | 3 +- .../midi/midicontrollerpresetfilehandler.cpp | 4 +- .../midi/midicontrollerpresetfilehandler.h | 4 +- 11 files changed, 85 insertions(+), 87 deletions(-) diff --git a/src/controllers/controller.cpp b/src/controllers/controller.cpp index f1ac6dc8f48..97be00322ae 100644 --- a/src/controllers/controller.cpp +++ b/src/controllers/controller.cpp @@ -61,23 +61,16 @@ bool Controller::applyPreset(const QString& fallbackScriptPath, bool initializeS return false; } - if (pPreset->scripts.isEmpty()) { + QList scriptFiles = + pPreset->getScriptFiles(fallbackScriptPath); + if (scriptFiles.isEmpty()) { qWarning() << "No script functions available! Did the XML file(s) load successfully? See above for any errors."; return true; } - // Always prefer script from the mapping's directory - QList scriptPaths = {pPreset->dirPath().absolutePath()}; - - // Additional fallback path if a script file is not present in the - // mapping's directory - if (!scriptPaths.contains(fallbackScriptPath)) { - scriptPaths << fallbackScriptPath; - } - - bool success = m_pEngine->loadScriptFiles(scriptPaths, pPreset->scripts); + bool success = m_pEngine->loadScriptFiles(scriptFiles); if (initializeScripts) { - m_pEngine->initializeScripts(pPreset->scripts); + m_pEngine->initializeScripts(scriptFiles); } return success; } diff --git a/src/controllers/controllerengine.cpp b/src/controllers/controllerengine.cpp index 1488353b5d4..0f10d74c19e 100644 --- a/src/controllers/controllerengine.cpp +++ b/src/controllers/controllerengine.cpp @@ -227,14 +227,10 @@ void ControllerEngine::initializeScriptEngine() { Input: List of script paths and file names to load Output: Returns true if no errors occurred. -------- ------------------------------------------------------ */ -bool ControllerEngine::loadScriptFiles(const QList& scriptPaths, - const QList& scripts) { - m_lastScriptPaths = scriptPaths; - - // scriptPaths holds the paths to search in when we're looking for scripts +bool ControllerEngine::loadScriptFiles(const QList& scripts) { bool result = true; - for (const ControllerPreset::ScriptFileInfo& script : scripts) { - if (!evaluate(script.name, scriptPaths)) { + for (const auto& script : scripts) { + if (!evaluate(script.file)) { result = false; } @@ -243,6 +239,8 @@ bool ControllerEngine::loadScriptFiles(const QList& scriptPaths, } } + m_lastScriptFiles = scripts; + connect(&m_scriptWatcher, SIGNAL(fileChanged(QString)), this, SLOT(scriptHasChanged(QString))); @@ -271,10 +269,10 @@ void ControllerEngine::scriptHasChanged(const QString& scriptFilename) { } initializeScriptEngine(); - loadScriptFiles(m_lastScriptPaths, pPreset->scripts); + loadScriptFiles(m_lastScriptFiles); qDebug() << "Re-initializing scripts"; - initializeScripts(pPreset->scripts); + initializeScripts(m_lastScriptFiles); } /* -------- ------------------------------------------------------ @@ -310,10 +308,7 @@ void ControllerEngine::initializeScripts(const QList dummy; - bool ret = evaluate(filepath, dummy); - - return ret; + return evaluate(QFileInfo(filepath)); } bool ControllerEngine::syntaxIsValid(const QString& scriptCode) { @@ -933,35 +928,22 @@ void ControllerEngine::trigger(QString group, QString name) { Input: Script filename Output: false if the script file has errors or doesn't exist -------- ------------------------------------------------------ */ -bool ControllerEngine::evaluate(const QString& scriptName, QList scriptPaths) { +bool ControllerEngine::evaluate(const QFileInfo& scriptFile) { if (m_pEngine == nullptr) { return false; } - QString filename = ""; - QFile input; - - if (scriptPaths.length() == 0) { - // If we aren't given any paths to search, assume that scriptName - // contains the full file name - filename = scriptName; - input.setFileName(filename); - } else { - for (const QString& scriptPath : scriptPaths) { - QDir scriptPathDir(scriptPath); - filename = scriptPathDir.absoluteFilePath(scriptName); - input.setFileName(filename); - if (input.exists()) { - qDebug() << "ControllerEngine: Watching JS File:" << filename; - m_scriptWatcher.addPath(filename); - break; - } - } + if (!scriptFile.exists()) { + qWarning() << "ControllerEngine: File does not exist:" << scriptFile; + return false; } + m_scriptWatcher.addPath(scriptFile.absoluteFilePath()); - qDebug() << "ControllerEngine: Loading" << filename; + qDebug() << "ControllerEngine: Loading" << scriptFile; // Read in the script file + QString filename = scriptFile.absoluteFilePath(); + QFile input(filename); if (!input.open(QIODevice::ReadOnly)) { qWarning() << QString("ControllerEngine: Problem opening the script file: %1, error # %2, %3") .arg(filename, QString::number(input.error()), input.errorString()); diff --git a/src/controllers/controllerengine.h b/src/controllers/controllerengine.h index 87a75abd730..ecc1c4a4761 100644 --- a/src/controllers/controllerengine.h +++ b/src/controllers/controllerengine.h @@ -158,8 +158,7 @@ class ControllerEngine : public QObject { // Evaluates all provided script files and returns true if no script errors // occurred while evaluating them. - bool loadScriptFiles(const QList& scriptPaths, - const QList& scripts); + bool loadScriptFiles(const QList& scripts); void initializeScripts(const QList& scripts); void gracefulShutdown(); void scriptHasChanged(const QString&); @@ -173,7 +172,7 @@ class ControllerEngine : public QObject { private: bool syntaxIsValid(const QString& scriptCode); - bool evaluate(const QString& scriptName, QList scriptPaths); + bool evaluate(const QFileInfo& scriptFile); bool internalExecute(QScriptValue thisObject, const QString& scriptCode); bool internalExecute(QScriptValue thisObject, QScriptValue functionObject, QScriptValueList arguments); @@ -221,7 +220,7 @@ class ControllerEngine : public QObject { QHash m_scriptWrappedFunctionCache; // Filesystem watcher for script auto-reload QFileSystemWatcher m_scriptWatcher; - QList m_lastScriptPaths; + QList m_lastScriptFiles; friend class ControllerEngineTest; }; diff --git a/src/controllers/controllerpreset.h b/src/controllers/controllerpreset.h index b8acab95765..8ed4cd15cd6 100644 --- a/src/controllers/controllerpreset.h +++ b/src/controllers/controllerpreset.h @@ -11,6 +11,7 @@ #ifndef CONTROLLERPRESET_H #define CONTROLLERPRESET_H +#include #include #include #include @@ -35,6 +36,7 @@ class ControllerPreset { QString name; QString functionPrefix; + QFileInfo file; bool builtin; }; @@ -43,16 +45,38 @@ class ControllerPreset { * @param filename Name of the XML file to add * @param functionprefix Function prefix to add */ - void addScriptFile(QString filename, QString functionprefix, - bool builtin=false) { + void addScriptFile(QString filename, QString functionprefix, bool builtin = false) { ScriptFileInfo info; info.name = filename; info.functionPrefix = functionprefix; + // Always try to load script from the mapping's directory first + info.file = QFileInfo(dirPath().absoluteFilePath(filename)); info.builtin = builtin; - scripts.append(info); + m_scripts.append(info); setDirty(true); } + QList getScriptFiles(const QString& fallbackPath = QString()) const { + if (fallbackPath.isEmpty()) { + return m_scripts; + } + + QDir path(fallbackPath); + QList scriptsWithFallbackPath; + for (const ScriptFileInfo& script : m_scripts) { + qDebug() << "script" << script.file; + if (script.file.exists()) { + scriptsWithFallbackPath << script; + continue; + } + + ScriptFileInfo info(script); + info.file = QFileInfo(path.absoluteFilePath(info.name)); + scriptsWithFallbackPath << info; + } + return scriptsWithFallbackPath; + } + inline void setDirty(bool bDirty) { m_bDirty = bDirty; } @@ -171,6 +195,8 @@ class ControllerPreset { QString m_wikilink; QString m_schemaVersion; QString m_mixxxVersion; + + QList m_scripts; }; typedef QSharedPointer ControllerPresetPointer; diff --git a/src/controllers/controllerpresetfilehandler.cpp b/src/controllers/controllerpresetfilehandler.cpp index 22e045bef52..ec063ac9e3c 100644 --- a/src/controllers/controllerpresetfilehandler.cpp +++ b/src/controllers/controllerpresetfilehandler.cpp @@ -56,10 +56,8 @@ ControllerPresetPointer ControllerPresetFileHandler::load(const QString path, const QString deviceName) { qDebug() << "Loading controller preset from" << path; ControllerPresetPointer pPreset = load(XmlParse::openXMLFile(path, "controller"), - deviceName); - if (pPreset) { - pPreset->setFilePath(path); - } + path, + deviceName); return pPreset; } @@ -198,7 +196,7 @@ QDomDocument ControllerPresetFileHandler::buildRootWithScripts(const ControllerP QDomElement scriptFiles = doc.createElement("scriptfiles"); controller.appendChild(scriptFiles); - foreach (const ControllerPreset::ScriptFileInfo& script, preset.scripts) { + foreach (const ControllerPreset::ScriptFileInfo& script, preset.getScriptFiles()) { QString filename = script.name; // Don't need to write anything for built-in files. if (script.builtin) { diff --git a/src/controllers/controllerpresetfilehandler.h b/src/controllers/controllerpresetfilehandler.h index 904a8721960..04a1f266c15 100644 --- a/src/controllers/controllerpresetfilehandler.h +++ b/src/controllers/controllerpresetfilehandler.h @@ -58,7 +58,9 @@ class ControllerPresetFileHandler { private: // Sub-classes implement this. - virtual ControllerPresetPointer load(const QDomElement root, const QString deviceName) = 0; + virtual ControllerPresetPointer load(const QDomElement root, + const QString filePath, + const QString deviceName) = 0; }; #endif diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index c945029f0f5..04fc78e096f 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -221,35 +221,26 @@ QString DlgPrefController::presetWikiLink(const ControllerPresetPointer pPreset) } QString DlgPrefController::presetScriptFileLinks(const ControllerPresetPointer pPreset) const { - QString scriptFileLinks; + if (!pPreset) { + return QString(); + } - if (pPreset) { - // Always prefer script from the mapping's directory - QList scriptPaths = {pPreset->dirPath().absolutePath()}; + QString systemPresetPath = resourcePresetsPath(m_pConfig); + QStringList linkList; + for (const auto& script : pPreset->getScriptFiles(resourcePresetsPath(m_pConfig))) { + QString scriptFileLink = QStringLiteral("") + + script.name + QStringLiteral(""); - QString systemPresetPath = resourcePresetsPath(m_pConfig); - if (!scriptPaths.contains(systemPresetPath)) { - scriptPaths << systemPresetPath; + if (!script.file.exists()) { + scriptFileLink += QStringLiteral(" (") + tr("missing") + QStringLiteral(")"); + } else if (script.file.absoluteFilePath().startsWith(systemPresetPath)) { + scriptFileLink += QStringLiteral(" (") + tr("built-in") + QStringLiteral(")"); } - QStringList linkList; - for (QList::iterator it = - pPreset->scripts.begin(); it != pPreset->scripts.end(); ++it) { - QString name = it->name; - QString path = ControllerManager::getAbsolutePath( - name, scriptPaths); - QString scriptFileLink = "" + name + ""; - - qDebug() << "path" << path << systemPresetPath; - if (path.startsWith(systemPresetPath)) { - scriptFileLink = QString(tr("%1 (built-in)")).arg(scriptFileLink); - } - - linkList << scriptFileLink; - } - scriptFileLinks = linkList.join("
"); + linkList << scriptFileLink; } - return scriptFileLinks; + return linkList.join("
"); } void DlgPrefController::slotDirty() { diff --git a/src/controllers/hid/hidcontrollerpresetfilehandler.cpp b/src/controllers/hid/hidcontrollerpresetfilehandler.cpp index c300103a6fd..09616054bc5 100644 --- a/src/controllers/hid/hidcontrollerpresetfilehandler.cpp +++ b/src/controllers/hid/hidcontrollerpresetfilehandler.cpp @@ -8,7 +8,8 @@ bool HidControllerPresetFileHandler::save(const HidControllerPreset& preset, } ControllerPresetPointer HidControllerPresetFileHandler::load(const QDomElement root, - const QString deviceName) { + const QString filePath, + const QString deviceName) { if (root.isNull()) { return ControllerPresetPointer(); } @@ -19,6 +20,7 @@ ControllerPresetPointer HidControllerPresetFileHandler::load(const QDomElement r } HidControllerPreset* preset = new HidControllerPreset(); + preset->setFilePath(filePath); parsePresetInfo(root, preset); addScriptFilesToPreset(controller, preset); return ControllerPresetPointer(preset); diff --git a/src/controllers/hid/hidcontrollerpresetfilehandler.h b/src/controllers/hid/hidcontrollerpresetfilehandler.h index 7e27fc0eafe..ee1eff7fbf8 100644 --- a/src/controllers/hid/hidcontrollerpresetfilehandler.h +++ b/src/controllers/hid/hidcontrollerpresetfilehandler.h @@ -14,7 +14,8 @@ class HidControllerPresetFileHandler : public ControllerPresetFileHandler { private: virtual ControllerPresetPointer load(const QDomElement root, - const QString deviceName); + const QString filePath, + const QString deviceName); }; #endif /* HIDCONTROLLERPRESETFILEHANDLER_H */ diff --git a/src/controllers/midi/midicontrollerpresetfilehandler.cpp b/src/controllers/midi/midicontrollerpresetfilehandler.cpp index beafe38b753..51f67473666 100644 --- a/src/controllers/midi/midicontrollerpresetfilehandler.cpp +++ b/src/controllers/midi/midicontrollerpresetfilehandler.cpp @@ -15,7 +15,8 @@ #define DEFAULT_OUTPUT_OFF 0x00 ControllerPresetPointer MidiControllerPresetFileHandler::load(const QDomElement root, - const QString deviceName) { + const QString filePath, + const QString deviceName) { if (root.isNull()) { return ControllerPresetPointer(); } @@ -26,6 +27,7 @@ ControllerPresetPointer MidiControllerPresetFileHandler::load(const QDomElement } MidiControllerPreset* preset = new MidiControllerPreset(); + preset->setFilePath(filePath); // Superclass handles parsing tag and script files parsePresetInfo(root, preset); diff --git a/src/controllers/midi/midicontrollerpresetfilehandler.h b/src/controllers/midi/midicontrollerpresetfilehandler.h index e43e850580f..b1767b4b520 100644 --- a/src/controllers/midi/midicontrollerpresetfilehandler.h +++ b/src/controllers/midi/midicontrollerpresetfilehandler.h @@ -20,7 +20,9 @@ class MidiControllerPresetFileHandler : public ControllerPresetFileHandler { const QString deviceName, const QString fileName) const; private: - virtual ControllerPresetPointer load(const QDomElement root, const QString deviceName); + virtual ControllerPresetPointer load(const QDomElement root, + const QString filePath, + const QString deviceName); void addControlsToDocument(const MidiControllerPreset& preset, QDomDocument* doc) const; From 86829dfd1f9f87d6af9f6994fedce551b6b8519a Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Apr 2020 21:32:35 +0200 Subject: [PATCH 33/55] controllers/controllerpreset: Remove leftover qDebug() statement --- src/controllers/controllerpreset.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/controllerpreset.h b/src/controllers/controllerpreset.h index 8ed4cd15cd6..45dccd1156e 100644 --- a/src/controllers/controllerpreset.h +++ b/src/controllers/controllerpreset.h @@ -64,7 +64,6 @@ class ControllerPreset { QDir path(fallbackPath); QList scriptsWithFallbackPath; for (const ScriptFileInfo& script : m_scripts) { - qDebug() << "script" << script.file; if (script.file.exists()) { scriptsWithFallbackPath << script; continue; From 6ac15f13d79a475a5037b93b78afd1936d4cbbca Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Apr 2020 21:33:33 +0200 Subject: [PATCH 34/55] controllers/controllerpresetfilehandler: Use for loop instead of foreach --- src/controllers/controllerpresetfilehandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/controllerpresetfilehandler.cpp b/src/controllers/controllerpresetfilehandler.cpp index ec063ac9e3c..56a90bd2c0e 100644 --- a/src/controllers/controllerpresetfilehandler.cpp +++ b/src/controllers/controllerpresetfilehandler.cpp @@ -196,7 +196,7 @@ QDomDocument ControllerPresetFileHandler::buildRootWithScripts(const ControllerP QDomElement scriptFiles = doc.createElement("scriptfiles"); controller.appendChild(scriptFiles); - foreach (const ControllerPreset::ScriptFileInfo& script, preset.getScriptFiles()) { + for (const ControllerPreset::ScriptFileInfo& script : preset.getScriptFiles()) { QString filename = script.name; // Don't need to write anything for built-in files. if (script.builtin) { From 4fe397be6cb370184442c596a06fbfde813b6f8c Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 00:10:36 +0200 Subject: [PATCH 35/55] controllers: Move controller script file handling to FileHandler classes --- src/controllers/controller.cpp | 5 +- src/controllers/controller.h | 2 +- src/controllers/controllermanager.cpp | 16 +++- src/controllers/controllerpreset.h | 30 ++----- .../controllerpresetfilehandler.cpp | 80 +++++++++++-------- src/controllers/controllerpresetfilehandler.h | 14 ++-- src/controllers/dlgprefcontroller.cpp | 4 +- .../hid/hidcontrollerpresetfilehandler.cpp | 5 +- .../hid/hidcontrollerpresetfilehandler.h | 3 +- src/controllers/midi/midicontroller.cpp | 4 +- src/controllers/midi/midicontroller.h | 2 +- .../midi/midicontrollerpresetfilehandler.cpp | 5 +- .../midi/midicontrollerpresetfilehandler.h | 3 +- .../controller_preset_validation_test.cpp | 11 +-- 14 files changed, 98 insertions(+), 86 deletions(-) diff --git a/src/controllers/controller.cpp b/src/controllers/controller.cpp index 97be00322ae..fb16eea5a70 100644 --- a/src/controllers/controller.cpp +++ b/src/controllers/controller.cpp @@ -50,7 +50,7 @@ void Controller::stopEngine() { m_pEngine = NULL; } -bool Controller::applyPreset(const QString& fallbackScriptPath, bool initializeScripts) { +bool Controller::applyPreset(bool initializeScripts) { qDebug() << "Applying controller preset..."; const ControllerPreset* pPreset = preset(); @@ -61,8 +61,7 @@ bool Controller::applyPreset(const QString& fallbackScriptPath, bool initializeS return false; } - QList scriptFiles = - pPreset->getScriptFiles(fallbackScriptPath); + QList scriptFiles = pPreset->getScriptFiles(); if (scriptFiles.isEmpty()) { qWarning() << "No script functions available! Did the XML file(s) load successfully? See above for any errors."; return true; diff --git a/src/controllers/controller.h b/src/controllers/controller.h index f5deeb87ba7..34a74a329f6 100644 --- a/src/controllers/controller.h +++ b/src/controllers/controller.h @@ -83,7 +83,7 @@ class Controller : public QObject, ConstControllerPresetVisitor { virtual void receive(const QByteArray data, mixxx::Duration timestamp); // Initializes the controller engine and returns whether it was successful. - virtual bool applyPreset(const QString& fallbackScriptPath, bool initializeScripts); + virtual bool applyPreset(bool initializeScripts); // Puts the controller in and out of learning mode. void startLearning(); diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 0f90618fce9..64e2f8cc2c9 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -219,6 +219,7 @@ void ControllerManager::slotSetUpDevices() { updateControllerList(); QList deviceList = getControllerList(false, true); + QStringList presetPaths(getPresetPaths(m_pConfig)); foreach (Controller* pController, deviceList) { QString name = pController->getName(); @@ -241,9 +242,16 @@ void ControllerManager::slotSetUpDevices() { continue; } + qDebug() << "Searching for controller preset" << presetFile + << "in paths:" << presetPaths.join(","); + QString presetFilePath = ControllerManager::getAbsolutePath(presetFile, presetPaths); + if (presetFilePath.isEmpty()) { + qDebug() << "Could not find" << presetFilePath << "in any preset path."; + continue; + } + ControllerPresetPointer pPreset = ControllerPresetFileHandler::loadPreset( - presetFile, - getPresetPaths(m_pConfig)); + QFileInfo(presetFilePath), resourcePresetsPath(m_pConfig)); if (!loadPreset(pController, pPreset)) { // TODO(XXX) : auto load midi preset here. @@ -263,7 +271,7 @@ void ControllerManager::slotSetUpDevices() { qWarning() << "There was a problem opening" << name; continue; } - pController->applyPreset(resourcePresetsPath(m_pConfig), true); + pController->applyPreset(true); } maybeStartOrStopPolling(); @@ -355,7 +363,7 @@ void ControllerManager::openController(Controller* pController) { // If successfully opened the device, apply the preset and save the // preference setting. if (result == 0) { - pController->applyPreset(resourcePresetsPath(m_pConfig), true); + pController->applyPreset(true); // Update configuration to reflect controller is enabled. m_pConfig->setValue( diff --git a/src/controllers/controllerpreset.h b/src/controllers/controllerpreset.h index 45dccd1156e..d0a2576ba1a 100644 --- a/src/controllers/controllerpreset.h +++ b/src/controllers/controllerpreset.h @@ -45,35 +45,21 @@ class ControllerPreset { * @param filename Name of the XML file to add * @param functionprefix Function prefix to add */ - void addScriptFile(QString filename, QString functionprefix, bool builtin = false) { + void addScriptFile(const QString& name, + const QString& functionprefix, + const QFileInfo& file, + bool builtin = false) { ScriptFileInfo info; - info.name = filename; + info.name = name; info.functionPrefix = functionprefix; - // Always try to load script from the mapping's directory first - info.file = QFileInfo(dirPath().absoluteFilePath(filename)); + info.file = file; info.builtin = builtin; m_scripts.append(info); setDirty(true); } - QList getScriptFiles(const QString& fallbackPath = QString()) const { - if (fallbackPath.isEmpty()) { - return m_scripts; - } - - QDir path(fallbackPath); - QList scriptsWithFallbackPath; - for (const ScriptFileInfo& script : m_scripts) { - if (script.file.exists()) { - scriptsWithFallbackPath << script; - continue; - } - - ScriptFileInfo info(script); - info.file = QFileInfo(path.absoluteFilePath(info.name)); - scriptsWithFallbackPath << info; - } - return scriptsWithFallbackPath; + const QList& getScriptFiles() const { + return m_scripts; } inline void setDirty(bool bDirty) { diff --git a/src/controllers/controllerpresetfilehandler.cpp b/src/controllers/controllerpresetfilehandler.cpp index 56a90bd2c0e..4b5e06ac86e 100644 --- a/src/controllers/controllerpresetfilehandler.cpp +++ b/src/controllers/controllerpresetfilehandler.cpp @@ -13,39 +13,33 @@ #include "controllers/hid/hidcontrollerpresetfilehandler.h" // static -ControllerPresetPointer ControllerPresetFileHandler::loadPreset(const QString& pathOrFilename, - const QStringList& presetPaths) { - qDebug() << "Searching for controller preset" << pathOrFilename - << "in paths:" << presetPaths.join(","); - QString scriptPath = ControllerManager::getAbsolutePath(pathOrFilename, - presetPaths); - - if (scriptPath.isEmpty()) { - qDebug() << "Could not find" << pathOrFilename - << "in any preset path."; +ControllerPresetPointer ControllerPresetFileHandler::loadPreset( + const QFileInfo& presetFile, const QDir& systemPresetsPath) { + VERIFY_OR_DEBUG_ASSERT(presetFile.exists() && presetFile.isReadable()) { + qDebug() << "Preset" << presetFile.absoluteFilePath() + << "does not exist or is unreadable."; return ControllerPresetPointer(); } - QFileInfo scriptPathInfo(scriptPath); - if (!scriptPathInfo.exists() || !scriptPathInfo.isReadable()) { - qDebug() << "Preset" << scriptPath << "does not exist or is unreadable."; - return ControllerPresetPointer(); - } - - ControllerPresetFileHandler* pHandler = NULL; - if (scriptPath.endsWith(MIDI_PRESET_EXTENSION, Qt::CaseInsensitive)) { + ControllerPresetFileHandler* pHandler = nullptr; + if (presetFile.fileName().endsWith( + MIDI_PRESET_EXTENSION, Qt::CaseInsensitive)) { pHandler = new MidiControllerPresetFileHandler(); - } else if (scriptPath.endsWith(HID_PRESET_EXTENSION, Qt::CaseInsensitive) || - scriptPath.endsWith(BULK_PRESET_EXTENSION, Qt::CaseInsensitive)) { + } else if (presetFile.fileName().endsWith( + HID_PRESET_EXTENSION, Qt::CaseInsensitive) || + presetFile.fileName().endsWith( + BULK_PRESET_EXTENSION, Qt::CaseInsensitive)) { pHandler = new HidControllerPresetFileHandler(); } - if (pHandler == NULL) { - qDebug() << "Preset" << scriptPath << "has an unrecognized extension."; + if (pHandler == nullptr) { + qDebug() << "Preset" << presetFile.absoluteFilePath() + << "has an unrecognized extension."; return ControllerPresetPointer(); } - ControllerPresetPointer pPreset = pHandler->load(scriptPath, QString()); + ControllerPresetPointer pPreset = pHandler->load( + presetFile.absoluteFilePath(), QString(), systemPresetsPath); if (pPreset) { pPreset->setDirty(false); } @@ -53,16 +47,19 @@ ControllerPresetPointer ControllerPresetFileHandler::loadPreset(const QString& p } ControllerPresetPointer ControllerPresetFileHandler::load(const QString path, - const QString deviceName) { + const QString deviceName, + const QDir& systemPresetsPath) { qDebug() << "Loading controller preset from" << path; - ControllerPresetPointer pPreset = load(XmlParse::openXMLFile(path, "controller"), - path, - deviceName); + ControllerPresetPointer pPreset = + load(XmlParse::openXMLFile(path, "controller"), + path, + deviceName, + systemPresetsPath); return pPreset; } -void ControllerPresetFileHandler::parsePresetInfo(const QDomElement& root, - ControllerPreset* preset) const { +void ControllerPresetFileHandler::parsePresetInfo( + const QDomElement& root, ControllerPreset* preset) const { if (root.isNull() || !preset) { return; } @@ -88,8 +85,8 @@ void ControllerPresetFileHandler::parsePresetInfo(const QDomElement& root, preset->setWikiLink(wiki.isNull() ? "" : wiki.text()); } -QDomElement ControllerPresetFileHandler::getControllerNode(const QDomElement& root, - const QString deviceName) { +QDomElement ControllerPresetFileHandler::getControllerNode( + const QDomElement& root, const QString deviceName) { Q_UNUSED(deviceName); if (root.isNull()) { return QDomElement(); @@ -102,7 +99,9 @@ QDomElement ControllerPresetFileHandler::getControllerNode(const QDomElement& ro } void ControllerPresetFileHandler::addScriptFilesToPreset( - const QDomElement& controller, ControllerPreset* preset) const { + const QDomElement& controller, + ControllerPreset* preset, + const QDir& systemPresetsPath) const { if (controller.isNull()) return; @@ -111,16 +110,27 @@ void ControllerPresetFileHandler::addScriptFilesToPreset( // Build a list of script files to load QDomElement scriptFile = controller.firstChildElement("scriptfiles") - .firstChildElement("file"); + .firstChildElement("file"); // Default currently required file - preset->addScriptFile(REQUIRED_SCRIPT_FILE, "", true); + preset->addScriptFile(REQUIRED_SCRIPT_FILE, + "", + QFileInfo(systemPresetsPath.absoluteFilePath(REQUIRED_SCRIPT_FILE)), + true); // Look for additional ones while (!scriptFile.isNull()) { QString functionPrefix = scriptFile.attribute("functionprefix",""); QString filename = scriptFile.attribute("filename",""); - preset->addScriptFile(filename, functionPrefix); + + // Always try to load script from the mapping's directory first + QFileInfo file = QFileInfo(preset->dirPath().absoluteFilePath(filename)); + if (!file.exists()) { + // If the script does not exist, try to find it in the fallback dir + file = QFileInfo(systemPresetsPath.absoluteFilePath(filename)); + } + + preset->addScriptFile(filename, functionPrefix, file); scriptFile = scriptFile.nextSiblingElement("file"); } } diff --git a/src/controllers/controllerpresetfilehandler.h b/src/controllers/controllerpresetfilehandler.h index 04a1f266c15..527706c4d9e 100644 --- a/src/controllers/controllerpresetfilehandler.h +++ b/src/controllers/controllerpresetfilehandler.h @@ -16,15 +16,17 @@ class ControllerPresetFileHandler { ControllerPresetFileHandler() {}; virtual ~ControllerPresetFileHandler() {}; - static ControllerPresetPointer loadPreset(const QString& path, - const QStringList& presetPaths); + static ControllerPresetPointer loadPreset(const QFileInfo& presetFile, + const QDir& systemPresetsPath); /** load(QString,QString,bool) * Overloaded function for convenience * @param path The path to a controller preset XML file. * @param deviceName The name/id of the controller */ - ControllerPresetPointer load(const QString path, const QString deviceName); + ControllerPresetPointer load(const QString path, + const QString deviceName, + const QDir& systemPresetsPath); // Returns just the name of a given device (everything before the first // space) @@ -47,7 +49,8 @@ class ControllerPresetFileHandler { * @param preset The ControllerPreset into which the scripts should be placed. */ void addScriptFilesToPreset(const QDomElement& root, - ControllerPreset* preset) const; + ControllerPreset* preset, + const QDir& systemPresetsPath) const; // Creates the XML document and includes what script files are currently // loaded. Sub-classes need to call this before adding any other items. @@ -60,7 +63,8 @@ class ControllerPresetFileHandler { // Sub-classes implement this. virtual ControllerPresetPointer load(const QDomElement root, const QString filePath, - const QString deviceName) = 0; + const QString deviceName, + const QDir& systemPresetPath) = 0; }; #endif diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 04fc78e096f..73167ccc049 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -227,7 +227,7 @@ QString DlgPrefController::presetScriptFileLinks(const ControllerPresetPointer p QString systemPresetPath = resourcePresetsPath(m_pConfig); QStringList linkList; - for (const auto& script : pPreset->getScriptFiles(resourcePresetsPath(m_pConfig))) { + for (const auto& script : pPreset->getScriptFiles()) { QString scriptFileLink = QStringLiteral("") + script.name + QStringLiteral(""); @@ -390,7 +390,7 @@ void DlgPrefController::slotLoadPreset(int chosenIndex) { presetDirs.append(presetFileInfo.canonicalPath()); ControllerPresetPointer pPreset = ControllerPresetFileHandler::loadPreset( - presetPath, ControllerManager::getPresetPaths(m_pConfig)); + presetPath, QDir(resourcePresetsPath(m_pConfig))); if (!pPreset) { return; diff --git a/src/controllers/hid/hidcontrollerpresetfilehandler.cpp b/src/controllers/hid/hidcontrollerpresetfilehandler.cpp index 09616054bc5..7b04dda605c 100644 --- a/src/controllers/hid/hidcontrollerpresetfilehandler.cpp +++ b/src/controllers/hid/hidcontrollerpresetfilehandler.cpp @@ -9,7 +9,8 @@ bool HidControllerPresetFileHandler::save(const HidControllerPreset& preset, ControllerPresetPointer HidControllerPresetFileHandler::load(const QDomElement root, const QString filePath, - const QString deviceName) { + const QString deviceName, + const QDir& systemPresetsPath) { if (root.isNull()) { return ControllerPresetPointer(); } @@ -22,6 +23,6 @@ ControllerPresetPointer HidControllerPresetFileHandler::load(const QDomElement r HidControllerPreset* preset = new HidControllerPreset(); preset->setFilePath(filePath); parsePresetInfo(root, preset); - addScriptFilesToPreset(controller, preset); + addScriptFilesToPreset(controller, preset, systemPresetsPath); return ControllerPresetPointer(preset); } diff --git a/src/controllers/hid/hidcontrollerpresetfilehandler.h b/src/controllers/hid/hidcontrollerpresetfilehandler.h index ee1eff7fbf8..910900dabd8 100644 --- a/src/controllers/hid/hidcontrollerpresetfilehandler.h +++ b/src/controllers/hid/hidcontrollerpresetfilehandler.h @@ -15,7 +15,8 @@ class HidControllerPresetFileHandler : public ControllerPresetFileHandler { private: virtual ControllerPresetPointer load(const QDomElement root, const QString filePath, - const QString deviceName); + const QString deviceName, + const QDir& systemPresetsPath); }; #endif /* HIDCONTROLLERPRESETFILEHANDLER_H */ diff --git a/src/controllers/midi/midicontroller.cpp b/src/controllers/midi/midicontroller.cpp index a9554c30cda..dc3196ecc2a 100644 --- a/src/controllers/midi/midicontroller.cpp +++ b/src/controllers/midi/midicontroller.cpp @@ -59,9 +59,9 @@ bool MidiController::savePreset(const QString fileName) const { return handler.save(m_preset, getName(), fileName); } -bool MidiController::applyPreset(const QString& fallbackScriptPath, bool initializeScripts) { +bool MidiController::applyPreset(bool initializeScripts) { // Handles the engine - bool result = Controller::applyPreset(fallbackScriptPath, initializeScripts); + bool result = Controller::applyPreset(initializeScripts); // Only execute this code if this is an output device if (isOutputDevice()) { diff --git a/src/controllers/midi/midicontroller.h b/src/controllers/midi/midicontroller.h index ee173ee2914..04460a2b201 100644 --- a/src/controllers/midi/midicontroller.h +++ b/src/controllers/midi/midicontroller.h @@ -76,7 +76,7 @@ class MidiController : public Controller { private slots: // Initializes the engine and static output mappings. - bool applyPreset(const QString& fallbackScriptPath, bool initializeScripts) override; + bool applyPreset(bool initializeScripts) override; void learnTemporaryInputMappings(const MidiInputMappings& mappings); void clearTemporaryInputMappings(); diff --git a/src/controllers/midi/midicontrollerpresetfilehandler.cpp b/src/controllers/midi/midicontrollerpresetfilehandler.cpp index 51f67473666..4954d92f1d3 100644 --- a/src/controllers/midi/midicontrollerpresetfilehandler.cpp +++ b/src/controllers/midi/midicontrollerpresetfilehandler.cpp @@ -16,7 +16,8 @@ ControllerPresetPointer MidiControllerPresetFileHandler::load(const QDomElement root, const QString filePath, - const QString deviceName) { + const QString deviceName, + const QDir& systemPresetsPath) { if (root.isNull()) { return ControllerPresetPointer(); } @@ -31,7 +32,7 @@ ControllerPresetPointer MidiControllerPresetFileHandler::load(const QDomElement // Superclass handles parsing tag and script files parsePresetInfo(root, preset); - addScriptFilesToPreset(controller, preset); + addScriptFilesToPreset(controller, preset, systemPresetsPath); QDomElement control = controller.firstChildElement("controls").firstChildElement("control"); diff --git a/src/controllers/midi/midicontrollerpresetfilehandler.h b/src/controllers/midi/midicontrollerpresetfilehandler.h index b1767b4b520..020810386f7 100644 --- a/src/controllers/midi/midicontrollerpresetfilehandler.h +++ b/src/controllers/midi/midicontrollerpresetfilehandler.h @@ -22,7 +22,8 @@ class MidiControllerPresetFileHandler : public ControllerPresetFileHandler { private: virtual ControllerPresetPointer load(const QDomElement root, const QString filePath, - const QString deviceName); + const QString deviceName, + const QDir& systemPresetPath); void addControlsToDocument(const MidiControllerPreset& preset, QDomDocument* doc) const; diff --git a/src/test/controller_preset_validation_test.cpp b/src/test/controller_preset_validation_test.cpp index 5ce0cb64dfe..334205d7efe 100644 --- a/src/test/controller_preset_validation_test.cpp +++ b/src/test/controller_preset_validation_test.cpp @@ -122,15 +122,16 @@ FakeController::~FakeController() { class ControllerPresetValidationTest : public MixxxTest { protected: void SetUp() override { - m_presetPath = QDir::currentPath() + "/res/controllers"; - m_pEnumerator.reset(new PresetInfoEnumerator(QList{m_presetPath})); + m_presetPath = QDir::current(); + m_presetPath.cd("res/controllers"); + m_pEnumerator.reset(new PresetInfoEnumerator(QList{m_presetPath.absolutePath()})); } bool testLoadPreset(const PresetInfo& preset) { ControllerPresetPointer pPreset = ControllerPresetFileHandler::loadPreset( preset.getPath(), - QList{m_presetPath}); + m_presetPath); if (pPreset.isNull()) { return false; } @@ -140,12 +141,12 @@ class ControllerPresetValidationTest : public MixxxTest { controller.startEngine(); controller.setPreset(*pPreset); // Do not initialize the scripts. - bool result = controller.applyPreset(m_presetPath, false); + bool result = controller.applyPreset(false); controller.stopEngine(); return result; } - QString m_presetPath; + QDir m_presetPath; QScopedPointer m_pEnumerator; }; From a93cd8dac960aa8ebf2da7f66ed5f809d329e4d3 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 10:07:29 +0200 Subject: [PATCH 36/55] controllers: Make applyPreset initializeScripts param optional --- src/controllers/controller.h | 10 ++++++++-- src/controllers/controllermanager.cpp | 4 ++-- src/controllers/midi/midicontroller.h | 10 ++++++++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/controllers/controller.h b/src/controllers/controller.h index 34a74a329f6..215f4d24b06 100644 --- a/src/controllers/controller.h +++ b/src/controllers/controller.h @@ -82,8 +82,14 @@ class Controller : public QObject, ConstControllerPresetVisitor { // this if they have an alternate way of handling such data.) virtual void receive(const QByteArray data, mixxx::Duration timestamp); - // Initializes the controller engine and returns whether it was successful. - virtual bool applyPreset(bool initializeScripts); + /** Apply the preset to the controller. + * @brief Initializes both controller engine and static output mappings. + * + * @param initializeScripts Can be set to false to skip script + * initialization for unit tests. + * @return Returns whether it was successful. + */ + virtual bool applyPreset(bool initializeScripts = true); // Puts the controller in and out of learning mode. void startLearning(); diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 64e2f8cc2c9..69b9918d3d9 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -271,7 +271,7 @@ void ControllerManager::slotSetUpDevices() { qWarning() << "There was a problem opening" << name; continue; } - pController->applyPreset(true); + pController->applyPreset(); } maybeStartOrStopPolling(); @@ -363,7 +363,7 @@ void ControllerManager::openController(Controller* pController) { // If successfully opened the device, apply the preset and save the // preference setting. if (result == 0) { - pController->applyPreset(true); + pController->applyPreset(); // Update configuration to reflect controller is enabled. m_pConfig->setValue( diff --git a/src/controllers/midi/midicontroller.h b/src/controllers/midi/midicontroller.h index 04460a2b201..8b11b57c93b 100644 --- a/src/controllers/midi/midicontroller.h +++ b/src/controllers/midi/midicontroller.h @@ -75,8 +75,14 @@ class MidiController : public Controller { int close() override; private slots: - // Initializes the engine and static output mappings. - bool applyPreset(bool initializeScripts) override; + /** Apply the preset to the controller. + * @brief Initializes both controller engine and static output mappings. + * + * @param initializeScripts Can be set to false to skip script + * initialization for unit tests. + * @return Returns whether it was successful. + */ + bool applyPreset(bool initializeScripts = false) override; void learnTemporaryInputMappings(const MidiInputMappings& mappings); void clearTemporaryInputMappings(); From 43220941f729eaa9f66f99b7fbad0ff97766a464 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 10:12:43 +0200 Subject: [PATCH 37/55] controllers/controllermanager: Replace foreach for for loops --- src/controllers/controllermanager.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 69b9918d3d9..103a0ce4cd3 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -155,7 +155,7 @@ void ControllerManager::slotShutdown() { locker.unlock(); // Delete enumerators and they'll delete their Devices - foreach (ControllerEnumerator* pEnumerator, enumerators) { + for (ControllerEnumerator* pEnumerator : enumerators) { delete pEnumerator; } @@ -173,7 +173,7 @@ void ControllerManager::updateControllerList() { locker.unlock(); QList newDeviceList; - foreach (ControllerEnumerator* pEnumerator, enumerators) { + for (ControllerEnumerator* pEnumerator : enumerators) { newDeviceList.append(pEnumerator->queryDevices()); } @@ -201,7 +201,7 @@ QList ControllerManager::getControllerList(bool bOutputDevices, boo // options. QList filteredDeviceList; - foreach (Controller* device, controllers) { + for (Controller* device : controllers) { if ((bOutputDevices == device->isOutputDevice()) || (bInputDevices == device->isInputDevice())) { filteredDeviceList.push_back(device); @@ -221,7 +221,7 @@ void ControllerManager::slotSetUpDevices() { QList deviceList = getControllerList(false, true); QStringList presetPaths(getPresetPaths(m_pConfig)); - foreach (Controller* pController, deviceList) { + for (Controller* pController : deviceList) { QString name = pController->getName(); if (pController->isOpen()) { @@ -283,7 +283,7 @@ void ControllerManager::maybeStartOrStopPolling() { locker.unlock(); bool shouldPoll = false; - foreach (Controller* pController, controllers) { + for (Controller* pController : controllers) { if (pController->isOpen() && pController->isPolling()) { shouldPoll = true; } @@ -337,7 +337,7 @@ void ControllerManager::pollDevices() { } mixxx::Duration start = mixxx::Time::elapsed(); - foreach (Controller* pDevice, m_controllers) { + for (Controller* pDevice : m_controllers) { if (pDevice->isOpen() && pDevice->isPolling()) { pDevice->poll(); } @@ -403,7 +403,7 @@ void ControllerManager::slotSavePresets(bool onlyActive) { // TODO(rryan): This should be split up somehow but the filename selection // is dependent on all of the controllers to prevent over-writing each // other. We need a better solution. - foreach (Controller* pController, deviceList) { + for (Controller* pController : deviceList) { if (onlyActive && !pController->isOpen()) { continue; } @@ -477,7 +477,7 @@ QString ControllerManager::getAbsolutePath(const QString& pathOrFilename, return pathOrFilename; } - foreach (const QString& path, paths) { + for (const QString& path : paths) { QDir pathDir(path); if (pathDir.exists(pathOrFilename)) { From e18e5d6eb15644ea14f635ff9d8e3f613345bcf8 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 10:27:05 +0200 Subject: [PATCH 38/55] controllers/controllerpresetfilehandler: Improve script file search code --- .../controllerpresetfilehandler.cpp | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/controllers/controllerpresetfilehandler.cpp b/src/controllers/controllerpresetfilehandler.cpp index 4b5e06ac86e..2e5a7e5c952 100644 --- a/src/controllers/controllerpresetfilehandler.cpp +++ b/src/controllers/controllerpresetfilehandler.cpp @@ -12,6 +12,32 @@ #include "controllers/midi/midicontrollerpresetfilehandler.h" #include "controllers/hid/hidcontrollerpresetfilehandler.h" +namespace { + +/** Find script file in the preset or system path. + * + * @param preset The controller preset the script belongs to. + * @param filename The script filename. + * @param systemPresetsPath The system presets path to use as fallback. + * @return Returns a QFileInfo object. If the script was not found in either + * of the search directories, the QFileInfo object might point to a + * non-existing file. + */ +QFileInfo findScriptFile(ControllerPreset* preset, + const QString& filename, + const QDir& systemPresetsPath) { + // Always try to load script from the mapping's directory first + QFileInfo file = QFileInfo(preset->dirPath().absoluteFilePath(filename)); + + // If the script does not exist, try to find it in the fallback dir + if (!file.exists()) { + file = QFileInfo(systemPresetsPath.absoluteFilePath(filename)); + } + return file; +} + +} // namespace + // static ControllerPresetPointer ControllerPresetFileHandler::loadPreset( const QFileInfo& presetFile, const QDir& systemPresetsPath) { @@ -115,20 +141,14 @@ void ControllerPresetFileHandler::addScriptFilesToPreset( // Default currently required file preset->addScriptFile(REQUIRED_SCRIPT_FILE, "", - QFileInfo(systemPresetsPath.absoluteFilePath(REQUIRED_SCRIPT_FILE)), + findScriptFile(preset, REQUIRED_SCRIPT_FILE, systemPresetsPath), true); // Look for additional ones while (!scriptFile.isNull()) { QString functionPrefix = scriptFile.attribute("functionprefix",""); QString filename = scriptFile.attribute("filename",""); - - // Always try to load script from the mapping's directory first - QFileInfo file = QFileInfo(preset->dirPath().absoluteFilePath(filename)); - if (!file.exists()) { - // If the script does not exist, try to find it in the fallback dir - file = QFileInfo(systemPresetsPath.absoluteFilePath(filename)); - } + QFileInfo file = findScriptFile(preset, filename, systemPresetsPath); preset->addScriptFile(filename, functionPrefix, file); scriptFile = scriptFile.nextSiblingElement("file"); From 814b2435d3e8031fa33ea492c81ed2e7c2c79194 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 10:32:30 +0200 Subject: [PATCH 39/55] controllers/controllerpresetfilehandler: Remove wrong debug assertion --- src/controllers/controllerpresetfilehandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/controllerpresetfilehandler.cpp b/src/controllers/controllerpresetfilehandler.cpp index 2e5a7e5c952..ba00b92f1c3 100644 --- a/src/controllers/controllerpresetfilehandler.cpp +++ b/src/controllers/controllerpresetfilehandler.cpp @@ -41,7 +41,7 @@ QFileInfo findScriptFile(ControllerPreset* preset, // static ControllerPresetPointer ControllerPresetFileHandler::loadPreset( const QFileInfo& presetFile, const QDir& systemPresetsPath) { - VERIFY_OR_DEBUG_ASSERT(presetFile.exists() && presetFile.isReadable()) { + if (!presetFile.exists() || !presetFile.isReadable()) { qDebug() << "Preset" << presetFile.absoluteFilePath() << "does not exist or is unreadable."; return ControllerPresetPointer(); From a0d395f472a42cdf760fcfb0a45110b7913c0dfb Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 10:44:18 +0200 Subject: [PATCH 40/55] controllers/controllerpresetfilehandler: Improve comments --- src/controllers/controllerpresetfilehandler.h | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/controllers/controllerpresetfilehandler.h b/src/controllers/controllerpresetfilehandler.h index 527706c4d9e..66891f44e5a 100644 --- a/src/controllers/controllerpresetfilehandler.h +++ b/src/controllers/controllerpresetfilehandler.h @@ -1,12 +1,17 @@ +#pragma once /** * @file controllerpresetfilehandler.h * @author Sean Pappalardo spappalardo@mixxx.org * @date Mon 9 Apr 2012 * @brief Handles loading and saving of Controller presets. * +* The ControllerPresetFileHandler is used for serializing/deserializing the +* ControllerPreset objects to/from XML files and is also responsible +* finding the script files that belong to a preset in the file system. +* +* Subclasses can implement the private load function to add support for XML +* elements that are only useful for certain mapping types. */ -#ifndef CONTROLLERPRESETFILEHANDLER_H -#define CONTROLLERPRESETFILEHANDLER_H #include "util/xml.h" #include "controllers/controllerpreset.h" @@ -19,8 +24,8 @@ class ControllerPresetFileHandler { static ControllerPresetPointer loadPreset(const QFileInfo& presetFile, const QDir& systemPresetsPath); - /** load(QString,QString,bool) - * Overloaded function for convenience + /** Overloaded function for convenience + * * @param path The path to a controller preset XML file. * @param deviceName The name/id of the controller */ @@ -41,12 +46,15 @@ class ControllerPresetFileHandler { void parsePresetInfo(const QDomElement& root, ControllerPreset* preset) const; - /** addScriptFilesToPreset(QDomElement,QString,bool) - * Loads script files specified in a QDomElement structure into the supplied - * ControllerPreset. + /** Adds script files from XML to the ControllerPreset. + * + * This function parses the supplied QDomElement structure, finds the + * matching script files inside the search paths and adds them to + * ControllerPreset. + * * @param root The root node of the XML document for the preset. - * @param deviceName The name/id of the controller - * @param preset The ControllerPreset into which the scripts should be placed. + * @param deviceName The name/id of the controller. + * @param preset The ControllerPreset these scripts belong to. */ void addScriptFilesToPreset(const QDomElement& root, ControllerPreset* preset, @@ -66,5 +74,3 @@ class ControllerPresetFileHandler { const QString deviceName, const QDir& systemPresetPath) = 0; }; - -#endif From e59d4654c1c9b704cbe58e445c5778f3c7baeadc Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 10:46:09 +0200 Subject: [PATCH 41/55] controllers/dlgprefcontroller: Remove unused presetDir code --- src/controllers/dlgprefcontroller.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 73167ccc049..bfd7bee5d74 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -381,14 +381,6 @@ void DlgPrefController::slotLoadPreset(int chosenIndex) { m_ui.chkEnabledDevice->setEnabled(true); const QString presetPath = m_ui.comboBoxPreset->itemData(chosenIndex).toString(); - // When loading the preset, we only want to load from the same dir as the - // preset itself, otherwise when loading from the system-wide dir we'll - // start the search in the user's dir find the existing script, - // and do nothing. - const QFileInfo presetFileInfo(presetPath); - QList presetDirs; - presetDirs.append(presetFileInfo.canonicalPath()); - ControllerPresetPointer pPreset = ControllerPresetFileHandler::loadPreset( presetPath, QDir(resourcePresetsPath(m_pConfig))); From d4ee3889e62e37870d6448216b6404354cc9ecea Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 13:55:09 +0200 Subject: [PATCH 42/55] controllers/controllerengine: Fix warnings for older Qt5 versions --- src/controllers/controllerengine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/controllerengine.cpp b/src/controllers/controllerengine.cpp index 0f10d74c19e..7739b742d4a 100644 --- a/src/controllers/controllerengine.cpp +++ b/src/controllers/controllerengine.cpp @@ -934,12 +934,12 @@ bool ControllerEngine::evaluate(const QFileInfo& scriptFile) { } if (!scriptFile.exists()) { - qWarning() << "ControllerEngine: File does not exist:" << scriptFile; + qWarning() << "ControllerEngine: File does not exist:" << scriptFile.absoluteFilePath(); return false; } m_scriptWatcher.addPath(scriptFile.absoluteFilePath()); - qDebug() << "ControllerEngine: Loading" << scriptFile; + qDebug() << "ControllerEngine: Loading" << scriptFile.absoluteFilePath(); // Read in the script file QString filename = scriptFile.absoluteFilePath(); From 13c2d599470d3aed9ce58624cbba7b3cd5a1f9ba Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 15:15:54 +0200 Subject: [PATCH 43/55] controllers: Move savePreset() from Controller into Preset classes --- CMakeLists.txt | 2 + build/depends.py | 1 + build/features.py | 3 +- src/controllers/bulk/bulkcontroller.cpp | 5 -- src/controllers/bulk/bulkcontroller.h | 2 - src/controllers/controller.h | 2 - src/controllers/controllermanager.cpp | 2 +- src/controllers/controllerpreset.h | 2 + .../controllerpresetfilehandler.cpp | 37 ++++----- src/controllers/controllerpresetfilehandler.h | 15 ++-- src/controllers/hid/hidcontroller.cpp | 5 -- src/controllers/hid/hidcontroller.h | 2 - src/controllers/hid/hidcontrollerpreset.cpp | 36 +++++++++ src/controllers/hid/hidcontrollerpreset.h | 31 +++---- .../hid/hidcontrollerpresetfilehandler.cpp | 12 ++- .../hid/hidcontrollerpresetfilehandler.h | 8 +- src/controllers/midi/midicontroller.cpp | 5 -- src/controllers/midi/midicontroller.h | 2 - src/controllers/midi/midicontrollerpreset.cpp | 79 ++++++++++++++++++ src/controllers/midi/midicontrollerpreset.h | 80 ++++--------------- .../midi/midicontrollerpresetfilehandler.cpp | 14 ++-- .../midi/midicontrollerpresetfilehandler.h | 8 +- .../controller_preset_validation_test.cpp | 5 -- 23 files changed, 192 insertions(+), 166 deletions(-) create mode 100644 src/controllers/hid/hidcontrollerpreset.cpp create mode 100644 src/controllers/midi/midicontrollerpreset.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d8c5f9385b..66c2b5aecf1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,6 +217,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/controllers/keyboard/keyboardeventfilter.cpp src/controllers/learningutils.cpp src/controllers/midi/midicontroller.cpp + src/controllers/midi/midicontrollerpreset.cpp src/controllers/midi/midicontrollerpresetfilehandler.cpp src/controllers/midi/midienumerator.cpp src/controllers/midi/midimessage.cpp @@ -1979,6 +1980,7 @@ if(HID) target_sources(mixxx-lib PRIVATE src/controllers/hid/hidcontroller.cpp src/controllers/hid/hidenumerator.cpp + src/controllers/hid/hidcontrollerpreset.cpp src/controllers/hid/hidcontrollerpresetfilehandler.cpp ) target_compile_definitions(mixxx-lib PUBLIC __HID__) diff --git a/build/depends.py b/build/depends.py index b68c7f85cdf..f8794c9a680 100644 --- a/build/depends.py +++ b/build/depends.py @@ -924,6 +924,7 @@ def sources(self, build): "src/controllers/midi/midimessage.cpp", "src/controllers/midi/midiutils.cpp", "src/controllers/midi/midicontroller.cpp", + "src/controllers/midi/midicontrollerpreset.cpp", "src/controllers/midi/midicontrollerpresetfilehandler.cpp", "src/controllers/midi/midienumerator.cpp", "src/controllers/midi/midioutputhandler.cpp", diff --git a/build/features.py b/build/features.py index 993d6a2824b..ed9a80858d7 100644 --- a/build/features.py +++ b/build/features.py @@ -100,6 +100,7 @@ def configure(self, build, conf): def sources(self, build): sources = ['src/controllers/hid/hidcontroller.cpp', + 'src/controllers/hid/hidcontrollerpreset.cpp', 'src/controllers/hid/hidenumerator.cpp', 'src/controllers/hid/hidcontrollerpresetfilehandler.cpp'] @@ -707,7 +708,7 @@ def configure(self, build, conf): # https://bugs.launchpad.net/mixxx/+bug/1833225 if not conf.CheckForPKG('shout', '2.4.4'): self.INTERNAL_LINK = True - + if not self.INTERNAL_LINK: self.INTERNAL_LINK = not conf.CheckLib(['libshout', 'shout']) diff --git a/src/controllers/bulk/bulkcontroller.cpp b/src/controllers/bulk/bulkcontroller.cpp index 49468b1ceab..4280cc75bee 100644 --- a/src/controllers/bulk/bulkcontroller.cpp +++ b/src/controllers/bulk/bulkcontroller.cpp @@ -116,11 +116,6 @@ void BulkController::visit(const HidControllerPreset* preset) { emit presetLoaded(getPreset()); } -bool BulkController::savePreset(const QString fileName) const { - HidControllerPresetFileHandler handler; - return handler.save(m_preset, getName(), fileName); -} - bool BulkController::matchPreset(const PresetInfo& preset) { const QList& products = preset.getProducts(); for (const auto& product : products) { diff --git a/src/controllers/bulk/bulkcontroller.h b/src/controllers/bulk/bulkcontroller.h index 9d67c1041ea..94e32869ba1 100644 --- a/src/controllers/bulk/bulkcontroller.h +++ b/src/controllers/bulk/bulkcontroller.h @@ -56,8 +56,6 @@ class BulkController : public Controller { return ControllerPresetPointer(pClone); } - bool savePreset(const QString fileName) const override; - void visit(const MidiControllerPreset* preset) override; void visit(const HidControllerPreset* preset) override; diff --git a/src/controllers/controller.h b/src/controllers/controller.h index 215f4d24b06..c831134d0b2 100644 --- a/src/controllers/controller.h +++ b/src/controllers/controller.h @@ -39,8 +39,6 @@ class Controller : public QObject, ConstControllerPresetVisitor { virtual void accept(ControllerVisitor* visitor) = 0; - virtual bool savePreset(const QString filename) const = 0; - // Returns a clone of the Controller's loaded preset. virtual ControllerPresetPointer getPreset() const = 0; diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 103a0ce4cd3..5617713c312 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -432,7 +432,7 @@ void ControllerManager::slotSavePresets(bool onlyActive) { QString filename = firstAvailableFilename(filenames, deviceName); QString presetPath = userPresetsPath(m_pConfig) + filename + pController->presetExtension(); - if (!pController->savePreset(presetPath)) { + if (!pPreset->savePreset(presetPath)) { qWarning() << "Failed to write preset for device" << deviceName << "to" << presetPath; } diff --git a/src/controllers/controllerpreset.h b/src/controllers/controllerpreset.h index d0a2576ba1a..d49f57fb7ba 100644 --- a/src/controllers/controllerpreset.h +++ b/src/controllers/controllerpreset.h @@ -160,6 +160,8 @@ class ControllerPreset { setDirty(true); } + virtual bool savePreset(const QString& filename) const = 0; + virtual void accept(ControllerPresetVisitor* visitor) = 0; virtual void accept(ConstControllerPresetVisitor* visitor) const = 0; virtual bool isMappable() const = 0; diff --git a/src/controllers/controllerpresetfilehandler.cpp b/src/controllers/controllerpresetfilehandler.cpp index ba00b92f1c3..eb27038e4f6 100644 --- a/src/controllers/controllerpresetfilehandler.cpp +++ b/src/controllers/controllerpresetfilehandler.cpp @@ -65,22 +65,18 @@ ControllerPresetPointer ControllerPresetFileHandler::loadPreset( } ControllerPresetPointer pPreset = pHandler->load( - presetFile.absoluteFilePath(), QString(), systemPresetsPath); + presetFile.absoluteFilePath(), systemPresetsPath); if (pPreset) { pPreset->setDirty(false); } return pPreset; } -ControllerPresetPointer ControllerPresetFileHandler::load(const QString path, - const QString deviceName, - const QDir& systemPresetsPath) { +ControllerPresetPointer ControllerPresetFileHandler::load( + const QString& path, const QDir& systemPresetsPath) { qDebug() << "Loading controller preset from" << path; - ControllerPresetPointer pPreset = - load(XmlParse::openXMLFile(path, "controller"), - path, - deviceName, - systemPresetsPath); + ControllerPresetPointer pPreset = load( + XmlParse::openXMLFile(path, "controller"), path, systemPresetsPath); return pPreset; } @@ -112,8 +108,7 @@ void ControllerPresetFileHandler::parsePresetInfo( } QDomElement ControllerPresetFileHandler::getControllerNode( - const QDomElement& root, const QString deviceName) { - Q_UNUSED(deviceName); + const QDomElement& root) { if (root.isNull()) { return QDomElement(); } @@ -146,8 +141,8 @@ void ControllerPresetFileHandler::addScriptFilesToPreset( // Look for additional ones while (!scriptFile.isNull()) { - QString functionPrefix = scriptFile.attribute("functionprefix",""); - QString filename = scriptFile.attribute("filename",""); + QString functionPrefix = scriptFile.attribute("functionprefix", ""); + QString filename = scriptFile.attribute("filename", ""); QFileInfo file = findScriptFile(preset, filename, systemPresetsPath); preset->addScriptFile(filename, functionPrefix, file); @@ -155,8 +150,8 @@ void ControllerPresetFileHandler::addScriptFilesToPreset( } } -bool ControllerPresetFileHandler::writeDocument(QDomDocument root, - const QString fileName) const { +bool ControllerPresetFileHandler::writeDocument( + QDomDocument root, const QString fileName) const { // Need to do this on Windows QDir directory; if (!directory.mkpath(fileName.left(fileName.lastIndexOf("/")))) { @@ -180,16 +175,18 @@ bool ControllerPresetFileHandler::writeDocument(QDomDocument root, return true; } -void addTextTag(QDomDocument& doc, QDomElement& holder, - QString tagName, QString tagText) { +void addTextTag(QDomDocument& doc, + QDomElement& holder, + QString tagName, + QString tagText) { QDomElement tag = doc.createElement(tagName); QDomText textNode = doc.createTextNode(tagText); tag.appendChild(textNode); holder.appendChild(tag); } -QDomDocument ControllerPresetFileHandler::buildRootWithScripts(const ControllerPreset& preset, - const QString deviceName) const { +QDomDocument ControllerPresetFileHandler::buildRootWithScripts( + const ControllerPreset& preset) const { QDomDocument doc("Preset"); QString blank = "\n" "\n" @@ -220,7 +217,7 @@ QDomDocument ControllerPresetFileHandler::buildRootWithScripts(const ControllerP QDomElement controller = doc.createElement("controller"); // Strip off the serial number - controller.setAttribute("id", rootDeviceName(deviceName)); + controller.setAttribute("id", rootDeviceName(preset.deviceId())); rootNode.appendChild(controller); QDomElement scriptFiles = doc.createElement("scriptfiles"); diff --git a/src/controllers/controllerpresetfilehandler.h b/src/controllers/controllerpresetfilehandler.h index 66891f44e5a..fce44f55d80 100644 --- a/src/controllers/controllerpresetfilehandler.h +++ b/src/controllers/controllerpresetfilehandler.h @@ -29,9 +29,7 @@ class ControllerPresetFileHandler { * @param path The path to a controller preset XML file. * @param deviceName The name/id of the controller */ - ControllerPresetPointer load(const QString path, - const QString deviceName, - const QDir& systemPresetsPath); + ControllerPresetPointer load(const QString& path, const QDir& systemPresetsPath); // Returns just the name of a given device (everything before the first // space) @@ -40,8 +38,7 @@ class ControllerPresetFileHandler { } protected: - QDomElement getControllerNode(const QDomElement& root, - const QString deviceName); + QDomElement getControllerNode(const QDomElement& root); void parsePresetInfo(const QDomElement& root, ControllerPreset* preset) const; @@ -62,15 +59,13 @@ class ControllerPresetFileHandler { // Creates the XML document and includes what script files are currently // loaded. Sub-classes need to call this before adding any other items. - QDomDocument buildRootWithScripts(const ControllerPreset& preset, - const QString deviceName) const; + QDomDocument buildRootWithScripts(const ControllerPreset& preset) const; bool writeDocument(QDomDocument root, const QString fileName) const; private: // Sub-classes implement this. - virtual ControllerPresetPointer load(const QDomElement root, - const QString filePath, - const QString deviceName, + virtual ControllerPresetPointer load(const QDomElement& root, + const QString& filePath, const QDir& systemPresetPath) = 0; }; diff --git a/src/controllers/hid/hidcontroller.cpp b/src/controllers/hid/hidcontroller.cpp index ec118012088..08bff7ef126 100644 --- a/src/controllers/hid/hidcontroller.cpp +++ b/src/controllers/hid/hidcontroller.cpp @@ -101,11 +101,6 @@ void HidController::visit(const HidControllerPreset* preset) { emit presetLoaded(getPreset()); } -bool HidController::savePreset(const QString fileName) const { - HidControllerPresetFileHandler handler; - return handler.save(m_preset, getName(), fileName); -} - bool HidController::matchPreset(const PresetInfo& preset) { const QList& products = preset.getProducts(); for (const auto& product : products) { diff --git a/src/controllers/hid/hidcontroller.h b/src/controllers/hid/hidcontroller.h index f60843067a8..543684ee766 100644 --- a/src/controllers/hid/hidcontroller.h +++ b/src/controllers/hid/hidcontroller.h @@ -31,8 +31,6 @@ class HidController final : public Controller { return ControllerPresetPointer(pClone); } - bool savePreset(const QString fileName) const override; - void visit(const MidiControllerPreset* preset) override; void visit(const HidControllerPreset* preset) override; diff --git a/src/controllers/hid/hidcontrollerpreset.cpp b/src/controllers/hid/hidcontrollerpreset.cpp new file mode 100644 index 00000000000..f5e8d49331e --- /dev/null +++ b/src/controllers/hid/hidcontrollerpreset.cpp @@ -0,0 +1,36 @@ +/** + * @file hidcontrollerpreset.cpp + * @author Jan Holthuis holzhaus@mixxx.org + * @date Mon 8 Apr 2020 + * @brief HID/Bulk Controller Preset + * + * This class represents a HID or Bulk controller preset, containing the data + * elements that make it up. + */ + +#include "controllers/hid/hidcontrollerpreset.h" + +#include "controllers/controllerpresetvisitor.h" +#include "controllers/defs_controllers.h" +#include "controllers/hid/hidcontrollerpresetfilehandler.h" + +bool HidControllerPreset::savePreset(const QString& fileName) const { + HidControllerPresetFileHandler handler; + return handler.save(*this, fileName); +} + +void HidControllerPreset::accept(ControllerPresetVisitor* visitor) { + if (visitor) { + visitor->visit(this); + } +} + +void HidControllerPreset::accept(ConstControllerPresetVisitor* visitor) const { + if (visitor) { + visitor->visit(this); + } +} + +bool HidControllerPreset::isMappable() const { + return false; +} diff --git a/src/controllers/hid/hidcontrollerpreset.h b/src/controllers/hid/hidcontrollerpreset.h index 4a66ea0554b..f1e2b8e36b8 100644 --- a/src/controllers/hid/hidcontrollerpreset.h +++ b/src/controllers/hid/hidcontrollerpreset.h @@ -1,29 +1,24 @@ -#ifndef HIDCONTROLLERPRESET_H -#define HIDCONTROLLERPRESET_H +#pragma once +/** + * @file hidcontrollerpreset.h + * @brief HID/Bulk Controller Preset + * + * This class represents a HID or Bulk controller preset, containing the data + * elements that make it up. + */ #include "controllers/controllerpreset.h" #include "controllers/controllerpresetvisitor.h" +#include "controllers/hid/hidcontrollerpresetfilehandler.h" class HidControllerPreset : public ControllerPreset { public: HidControllerPreset() {} virtual ~HidControllerPreset() {} - virtual void accept(ControllerPresetVisitor* visitor) { - if (visitor) { - visitor->visit(this); - } - } + bool savePreset(const QString& fileName) const override; - virtual void accept(ConstControllerPresetVisitor* visitor) const { - if (visitor) { - visitor->visit(this); - } - } - - virtual bool isMappable() const { - return false; - } + virtual void accept(ControllerPresetVisitor* visitor); + virtual void accept(ConstControllerPresetVisitor* visitor) const; + virtual bool isMappable() const; }; - -#endif /* HIDCONTROLLERPRESET_H */ diff --git a/src/controllers/hid/hidcontrollerpresetfilehandler.cpp b/src/controllers/hid/hidcontrollerpresetfilehandler.cpp index 7b04dda605c..253090ce9fe 100644 --- a/src/controllers/hid/hidcontrollerpresetfilehandler.cpp +++ b/src/controllers/hid/hidcontrollerpresetfilehandler.cpp @@ -1,21 +1,19 @@ #include "controllers/hid/hidcontrollerpresetfilehandler.h" bool HidControllerPresetFileHandler::save(const HidControllerPreset& preset, - const QString deviceName, - const QString fileName) const { - QDomDocument doc = buildRootWithScripts(preset, deviceName); + const QString& fileName) const { + QDomDocument doc = buildRootWithScripts(preset); return writeDocument(doc, fileName); } -ControllerPresetPointer HidControllerPresetFileHandler::load(const QDomElement root, - const QString filePath, - const QString deviceName, +ControllerPresetPointer HidControllerPresetFileHandler::load(const QDomElement& root, + const QString& filePath, const QDir& systemPresetsPath) { if (root.isNull()) { return ControllerPresetPointer(); } - QDomElement controller = getControllerNode(root, deviceName); + QDomElement controller = getControllerNode(root); if (controller.isNull()) { return ControllerPresetPointer(); } diff --git a/src/controllers/hid/hidcontrollerpresetfilehandler.h b/src/controllers/hid/hidcontrollerpresetfilehandler.h index 910900dabd8..7f99f56481d 100644 --- a/src/controllers/hid/hidcontrollerpresetfilehandler.h +++ b/src/controllers/hid/hidcontrollerpresetfilehandler.h @@ -9,13 +9,11 @@ class HidControllerPresetFileHandler : public ControllerPresetFileHandler { HidControllerPresetFileHandler() {}; virtual ~HidControllerPresetFileHandler() {}; - bool save(const HidControllerPreset& preset, - const QString deviceName, const QString fileName) const; + bool save(const HidControllerPreset& preset, const QString& fileName) const; private: - virtual ControllerPresetPointer load(const QDomElement root, - const QString filePath, - const QString deviceName, + virtual ControllerPresetPointer load(const QDomElement& root, + const QString& filePath, const QDir& systemPresetsPath); }; diff --git a/src/controllers/midi/midicontroller.cpp b/src/controllers/midi/midicontroller.cpp index dc3196ecc2a..7f6c8ea5d6b 100644 --- a/src/controllers/midi/midicontroller.cpp +++ b/src/controllers/midi/midicontroller.cpp @@ -54,11 +54,6 @@ bool MidiController::matchPreset(const PresetInfo& preset) { return false; } -bool MidiController::savePreset(const QString fileName) const { - MidiControllerPresetFileHandler handler; - return handler.save(m_preset, getName(), fileName); -} - bool MidiController::applyPreset(bool initializeScripts) { // Handles the engine bool result = Controller::applyPreset(initializeScripts); diff --git a/src/controllers/midi/midicontroller.h b/src/controllers/midi/midicontroller.h index 8b11b57c93b..25a555c8373 100644 --- a/src/controllers/midi/midicontroller.h +++ b/src/controllers/midi/midicontroller.h @@ -34,8 +34,6 @@ class MidiController : public Controller { return ControllerPresetPointer(pClone); } - bool savePreset(const QString fileName) const override; - void visit(const MidiControllerPreset* preset) override; void visit(const HidControllerPreset* preset) override; diff --git a/src/controllers/midi/midicontrollerpreset.cpp b/src/controllers/midi/midicontrollerpreset.cpp new file mode 100644 index 00000000000..c3ac3efe153 --- /dev/null +++ b/src/controllers/midi/midicontrollerpreset.cpp @@ -0,0 +1,79 @@ +/** + * @file midicontrollerpreset.cpp + * @author Jan Holthuis holzhaus@mixxx.org + * @date Wed 8 Apr 2020 + * @brief MIDI Controller Preset + * + * This class represents a MIDI controller preset, containing the data elements + * that make it up. + */ + +#include "controllers/midi/midicontrollerpreset.h" + +#include "controllers/defs_controllers.h" +#include "controllers/midi/midicontrollerpresetfilehandler.h" + +bool MidiControllerPreset::savePreset(const QString& fileName) const { + MidiControllerPresetFileHandler handler; + return handler.save(*this, fileName); +} + +void MidiControllerPreset::accept(ControllerPresetVisitor* visitor) { + if (visitor) { + visitor->visit(this); + } +} + +void MidiControllerPreset::accept(ConstControllerPresetVisitor* visitor) const { + if (visitor) { + visitor->visit(this); + } +} + +bool MidiControllerPreset::isMappable() const { + return true; +} + +void MidiControllerPreset::addInputMapping(uint16_t key, MidiInputMapping mapping) { + m_inputMappings.insertMulti(key, mapping); + setDirty(true); +} + +void MidiControllerPreset::removeInputMapping(uint16_t key) { + m_inputMappings.remove(key); + setDirty(true); +} + +const QHash& MidiControllerPreset::getInputMappings() const { + return m_inputMappings; +} + +void MidiControllerPreset::setInputMappings(const QHash& mappings) { + if (m_inputMappings != mappings) { + m_inputMappings.clear(); + m_inputMappings.unite(mappings); + setDirty(true); + } +} + +void MidiControllerPreset::addOutputMapping(ConfigKey key, MidiOutputMapping mapping) { + m_outputMappings.insertMulti(key, mapping); + setDirty(true); +} + +void MidiControllerPreset::removeOutputMapping(ConfigKey key) { + m_outputMappings.remove(key); + setDirty(true); +} + +const QHash& MidiControllerPreset::getOutputMappings() const { + return m_outputMappings; +} + +void MidiControllerPreset::setOutputMappings(const QHash& mappings) { + if (m_outputMappings != mappings) { + m_outputMappings.clear(); + m_outputMappings.unite(mappings); + setDirty(true); + } +} diff --git a/src/controllers/midi/midicontrollerpreset.h b/src/controllers/midi/midicontrollerpreset.h index 1c25659059b..a2f16e5efc8 100644 --- a/src/controllers/midi/midicontrollerpreset.h +++ b/src/controllers/midi/midicontrollerpreset.h @@ -1,3 +1,4 @@ +#pragma once /** * @file midicontrollerpreset.h * @author Sean Pappalardo spappalardo@mixxx.org @@ -9,9 +10,6 @@ * */ -#ifndef MIDICONTROLLERPRESET_H -#define MIDICONTROLLERPRESET_H - #include #include "controllers/controllerpreset.h" @@ -20,73 +18,29 @@ class MidiControllerPreset : public ControllerPreset { public: - MidiControllerPreset() {} - virtual ~MidiControllerPreset() {} - - virtual void accept(ControllerPresetVisitor* visitor) { - if (visitor) { - visitor->visit(this); - } - } - - virtual void accept(ConstControllerPresetVisitor* visitor) const { - if (visitor) { - visitor->visit(this); - } - } - - virtual bool isMappable() const { - return true; - } - - void addInputMapping(uint16_t key, MidiInputMapping mapping) { - m_inputMappings.insertMulti(key, mapping); - setDirty(true); - } + MidiControllerPreset(){}; + virtual ~MidiControllerPreset(){}; - void removeInputMapping(uint16_t key) { - m_inputMappings.remove(key); - setDirty(true); - } + bool savePreset(const QString& fileName) const override; - const QHash& getInputMappings() const { - return m_inputMappings; - } + virtual void accept(ControllerPresetVisitor* visitor); + virtual void accept(ConstControllerPresetVisitor* visitor) const; + virtual bool isMappable() const; - void setInputMappings(const QHash& mappings) { - if (m_inputMappings != mappings) { - m_inputMappings.clear(); - m_inputMappings.unite(mappings); - setDirty(true); - } - } + // Input mappings + void addInputMapping(uint16_t key, MidiInputMapping mapping); + void removeInputMapping(uint16_t key); + const QHash& getInputMappings() const; + void setInputMappings(const QHash& mappings); - void addOutputMapping(ConfigKey key, MidiOutputMapping mapping) { - m_outputMappings.insertMulti(key, mapping); - setDirty(true); - } - - void removeOutputMapping(ConfigKey key) { - m_outputMappings.remove(key); - setDirty(true); - } - - const QHash& getOutputMappings() const { - return m_outputMappings; - } - - void setOutputMappings(const QHash& mappings) { - if (m_outputMappings != mappings) { - m_outputMappings.clear(); - m_outputMappings.unite(mappings); - setDirty(true); - } - } + // Output mappings + void addOutputMapping(ConfigKey key, MidiOutputMapping mapping); + void removeOutputMapping(ConfigKey key); + const QHash& getOutputMappings() const; + void setOutputMappings(const QHash& mappings); private: // MIDI input and output mappings. QHash m_inputMappings; QHash m_outputMappings; }; - -#endif diff --git a/src/controllers/midi/midicontrollerpresetfilehandler.cpp b/src/controllers/midi/midicontrollerpresetfilehandler.cpp index 4954d92f1d3..fddafd929a7 100644 --- a/src/controllers/midi/midicontrollerpresetfilehandler.cpp +++ b/src/controllers/midi/midicontrollerpresetfilehandler.cpp @@ -14,15 +14,14 @@ #define DEFAULT_OUTPUT_ON 0x7F #define DEFAULT_OUTPUT_OFF 0x00 -ControllerPresetPointer MidiControllerPresetFileHandler::load(const QDomElement root, - const QString filePath, - const QString deviceName, +ControllerPresetPointer MidiControllerPresetFileHandler::load(const QDomElement& root, + const QString& filePath, const QDir& systemPresetsPath) { if (root.isNull()) { return ControllerPresetPointer(); } - QDomElement controller = getControllerNode(root, deviceName); + QDomElement controller = getControllerNode(root); if (controller.isNull()) { return ControllerPresetPointer(); } @@ -195,10 +194,9 @@ ControllerPresetPointer MidiControllerPresetFileHandler::load(const QDomElement } bool MidiControllerPresetFileHandler::save(const MidiControllerPreset& preset, - const QString deviceName, - const QString fileName) const { - qDebug() << "Saving preset" << preset.name() << "for" << deviceName << "to" << fileName; - QDomDocument doc = buildRootWithScripts(preset, deviceName); + const QString& fileName) const { + qDebug() << "Saving preset" << preset.name() << "to" << fileName; + QDomDocument doc = buildRootWithScripts(preset); addControlsToDocument(preset, &doc); return writeDocument(doc, fileName); } diff --git a/src/controllers/midi/midicontrollerpresetfilehandler.h b/src/controllers/midi/midicontrollerpresetfilehandler.h index 020810386f7..ad7c43419e0 100644 --- a/src/controllers/midi/midicontrollerpresetfilehandler.h +++ b/src/controllers/midi/midicontrollerpresetfilehandler.h @@ -16,13 +16,11 @@ class MidiControllerPresetFileHandler : public ControllerPresetFileHandler { MidiControllerPresetFileHandler() {}; virtual ~MidiControllerPresetFileHandler() {}; - bool save(const MidiControllerPreset& preset, - const QString deviceName, const QString fileName) const; + bool save(const MidiControllerPreset& preset, const QString& fileName) const; private: - virtual ControllerPresetPointer load(const QDomElement root, - const QString filePath, - const QString deviceName, + virtual ControllerPresetPointer load(const QDomElement& root, + const QString& filePath, const QDir& systemPresetPath); void addControlsToDocument(const MidiControllerPreset& preset, diff --git a/src/test/controller_preset_validation_test.cpp b/src/test/controller_preset_validation_test.cpp index 334205d7efe..415ca1920d8 100644 --- a/src/test/controller_preset_validation_test.cpp +++ b/src/test/controller_preset_validation_test.cpp @@ -35,11 +35,6 @@ class FakeController : public Controller { } } - bool savePreset(const QString fileName) const override { - Q_UNUSED(fileName); - return true; - } - void visit(const MidiControllerPreset* preset) override { m_bMidiPreset = true; m_bHidPreset = false; From f79cdf254b46c8efc80c53a078bc4a6abffcf81e Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 17:52:13 +0200 Subject: [PATCH 44/55] controllers: Move preset saving from ControllerManger to Preferences --- src/controllers/controller.h | 7 +- src/controllers/controllermanager.cpp | 139 ++++------ src/controllers/controllermanager.h | 16 +- src/controllers/dlgprefcontroller.cpp | 341 +++++++++++++++---------- src/controllers/dlgprefcontroller.h | 44 +++- src/controllers/dlgprefcontrollers.cpp | 12 +- 6 files changed, 286 insertions(+), 273 deletions(-) diff --git a/src/controllers/controller.h b/src/controllers/controller.h index c831134d0b2..058537f5a81 100644 --- a/src/controllers/controller.h +++ b/src/controllers/controller.h @@ -69,8 +69,10 @@ class Controller : public QObject, ConstControllerPresetVisitor { // preset, not a pointer to the preset itself. void presetLoaded(ControllerPresetPointer pPreset); - // Making these slots protected/private ensures that other parts of Mixxx can - // only signal them which allows us to use no locks. + void openChanged(bool bOpen); + + // Making these slots protected/private ensures that other parts of Mixxx can + // only signal them which allows us to use no locks. protected slots: // TODO(XXX) move this into the inherited classes since is not called here // (via Controller) and re-implemented anyway in most cases. @@ -126,6 +128,7 @@ class Controller : public QObject, ConstControllerPresetVisitor { } inline void setOpen(bool open) { m_bIsOpen = open; + emit openChanged(m_bIsOpen); } private: // but used by ControllerManager diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 5617713c312..17ce5433c20 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -45,6 +45,23 @@ QString sanitizeDeviceName(QString name) { return name.replace(" ", "_").replace("/", "_").replace("\\", "_"); } +QString findPresetFile(const QString& pathOrFilename, const QStringList& paths) { + QFileInfo fileInfo(pathOrFilename); + if (fileInfo.isAbsolute()) { + return pathOrFilename; + } + + for (const QString& path : paths) { + QDir pathDir(path); + + if (pathDir.exists(pathOrFilename)) { + return pathDir.absoluteFilePath(pathOrFilename); + } + } + + return QString(); +} + } // anonymous namespace QString firstAvailableFilename(QSet& filenames, @@ -101,8 +118,6 @@ ControllerManager::ControllerManager(UserSettingsPointer pConfig) this, SLOT(slotSetUpDevices())); connect(this, SIGNAL(requestShutdown()), this, SLOT(slotShutdown())); - connect(this, SIGNAL(requestSave(bool)), - this, SLOT(slotSavePresets(bool))); // Signal that we should run slotInitialize once our event loop has started // up. @@ -244,7 +259,7 @@ void ControllerManager::slotSetUpDevices() { qDebug() << "Searching for controller preset" << presetFile << "in paths:" << presetPaths.join(","); - QString presetFilePath = ControllerManager::getAbsolutePath(presetFile, presetPaths); + QString presetFilePath = findPresetFile(presetFile, presetPaths); if (presetFilePath.isEmpty()) { qDebug() << "Could not find" << presetFilePath << "in any preset path."; continue; @@ -253,11 +268,12 @@ void ControllerManager::slotSetUpDevices() { ControllerPresetPointer pPreset = ControllerPresetFileHandler::loadPreset( QFileInfo(presetFilePath), resourcePresetsPath(m_pConfig)); - if (!loadPreset(pController, pPreset)) { - // TODO(XXX) : auto load midi preset here. + if (!pPreset) { continue; } + pController->setPreset(*pPreset); + // If we are in safe mode, skip opening controllers. if (CmdlineArgs::Instance().getSafeMode()) { qDebug() << "We are in safe mode -- skipping opening controller."; @@ -382,61 +398,36 @@ void ControllerManager::closeController(Controller* pController) { ConfigKey("[Controller]", sanitizeDeviceName(pController->getName())), 0); } -bool ControllerManager::loadPreset(Controller* pController, - ControllerPresetPointer preset) { - if (!preset) { - return false; +void ControllerManager::slotApplyPreset(Controller* pController, + ControllerPresetPointer pPreset, + bool bEnabled) { + VERIFY_OR_DEBUG_ASSERT(pController) { + qWarning() << "slotApplyPreset got invalid controller!"; + return; } - pController->setPreset(*preset.data()); - // Save the file path/name in the config so it can be auto-loaded at - // startup next time - m_pConfig->set( - ConfigKey("[ControllerPreset]", sanitizeDeviceName(pController->getName())), - preset->filePath()); - return true; -} - -void ControllerManager::slotSavePresets(bool onlyActive) { - QList deviceList = getControllerList(false, true); - QSet filenames; - - // TODO(rryan): This should be split up somehow but the filename selection - // is dependent on all of the controllers to prevent over-writing each - // other. We need a better solution. - for (Controller* pController : deviceList) { - if (onlyActive && !pController->isOpen()) { - continue; - } - QString deviceName = sanitizeDeviceName(pController->getName()); + ConfigKey key("[ControllerPreset]", sanitizeDeviceName(pController->getName())); + if (!pPreset) { + closeController(pController); + // Unset the controller preset for this controller + m_pConfig->remove(key); + return; + } - ControllerPresetPointer pPreset = pController->getPreset(); - if (!pPreset) { - qDebug() << "Device" << deviceName << "has no configured preset"; - continue; - } + VERIFY_OR_DEBUG_ASSERT(!pPreset->isDirty()) { + qWarning() << "Preset is dirty, changes might be lost on restart!"; + } - if (!pPreset->isDirty()) { - qDebug() - << "Preset for device" << deviceName - << "is not dirty, no need to save it to the user presets."; - continue; - } + pController->setPreset(*pPreset); - if (pPreset->filePath().startsWith(resourcePresetsPath(m_pConfig))) { - pPreset->setName(QString(tr("%1 (edited)")).arg(pPreset->name())); - pController->setPreset(*pPreset); - qDebug() << "Renamed preset to " << pPreset->name(); - } + // Save the file path/name in the config so it can be auto-loaded at + // startup next time + m_pConfig->set(key, pPreset->filePath()); - QString filename = firstAvailableFilename(filenames, deviceName); - QString presetPath = userPresetsPath(m_pConfig) + filename - + pController->presetExtension(); - if (!pPreset->savePreset(presetPath)) { - qWarning() << "Failed to write preset for device" - << deviceName << "to" << presetPath; - } - m_pConfig->set(ConfigKey("[ControllerPreset]", deviceName), presetPath); + if (bEnabled) { + openController(pController); + } else { + closeController(pController); } } @@ -447,43 +438,3 @@ QList ControllerManager::getPresetPaths(UserSettingsPointer pConfig) { scriptPaths.append(resourcePresetsPath(pConfig)); return scriptPaths; } - -// static -bool ControllerManager::checksumFile(const QString& filename, - quint16* pChecksum) { - QFile file(filename); - if (!file.open(QIODevice::ReadOnly)) { - return false; - } - - qint64 fileSize = file.size(); - const char* pFile = reinterpret_cast(file.map(0, fileSize)); - - if (pFile == NULL) { - file.close(); - return false; - } - - *pChecksum = qChecksum(pFile, fileSize); - file.close(); - return true; -} - -// static -QString ControllerManager::getAbsolutePath(const QString& pathOrFilename, - const QStringList& paths) { - QFileInfo fileInfo(pathOrFilename); - if (fileInfo.isAbsolute()) { - return pathOrFilename; - } - - for (const QString& path : paths) { - QDir pathDir(path); - - if (pathDir.exists(pathOrFilename)) { - return pathDir.absoluteFilePath(pathOrFilename); - } - } - - return QString(); -} diff --git a/src/controllers/controllermanager.h b/src/controllers/controllermanager.h index e1047f09d7d..8837d903580 100644 --- a/src/controllers/controllermanager.h +++ b/src/controllers/controllermanager.h @@ -43,34 +43,22 @@ class ControllerManager : public QObject { // Prevent other parts of Mixxx from having to manually connect to our slots void setUpDevices() { emit requestSetUpDevices(); }; - void savePresets(bool onlyActive=false) { emit requestSave(onlyActive); }; static QList getPresetPaths(UserSettingsPointer pConfig); - // If pathOrFilename is an absolute path, returns it. If it is a relative - // path and it is contained within any of the directories in presetPaths, - // returns the path to the first file in the path that exists. - static QString getAbsolutePath(const QString& pathOrFilename, - const QStringList& presetPaths); - - static bool checksumFile(const QString& filename, quint16* pChecksum); - signals: void devicesChanged(); void requestSetUpDevices(); void requestShutdown(); - void requestSave(bool onlyActive); void requestInitialize(); public slots: void updateControllerList(); + void slotApplyPreset(Controller* pController, ControllerPresetPointer pPreset, bool bEnabled); void openController(Controller* pController); void closeController(Controller* pController); - // Writes out presets for currently connected input devices - void slotSavePresets(bool onlyActive=false); - private slots: // Perform initialization that should be delayed until the ControllerManager // thread is started. @@ -80,8 +68,6 @@ class ControllerManager : public QObject { // preferences dialog on apply, and only open/close changed devices void slotSetUpDevices(); void slotShutdown(); - bool loadPreset(Controller* pController, - ControllerPresetPointer preset); // Calls poll() on all devices that have isPolling() true. void pollDevices(); void startPolling(); diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index bfd7bee5d74..1b54eb42a39 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -39,15 +39,14 @@ DlgPrefController::DlgPrefController(QWidget* parent, Controller* controller, initTableView(m_ui.m_pInputMappingTableView); initTableView(m_ui.m_pOutputMappingTableView); - connect(m_pController, SIGNAL(presetLoaded(ControllerPresetPointer)), - this, SLOT(slotPresetLoaded(ControllerPresetPointer))); + connect(m_pController, &Controller::presetLoaded, this, &DlgPrefController::slotShowPreset); // TODO(rryan): Eh, this really isn't thread safe but it's the way it's been // since 1.11.0. We shouldn't be calling Controller methods because it lives // in a different thread. Booleans (like isOpen()) are fine but a complex // object like a preset involves QHash's and other data structures that // really don't like concurrent access. ControllerPresetPointer pPreset = m_pController->getPreset(); - slotPresetLoaded(pPreset); + slotShowPreset(pPreset); m_ui.labelDeviceName->setText(m_pController->getName()); QString category = m_pController->getCategory(); @@ -58,44 +57,55 @@ DlgPrefController::DlgPrefController(QWidget* parent, Controller* controller, } // When the user picks a preset, load it. - connect(m_ui.comboBoxPreset, SIGNAL(activated(int)), - this, SLOT(slotLoadPreset(int))); + connect(m_ui.comboBoxPreset, SIGNAL(activated(int)), this, SLOT(slotPresetSelected(int))); - // When the user toggles the Enabled checkbox, toggle. - connect(m_ui.chkEnabledDevice, SIGNAL(clicked(bool)), - this, SLOT(slotEnableDevice(bool))); + // When the user toggles the Enabled checkbox, mark as dirty + connect(m_ui.chkEnabledDevice, &QCheckBox::clicked, [this] { setDirty(true); }); // Connect our signals to controller manager. - connect(this, SIGNAL(openController(Controller*)), - m_pControllerManager, SLOT(openController(Controller*))); - connect(this, SIGNAL(closeController(Controller*)), - m_pControllerManager, SLOT(closeController(Controller*))); - connect(this, SIGNAL(loadPreset(Controller*, ControllerPresetPointer)), - m_pControllerManager, SLOT(loadPreset(Controller*, ControllerPresetPointer))); + connect(this, + &DlgPrefController::applyPreset, + m_pControllerManager, + &ControllerManager::slotApplyPreset); // Open script file links connect(m_ui.labelLoadedPresetScriptFileLinks, &QLabel::linkActivated, - [](const QString & path) { - QDesktopServices::openUrl(QUrl::fromLocalFile(path)); }); + [](const QString& path) { + QDesktopServices::openUrl(QUrl::fromLocalFile(path)); + }); // Input mappings - connect(m_ui.btnAddInputMapping, SIGNAL(clicked()), - this, SLOT(addInputMapping())); - connect(m_ui.btnRemoveInputMappings, SIGNAL(clicked()), - this, SLOT(removeInputMappings())); - connect(m_ui.btnLearningWizard, SIGNAL(clicked()), - this, SLOT(showLearningWizard())); - connect(m_ui.btnClearAllInputMappings, SIGNAL(clicked()), - this, SLOT(clearAllInputMappings())); + connect(m_ui.btnAddInputMapping, + SIGNAL(clicked()), + this, + SLOT(addInputMapping())); + connect(m_ui.btnRemoveInputMappings, + SIGNAL(clicked()), + this, + SLOT(removeInputMappings())); + connect(m_ui.btnLearningWizard, + SIGNAL(clicked()), + this, + SLOT(showLearningWizard())); + connect(m_ui.btnClearAllInputMappings, + SIGNAL(clicked()), + this, + SLOT(clearAllInputMappings())); // Output mappings - connect(m_ui.btnAddOutputMapping, SIGNAL(clicked()), - this, SLOT(addOutputMapping())); - connect(m_ui.btnRemoveOutputMappings, SIGNAL(clicked()), - this, SLOT(removeOutputMappings())); - connect(m_ui.btnClearAllOutputMappings, SIGNAL(clicked()), - this, SLOT(clearAllOutputMappings())); + connect(m_ui.btnAddOutputMapping, + SIGNAL(clicked()), + this, + SLOT(addOutputMapping())); + connect(m_ui.btnRemoveOutputMappings, + SIGNAL(clicked()), + this, + SLOT(removeOutputMappings())); + connect(m_ui.btnClearAllOutputMappings, + SIGNAL(clicked()), + this, + SLOT(clearAllOutputMappings())); } DlgPrefController::~DlgPrefController() { @@ -107,13 +117,14 @@ void DlgPrefController::showLearningWizard() { // learning dialog. If we don't apply the settings first and open the // device, the dialog won't react to controller messages. if (m_ui.chkEnabledDevice->isChecked() && !m_pController->isOpen()) { - QMessageBox::StandardButton result = QMessageBox::question( - this, - tr("Apply device settings?"), - tr("Your settings must be applied before starting the learning wizard.\n" - "Apply settings and continue?"), - QMessageBox::Ok | QMessageBox::Cancel, // Buttons to be displayed - QMessageBox::Ok); // Default button + QMessageBox::StandardButton result = QMessageBox::question(this, + tr("Apply device settings?"), + tr("Your settings must be applied before starting the learning " + "wizard.\n" + "Apply settings and continue?"), + QMessageBox::Ok | + QMessageBox::Cancel, // Buttons to be displayed + QMessageBox::Ok); // Default button // Stop if the user has not pressed the Ok button, // which could be the Cancel or the Close Button. if (result != QMessageBox::Ok) { @@ -123,7 +134,7 @@ void DlgPrefController::showLearningWizard() { slotApply(); // After this point we consider the mapping wizard as dirtying the preset. - slotDirty(); + setDirty(true); // Note that DlgControllerLearning is set to delete itself on close using // the Qt::WA_DeleteOnClose attribute (so this "new" doesn't leak memory) @@ -132,23 +143,36 @@ void DlgPrefController::showLearningWizard() { ControllerLearningEventFilter* pControllerLearning = m_pControllerManager->getControllerLearningEventFilter(); pControllerLearning->startListening(); - connect(pControllerLearning, SIGNAL(controlClicked(ControlObject*)), - m_pDlgControllerLearning, SLOT(controlClicked(ControlObject*))); - connect(m_pDlgControllerLearning, SIGNAL(listenForClicks()), - pControllerLearning, SLOT(startListening())); - connect(m_pDlgControllerLearning, SIGNAL(stopListeningForClicks()), - pControllerLearning, SLOT(stopListening())); - connect(m_pDlgControllerLearning, SIGNAL(stopLearning()), - this, SLOT(show())); - connect(m_pDlgControllerLearning, SIGNAL(inputMappingsLearned(MidiInputMappings)), - this, SLOT(midiInputMappingsLearned(MidiInputMappings))); + connect(pControllerLearning, + SIGNAL(controlClicked(ControlObject*)), + m_pDlgControllerLearning, + SLOT(controlClicked(ControlObject*))); + connect(m_pDlgControllerLearning, + SIGNAL(listenForClicks()), + pControllerLearning, + SLOT(startListening())); + connect(m_pDlgControllerLearning, + SIGNAL(stopListeningForClicks()), + pControllerLearning, + SLOT(stopListening())); + connect(m_pDlgControllerLearning, + SIGNAL(stopLearning()), + this, + SLOT(show())); + connect(m_pDlgControllerLearning, + SIGNAL(inputMappingsLearned(MidiInputMappings)), + this, + SLOT(midiInputMappingsLearned(MidiInputMappings))); emit mappingStarted(); - connect(m_pDlgControllerLearning, SIGNAL(stopLearning()), - this, SIGNAL(mappingEnded())); + connect(m_pDlgControllerLearning, + SIGNAL(stopLearning()), + this, + SIGNAL(mappingEnded())); } -void DlgPrefController::midiInputMappingsLearned(const MidiInputMappings& mappings) { +void DlgPrefController::midiInputMappingsLearned( + const MidiInputMappings& mappings) { // This is just a shortcut since doing a round-trip from Learning -> // Controller -> slotPresetLoaded -> setPreset is too heavyweight. if (m_pInputTableModel != NULL) { @@ -156,7 +180,8 @@ void DlgPrefController::midiInputMappingsLearned(const MidiInputMappings& mappin } } -QString DlgPrefController::presetShortName(const ControllerPresetPointer pPreset) const { +QString DlgPrefController::presetShortName( + const ControllerPresetPointer pPreset) const { QString presetName = tr("None"); if (pPreset) { QString name = pPreset->name(); @@ -173,7 +198,8 @@ QString DlgPrefController::presetShortName(const ControllerPresetPointer pPreset return presetName; } -QString DlgPrefController::presetName(const ControllerPresetPointer pPreset) const { +QString DlgPrefController::presetName( + const ControllerPresetPointer pPreset) const { if (pPreset) { QString name = pPreset->name(); if (name.length() > 0) @@ -182,7 +208,8 @@ QString DlgPrefController::presetName(const ControllerPresetPointer pPreset) con return tr("No Name"); } -QString DlgPrefController::presetDescription(const ControllerPresetPointer pPreset) const { +QString DlgPrefController::presetDescription( + const ControllerPresetPointer pPreset) const { if (pPreset) { QString description = pPreset->description(); if (description.length() > 0) @@ -191,7 +218,8 @@ QString DlgPrefController::presetDescription(const ControllerPresetPointer pPres return tr("No Description"); } -QString DlgPrefController::presetAuthor(const ControllerPresetPointer pPreset) const { +QString DlgPrefController::presetAuthor( + const ControllerPresetPointer pPreset) const { if (pPreset) { QString author = pPreset->author(); if (author.length() > 0) @@ -200,7 +228,8 @@ QString DlgPrefController::presetAuthor(const ControllerPresetPointer pPreset) c return tr("No Author"); } -QString DlgPrefController::presetForumLink(const ControllerPresetPointer pPreset) const { +QString DlgPrefController::presetForumLink( + const ControllerPresetPointer pPreset) const { QString url; if (pPreset) { QString link = pPreset->forumlink(); @@ -210,7 +239,8 @@ QString DlgPrefController::presetForumLink(const ControllerPresetPointer pPreset return url; } -QString DlgPrefController::presetWikiLink(const ControllerPresetPointer pPreset) const { +QString DlgPrefController::presetWikiLink( + const ControllerPresetPointer pPreset) const { QString url; if (pPreset) { QString link = pPreset->wikilink(); @@ -220,7 +250,8 @@ QString DlgPrefController::presetWikiLink(const ControllerPresetPointer pPreset) return url; } -QString DlgPrefController::presetScriptFileLinks(const ControllerPresetPointer pPreset) const { +QString DlgPrefController::presetScriptFileLinks( + const ControllerPresetPointer pPreset) const { if (!pPreset) { return QString(); } @@ -233,9 +264,12 @@ QString DlgPrefController::presetScriptFileLinks(const ControllerPresetPointer p script.name + QStringLiteral(""); if (!script.file.exists()) { - scriptFileLink += QStringLiteral(" (") + tr("missing") + QStringLiteral(")"); - } else if (script.file.absoluteFilePath().startsWith(systemPresetPath)) { - scriptFileLink += QStringLiteral(" (") + tr("built-in") + QStringLiteral(")"); + scriptFileLink += + QStringLiteral(" (") + tr("missing") + QStringLiteral(")"); + } else if (script.file.absoluteFilePath().startsWith( + systemPresetPath)) { + scriptFileLink += + QStringLiteral(" (") + tr("built-in") + QStringLiteral(")"); } linkList << scriptFileLink; @@ -243,11 +277,7 @@ QString DlgPrefController::presetScriptFileLinks(const ControllerPresetPointer p return linkList.join("
"); } -void DlgPrefController::slotDirty() { - m_bDirty = true; -} - -void DlgPrefController::enumeratePresets() { +void DlgPrefController::enumeratePresets(const QString& selectedPresetPath) { m_ui.comboBoxPreset->clear(); // qDebug() << "Enumerating presets for controller" << m_pController->getName(); @@ -262,7 +292,8 @@ void DlgPrefController::enumeratePresets() { // Enumerate user presets QIcon userPresetIcon(":/images/ic_custom.svg"); PresetInfo userPresetsMatch = enumeratePresetsFromEnumerator( - m_pControllerManager->getMainThreadUserPresetEnumerator(), userPresetIcon); + m_pControllerManager->getMainThreadUserPresetEnumerator(), + userPresetIcon); if (userPresetsMatch.isValid()) { match = userPresetsMatch; } @@ -273,18 +304,16 @@ void DlgPrefController::enumeratePresets() { // Enumerate system presets QIcon systemPresetIcon(":/images/ic_mixxx_symbolic.svg"); PresetInfo systemPresetsMatch = enumeratePresetsFromEnumerator( - m_pControllerManager->getMainThreadSystemPresetEnumerator(), systemPresetIcon); + m_pControllerManager->getMainThreadSystemPresetEnumerator(), + systemPresetIcon); if (systemPresetsMatch.isValid()) { match = systemPresetsMatch; } - QString configuredPresetFile = m_pControllerManager->getConfiguredPresetFileForDevice( - m_pController->getName()); - // Preselect configured or matching preset int index = -1; - if (!configuredPresetFile.isEmpty()) { - index = m_ui.comboBoxPreset->findData(configuredPresetFile); + if (!selectedPresetPath.isEmpty()) { + index = m_ui.comboBoxPreset->findData(selectedPresetPath); } else if (match.isValid()) { index = m_ui.comboBoxPreset->findText(match.getName()); } @@ -304,11 +333,13 @@ PresetInfo DlgPrefController::enumeratePresetsFromEnumerator( // re-enumerate on the next open of the preferences. if (!pPresetEnumerator.isNull()) { // Get a list of presets in alphabetical order - QList systemPresets = pPresetEnumerator->getPresetsByExtension( - m_pController->presetExtension()); + QList systemPresets = + pPresetEnumerator->getPresetsByExtension( + m_pController->presetExtension()); for (const PresetInfo& preset : systemPresets) { - m_ui.comboBoxPreset->addItem(icon, preset.getName(), preset.getPath()); + m_ui.comboBoxPreset->addItem( + icon, preset.getName(), preset.getPath()); if (m_pController->matchPreset(preset)) { match = preset; } @@ -319,7 +350,8 @@ PresetInfo DlgPrefController::enumeratePresetsFromEnumerator( } void DlgPrefController::slotUpdate() { - enumeratePresets(); + enumeratePresets(m_pControllerManager->getConfiguredPresetFileForDevice( + m_pController->getName())); // Check if the controller is open. bool deviceOpen = m_pController->isOpen(); @@ -335,64 +367,121 @@ void DlgPrefController::slotUpdate() { } void DlgPrefController::slotCancel() { - if (m_pInputTableModel != NULL) { + slotShowPreset(m_pController->getPreset()); +} + +void DlgPrefController::revertPresetChanges() { + if (m_pInputTableModel) { m_pInputTableModel->cancel(); } - if (m_pOutputTableModel != NULL) { + if (m_pOutputTableModel) { m_pOutputTableModel->cancel(); } } +void DlgPrefController::applyPresetChanges() { + if (m_pInputTableModel) { + m_pInputTableModel->apply(); + } + + if (m_pOutputTableModel) { + m_pOutputTableModel->apply(); + } +} + void DlgPrefController::slotApply() { - if (m_bDirty) { - // Apply the presets and load the resulting preset. - if (m_pInputTableModel != NULL) { - m_pInputTableModel->apply(); - } + applyPresetChanges(); - if (m_pOutputTableModel != NULL) { - m_pOutputTableModel->apply(); - } + // If no changes were made, do nothing + if (!isDirty() && (!m_pPreset || m_pPreset->isDirty())) { + return; + } - // Load the resulting preset (which has been mutated by the input/output - // table models). The controller clones the preset so we aren't touching - // the same preset. - emit loadPreset(m_pController, m_pPreset); - - bool wantEnabled = m_ui.chkEnabledDevice->isChecked(); - bool enabled = m_pController->isOpen(); - if (wantEnabled && !enabled) { - enableDevice(); - } else if (!wantEnabled && enabled) { - disableDevice(); + bool bEnabled = false; + if (m_pPreset) { + bEnabled = m_ui.chkEnabledDevice->isChecked(); + + if (m_pPreset->isDirty()) { + savePreset(); } + } + m_ui.chkEnabledDevice->setChecked(bEnabled); - m_bDirty = false; + // The shouldn't be dirty at this pint because we already tried to save + // it. If that failed, don't apply the preset. + if (m_pPreset && m_pPreset->isDirty()) { + return; } + + // Load the resulting preset (which has been mutated by the input/output + // table models). The controller clones the preset so we aren't touching + // the same preset. + emit applyPreset(m_pController, m_pPreset, bEnabled); } -void DlgPrefController::slotLoadPreset(int chosenIndex) { +void DlgPrefController::slotPresetSelected(int chosenIndex) { + QString presetPath; if (chosenIndex == 0) { - // User picked no preset + // User picked "No Preset" item m_ui.chkEnabledDevice->setEnabled(false); - return; + } else { + // User picked a preset + m_ui.chkEnabledDevice->setEnabled(true); + + presetPath = m_ui.comboBoxPreset->itemData(chosenIndex).toString(); + } + + if (m_pControllerManager->getConfiguredPresetFileForDevice( + m_pController->getName()) != presetPath) { + setDirty(true); + } + + applyPresetChanges(); + if (m_pPreset && m_pPreset->isDirty()) { + if (QMessageBox::question(this, + tr("Preset has been edited"), + tr("Do you want to save the changes?")) == + QMessageBox::Yes) { + savePreset(); + } } - m_ui.chkEnabledDevice->setEnabled(true); - const QString presetPath = m_ui.comboBoxPreset->itemData(chosenIndex).toString(); ControllerPresetPointer pPreset = ControllerPresetFileHandler::loadPreset( presetPath, QDir(resourcePresetsPath(m_pConfig))); - if (!pPreset) { + if (pPreset) { + DEBUG_ASSERT(!pPreset->isDirty()); + } + + slotShowPreset(pPreset); +} + +void DlgPrefController::savePreset() { + VERIFY_OR_DEBUG_ASSERT(m_pPreset) { + return; + } + + if (!m_pPreset->isDirty()) { + qDebug() << "Preset is not dirty, no need to save it."; return; } - // TODO(rryan): We really should not load the preset here. We should load it - // into the preferences GUI and then load it to the actual controller once - // the user hits apply. - emit loadPreset(m_pController, pPreset); - slotDirty(); + if (m_pPreset->filePath().startsWith(resourcePresetsPath(m_pConfig))) { + m_pPreset->setName(QString(tr("%1 (edited)")).arg(m_pPreset->name())); + qDebug() << "Renamed preset to " << m_pPreset->name(); + } + + QString fileName = QFileInfo(m_pPreset->filePath()).fileName(); + QString filePath = QDir(userPresetsPath(m_pConfig)).absoluteFilePath(fileName); + if (!m_pPreset->savePreset(filePath)) { + qDebug() << "Failed to save preset!"; + } + + m_pPreset->setFilePath(filePath); + m_pPreset->setDirty(false); + + enumeratePresets(m_pPreset->filePath()); } void DlgPrefController::initTableView(QTableView* pTable) { @@ -415,7 +504,7 @@ void DlgPrefController::initTableView(QTableView* pTable) { pTable->setAlternatingRowColors(true); } -void DlgPrefController::slotPresetLoaded(ControllerPresetPointer preset) { +void DlgPrefController::slotShowPreset(ControllerPresetPointer preset) { m_ui.labelLoadedPreset->setText(presetName(preset)); m_ui.labelLoadedPresetDescription->setText(presetDescription(preset)); m_ui.labelLoadedPresetAuthor->setText(presetAuthor(preset)); @@ -451,13 +540,6 @@ void DlgPrefController::slotPresetLoaded(ControllerPresetPointer preset) { ControllerInputMappingTableModel* pInputModel = new ControllerInputMappingTableModel(this); - // If the model reports changes, mark ourselves as dirty. - connect(pInputModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), - this, SLOT(slotDirty())); - connect(pInputModel, SIGNAL(rowsInserted(QModelIndex, int, int)), - this, SLOT(slotDirty())); - connect(pInputModel, SIGNAL(rowsRemoved(QModelIndex, int, int)), - this, SLOT(slotDirty())); pInputModel->setPreset(preset); QSortFilterProxyModel* pInputProxyModel = new QSortFilterProxyModel(this); @@ -505,23 +587,6 @@ void DlgPrefController::slotPresetLoaded(ControllerPresetPointer preset) { m_pOutputTableModel = pOutputModel; } -void DlgPrefController::slotEnableDevice(bool enable) { - slotDirty(); - - // Set tree item text to normal/bold. - emit controllerEnabled(this, enable); -} - -void DlgPrefController::enableDevice() { - emit openController(m_pController); - //TODO: Should probably check if open() actually succeeded. -} - -void DlgPrefController::disableDevice() { - emit closeController(m_pController); - //TODO: Should probably check if close() actually succeeded. -} - void DlgPrefController::addInputMapping() { if (m_pInputTableModel) { m_pInputTableModel->addEmptyMapping(); @@ -534,7 +599,6 @@ void DlgPrefController::addInputMapping() { m_ui.m_pInputMappingTableView->selectionModel()->select( QItemSelection(left, right), QItemSelectionModel::Clear | QItemSelectionModel::Select); m_ui.m_pInputMappingTableView->scrollTo(left); - slotDirty(); } } @@ -545,7 +609,6 @@ void DlgPrefController::removeInputMappings() { QModelIndexList selectedIndices = selection.indexes(); if (selectedIndices.size() > 0 && m_pInputTableModel) { m_pInputTableModel->removeMappings(selectedIndices); - slotDirty(); } } } @@ -559,7 +622,6 @@ void DlgPrefController::clearAllInputMappings() { } if (m_pInputTableModel) { m_pInputTableModel->clear(); - slotDirty(); } } @@ -575,7 +637,6 @@ void DlgPrefController::addOutputMapping() { m_ui.m_pOutputMappingTableView->selectionModel()->select( QItemSelection(left, right), QItemSelectionModel::Clear | QItemSelectionModel::Select); m_ui.m_pOutputMappingTableView->scrollTo(left); - slotDirty(); } } @@ -586,7 +647,6 @@ void DlgPrefController::removeOutputMappings() { QModelIndexList selectedIndices = selection.indexes(); if (selectedIndices.size() > 0 && m_pOutputTableModel) { m_pOutputTableModel->removeMappings(selectedIndices); - slotDirty(); } } } @@ -600,6 +660,5 @@ void DlgPrefController::clearAllOutputMappings() { } if (m_pOutputTableModel) { m_pOutputTableModel->clear(); - slotDirty(); } } diff --git a/src/controllers/dlgprefcontroller.h b/src/controllers/dlgprefcontroller.h index 30c354de9b6..2e066357bdf 100644 --- a/src/controllers/dlgprefcontroller.h +++ b/src/controllers/dlgprefcontroller.h @@ -40,24 +40,16 @@ class DlgPrefController : public DlgPreferencePage { void slotCancel(); // Called when preference dialog (not this dialog) is displayed. void slotUpdate(); - // Called when the user toggles the enabled checkbox. - void slotEnableDevice(bool enable); - // Called when the user selects a preset from the combobox. - void slotLoadPreset(int index); - // Mark that we need to apply the settings. - void slotDirty(); signals: - void controllerEnabled(DlgPrefController*, bool); - void openController(Controller* pController); - void closeController(Controller* pController); - void loadPreset(Controller* pController, QString controllerName); - void loadPreset(Controller* pController, ControllerPresetPointer pPreset); + void applyPreset(Controller* pController, ControllerPresetPointer pPreset, bool bEnabled); void mappingStarted(); void mappingEnded(); private slots: - void slotPresetLoaded(ControllerPresetPointer preset); + // Called when the user toggles the enabled checkbox. + void slotPresetSelected(int index); + void slotShowPreset(ControllerPresetPointer preset); // Input mappings void addInputMapping(); @@ -80,11 +72,35 @@ class DlgPrefController : public DlgPreferencePage { QString presetForumLink(const ControllerPresetPointer pPreset) const; QString presetWikiLink(const ControllerPresetPointer pPreset) const; QString presetScriptFileLinks(const ControllerPresetPointer pPreset) const; - void savePreset(QString path); + void revertPresetChanges(); + void applyPresetChanges(); + void savePreset(); void initTableView(QTableView* pTable); + /** Set dirty state (i.e. changes have been made). + * + * When this preferences page is marked as "dirty", changes have occured + * that can be applied or discarded. + * + * @param bDirty The new dialog's dirty state. + */ + void setDirty(bool bDirty) { + m_bDirty = bDirty; + } + + /** Set dirty state (i.e. changes have been made). + * + * When this preferences page is marked as "dirty", changes have occured + * that can be applied or discarded. + * + * @param bDirty The new dialog's dirty state. + */ + bool isDirty() { + return m_bDirty; + } + // Reload the mappings in the dropdown dialog - void enumeratePresets(); + void enumeratePresets(const QString& selectedPresetPath); PresetInfo enumeratePresetsFromEnumerator( QSharedPointer pPresetEnumerator, QIcon icon = QIcon()); diff --git a/src/controllers/dlgprefcontrollers.cpp b/src/controllers/dlgprefcontrollers.cpp index babf12c0887..3af59017f85 100644 --- a/src/controllers/dlgprefcontrollers.cpp +++ b/src/controllers/dlgprefcontrollers.cpp @@ -55,11 +55,6 @@ void DlgPrefControllers::slotApply() { foreach (DlgPrefController* pControllerWindows, m_controllerWindows) { pControllerWindows->slotApply(); } - - // Save all controller presets. - // TODO(rryan): Get rid of this and make DlgPrefController do this for each - // preset. - m_pControllerManager->savePresets(); } bool DlgPrefControllers::handleTreeItemClick(QTreeWidgetItem* clickedItem) { @@ -116,8 +111,11 @@ void DlgPrefControllers::setupControllerWidgets() { m_controllerWindows.append(controllerDlg); m_pDlgPreferences->addPageWidget(controllerDlg); - connect(controllerDlg, SIGNAL(controllerEnabled(DlgPrefController*, bool)), - this, SLOT(slotHighlightDevice(DlgPrefController*, bool))); + connect(pController, + &Controller::openChanged, + [this, controllerDlg](bool bOpen) { + slotHighlightDevice(controllerDlg, bOpen); + }); QTreeWidgetItem * controllerWindowLink = new QTreeWidgetItem(QTreeWidgetItem::Type); controllerWindowLink->setIcon(0, QIcon(":/images/preferences/ic_preferences_controllers.png")); From ffec734edd0dc85ba85d4493abb4b0d62ce3470d Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 18:59:31 +0200 Subject: [PATCH 45/55] controllers/dlgprefcontroller: Reload user presets after saving --- src/controllers/controllerpresetinfoenumerator.cpp | 4 ++++ src/controllers/controllerpresetinfoenumerator.h | 2 -- src/controllers/dlgprefcontroller.cpp | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/controllers/controllerpresetinfoenumerator.cpp b/src/controllers/controllerpresetinfoenumerator.cpp index 14f43a247eb..becbad20a4d 100644 --- a/src/controllers/controllerpresetinfoenumerator.cpp +++ b/src/controllers/controllerpresetinfoenumerator.cpp @@ -52,6 +52,10 @@ QList PresetInfoEnumerator::getPresetsByExtension(const QString& ext } void PresetInfoEnumerator::loadSupportedPresets() { + m_midiPresets.clear(); + m_hidPresets.clear(); + m_bulkPresets.clear(); + for (const QString& dirPath : m_controllerDirPaths) { QDirIterator it(dirPath); while (it.hasNext()) { diff --git a/src/controllers/controllerpresetinfoenumerator.h b/src/controllers/controllerpresetinfoenumerator.h index 24b5a7be4db..07a71dfd10d 100644 --- a/src/controllers/controllerpresetinfoenumerator.h +++ b/src/controllers/controllerpresetinfoenumerator.h @@ -20,8 +20,6 @@ class PresetInfoEnumerator { // Return cached list of presets for this extension QList getPresetsByExtension(const QString& extension); - - protected: void loadSupportedPresets(); private: diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 1b54eb42a39..19e64b53db1 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -291,6 +291,10 @@ void DlgPrefController::enumeratePresets(const QString& selectedPresetPath) { PresetInfo match; // Enumerate user presets QIcon userPresetIcon(":/images/ic_custom.svg"); + + // Reload user presets to detect added, changed or removed mappings + m_pControllerManager->getMainThreadUserPresetEnumerator()->loadSupportedPresets(); + PresetInfo userPresetsMatch = enumeratePresetsFromEnumerator( m_pControllerManager->getMainThreadUserPresetEnumerator(), userPresetIcon); From c562f66872f90825c19912fc184c1abb17bd33f4 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 19:04:11 +0200 Subject: [PATCH 46/55] controllers/dlgprefcontroller: Remove obsolete method --- src/controllers/dlgprefcontroller.cpp | 10 ---------- src/controllers/dlgprefcontroller.h | 1 - 2 files changed, 11 deletions(-) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 19e64b53db1..692808518df 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -374,16 +374,6 @@ void DlgPrefController::slotCancel() { slotShowPreset(m_pController->getPreset()); } -void DlgPrefController::revertPresetChanges() { - if (m_pInputTableModel) { - m_pInputTableModel->cancel(); - } - - if (m_pOutputTableModel) { - m_pOutputTableModel->cancel(); - } -} - void DlgPrefController::applyPresetChanges() { if (m_pInputTableModel) { m_pInputTableModel->apply(); diff --git a/src/controllers/dlgprefcontroller.h b/src/controllers/dlgprefcontroller.h index 2e066357bdf..084e46b306e 100644 --- a/src/controllers/dlgprefcontroller.h +++ b/src/controllers/dlgprefcontroller.h @@ -72,7 +72,6 @@ class DlgPrefController : public DlgPreferencePage { QString presetForumLink(const ControllerPresetPointer pPreset) const; QString presetWikiLink(const ControllerPresetPointer pPreset) const; QString presetScriptFileLinks(const ControllerPresetPointer pPreset) const; - void revertPresetChanges(); void applyPresetChanges(); void savePreset(); void initTableView(QTableView* pTable); From b4db43b63e6bc3965c59859307bf3cde3448d307 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 19:33:25 +0200 Subject: [PATCH 47/55] controllers/dlgprefcontroller: Fix dirty detection in slotApply() --- src/controllers/dlgprefcontroller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 692808518df..4a29e6af4c8 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -388,7 +388,7 @@ void DlgPrefController::slotApply() { applyPresetChanges(); // If no changes were made, do nothing - if (!isDirty() && (!m_pPreset || m_pPreset->isDirty())) { + if (!(isDirty() || (m_pPreset && m_pPreset->isDirty()))) { return; } From 6dcffced4be30f77cad34d3c45566de0a362ec6e Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 20:19:27 +0200 Subject: [PATCH 48/55] controllers/dlgprefcontroller: Reset dialog dirty state on apply --- src/controllers/dlgprefcontroller.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 4a29e6af4c8..e440bda1ddf 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -412,6 +412,9 @@ void DlgPrefController::slotApply() { // table models). The controller clones the preset so we aren't touching // the same preset. emit applyPreset(m_pController, m_pPreset, bEnabled); + + // Mark the dialog as not dirty + setDirty(false); } void DlgPrefController::slotPresetSelected(int chosenIndex) { From 47f1ccd59c1d846a38677144dd53ab69dfb16f29 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 21:10:45 +0200 Subject: [PATCH 49/55] controllers/dlgprefcontroller: Remove wrong dirty state change --- src/controllers/dlgprefcontroller.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index e440bda1ddf..5e770955aab 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -133,9 +133,6 @@ void DlgPrefController::showLearningWizard() { } slotApply(); - // After this point we consider the mapping wizard as dirtying the preset. - setDirty(true); - // Note that DlgControllerLearning is set to delete itself on close using // the Qt::WA_DeleteOnClose attribute (so this "new" doesn't leak memory) m_pDlgControllerLearning = new DlgControllerLearning(this, m_pController); From 420ceb91b45fcfedb0e4c7629362ec43677b033c Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 21:11:13 +0200 Subject: [PATCH 50/55] controllers/dlgprefcontroller: Add acomment --- src/controllers/dlgprefcontroller.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 5e770955aab..ab6ed7bd88a 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -426,6 +426,7 @@ void DlgPrefController::slotPresetSelected(int chosenIndex) { presetPath = m_ui.comboBoxPreset->itemData(chosenIndex).toString(); } + // Check if the preset is different from the configured preset if (m_pControllerManager->getConfiguredPresetFileForDevice( m_pController->getName()) != presetPath) { setDirty(true); From 54c38e11279810b74c27cdce76a016d0c4ca10ff Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Apr 2020 23:46:09 +0200 Subject: [PATCH 51/55] controllers/controllermanager: Return QFileInfo in findPresetFile() --- src/controllers/controllermanager.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 17ce5433c20..6bc5f42e744 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -45,21 +45,20 @@ QString sanitizeDeviceName(QString name) { return name.replace(" ", "_").replace("/", "_").replace("\\", "_"); } -QString findPresetFile(const QString& pathOrFilename, const QStringList& paths) { +QFileInfo findPresetFile(const QString& pathOrFilename, const QStringList& paths) { QFileInfo fileInfo(pathOrFilename); if (fileInfo.isAbsolute()) { - return pathOrFilename; + return fileInfo; } for (const QString& path : paths) { - QDir pathDir(path); - - if (pathDir.exists(pathOrFilename)) { - return pathDir.absoluteFilePath(pathOrFilename); + fileInfo = QFileInfo(QDir(path).absoluteFilePath(pathOrFilename)); + if (fileInfo.exists()) { + return fileInfo; } } - return QString(); + return QFileInfo(); } } // anonymous namespace @@ -252,21 +251,21 @@ void ControllerManager::slotSetUpDevices() { } // Check if device has a configured preset - QString presetFile = getConfiguredPresetFileForDevice(deviceName); - if (presetFile.isEmpty()) { + QString presetFilePath = getConfiguredPresetFileForDevice(deviceName); + if (presetFilePath.isEmpty()) { continue; } - qDebug() << "Searching for controller preset" << presetFile + qDebug() << "Searching for controller preset" << presetFilePath << "in paths:" << presetPaths.join(","); - QString presetFilePath = findPresetFile(presetFile, presetPaths); - if (presetFilePath.isEmpty()) { + QFileInfo presetFile = findPresetFile(presetFilePath, presetPaths); + if (!presetFile.exists()) { qDebug() << "Could not find" << presetFilePath << "in any preset path."; continue; } ControllerPresetPointer pPreset = ControllerPresetFileHandler::loadPreset( - QFileInfo(presetFilePath), resourcePresetsPath(m_pConfig)); + presetFile, resourcePresetsPath(m_pConfig)); if (!pPreset) { continue; From 00ad201acc04b3443b26d6f363e24163e6ed83ba Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 9 Apr 2020 01:16:17 +0200 Subject: [PATCH 52/55] controllers/dlgprefcontroller: Add edited suffix to filenames This allows editing user controller scripts (e.g. downloaded from the forum) as well. --- src/controllers/dlgprefcontroller.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index ab6ed7bd88a..3a2c99a58fd 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -462,13 +462,24 @@ void DlgPrefController::savePreset() { return; } - if (m_pPreset->filePath().startsWith(resourcePresetsPath(m_pConfig))) { - m_pPreset->setName(QString(tr("%1 (edited)")).arg(m_pPreset->name())); + QFileInfo fileInfo(m_pPreset->filePath()); + QString fileName = fileInfo.fileName(); + + // Add " (edited)" to preset name (if it's not already present) + QString editedSuffix = QStringLiteral(" (") + tr("edited") + QStringLiteral(")"); + if (!m_pPreset->name().endsWith(editedSuffix)) { + m_pPreset->setName(m_pPreset->name() + editedSuffix); qDebug() << "Renamed preset to " << m_pPreset->name(); - } - QString fileName = QFileInfo(m_pPreset->filePath()).fileName(); + // Add " (edited)" to file name (if it's not already present) + QString baseName = fileInfo.baseName(); + if (baseName.endsWith(editedSuffix)) { + baseName.chop(editedSuffix.size()); + } + fileName = baseName + editedSuffix + QStringLiteral(".") + fileInfo.completeSuffix(); + } QString filePath = QDir(userPresetsPath(m_pConfig)).absoluteFilePath(fileName); + if (!m_pPreset->savePreset(filePath)) { qDebug() << "Failed to save preset!"; } From 419ccf468c101e67fe5cb14818c42b0e5fcc8501 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 9 Apr 2020 02:06:00 +0200 Subject: [PATCH 53/55] controllers/dlgprefcontroller: Tick Enabled checkbox on preset change --- src/controllers/dlgprefcontroller.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 3a2c99a58fd..4ac394989b7 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -419,10 +419,20 @@ void DlgPrefController::slotPresetSelected(int chosenIndex) { if (chosenIndex == 0) { // User picked "No Preset" item m_ui.chkEnabledDevice->setEnabled(false); + + if (m_ui.chkEnabledDevice->isChecked()) { + m_ui.chkEnabledDevice->setChecked(false); + setDirty(true); + } } else { // User picked a preset m_ui.chkEnabledDevice->setEnabled(true); + if (!m_ui.chkEnabledDevice->isChecked()) { + m_ui.chkEnabledDevice->setChecked(true); + setDirty(true); + } + presetPath = m_ui.comboBoxPreset->itemData(chosenIndex).toString(); } From b9079e040c7a948cb029ea0bca76d0b0d3b800b0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 9 Apr 2020 11:15:06 +0200 Subject: [PATCH 54/55] controllers/dlgprefcontroller: Display "No scripts" for scriptless presets --- src/controllers/dlgprefcontroller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/dlgprefcontroller.cpp b/src/controllers/dlgprefcontroller.cpp index 4ac394989b7..e281bbb5011 100644 --- a/src/controllers/dlgprefcontroller.cpp +++ b/src/controllers/dlgprefcontroller.cpp @@ -249,8 +249,8 @@ QString DlgPrefController::presetWikiLink( QString DlgPrefController::presetScriptFileLinks( const ControllerPresetPointer pPreset) const { - if (!pPreset) { - return QString(); + if (!pPreset || pPreset->getScriptFiles().empty()) { + return tr("No Scripts"); } QString systemPresetPath = resourcePresetsPath(m_pConfig); From 4760291684b6bd79f4e5d09ddc2f32337eba1693 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 9 Apr 2020 12:52:16 +0200 Subject: [PATCH 55/55] controllers: Fix comments and include guards --- src/controllers/controller.h | 20 +++---- .../controllerinputmappingtablemodel.h | 12 ++-- src/controllers/controllermanager.cpp | 4 +- .../controlleroutputmappingtablemodel.h | 12 ++-- src/controllers/controllerpreset.h | 31 ++++------- .../controllerpresetfilehandler.cpp | 28 ++++------ src/controllers/controllerpresetfilehandler.h | 55 +++++++++---------- src/controllers/dlgprefcontroller.h | 42 +++++++------- src/controllers/dlgprefcontrollers.h | 7 +-- src/controllers/hid/hidcontrollerpreset.cpp | 16 +++--- src/controllers/hid/hidcontrollerpreset.h | 11 ++-- src/controllers/midi/midicontroller.h | 23 ++++---- src/controllers/midi/midicontrollerpreset.cpp | 16 +++--- src/controllers/midi/midicontrollerpreset.h | 16 ++---- src/test/learningutilstest.cpp | 7 +-- 15 files changed, 130 insertions(+), 170 deletions(-) diff --git a/src/controllers/controller.h b/src/controllers/controller.h index 058537f5a81..06fed55a482 100644 --- a/src/controllers/controller.h +++ b/src/controllers/controller.h @@ -26,9 +26,9 @@ class Controller : public QObject, ConstControllerPresetVisitor { explicit Controller(UserSettingsPointer pConfig); ~Controller() override; // Subclass should call close() at minimum. - // Returns the extension for the controller (type) preset files. This is - // used by the ControllerManager to display only relevant preset files for - // the controller (type.) + /// Returns the extension for the controller (type) preset files. This is + /// used by the ControllerManager to display only relevant preset files for + /// the controller (type.) virtual QString presetExtension() = 0; void setPreset(const ControllerPreset& preset) { @@ -69,6 +69,7 @@ class Controller : public QObject, ConstControllerPresetVisitor { // preset, not a pointer to the preset itself. void presetLoaded(ControllerPresetPointer pPreset); + /// Emitted when the controller is opened or closed. void openChanged(bool bOpen); // Making these slots protected/private ensures that other parts of Mixxx can @@ -82,13 +83,12 @@ class Controller : public QObject, ConstControllerPresetVisitor { // this if they have an alternate way of handling such data.) virtual void receive(const QByteArray data, mixxx::Duration timestamp); - /** Apply the preset to the controller. - * @brief Initializes both controller engine and static output mappings. - * - * @param initializeScripts Can be set to false to skip script - * initialization for unit tests. - * @return Returns whether it was successful. - */ + /// Apply the preset to the controller. + /// @brief Initializes both controller engine and static output mappings. + /// + /// @param initializeScripts Can be set to false to skip script + /// initialization for unit tests. + /// @return Returns whether it was successful. virtual bool applyPreset(bool initializeScripts = true); // Puts the controller in and out of learning mode. diff --git a/src/controllers/controllerinputmappingtablemodel.h b/src/controllers/controllerinputmappingtablemodel.h index 6abaa5ed6d0..40d51d08c63 100644 --- a/src/controllers/controllerinputmappingtablemodel.h +++ b/src/controllers/controllerinputmappingtablemodel.h @@ -1,5 +1,4 @@ -#ifndef CONTROLLERINPUTMAPPINGTABLEMODEL_H -#define CONTROLLERINPUTMAPPINGTABLEMODEL_H +#pragma once #include #include @@ -9,10 +8,9 @@ #include "controllers/controllermappingtablemodel.h" #include "controllers/midi/midimessage.h" -/** Table Model for the "Inputs" table view in the preferences dialog. - * - * This allows editing the input mappings for a MIDI preset. - */ +/// Table Model for the "Inputs" table view in the preferences dialog. +/// +/// This allows editing the input mappings for a MIDI preset. class ControllerInputMappingTableModel : public ControllerMappingTableModel { Q_OBJECT public: @@ -68,5 +66,3 @@ class ControllerInputMappingTableModel : public ControllerMappingTableModel { QList m_midiInputMappings; }; - -#endif /* CONTROLLERINPUTMAPPINGTABLEMODEL_H */ diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 6bc5f42e744..a232fbfa294 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -39,8 +39,8 @@ const int kPollIntervalMillis = 5; const int kPollIntervalMillis = 1; #endif -// Strip slashes and spaces from device name, so that it can be used as config -// key or a filename. +/// Strip slashes and spaces from device name, so that it can be used as config +/// key or a filename. QString sanitizeDeviceName(QString name) { return name.replace(" ", "_").replace("/", "_").replace("\\", "_"); } diff --git a/src/controllers/controlleroutputmappingtablemodel.h b/src/controllers/controlleroutputmappingtablemodel.h index 317837b7fef..36be40f69a6 100644 --- a/src/controllers/controlleroutputmappingtablemodel.h +++ b/src/controllers/controlleroutputmappingtablemodel.h @@ -1,5 +1,4 @@ -#ifndef CONTROLLEROUTPUTMAPPINGTABLEMODEL_H -#define CONTROLLEROUTPUTMAPPINGTABLEMODEL_H +#pragma once #include #include @@ -9,10 +8,9 @@ #include "controllers/controllermappingtablemodel.h" #include "controllers/midi/midimessage.h" -/** Table Model for the "Outputs" table view in the preferences dialog. - * - * This allows editing the output mappings for a MIDI preset. - */ +/// Table Model for the "Outputs" table view in the preferences dialog. +/// +/// This allows editing the output mappings for a MIDI preset. class ControllerOutputMappingTableModel : public ControllerMappingTableModel { Q_OBJECT public: @@ -62,5 +60,3 @@ class ControllerOutputMappingTableModel : public ControllerMappingTableModel { QList m_midiOutputMappings; }; - -#endif /* CONTROLLEROUTPUTMAPPINGTABLEMODEL_H */ diff --git a/src/controllers/controllerpreset.h b/src/controllers/controllerpreset.h index d49f57fb7ba..e51092961de 100644 --- a/src/controllers/controllerpreset.h +++ b/src/controllers/controllerpreset.h @@ -1,15 +1,8 @@ -/** -* @file controllerpreset.h -* @author Sean Pappalardo spappalardo@mixxx.org -* @date Mon 9 Apr 2012 -* @brief Controller preset -* -* This class represents a controller preset, containing the data elements that -* make it up. -*/ - -#ifndef CONTROLLERPRESET_H -#define CONTROLLERPRESET_H +#pragma once +/// @file controllerpreset.h +/// @author Sean Pappalardo spappalardo@mixxx.org +/// @date Mon 9 Apr 2012 +/// @brief Controller Preset #include #include @@ -21,6 +14,8 @@ class ControllerPresetVisitor; class ConstControllerPresetVisitor; +/// This class represents a controller preset, containing the data elements that +/// make it up. class ControllerPreset { public: ControllerPreset() @@ -40,11 +35,11 @@ class ControllerPreset { bool builtin; }; - /** addScriptFile(QString,QString) - * Adds an entry to the list of script file names & associated list of function prefixes - * @param filename Name of the XML file to add - * @param functionprefix Function prefix to add - */ + /// Adds a script file to the list of controller scripts for this preset. + /// @param filename Name of the script file to add + /// @param functionprefix The script's function prefix (or empty string) + /// @param file A FileInfo object pointing to the script file + /// @param builtin If this is true, the script won't be written to the XML void addScriptFile(const QString& name, const QString& functionprefix, const QFileInfo& file, @@ -187,5 +182,3 @@ class ControllerPreset { }; typedef QSharedPointer ControllerPresetPointer; - -#endif diff --git a/src/controllers/controllerpresetfilehandler.cpp b/src/controllers/controllerpresetfilehandler.cpp index eb27038e4f6..6d147a6e885 100644 --- a/src/controllers/controllerpresetfilehandler.cpp +++ b/src/controllers/controllerpresetfilehandler.cpp @@ -1,10 +1,7 @@ -/** -* @file controllerpresetfilehandler.cpp -* @author Sean Pappalardo spappalardo@mixxx.org -* @date Mon 9 Apr 2012 -* @brief Handles loading and saving of Controller presets. -* -*/ +/// @file controllerpresetfilehandler.cpp +/// @author Sean Pappalardo spappalardo@mixxx.org +/// @date Mon 9 Apr 2012 +/// @brief Handles loading and saving of Controller presets. #include "controllers/controllerpresetfilehandler.h" #include "controllers/controllermanager.h" @@ -14,15 +11,14 @@ namespace { -/** Find script file in the preset or system path. - * - * @param preset The controller preset the script belongs to. - * @param filename The script filename. - * @param systemPresetsPath The system presets path to use as fallback. - * @return Returns a QFileInfo object. If the script was not found in either - * of the search directories, the QFileInfo object might point to a - * non-existing file. - */ +/// Find script file in the preset or system path. +/// +/// @param preset The controller preset the script belongs to. +/// @param filename The script filename. +/// @param systemPresetsPath The system presets path to use as fallback. +/// @return Returns a QFileInfo object. If the script was not found in either +/// of the search directories, the QFileInfo object might point to a +/// non-existing file. QFileInfo findScriptFile(ControllerPreset* preset, const QString& filename, const QDir& systemPresetsPath) { diff --git a/src/controllers/controllerpresetfilehandler.h b/src/controllers/controllerpresetfilehandler.h index fce44f55d80..2ee8c34e37d 100644 --- a/src/controllers/controllerpresetfilehandler.h +++ b/src/controllers/controllerpresetfilehandler.h @@ -1,21 +1,18 @@ #pragma once -/** -* @file controllerpresetfilehandler.h -* @author Sean Pappalardo spappalardo@mixxx.org -* @date Mon 9 Apr 2012 -* @brief Handles loading and saving of Controller presets. -* -* The ControllerPresetFileHandler is used for serializing/deserializing the -* ControllerPreset objects to/from XML files and is also responsible -* finding the script files that belong to a preset in the file system. -* -* Subclasses can implement the private load function to add support for XML -* elements that are only useful for certain mapping types. -*/ +/// @file controllerpresetfilehandler.h +/// @author Sean Pappalardo spappalardo@mixxx.org +/// @date Mon 9 Apr 2012 +/// @brief Handles loading and saving of Controller presets. #include "util/xml.h" #include "controllers/controllerpreset.h" +/// The ControllerPresetFileHandler is used for serializing/deserializing the +/// ControllerPreset objects to/from XML files and is also responsible +/// finding the script files that belong to a preset in the file system. +/// +/// Subclasses can implement the private load function to add support for XML +/// elements that are only useful for certain mapping types. class ControllerPresetFileHandler { public: ControllerPresetFileHandler() {}; @@ -24,11 +21,10 @@ class ControllerPresetFileHandler { static ControllerPresetPointer loadPreset(const QFileInfo& presetFile, const QDir& systemPresetsPath); - /** Overloaded function for convenience - * - * @param path The path to a controller preset XML file. - * @param deviceName The name/id of the controller - */ + /// Overloaded function for convenience + /// + /// @param path The path to a controller preset XML file. + /// @param systemPresetsPath Fallback directory for searching script files. ControllerPresetPointer load(const QString& path, const QDir& systemPresetsPath); // Returns just the name of a given device (everything before the first @@ -43,22 +39,21 @@ class ControllerPresetFileHandler { void parsePresetInfo(const QDomElement& root, ControllerPreset* preset) const; - /** Adds script files from XML to the ControllerPreset. - * - * This function parses the supplied QDomElement structure, finds the - * matching script files inside the search paths and adds them to - * ControllerPreset. - * - * @param root The root node of the XML document for the preset. - * @param deviceName The name/id of the controller. - * @param preset The ControllerPreset these scripts belong to. - */ + /// Adds script files from XML to the ControllerPreset. + /// + /// This function parses the supplied QDomElement structure, finds the + /// matching script files inside the search paths and adds them to + /// ControllerPreset. + /// + /// @param root The root node of the XML document for the preset. + /// @param preset The ControllerPreset these scripts belong to. + /// @param systemPresetsPath Fallback directory for searching script files. void addScriptFilesToPreset(const QDomElement& root, ControllerPreset* preset, const QDir& systemPresetsPath) const; - // Creates the XML document and includes what script files are currently - // loaded. Sub-classes need to call this before adding any other items. + /// Creates the XML document and includes what script files are currently + /// loaded. Sub-classes need to call this before adding any other items. QDomDocument buildRootWithScripts(const ControllerPreset& preset) const; bool writeDocument(QDomDocument root, const QString fileName) const; diff --git a/src/controllers/dlgprefcontroller.h b/src/controllers/dlgprefcontroller.h index 084e46b306e..45774383310 100644 --- a/src/controllers/dlgprefcontroller.h +++ b/src/controllers/dlgprefcontroller.h @@ -1,9 +1,7 @@ -/** -* @file dlgprefcontroller.h -* @author Sean M. Pappalardo spappalardo@mixxx.org -* @date Mon May 2 2011 -* @brief Configuration dialog for a single DJ controller -*/ +/// @file dlgprefcontroller.h +/// @author Sean M. Pappalardo spappalardo@mixxx.org +/// @date Mon May 2 2011 +/// @brief Configuration dialog for a single DJ controller #ifndef DLGPREFCONTROLLER_H #define DLGPREFCONTROLLER_H @@ -47,8 +45,10 @@ class DlgPrefController : public DlgPreferencePage { void mappingEnded(); private slots: - // Called when the user toggles the enabled checkbox. + /// Called when the user selects another preset in the combobox void slotPresetSelected(int index); + /// Used to selected the current preset in the combobox and display the + /// preset information. void slotShowPreset(ControllerPresetPointer preset); // Input mappings @@ -76,29 +76,27 @@ class DlgPrefController : public DlgPreferencePage { void savePreset(); void initTableView(QTableView* pTable); - /** Set dirty state (i.e. changes have been made). - * - * When this preferences page is marked as "dirty", changes have occured - * that can be applied or discarded. - * - * @param bDirty The new dialog's dirty state. - */ + /// Set dirty state (i.e. changes have been made). + /// + /// When this preferences page is marked as "dirty", changes have occured + /// that can be applied or discarded. + /// + /// @param bDirty The new dialog's dirty state. void setDirty(bool bDirty) { m_bDirty = bDirty; } - /** Set dirty state (i.e. changes have been made). - * - * When this preferences page is marked as "dirty", changes have occured - * that can be applied or discarded. - * - * @param bDirty The new dialog's dirty state. - */ + /// Set dirty state (i.e. changes have been made). + /// + /// When this preferences page is marked as "dirty", changes have occured + /// that can be applied or discarded. + /// + /// @param bDirty The new dialog's dirty state. bool isDirty() { return m_bDirty; } - // Reload the mappings in the dropdown dialog + /// Reload the mappings in the dropdown dialog void enumeratePresets(const QString& selectedPresetPath); PresetInfo enumeratePresetsFromEnumerator( QSharedPointer pPresetEnumerator, diff --git a/src/controllers/dlgprefcontrollers.h b/src/controllers/dlgprefcontrollers.h index 66be4651cf8..5e704f211ca 100644 --- a/src/controllers/dlgprefcontrollers.h +++ b/src/controllers/dlgprefcontrollers.h @@ -10,10 +10,9 @@ class DlgPreferences; class DlgPrefController; class ControllerManager; -/** Controllers Overview in the preferences - * - * This dialog allows selecting controllers for configuration. - */ +/// Controllers Overview in the preferences +/// +/// This dialog allows selecting controllers for configuration. class DlgPrefControllers : public DlgPreferencePage, public Ui::DlgPrefControllersDlg { Q_OBJECT diff --git a/src/controllers/hid/hidcontrollerpreset.cpp b/src/controllers/hid/hidcontrollerpreset.cpp index f5e8d49331e..5bcbd327255 100644 --- a/src/controllers/hid/hidcontrollerpreset.cpp +++ b/src/controllers/hid/hidcontrollerpreset.cpp @@ -1,12 +1,10 @@ -/** - * @file hidcontrollerpreset.cpp - * @author Jan Holthuis holzhaus@mixxx.org - * @date Mon 8 Apr 2020 - * @brief HID/Bulk Controller Preset - * - * This class represents a HID or Bulk controller preset, containing the data - * elements that make it up. - */ +/// @file hidcontrollerpreset.cpp +/// @author Jan Holthuis holzhaus@mixxx.org +/// @date Mon 8 Apr 2020 +/// @brief HID/Bulk Controller Preset +/// +/// This class represents a HID or Bulk controller preset, containing the data +/// elements that make it up. #include "controllers/hid/hidcontrollerpreset.h" diff --git a/src/controllers/hid/hidcontrollerpreset.h b/src/controllers/hid/hidcontrollerpreset.h index f1e2b8e36b8..77cfc7f34b3 100644 --- a/src/controllers/hid/hidcontrollerpreset.h +++ b/src/controllers/hid/hidcontrollerpreset.h @@ -1,16 +1,13 @@ #pragma once -/** - * @file hidcontrollerpreset.h - * @brief HID/Bulk Controller Preset - * - * This class represents a HID or Bulk controller preset, containing the data - * elements that make it up. - */ +/// @file hidcontrollerpreset.h +/// @brief HID/Bulk Controller Preset #include "controllers/controllerpreset.h" #include "controllers/controllerpresetvisitor.h" #include "controllers/hid/hidcontrollerpresetfilehandler.h" +/// This class represents a HID or Bulk controller preset, containing the data +/// elements that make it up. class HidControllerPreset : public ControllerPreset { public: HidControllerPreset() {} diff --git a/src/controllers/midi/midicontroller.h b/src/controllers/midi/midicontroller.h index 25a555c8373..0fe825f5661 100644 --- a/src/controllers/midi/midicontroller.h +++ b/src/controllers/midi/midicontroller.h @@ -57,9 +57,9 @@ class MidiController : public Controller { Q_INVOKABLE virtual void sendShortMsg(unsigned char status, unsigned char byte1, unsigned char byte2) = 0; - // Alias for send() - // The length parameter is here for backwards compatibility for when scripts - // were required to specify it. + /// Alias for send() + /// The length parameter is here for backwards compatibility for when scripts + /// were required to specify it. Q_INVOKABLE inline void sendSysexMsg(QList data, unsigned int length = 0) { Q_UNUSED(length); send(data); @@ -73,13 +73,12 @@ class MidiController : public Controller { int close() override; private slots: - /** Apply the preset to the controller. - * @brief Initializes both controller engine and static output mappings. - * - * @param initializeScripts Can be set to false to skip script - * initialization for unit tests. - * @return Returns whether it was successful. - */ + /// Apply the preset to the controller. + /// @brief Initializes both controller engine and static output mappings. + /// + /// @param initializeScripts Can be set to false to skip script + /// initialization for unit tests. + /// @return Returns whether it was successful. bool applyPreset(bool initializeScripts = false) override; void learnTemporaryInputMappings(const MidiInputMappings& mappings); @@ -101,8 +100,8 @@ class MidiController : public Controller { void updateAllOutputs(); void destroyOutputHandlers(); - // Returns a pointer to the currently loaded controller preset. For internal - // use only. + /// Returns a pointer to the currently loaded controller preset. For internal + /// use only. ControllerPreset* preset() override { return &m_preset; } diff --git a/src/controllers/midi/midicontrollerpreset.cpp b/src/controllers/midi/midicontrollerpreset.cpp index c3ac3efe153..31d363349ac 100644 --- a/src/controllers/midi/midicontrollerpreset.cpp +++ b/src/controllers/midi/midicontrollerpreset.cpp @@ -1,12 +1,10 @@ -/** - * @file midicontrollerpreset.cpp - * @author Jan Holthuis holzhaus@mixxx.org - * @date Wed 8 Apr 2020 - * @brief MIDI Controller Preset - * - * This class represents a MIDI controller preset, containing the data elements - * that make it up. - */ +/// @file midicontrollerpreset.cpp +/// @author Jan Holthuis holzhaus@mixxx.org +/// @date Wed 8 Apr 2020 +/// @brief MIDI Controller Preset +/// +/// This class represents a MIDI controller preset, containing the data elements +/// that make it up. #include "controllers/midi/midicontrollerpreset.h" diff --git a/src/controllers/midi/midicontrollerpreset.h b/src/controllers/midi/midicontrollerpreset.h index a2f16e5efc8..530e1e34950 100644 --- a/src/controllers/midi/midicontrollerpreset.h +++ b/src/controllers/midi/midicontrollerpreset.h @@ -1,14 +1,8 @@ #pragma once -/** - * @file midicontrollerpreset.h - * @author Sean Pappalardo spappalardo@mixxx.org - * @date Mon 9 Apr 2012 - * @brief MIDI Controller preset - * - * This class represents a MIDI controller preset, containing the data elements - * that make it up. - * - */ +/// @file midicontrollerpreset.h +/// @author Sean Pappalardo spappalardo@mixxx.org +/// @date Mon 9 Apr 2012 +/// @brief MIDI Controller preset #include @@ -16,6 +10,8 @@ #include "controllers/controllerpresetvisitor.h" #include "controllers/midi/midimessage.h" +/// This class represents a MIDI controller preset, containing the data elements +/// that make it up. class MidiControllerPreset : public ControllerPreset { public: MidiControllerPreset(){}; diff --git a/src/test/learningutilstest.cpp b/src/test/learningutilstest.cpp index 07ca3c995b2..c6e2057503b 100644 --- a/src/test/learningutilstest.cpp +++ b/src/test/learningutilstest.cpp @@ -15,10 +15,9 @@ class LearningUtilsTest : public MixxxTest { m_messages.append(qMakePair(MidiKey(status, control), value)); } - /** Check if mapping in present in mapping list. - * Similar to MidiInputMappings::contains(const MidiInputMapping&), but - * does not compare the description. - */ + /// Check if mapping in present in mapping list. + /// Similar to MidiInputMappings::contains(const MidiInputMapping&), but + /// does not compare the description. bool containsMapping(const MidiInputMappings& haystack, const MidiInputMapping& needle) { for (const MidiInputMapping& mapping : haystack) { if (mapping.key == needle.key &&