diff -r b2fa5f89798a -r 24ba5aa3393f src/dialogs/configdialog.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dialogs/configdialog.cpp Mon Aug 31 23:23:45 2015 +0300 @@ -0,0 +1,703 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2015 Teemu Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * ===================================================================== + * + * configDialog.cxx: Settings dialog and everything related to it. + * Actual configuration core is in config.cxx. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../main.h" +#include "../ldDocument.h" +#include "../miscallenous.h" +#include "../glRenderer.h" +#include "../guiutilities.h" +#include "colorselector.h" +#include "configdialog.h" +#include "ui_configdialog.h" + +const char* g_extProgPathFilter = +#ifdef _WIN32 + "Applications (*.exe)(*.exe);;" +#endif + "All files (*.*)(*.*)"; + +ConfigDialog::ConfigDialog (QWidget* parent, ConfigDialog::Tab defaulttab, Qt::WindowFlags f) : + QDialog (parent, f), + HierarchyElement (parent), + m_settings (m_window->makeSettings (this)) +{ + ui = new Ui_ConfigDialog; + ui->setupUi (this); + + // Set defaults + applyToWidgetOptions ( + [&](QWidget* widget, QString confname) + { + QVariant value = m_settings->value (confname, m_config->defaultValueByName (confname)); + QLineEdit* le; + QSpinBox* spinbox; + QDoubleSpinBox* doublespinbox; + QSlider* slider; + QCheckBox* checkbox; + QPushButton* button; + + if ((le = qobject_cast (widget)) != null) + { + le->setText (value.toString()); + } + else if ((spinbox = qobject_cast (widget)) != null) + { + spinbox->setValue (value.toInt()); + } + else if ((doublespinbox = qobject_cast (widget)) != null) + { + doublespinbox->setValue (value.toDouble()); + } + else if ((slider = qobject_cast (widget)) != null) + { + slider->setValue (value.toInt()); + } + else if ((checkbox = qobject_cast (widget)) != null) + { + checkbox->setChecked (value.toBool()); + } + else if ((button = qobject_cast (widget)) != null) + { + setButtonBackground (button, value.toString()); + connect (button, SIGNAL (clicked()), this, SLOT (setButtonColor())); + } + else + { + print ("Unknown widget of type %1\n", widget->metaObject()->className()); + } + }); + + m_window->applyToActions ([&](QAction* act) + { + addShortcut (act); + }); + + ui->shortcutsList->setSortingEnabled (true); + ui->shortcutsList->sortItems(); + quickColors = LoadQuickColorList(); + updateQuickColorList(); + initExtProgs(); + selectPage (defaulttab); + connect (ui->shortcut_set, SIGNAL (clicked()), this, SLOT (slot_setShortcut())); + connect (ui->shortcut_reset, SIGNAL (clicked()), this, SLOT (slot_resetShortcut())); + connect (ui->shortcut_clear, SIGNAL (clicked()), this, SLOT (slot_clearShortcut())); + connect (ui->quickColor_add, SIGNAL (clicked()), this, SLOT (slot_setColor())); + connect (ui->quickColor_remove, SIGNAL (clicked()), this, SLOT (slot_delColor())); + connect (ui->quickColor_edit, SIGNAL (clicked()), this, SLOT (slot_setColor())); + connect (ui->quickColor_addSep, SIGNAL (clicked()), this, SLOT (slot_addColorSeparator())); + connect (ui->quickColor_moveUp, SIGNAL (clicked()), this, SLOT (slot_moveColor())); + connect (ui->quickColor_moveDown, SIGNAL (clicked()), this, SLOT (slot_moveColor())); + connect (ui->quickColor_clear, SIGNAL (clicked()), this, SLOT (slot_clearColors())); + connect (ui->findDownloadPath, SIGNAL (clicked (bool)), this, SLOT (slot_findDownloadFolder())); + connect (ui->buttonBox, SIGNAL (clicked (QAbstractButton*)), + this, SLOT (buttonClicked (QAbstractButton*))); + connect (ui->m_pages, SIGNAL (currentChanged (int)), this, SLOT (selectPage (int))); + connect (ui->m_pagelist, SIGNAL (currentRowChanged (int)), this, SLOT (selectPage (int))); +} + +ConfigDialog::~ConfigDialog() +{ + delete ui; +} + +void ConfigDialog::selectPage (int row) +{ + ui->m_pagelist->setCurrentRow (row); + ui->m_pages->setCurrentIndex (row); +} + +// +// Adds a shortcut entry to the list of shortcuts. +// +void ConfigDialog::addShortcut (QAction* act) +{ + ShortcutListItem* item = new ShortcutListItem; + item->setIcon (act->icon()); + item->setAction (act); + item->setSequence (act->shortcut()); + setShortcutText (item); + + // If the action doesn't have a valid icon, use an empty one + // so that the list is kept aligned. + if (act->icon().isNull()) + item->setIcon (GetIcon ("empty")); + + ui->shortcutsList->insertItem (ui->shortcutsList->count(), item); +} + +// +// Initializes the stuff in the ext programs tab +// +void ConfigDialog::initExtProgs() +{ + QGridLayout* pathsLayout = new QGridLayout; + int row = 0; + + for (int i = 0; i < NumExternalPrograms; ++i) + { + ExtProgramType program = (ExtProgramType) i; + ExternalProgramWidgets& widgets = m_externalProgramWidgets[i]; + QString name = m_window->externalPrograms()->externalProgramName (program); + QLabel* icon = new QLabel; + QLabel* progLabel = new QLabel (name); + QLineEdit* input = new QLineEdit; + QPushButton* setPathButton = new QPushButton; + + icon->setPixmap (GetIcon (name.toLower())); + input->setText (m_window->externalPrograms()->getPathSetting (program)); + setPathButton->setIcon (GetIcon ("folder")); + widgets.input = input; + widgets.setPathButton = setPathButton; + widgets.wineBox = nullptr; + connect (setPathButton, SIGNAL (clicked()), this, SLOT (slot_setExtProgPath())); + pathsLayout->addWidget (icon, row, 0); + pathsLayout->addWidget (progLabel, row, 1); + pathsLayout->addWidget (input, row, 2); + pathsLayout->addWidget (setPathButton, row, 3); + +#ifdef Q_OS_UNIX + { + QCheckBox* wineBox = new QCheckBox ("Wine"); + wineBox->setChecked (m_window->externalPrograms()->programUsesWine (program)); + widgets.wineBox = wineBox; + pathsLayout->addWidget (wineBox, row, 4); + } +#endif + ++row; + } + ui->extProgs->setLayout (pathsLayout); +} + +void ConfigDialog::applyToWidgetOptions (std::function func) +{ + // Apply configuration + for (QWidget* widget : findChildren()) + { + if (not widget->objectName().startsWith ("config")) + continue; + + QString optionname (widget->objectName().mid (strlen ("config"))); + + if (m_config->existsEntry (optionname)) + func (widget, optionname); + else + print ("Couldn't find configuration entry named %1", optionname); + } +} + +// +// Set the settings based on widget data. +// +void ConfigDialog::applySettings() +{ + applyToWidgetOptions ([&](QWidget* widget, QString confname) + { + QVariant value; + QLineEdit* le; + QSpinBox* spinbox; + QDoubleSpinBox* doublespinbox; + QSlider* slider; + QCheckBox* checkbox; + QPushButton* button; + + if ((le = qobject_cast (widget)) != null) + value = le->text(); + else if ((spinbox = qobject_cast (widget)) != null) + value = spinbox->value(); + else if ((doublespinbox = qobject_cast (widget)) != null) + value = doublespinbox->value(); + else if ((slider = qobject_cast (widget)) != null) + value = slider->value(); + else if ((checkbox = qobject_cast (widget)) != null) + value = checkbox->isChecked(); + else if ((button = qobject_cast (widget)) != null) + value = m_buttonColors[button]; + else + { + print ("Unknown widget of type %1\n", widget->metaObject()->className()); + return; + } + + m_settings->setValue (confname, value); + }); + + // Rebuild the quick color toolbar + m_window->setQuickColors (quickColors); + m_config->setQuickColorToolbar (quickColorString()); + + // Ext program settings + for (int i = 0; i < NumExternalPrograms; ++i) + { + ExtProgramType program = (ExtProgramType) i; + ExtProgramToolset* toolset = m_window->externalPrograms(); + ExternalProgramWidgets& widgets = m_externalProgramWidgets[i]; + toolset->getPathSetting (program) = widgets.input->text(); + + if (widgets.wineBox) + toolset->setWineSetting (program, widgets.wineBox->isChecked()); + } + + // Apply shortcuts + for (int i = 0; i < ui->shortcutsList->count(); ++i) + { + auto item = static_cast (ui->shortcutsList->item (i)); + item->action()->setShortcut (item->sequence()); + } + + m_window->syncSettings(); + LDDocument::current()->reloadAllSubfiles(); + LoadLogoStuds(); + + m_window->R()->setBackground(); + m_window->doFullRefresh(); + m_window->updateDocumentList(); +} + +// +// A dialog button was clicked +// +void ConfigDialog::buttonClicked (QAbstractButton* button) +{ + QDialogButtonBox* dbb = ui->buttonBox; + + if (button == dbb->button (QDialogButtonBox::Ok)) + { + applySettings(); + accept(); + } + else if (button == dbb->button (QDialogButtonBox::Apply)) + { + applySettings(); + } + else if (button == dbb->button (QDialogButtonBox::Cancel)) + { + reject(); + } +} + +// +// Update the list of color toolbar items in the quick color tab. +// +void ConfigDialog::updateQuickColorList (LDQuickColor* sel) +{ + for (QListWidgetItem * item : quickColorItems) + delete item; + + quickColorItems.clear(); + + // Init table items + for (LDQuickColor& entry : quickColors) + { + QListWidgetItem* item = new QListWidgetItem; + + if (entry.isSeparator()) + { + item->setText ("
"); + item->setIcon (GetIcon ("empty")); + } + else + { + LDColor color = entry.color(); + + if (color.isValid()) + { + item->setText (color.name()); + item->setIcon (guiUtilities()->makeColorIcon (color, 16)); + } + else + { + item->setText ("[[unknown color]]"); + item->setIcon (GetIcon ("error")); + } + } + + ui->quickColorList->addItem (item); + quickColorItems << item; + + if (sel and &entry == sel) + { + ui->quickColorList->setCurrentItem (item); + ui->quickColorList->scrollToItem (item); + } + } +} + +// +// Quick colors: add or edit button was clicked. +// +void ConfigDialog::slot_setColor() +{ + LDQuickColor* entry = null; + QListWidgetItem* item = null; + const bool isNew = static_cast (sender()) == ui->quickColor_add; + + if (not isNew) + { + item = getSelectedQuickColor(); + + if (not item) + return; + + int i = getItemRow (item, quickColorItems); + entry = &quickColors[i]; + + if (entry->isSeparator() == true) + return; // don't color separators + } + + LDColor defaultValue = entry ? entry->color() : LDColor::nullColor(); + LDColor value; + + if (not ColorSelector::selectColor (this, value, defaultValue)) + return; + + if (entry != null) + { + entry->setColor (value); + } + else + { + LDQuickColor newentry (value, null); + item = getSelectedQuickColor(); + int idx = (item) ? getItemRow (item, quickColorItems) + 1 : quickColorItems.size(); + quickColors.insert (idx, newentry); + entry = &quickColors[idx]; + } + + updateQuickColorList (entry); +} + +// +// Remove a quick color +// +void ConfigDialog::slot_delColor() +{ + if (ui->quickColorList->selectedItems().isEmpty()) + return; + + QListWidgetItem* item = ui->quickColorList->selectedItems() [0]; + quickColors.removeAt (getItemRow (item, quickColorItems)); + updateQuickColorList(); +} + +// +// Move a quick color up/down +// +void ConfigDialog::slot_moveColor() +{ + const bool up = (static_cast (sender()) == ui->quickColor_moveUp); + + if (ui->quickColorList->selectedItems().isEmpty()) + return; + + QListWidgetItem* item = ui->quickColorList->selectedItems() [0]; + int idx = getItemRow (item, quickColorItems); + int dest = up ? (idx - 1) : (idx + 1); + + if (dest < 0 or dest >= quickColorItems.size()) + return; // destination out of bounds + + qSwap (quickColors[dest], quickColors[idx]); + updateQuickColorList (&quickColors[dest]); +} + +// +// +// Add a separator to quick colors +// +void ConfigDialog::slot_addColorSeparator() +{ + quickColors << LDQuickColor::getSeparator(); + updateQuickColorList (&quickColors[quickColors.size() - 1]); +} + +// +// +// Clear all quick colors +// +void ConfigDialog::slot_clearColors() +{ + quickColors.clear(); + updateQuickColorList(); +} + +// +// +void ConfigDialog::setButtonColor() +{ + QPushButton* button = qobject_cast (sender()); + + if (button == null) + { + print ("setButtonColor: null sender!\n"); + return; + } + + QColor color = QColorDialog::getColor (m_buttonColors[button]); + + if (color.isValid()) + { + QString colorname; + colorname.sprintf ("#%.2X%.2X%.2X", color.red(), color.green(), color.blue()); + setButtonBackground (button, colorname); + } +} + +// +// Sets background color of a given button. +// +void ConfigDialog::setButtonBackground (QPushButton* button, QString value) +{ + button->setIcon (GetIcon ("colorselect")); + button->setAutoFillBackground (true); + button->setStyleSheet (format ("background-color: %1", value)); + m_buttonColors[button] = QColor (value); +} + +// +// Finds the given list widget item in the list of widget items given. +// +int ConfigDialog::getItemRow (QListWidgetItem* item, QList& haystack) +{ + int i = 0; + + for (QListWidgetItem* it : haystack) + { + if (it == item) + return i; + + ++i; + } + + return -1; +} + +// +// Which quick color is currently selected? +// +QListWidgetItem* ConfigDialog::getSelectedQuickColor() +{ + if (ui->quickColorList->selectedItems().isEmpty()) + return null; + + return ui->quickColorList->selectedItems() [0]; +} + +// +// Get the list of shortcuts selected +// +QList ConfigDialog::getShortcutSelection() +{ + QList out; + + for (QListWidgetItem* entry : ui->shortcutsList->selectedItems()) + out << static_cast (entry); + + return out; +} + +// +// Edit the shortcut of a given action. +// +void ConfigDialog::slot_setShortcut() +{ + QList sel = getShortcutSelection(); + + if (sel.size() < 1) + return; + + ShortcutListItem* item = sel[0]; + + if (KeySequenceDialog::staticDialog (item, this)) + setShortcutText (item); +} + +// +// Reset a shortcut to defaults +// +void ConfigDialog::slot_resetShortcut() +{ + QList sel = getShortcutSelection(); + + for (ShortcutListItem* item : sel) + { + item->setSequence (MainWindow::defaultShortcut (item->action())); + setShortcutText (item); + } +} + +// +// Remove the shortcut of an action. +// +void ConfigDialog::slot_clearShortcut() +{ + QList sel = getShortcutSelection(); + + for (ShortcutListItem* item : sel) + { + item->setSequence (QKeySequence()); + setShortcutText (item); + } +} + +// +// Set the path of an external program +// +void ConfigDialog::slot_setExtProgPath() +{ + ExtProgramType program = NumExternalPrograms; + + for (int i = 0; i < NumExternalPrograms; ++i) + { + if (m_externalProgramWidgets[i].setPathButton == sender()) + { + program = (ExtProgramType) i; + break; + } + } + + if (program != NumExternalPrograms) + { + ExtProgramToolset* toolset = m_window->externalPrograms(); + ExternalProgramWidgets& widgets = m_externalProgramWidgets[program]; + QString filepath = QFileDialog::getOpenFileName (this, + format ("Path to %1", toolset->externalProgramName (program)), + widgets.input->text(), g_extProgPathFilter); + + if (filepath.isEmpty()) + return; + + widgets.input->setText (filepath); + } +} + +// +// '...' button pressed for the download path +// +void ConfigDialog::slot_findDownloadFolder() +{ + QString dpath = QFileDialog::getExistingDirectory(); + + if (not dpath.isEmpty()) + ui->configDownloadFilePath->setText (dpath); +} + +// +// +// Updates the text string for a given shortcut list item +// +void ConfigDialog::setShortcutText (ShortcutListItem* item) +{ + QAction* act = item->action(); + QString label = act->iconText(); + QString keybind = item->sequence().toString(); + item->setText (format ("%1 (%2)", label, keybind)); +} + +// +// Gets the configuration string of the quick color toolbar +// +QString ConfigDialog::quickColorString() +{ + QString val; + + for (const LDQuickColor& entry : quickColors) + { + if (val.length() > 0) + val += ':'; + + if (entry.isSeparator()) + val += '|'; + else + val += format ("%1", entry.color().index()); + } + + return val; +} + +// +// +KeySequenceDialog::KeySequenceDialog (QKeySequence seq, QWidget* parent, Qt::WindowFlags f) : + QDialog (parent, f), seq (seq) +{ + lb_output = new QLabel; + + bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel); \ + connect (bbx_buttons, SIGNAL (accepted()), this, SLOT (accept())); \ + connect (bbx_buttons, SIGNAL (rejected()), this, SLOT (reject())); \ + + setWhatsThis (tr ("Into this dialog you can input a key sequence for use as a " + "shortcut in LDForge. Use OK to confirm the new shortcut and Cancel to " + "dismiss.")); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget (lb_output); + layout->addWidget (bbx_buttons); + setLayout (layout); + + updateOutput(); +} + +// +// +bool KeySequenceDialog::staticDialog (ShortcutListItem* item, QWidget* parent) +{ + KeySequenceDialog dlg (item->sequence(), parent); + + if (dlg.exec() == QDialog::Rejected) + return false; + + item->setSequence (dlg.seq); + return true; +} + +// +// +void KeySequenceDialog::updateOutput() +{ + QString shortcut = seq.toString(); + + if (seq == QKeySequence()) + shortcut = "<empty>"; + + QString text = format ("
%1
", shortcut); + lb_output->setText (text); +} + +// +// +void KeySequenceDialog::keyPressEvent (QKeyEvent* ev) +{ + seq = ev->key() + ev->modifiers(); + updateOutput(); +}