src/dialogs/configdialog.cpp

changeset 975
24ba5aa3393f
parent 974
b2fa5f89798a
child 976
b7aac3606b65
equal deleted inserted replaced
974:b2fa5f89798a 975:24ba5aa3393f
1 /*
2 * LDForge: LDraw parts authoring CAD
3 * Copyright (C) 2013 - 2015 Teemu Piippo
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * =====================================================================
18 *
19 * configDialog.cxx: Settings dialog and everything related to it.
20 * Actual configuration core is in config.cxx.
21 */
22
23 #include <QGridLayout>
24 #include <QFileDialog>
25 #include <QColorDialog>
26 #include <QBoxLayout>
27 #include <QKeyEvent>
28 #include <QGroupBox>
29 #include <QDoubleSpinBox>
30 #include <QLineEdit>
31 #include <QCheckBox>
32 #include <QSettings>
33 #include <QPushButton>
34 #include "../main.h"
35 #include "../ldDocument.h"
36 #include "../miscallenous.h"
37 #include "../glRenderer.h"
38 #include "../guiutilities.h"
39 #include "colorselector.h"
40 #include "configdialog.h"
41 #include "ui_configdialog.h"
42
43 const char* g_extProgPathFilter =
44 #ifdef _WIN32
45 "Applications (*.exe)(*.exe);;"
46 #endif
47 "All files (*.*)(*.*)";
48
49 ConfigDialog::ConfigDialog (QWidget* parent, ConfigDialog::Tab defaulttab, Qt::WindowFlags f) :
50 QDialog (parent, f),
51 HierarchyElement (parent),
52 m_settings (m_window->makeSettings (this))
53 {
54 ui = new Ui_ConfigDialog;
55 ui->setupUi (this);
56
57 // Set defaults
58 applyToWidgetOptions (
59 [&](QWidget* widget, QString confname)
60 {
61 QVariant value = m_settings->value (confname, m_config->defaultValueByName (confname));
62 QLineEdit* le;
63 QSpinBox* spinbox;
64 QDoubleSpinBox* doublespinbox;
65 QSlider* slider;
66 QCheckBox* checkbox;
67 QPushButton* button;
68
69 if ((le = qobject_cast<QLineEdit*> (widget)) != null)
70 {
71 le->setText (value.toString());
72 }
73 else if ((spinbox = qobject_cast<QSpinBox*> (widget)) != null)
74 {
75 spinbox->setValue (value.toInt());
76 }
77 else if ((doublespinbox = qobject_cast<QDoubleSpinBox*> (widget)) != null)
78 {
79 doublespinbox->setValue (value.toDouble());
80 }
81 else if ((slider = qobject_cast<QSlider*> (widget)) != null)
82 {
83 slider->setValue (value.toInt());
84 }
85 else if ((checkbox = qobject_cast<QCheckBox*> (widget)) != null)
86 {
87 checkbox->setChecked (value.toBool());
88 }
89 else if ((button = qobject_cast<QPushButton*> (widget)) != null)
90 {
91 setButtonBackground (button, value.toString());
92 connect (button, SIGNAL (clicked()), this, SLOT (setButtonColor()));
93 }
94 else
95 {
96 print ("Unknown widget of type %1\n", widget->metaObject()->className());
97 }
98 });
99
100 m_window->applyToActions ([&](QAction* act)
101 {
102 addShortcut (act);
103 });
104
105 ui->shortcutsList->setSortingEnabled (true);
106 ui->shortcutsList->sortItems();
107 quickColors = LoadQuickColorList();
108 updateQuickColorList();
109 initExtProgs();
110 selectPage (defaulttab);
111 connect (ui->shortcut_set, SIGNAL (clicked()), this, SLOT (slot_setShortcut()));
112 connect (ui->shortcut_reset, SIGNAL (clicked()), this, SLOT (slot_resetShortcut()));
113 connect (ui->shortcut_clear, SIGNAL (clicked()), this, SLOT (slot_clearShortcut()));
114 connect (ui->quickColor_add, SIGNAL (clicked()), this, SLOT (slot_setColor()));
115 connect (ui->quickColor_remove, SIGNAL (clicked()), this, SLOT (slot_delColor()));
116 connect (ui->quickColor_edit, SIGNAL (clicked()), this, SLOT (slot_setColor()));
117 connect (ui->quickColor_addSep, SIGNAL (clicked()), this, SLOT (slot_addColorSeparator()));
118 connect (ui->quickColor_moveUp, SIGNAL (clicked()), this, SLOT (slot_moveColor()));
119 connect (ui->quickColor_moveDown, SIGNAL (clicked()), this, SLOT (slot_moveColor()));
120 connect (ui->quickColor_clear, SIGNAL (clicked()), this, SLOT (slot_clearColors()));
121 connect (ui->findDownloadPath, SIGNAL (clicked (bool)), this, SLOT (slot_findDownloadFolder()));
122 connect (ui->buttonBox, SIGNAL (clicked (QAbstractButton*)),
123 this, SLOT (buttonClicked (QAbstractButton*)));
124 connect (ui->m_pages, SIGNAL (currentChanged (int)), this, SLOT (selectPage (int)));
125 connect (ui->m_pagelist, SIGNAL (currentRowChanged (int)), this, SLOT (selectPage (int)));
126 }
127
128 ConfigDialog::~ConfigDialog()
129 {
130 delete ui;
131 }
132
133 void ConfigDialog::selectPage (int row)
134 {
135 ui->m_pagelist->setCurrentRow (row);
136 ui->m_pages->setCurrentIndex (row);
137 }
138
139 //
140 // Adds a shortcut entry to the list of shortcuts.
141 //
142 void ConfigDialog::addShortcut (QAction* act)
143 {
144 ShortcutListItem* item = new ShortcutListItem;
145 item->setIcon (act->icon());
146 item->setAction (act);
147 item->setSequence (act->shortcut());
148 setShortcutText (item);
149
150 // If the action doesn't have a valid icon, use an empty one
151 // so that the list is kept aligned.
152 if (act->icon().isNull())
153 item->setIcon (GetIcon ("empty"));
154
155 ui->shortcutsList->insertItem (ui->shortcutsList->count(), item);
156 }
157
158 //
159 // Initializes the stuff in the ext programs tab
160 //
161 void ConfigDialog::initExtProgs()
162 {
163 QGridLayout* pathsLayout = new QGridLayout;
164 int row = 0;
165
166 for (int i = 0; i < NumExternalPrograms; ++i)
167 {
168 ExtProgramType program = (ExtProgramType) i;
169 ExternalProgramWidgets& widgets = m_externalProgramWidgets[i];
170 QString name = m_window->externalPrograms()->externalProgramName (program);
171 QLabel* icon = new QLabel;
172 QLabel* progLabel = new QLabel (name);
173 QLineEdit* input = new QLineEdit;
174 QPushButton* setPathButton = new QPushButton;
175
176 icon->setPixmap (GetIcon (name.toLower()));
177 input->setText (m_window->externalPrograms()->getPathSetting (program));
178 setPathButton->setIcon (GetIcon ("folder"));
179 widgets.input = input;
180 widgets.setPathButton = setPathButton;
181 widgets.wineBox = nullptr;
182 connect (setPathButton, SIGNAL (clicked()), this, SLOT (slot_setExtProgPath()));
183 pathsLayout->addWidget (icon, row, 0);
184 pathsLayout->addWidget (progLabel, row, 1);
185 pathsLayout->addWidget (input, row, 2);
186 pathsLayout->addWidget (setPathButton, row, 3);
187
188 #ifdef Q_OS_UNIX
189 {
190 QCheckBox* wineBox = new QCheckBox ("Wine");
191 wineBox->setChecked (m_window->externalPrograms()->programUsesWine (program));
192 widgets.wineBox = wineBox;
193 pathsLayout->addWidget (wineBox, row, 4);
194 }
195 #endif
196 ++row;
197 }
198 ui->extProgs->setLayout (pathsLayout);
199 }
200
201 void ConfigDialog::applyToWidgetOptions (std::function<void (QWidget*, QString)> func)
202 {
203 // Apply configuration
204 for (QWidget* widget : findChildren<QWidget*>())
205 {
206 if (not widget->objectName().startsWith ("config"))
207 continue;
208
209 QString optionname (widget->objectName().mid (strlen ("config")));
210
211 if (m_config->existsEntry (optionname))
212 func (widget, optionname);
213 else
214 print ("Couldn't find configuration entry named %1", optionname);
215 }
216 }
217
218 //
219 // Set the settings based on widget data.
220 //
221 void ConfigDialog::applySettings()
222 {
223 applyToWidgetOptions ([&](QWidget* widget, QString confname)
224 {
225 QVariant value;
226 QLineEdit* le;
227 QSpinBox* spinbox;
228 QDoubleSpinBox* doublespinbox;
229 QSlider* slider;
230 QCheckBox* checkbox;
231 QPushButton* button;
232
233 if ((le = qobject_cast<QLineEdit*> (widget)) != null)
234 value = le->text();
235 else if ((spinbox = qobject_cast<QSpinBox*> (widget)) != null)
236 value = spinbox->value();
237 else if ((doublespinbox = qobject_cast<QDoubleSpinBox*> (widget)) != null)
238 value = doublespinbox->value();
239 else if ((slider = qobject_cast<QSlider*> (widget)) != null)
240 value = slider->value();
241 else if ((checkbox = qobject_cast<QCheckBox*> (widget)) != null)
242 value = checkbox->isChecked();
243 else if ((button = qobject_cast<QPushButton*> (widget)) != null)
244 value = m_buttonColors[button];
245 else
246 {
247 print ("Unknown widget of type %1\n", widget->metaObject()->className());
248 return;
249 }
250
251 m_settings->setValue (confname, value);
252 });
253
254 // Rebuild the quick color toolbar
255 m_window->setQuickColors (quickColors);
256 m_config->setQuickColorToolbar (quickColorString());
257
258 // Ext program settings
259 for (int i = 0; i < NumExternalPrograms; ++i)
260 {
261 ExtProgramType program = (ExtProgramType) i;
262 ExtProgramToolset* toolset = m_window->externalPrograms();
263 ExternalProgramWidgets& widgets = m_externalProgramWidgets[i];
264 toolset->getPathSetting (program) = widgets.input->text();
265
266 if (widgets.wineBox)
267 toolset->setWineSetting (program, widgets.wineBox->isChecked());
268 }
269
270 // Apply shortcuts
271 for (int i = 0; i < ui->shortcutsList->count(); ++i)
272 {
273 auto item = static_cast<ShortcutListItem*> (ui->shortcutsList->item (i));
274 item->action()->setShortcut (item->sequence());
275 }
276
277 m_window->syncSettings();
278 LDDocument::current()->reloadAllSubfiles();
279 LoadLogoStuds();
280
281 m_window->R()->setBackground();
282 m_window->doFullRefresh();
283 m_window->updateDocumentList();
284 }
285
286 //
287 // A dialog button was clicked
288 //
289 void ConfigDialog::buttonClicked (QAbstractButton* button)
290 {
291 QDialogButtonBox* dbb = ui->buttonBox;
292
293 if (button == dbb->button (QDialogButtonBox::Ok))
294 {
295 applySettings();
296 accept();
297 }
298 else if (button == dbb->button (QDialogButtonBox::Apply))
299 {
300 applySettings();
301 }
302 else if (button == dbb->button (QDialogButtonBox::Cancel))
303 {
304 reject();
305 }
306 }
307
308 //
309 // Update the list of color toolbar items in the quick color tab.
310 //
311 void ConfigDialog::updateQuickColorList (LDQuickColor* sel)
312 {
313 for (QListWidgetItem * item : quickColorItems)
314 delete item;
315
316 quickColorItems.clear();
317
318 // Init table items
319 for (LDQuickColor& entry : quickColors)
320 {
321 QListWidgetItem* item = new QListWidgetItem;
322
323 if (entry.isSeparator())
324 {
325 item->setText ("<hr />");
326 item->setIcon (GetIcon ("empty"));
327 }
328 else
329 {
330 LDColor color = entry.color();
331
332 if (color.isValid())
333 {
334 item->setText (color.name());
335 item->setIcon (guiUtilities()->makeColorIcon (color, 16));
336 }
337 else
338 {
339 item->setText ("[[unknown color]]");
340 item->setIcon (GetIcon ("error"));
341 }
342 }
343
344 ui->quickColorList->addItem (item);
345 quickColorItems << item;
346
347 if (sel and &entry == sel)
348 {
349 ui->quickColorList->setCurrentItem (item);
350 ui->quickColorList->scrollToItem (item);
351 }
352 }
353 }
354
355 //
356 // Quick colors: add or edit button was clicked.
357 //
358 void ConfigDialog::slot_setColor()
359 {
360 LDQuickColor* entry = null;
361 QListWidgetItem* item = null;
362 const bool isNew = static_cast<QPushButton*> (sender()) == ui->quickColor_add;
363
364 if (not isNew)
365 {
366 item = getSelectedQuickColor();
367
368 if (not item)
369 return;
370
371 int i = getItemRow (item, quickColorItems);
372 entry = &quickColors[i];
373
374 if (entry->isSeparator() == true)
375 return; // don't color separators
376 }
377
378 LDColor defaultValue = entry ? entry->color() : LDColor::nullColor();
379 LDColor value;
380
381 if (not ColorSelector::selectColor (this, value, defaultValue))
382 return;
383
384 if (entry != null)
385 {
386 entry->setColor (value);
387 }
388 else
389 {
390 LDQuickColor newentry (value, null);
391 item = getSelectedQuickColor();
392 int idx = (item) ? getItemRow (item, quickColorItems) + 1 : quickColorItems.size();
393 quickColors.insert (idx, newentry);
394 entry = &quickColors[idx];
395 }
396
397 updateQuickColorList (entry);
398 }
399
400 //
401 // Remove a quick color
402 //
403 void ConfigDialog::slot_delColor()
404 {
405 if (ui->quickColorList->selectedItems().isEmpty())
406 return;
407
408 QListWidgetItem* item = ui->quickColorList->selectedItems() [0];
409 quickColors.removeAt (getItemRow (item, quickColorItems));
410 updateQuickColorList();
411 }
412
413 //
414 // Move a quick color up/down
415 //
416 void ConfigDialog::slot_moveColor()
417 {
418 const bool up = (static_cast<QPushButton*> (sender()) == ui->quickColor_moveUp);
419
420 if (ui->quickColorList->selectedItems().isEmpty())
421 return;
422
423 QListWidgetItem* item = ui->quickColorList->selectedItems() [0];
424 int idx = getItemRow (item, quickColorItems);
425 int dest = up ? (idx - 1) : (idx + 1);
426
427 if (dest < 0 or dest >= quickColorItems.size())
428 return; // destination out of bounds
429
430 qSwap (quickColors[dest], quickColors[idx]);
431 updateQuickColorList (&quickColors[dest]);
432 }
433
434 //
435 //
436 // Add a separator to quick colors
437 //
438 void ConfigDialog::slot_addColorSeparator()
439 {
440 quickColors << LDQuickColor::getSeparator();
441 updateQuickColorList (&quickColors[quickColors.size() - 1]);
442 }
443
444 //
445 //
446 // Clear all quick colors
447 //
448 void ConfigDialog::slot_clearColors()
449 {
450 quickColors.clear();
451 updateQuickColorList();
452 }
453
454 //
455 //
456 void ConfigDialog::setButtonColor()
457 {
458 QPushButton* button = qobject_cast<QPushButton*> (sender());
459
460 if (button == null)
461 {
462 print ("setButtonColor: null sender!\n");
463 return;
464 }
465
466 QColor color = QColorDialog::getColor (m_buttonColors[button]);
467
468 if (color.isValid())
469 {
470 QString colorname;
471 colorname.sprintf ("#%.2X%.2X%.2X", color.red(), color.green(), color.blue());
472 setButtonBackground (button, colorname);
473 }
474 }
475
476 //
477 // Sets background color of a given button.
478 //
479 void ConfigDialog::setButtonBackground (QPushButton* button, QString value)
480 {
481 button->setIcon (GetIcon ("colorselect"));
482 button->setAutoFillBackground (true);
483 button->setStyleSheet (format ("background-color: %1", value));
484 m_buttonColors[button] = QColor (value);
485 }
486
487 //
488 // Finds the given list widget item in the list of widget items given.
489 //
490 int ConfigDialog::getItemRow (QListWidgetItem* item, QList<QListWidgetItem*>& haystack)
491 {
492 int i = 0;
493
494 for (QListWidgetItem* it : haystack)
495 {
496 if (it == item)
497 return i;
498
499 ++i;
500 }
501
502 return -1;
503 }
504
505 //
506 // Which quick color is currently selected?
507 //
508 QListWidgetItem* ConfigDialog::getSelectedQuickColor()
509 {
510 if (ui->quickColorList->selectedItems().isEmpty())
511 return null;
512
513 return ui->quickColorList->selectedItems() [0];
514 }
515
516 //
517 // Get the list of shortcuts selected
518 //
519 QList<ShortcutListItem*> ConfigDialog::getShortcutSelection()
520 {
521 QList<ShortcutListItem*> out;
522
523 for (QListWidgetItem* entry : ui->shortcutsList->selectedItems())
524 out << static_cast<ShortcutListItem*> (entry);
525
526 return out;
527 }
528
529 //
530 // Edit the shortcut of a given action.
531 //
532 void ConfigDialog::slot_setShortcut()
533 {
534 QList<ShortcutListItem*> sel = getShortcutSelection();
535
536 if (sel.size() < 1)
537 return;
538
539 ShortcutListItem* item = sel[0];
540
541 if (KeySequenceDialog::staticDialog (item, this))
542 setShortcutText (item);
543 }
544
545 //
546 // Reset a shortcut to defaults
547 //
548 void ConfigDialog::slot_resetShortcut()
549 {
550 QList<ShortcutListItem*> sel = getShortcutSelection();
551
552 for (ShortcutListItem* item : sel)
553 {
554 item->setSequence (MainWindow::defaultShortcut (item->action()));
555 setShortcutText (item);
556 }
557 }
558
559 //
560 // Remove the shortcut of an action.
561 //
562 void ConfigDialog::slot_clearShortcut()
563 {
564 QList<ShortcutListItem*> sel = getShortcutSelection();
565
566 for (ShortcutListItem* item : sel)
567 {
568 item->setSequence (QKeySequence());
569 setShortcutText (item);
570 }
571 }
572
573 //
574 // Set the path of an external program
575 //
576 void ConfigDialog::slot_setExtProgPath()
577 {
578 ExtProgramType program = NumExternalPrograms;
579
580 for (int i = 0; i < NumExternalPrograms; ++i)
581 {
582 if (m_externalProgramWidgets[i].setPathButton == sender())
583 {
584 program = (ExtProgramType) i;
585 break;
586 }
587 }
588
589 if (program != NumExternalPrograms)
590 {
591 ExtProgramToolset* toolset = m_window->externalPrograms();
592 ExternalProgramWidgets& widgets = m_externalProgramWidgets[program];
593 QString filepath = QFileDialog::getOpenFileName (this,
594 format ("Path to %1", toolset->externalProgramName (program)),
595 widgets.input->text(), g_extProgPathFilter);
596
597 if (filepath.isEmpty())
598 return;
599
600 widgets.input->setText (filepath);
601 }
602 }
603
604 //
605 // '...' button pressed for the download path
606 //
607 void ConfigDialog::slot_findDownloadFolder()
608 {
609 QString dpath = QFileDialog::getExistingDirectory();
610
611 if (not dpath.isEmpty())
612 ui->configDownloadFilePath->setText (dpath);
613 }
614
615 //
616 //
617 // Updates the text string for a given shortcut list item
618 //
619 void ConfigDialog::setShortcutText (ShortcutListItem* item)
620 {
621 QAction* act = item->action();
622 QString label = act->iconText();
623 QString keybind = item->sequence().toString();
624 item->setText (format ("%1 (%2)", label, keybind));
625 }
626
627 //
628 // Gets the configuration string of the quick color toolbar
629 //
630 QString ConfigDialog::quickColorString()
631 {
632 QString val;
633
634 for (const LDQuickColor& entry : quickColors)
635 {
636 if (val.length() > 0)
637 val += ':';
638
639 if (entry.isSeparator())
640 val += '|';
641 else
642 val += format ("%1", entry.color().index());
643 }
644
645 return val;
646 }
647
648 //
649 //
650 KeySequenceDialog::KeySequenceDialog (QKeySequence seq, QWidget* parent, Qt::WindowFlags f) :
651 QDialog (parent, f), seq (seq)
652 {
653 lb_output = new QLabel;
654
655 bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel); \
656 connect (bbx_buttons, SIGNAL (accepted()), this, SLOT (accept())); \
657 connect (bbx_buttons, SIGNAL (rejected()), this, SLOT (reject())); \
658
659 setWhatsThis (tr ("Into this dialog you can input a key sequence for use as a "
660 "shortcut in LDForge. Use OK to confirm the new shortcut and Cancel to "
661 "dismiss."));
662
663 QVBoxLayout* layout = new QVBoxLayout;
664 layout->addWidget (lb_output);
665 layout->addWidget (bbx_buttons);
666 setLayout (layout);
667
668 updateOutput();
669 }
670
671 //
672 //
673 bool KeySequenceDialog::staticDialog (ShortcutListItem* item, QWidget* parent)
674 {
675 KeySequenceDialog dlg (item->sequence(), parent);
676
677 if (dlg.exec() == QDialog::Rejected)
678 return false;
679
680 item->setSequence (dlg.seq);
681 return true;
682 }
683
684 //
685 //
686 void KeySequenceDialog::updateOutput()
687 {
688 QString shortcut = seq.toString();
689
690 if (seq == QKeySequence())
691 shortcut = "&lt;empty&gt;";
692
693 QString text = format ("<center><b>%1</b></center>", shortcut);
694 lb_output->setText (text);
695 }
696
697 //
698 //
699 void KeySequenceDialog::keyPressEvent (QKeyEvent* ev)
700 {
701 seq = ev->key() + ev->modifiers();
702 updateOutput();
703 }

mercurial