Publish LumaOps source
This commit is contained in:
@@ -0,0 +1,340 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| ManualDevicesSettingsPage.cpp |
|
||||
| |
|
||||
| User interface for OpenRGB Manually Added Devices |
|
||||
| settings page |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "ManualDevicesSettingsPage.h"
|
||||
#include "ui_ManualDevicesSettingsPage.h"
|
||||
|
||||
#include "NanoleafSettingsEntry.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "SettingsManager.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
static void ManualDevicesPageReloadCallback(void* this_ptr)
|
||||
{
|
||||
ManualDevicesSettingsPage * this_obj = (ManualDevicesSettingsPage *)this_ptr;
|
||||
|
||||
QMetaObject::invokeMethod(this_obj, "reloadList", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
ManualDevicesSettingsPage::ManualDevicesSettingsPage(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::ManualDevicesSettingsPage)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ResourceManager::get()->RegisterDetectionEndCallback(&ManualDevicesPageReloadCallback, this);
|
||||
|
||||
addDeviceMenu = new QMenu(this);
|
||||
ui->addDeviceButton->setMenu(addDeviceMenu);
|
||||
connect(addDeviceMenu, &QMenu::triggered, this, &ManualDevicesSettingsPage::onAddDeviceItemSelected);
|
||||
|
||||
QMenu* saveButtonMenu = new QMenu(this);
|
||||
saveButtonMenu->addAction(ui->ActionSaveAndRescan);
|
||||
saveButtonMenu->addAction(ui->ActionSaveNoRescan);
|
||||
ui->saveConfigurationButton->setMenu(saveButtonMenu);
|
||||
ui->saveConfigurationButton->setDefaultAction(ui->ActionSaveAndRescan);
|
||||
|
||||
reloadList();
|
||||
}
|
||||
|
||||
ManualDevicesSettingsPage::~ManualDevicesSettingsPage()
|
||||
{
|
||||
ResourceManager::get()->UnregisterDetectionEndCallback(&ManualDevicesPageReloadCallback, this);
|
||||
clearList();
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ManualDevicesSettingsPage::changeEvent(QEvent *event)
|
||||
{
|
||||
if(event->type() == QEvent::LanguageChange)
|
||||
{
|
||||
ui->retranslateUi(this);
|
||||
reloadMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void ManualDevicesSettingsPage::on_removeDeviceButton_clicked()
|
||||
{
|
||||
int cur_row = ui->deviceList->currentRow();
|
||||
|
||||
if(cur_row < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QListWidgetItem* item = ui->deviceList->takeItem(cur_row);
|
||||
|
||||
ui->deviceList->removeItemWidget(item);
|
||||
delete item;
|
||||
|
||||
BaseManualDeviceEntry* entry = entries[cur_row];
|
||||
entries.erase(entries.begin() + cur_row);
|
||||
delete entry;
|
||||
|
||||
setUnsavedChanges(true);
|
||||
}
|
||||
|
||||
void ManualDevicesSettingsPage::saveSettings()
|
||||
{
|
||||
SettingsManager* sm = ResourceManager::get()->GetSettingsManager();
|
||||
|
||||
json result;
|
||||
|
||||
/*-----------------------------------------------------------------------------*\
|
||||
| First, cache the data that will be stored as JSON |
|
||||
| We wrap data into arrays by type (except Nanoleaf) |
|
||||
| Nanoleaf stores it's data as an object with "location" as key for some reason |
|
||||
\*-----------------------------------------------------------------------------*/
|
||||
for(std::size_t idx = 0; idx < entries.size(); idx++)
|
||||
{
|
||||
std::string section = entries[idx]->getSettingsSection();
|
||||
if(section == "NanoleafDevices")
|
||||
{
|
||||
NanoleafSettingsEntry* entry = dynamic_cast<NanoleafSettingsEntry*>(entries[idx]);
|
||||
result[section]["devices"][entry->getLocation()] = entries[idx]->saveSettings();
|
||||
}
|
||||
else if(section == "PhilipsHueDevices")
|
||||
{
|
||||
result[section]["bridges"].push_back(entries[idx]->saveSettings());
|
||||
}
|
||||
else
|
||||
{
|
||||
result[section]["devices"].push_back(entries[idx]->saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Transfer data from the cached object into config sections |
|
||||
| Use ALL possible settings entry names, so that those with |
|
||||
| all entries deleted are cleared properly |
|
||||
\*---------------------------------------------------------*/
|
||||
std::vector<ManualDeviceTypeBlock> blocks = ManualDevicesTypeManager::get()->getRegisteredTypes();
|
||||
for(std::size_t i = 0; i < blocks.size(); i++)
|
||||
{
|
||||
sm->SetSettings(blocks[i].settingsSection, result[blocks[i].settingsSection]);
|
||||
}
|
||||
sm->SaveSettings();
|
||||
|
||||
setUnsavedChanges(false);
|
||||
}
|
||||
|
||||
void ManualDevicesSettingsPage::reloadMenu()
|
||||
{
|
||||
std::vector<std::string> names = ManualDevicesTypeManager::get()->getRegisteredTypeNames();
|
||||
|
||||
addDeviceMenu->clear();
|
||||
for(std::size_t i = 0; i < names.size(); i++)
|
||||
{
|
||||
QAction* action = addDeviceMenu->addAction(qApp->translate("ManualDevice", names[i].c_str()));
|
||||
action->setData(QString::fromStdString(names[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void ManualDevicesSettingsPage::reloadList()
|
||||
{
|
||||
clearList();
|
||||
addDeviceMenu->clear();
|
||||
|
||||
std::vector<ManualDeviceTypeBlock> blocks = ManualDevicesTypeManager::get()->getRegisteredTypes();
|
||||
for(std::size_t i = 0; i < blocks.size(); i++)
|
||||
{
|
||||
addEntries(blocks[i]);
|
||||
|
||||
/*------------------------------------------------------------*\
|
||||
| While we have all the data at hand, load in the menu as well |
|
||||
\*------------------------------------------------------------*/
|
||||
QAction* action = addDeviceMenu->addAction(qApp->translate("ManualDevice", blocks[i].name.c_str()));
|
||||
action->setData(QString::fromStdString(blocks[i].name));
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Refresh button state |
|
||||
\*---------------------------------------------------------*/
|
||||
setUnsavedChanges(false);
|
||||
on_deviceList_itemSelectionChanged();
|
||||
}
|
||||
|
||||
void ManualDevicesSettingsPage::onTextEditChanged()
|
||||
{
|
||||
setUnsavedChanges(true);
|
||||
}
|
||||
|
||||
void ManualDevicesSettingsPage::clearList()
|
||||
{
|
||||
std::vector<BaseManualDeviceEntry*> entries_copy;
|
||||
entries_copy.swap(entries);
|
||||
ui->deviceList->clear();
|
||||
|
||||
for(std::size_t i = 0; i < entries_copy.size(); i++)
|
||||
{
|
||||
delete entries_copy[i];
|
||||
}
|
||||
|
||||
entries_copy.clear();
|
||||
setUnsavedChanges(true);
|
||||
}
|
||||
|
||||
void ManualDevicesSettingsPage::setUnsavedChanges(bool v)
|
||||
{
|
||||
unsavedChanges = v;
|
||||
|
||||
if(v)
|
||||
{
|
||||
ui->saveConfigurationButton->setStyleSheet("font: bold");
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->saveConfigurationButton->setStyleSheet("");
|
||||
}
|
||||
}
|
||||
|
||||
bool ManualDevicesSettingsPage::checkValidToSave()
|
||||
{
|
||||
for(std::size_t i = 0; i < entries.size(); i++)
|
||||
{
|
||||
if(!entries[i]->isDataValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QListWidgetItem* ManualDevicesSettingsPage::addEntry(BaseManualDeviceEntry* entry)
|
||||
{
|
||||
if(!entry)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Find EVERY QLineEdit in the entry and get notified if ANY |
|
||||
| text in them changes - for validation |
|
||||
| Validation mostly affects the "Save" button state |
|
||||
\*---------------------------------------------------------*/
|
||||
QList<QLineEdit*> textEditList = entry->findChildren<QLineEdit*>(QString(), Qt::FindChildrenRecursively);
|
||||
for(qsizetype i = 0; i < textEditList.size(); i++)
|
||||
{
|
||||
connect(textEditList[i], &QLineEdit::textChanged, this, &ManualDevicesSettingsPage::onTextEditChanged);
|
||||
}
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem;
|
||||
|
||||
item->setSizeHint(entry->sizeHint());
|
||||
|
||||
ui->deviceList->addItem(item);
|
||||
ui->deviceList->setItemWidget(item, entry);
|
||||
ui->deviceList->show();
|
||||
|
||||
entries.push_back(entry);
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| New entries generally indicate unsaved changes |
|
||||
\*---------------------------------------------------------*/
|
||||
setUnsavedChanges(true);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void ManualDevicesSettingsPage::addEntries(const ManualDeviceTypeBlock& block)
|
||||
{
|
||||
/*---------------------------------------------------------*\
|
||||
| Spawn list entries for all config entries of one type |
|
||||
\*---------------------------------------------------------*/
|
||||
json settings = ResourceManager::get()->GetSettingsManager()->GetSettings(block.settingsSection);
|
||||
const char* array_name = "devices";
|
||||
if(block.settingsSection == "PhilipsHueDevices")
|
||||
{
|
||||
array_name = "bridges";
|
||||
}
|
||||
|
||||
if(settings.contains(array_name))
|
||||
{
|
||||
json& array_ref = settings[array_name];
|
||||
|
||||
if(!array_ref.is_array() && !array_ref.is_object())
|
||||
{
|
||||
return;
|
||||
}
|
||||
/*-----------------------------------------------------------------*\
|
||||
| Nanoleaf stores it's data as objects with location field as "key" |
|
||||
| everything else is arrays |
|
||||
| For uniformity, use iterators, as if it's always an object |
|
||||
\*-----------------------------------------------------------------*/
|
||||
for(json::const_iterator iter = array_ref.begin(); iter != array_ref.end(); ++iter)
|
||||
{
|
||||
if(!iter.value().empty())
|
||||
{
|
||||
BaseManualDeviceEntry* entry = block.spawn(iter.value());
|
||||
|
||||
/*---------------------------------------------------*\
|
||||
| Note: spawn functions are allowed to return nullptr |
|
||||
\*---------------------------------------------------*/
|
||||
if(entry)
|
||||
{
|
||||
addEntry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ManualDevicesSettingsPage::onAddDeviceItemSelected(QAction* action)
|
||||
{
|
||||
/*---------------------------------------------------------*\
|
||||
| Spawn new entry based on name |
|
||||
\*---------------------------------------------------------*/
|
||||
std::string entryName = action->data().toString().toStdString();
|
||||
BaseManualDeviceEntry* entry = ManualDevicesTypeManager::get()->spawnByTypeName(entryName, json());
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Note: spawn functions are allowed to return nullptr |
|
||||
\*---------------------------------------------------------*/
|
||||
if(entry)
|
||||
{
|
||||
QListWidgetItem* item = addEntry(entry);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Scroll to the newly added entry (last one in the list |
|
||||
\*-----------------------------------------------------*/
|
||||
if(item)
|
||||
{
|
||||
ui->deviceList->scrollToItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ManualDevicesSettingsPage::on_deviceList_itemSelectionChanged()
|
||||
{
|
||||
/*---------------------------------------------------------*\
|
||||
| Enable Remove button if any entry is selected |
|
||||
\*---------------------------------------------------------*/
|
||||
int cur_row = ui->deviceList->currentRow();
|
||||
bool anySelected = (cur_row >= 0);
|
||||
|
||||
ui->removeDeviceButton->setEnabled(anySelected);
|
||||
}
|
||||
|
||||
void ManualDevicesSettingsPage::on_ActionSaveNoRescan_triggered()
|
||||
{
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
void ManualDevicesSettingsPage::on_ActionSaveAndRescan_triggered()
|
||||
{
|
||||
saveSettings();
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Trigger rescan |
|
||||
\*---------------------------------------------------------*/
|
||||
ResourceManager::get()->RescanDevices();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user