1 /*
2  * LibrePCB - Professional EDA for everyone!
3  * Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
4  * https://librepcb.org/
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 /*******************************************************************************
21  *  Includes
22  ******************************************************************************/
23 #include "workspacesettingsdialog.h"
24 
25 #include "../workspace.h"
26 #include "ui_workspacesettingsdialog.h"
27 #include "workspacesettings.h"
28 
29 #include <librepcb/common/application.h>
30 #include <librepcb/common/model/comboboxdelegate.h>
31 #include <librepcb/common/model/editablelistmodel.h>
32 #include <librepcb/common/norms.h>
33 #include <librepcb/common/toolbox.h>
34 
35 #include <QtCore>
36 #include <QtWidgets>
37 
38 /*******************************************************************************
39  *  Namespace
40  ******************************************************************************/
41 namespace librepcb {
42 namespace workspace {
43 
44 /*******************************************************************************
45  *  Constructors / Destructor
46  ******************************************************************************/
47 
WorkspaceSettingsDialog(WorkspaceSettings & settings,QWidget * parent)48 WorkspaceSettingsDialog::WorkspaceSettingsDialog(WorkspaceSettings& settings,
49                                                  QWidget* parent)
50   : QDialog(parent),
51     mSettings(settings),
52     mLibLocaleOrderModel(new LibraryLocaleOrderModel()),
53     mLibNormOrderModel(new LibraryNormOrderModel()),
54     mRepositoryUrlsModel(new RepositoryUrlModel()),
55     mUi(new Ui::WorkspaceSettingsDialog) {
56   mUi->setupUi(this);
57 
58   // Initialize application locale widgets
59   {
60     mUi->cbxAppLocale->addItem(tr("System Language"), QString(""));
61     QMap<QString, QString> map;  // map will be sorted by key
62     foreach (const QString& locale, qApp->getAvailableTranslationLocales()) {
63       map.insert(Toolbox::prettyPrintLocale(locale), locale);
64     }
65     QMap<QString, QString>::const_iterator i = map.constBegin();
66     while (i != map.constEnd()) {
67       mUi->cbxAppLocale->addItem(i.key(), i.value());
68       ++i;
69     }
70   }
71 
72   // Initialize library locale order widgets
73   {
74     QList<QLocale> locales = QLocale::matchingLocales(
75         QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
76     QStringList localesStr;
77     foreach (const QLocale& l, locales) { localesStr.append(l.name()); }
78     mLibLocaleOrderModel->setPlaceholderText(tr("Click here to add a locale"));
79     mLibLocaleOrderModel->setDefaultValue(QString(""));
80     mLibLocaleOrderModel->setChoices(localesStr);
81     mUi->tblLibLocaleOrder->setShowMoveButtons(true);
82     mUi->tblLibLocaleOrder->setModel(mLibLocaleOrderModel.data());
83     mUi->tblLibLocaleOrder->setItemDelegateForColumn(
84         LibraryLocaleOrderModel::COLUMN_TEXT,
85         new ComboBoxDelegate(false, this));
86     mUi->tblLibLocaleOrder->horizontalHeader()->setSectionResizeMode(
87         LibraryLocaleOrderModel::COLUMN_TEXT, QHeaderView::Stretch);
88     mUi->tblLibLocaleOrder->horizontalHeader()->setSectionResizeMode(
89         LibraryLocaleOrderModel::COLUMN_ACTIONS, QHeaderView::ResizeToContents);
90     connect(mUi->tblLibLocaleOrder, &EditableTableWidget::btnAddClicked,
91             mLibLocaleOrderModel.data(), &LibraryLocaleOrderModel::addItem);
92     connect(mUi->tblLibLocaleOrder, &EditableTableWidget::btnRemoveClicked,
93             mLibLocaleOrderModel.data(), &LibraryLocaleOrderModel::removeItem);
94     connect(mUi->tblLibLocaleOrder, &EditableTableWidget::btnMoveUpClicked,
95             mLibLocaleOrderModel.data(), &LibraryLocaleOrderModel::moveItemUp);
96     connect(mUi->tblLibLocaleOrder, &EditableTableWidget::btnMoveDownClicked,
97             mLibLocaleOrderModel.data(),
98             &LibraryLocaleOrderModel::moveItemDown);
99   }
100 
101   // Initialize library norm order widgets
102   {
103     mLibNormOrderModel->setPlaceholderText(tr("Click here to add a norm"));
104     mLibNormOrderModel->setDefaultValue(QString(""));
105     mLibNormOrderModel->setChoices(getAvailableNorms());
106     mUi->tblLibNormOrder->setShowMoveButtons(true);
107     mUi->tblLibNormOrder->setModel(mLibNormOrderModel.data());
108     mUi->tblLibNormOrder->setItemDelegateForColumn(
109         LibraryNormOrderModel::COLUMN_TEXT, new ComboBoxDelegate(true, this));
110     mUi->tblLibNormOrder->horizontalHeader()->setSectionResizeMode(
111         LibraryNormOrderModel::COLUMN_TEXT, QHeaderView::Stretch);
112     mUi->tblLibNormOrder->horizontalHeader()->setSectionResizeMode(
113         LibraryNormOrderModel::COLUMN_ACTIONS, QHeaderView::ResizeToContents);
114     connect(mUi->tblLibNormOrder, &EditableTableWidget::btnAddClicked,
115             mLibNormOrderModel.data(), &LibraryNormOrderModel::addItem);
116     connect(mUi->tblLibNormOrder, &EditableTableWidget::btnRemoveClicked,
117             mLibNormOrderModel.data(), &LibraryNormOrderModel::removeItem);
118     connect(mUi->tblLibNormOrder, &EditableTableWidget::btnMoveUpClicked,
119             mLibNormOrderModel.data(), &LibraryNormOrderModel::moveItemUp);
120     connect(mUi->tblLibNormOrder, &EditableTableWidget::btnMoveDownClicked,
121             mLibNormOrderModel.data(), &LibraryNormOrderModel::moveItemDown);
122   }
123 
124   // Initialize repository URL widgets
125   {
126     mRepositoryUrlsModel->setPlaceholderText(tr("Click here a add an URL"));
127     mUi->tblRepositoryUrls->setShowMoveButtons(true);
128     mUi->tblRepositoryUrls->setModel(mRepositoryUrlsModel.data());
129     mUi->tblRepositoryUrls->horizontalHeader()->setSectionResizeMode(
130         RepositoryUrlModel::COLUMN_TEXT, QHeaderView::Stretch);
131     mUi->tblRepositoryUrls->horizontalHeader()->setSectionResizeMode(
132         RepositoryUrlModel::COLUMN_ACTIONS, QHeaderView::ResizeToContents);
133     connect(mUi->tblRepositoryUrls, &EditableTableWidget::btnAddClicked,
134             mRepositoryUrlsModel.data(), &RepositoryUrlModel::addItem);
135     connect(mUi->tblRepositoryUrls, &EditableTableWidget::btnRemoveClicked,
136             mRepositoryUrlsModel.data(), &RepositoryUrlModel::removeItem);
137     connect(mUi->tblRepositoryUrls, &EditableTableWidget::btnMoveUpClicked,
138             mRepositoryUrlsModel.data(), &RepositoryUrlModel::moveItemUp);
139     connect(mUi->tblRepositoryUrls, &EditableTableWidget::btnMoveDownClicked,
140             mRepositoryUrlsModel.data(), &RepositoryUrlModel::moveItemDown);
141   }
142 
143   // Now load all current settings
144   loadSettings();
145 
146   // Load the window geometry
147   QSettings clientSettings;
148   restoreGeometry(
149       clientSettings.value("workspace_settings_dialog/window_geometry")
150           .toByteArray());
151 
152   // Just in case that the wrong tab is selected in the UI designer:
153   mUi->tabWidget->setCurrentIndex(0);
154 
155   // Connect event handlers
156   connect(mUi->buttonBox, &QDialogButtonBox::clicked, this,
157           &WorkspaceSettingsDialog::buttonBoxClicked);
158 }
159 
~WorkspaceSettingsDialog()160 WorkspaceSettingsDialog::~WorkspaceSettingsDialog() {
161   // Save the window geometry
162   QSettings clientSettings;
163   clientSettings.setValue("workspace_settings_dialog/window_geometry",
164                           saveGeometry());
165 }
166 
167 /*******************************************************************************
168  *  Private Slots for the GUI elements
169  ******************************************************************************/
170 
buttonBoxClicked(QAbstractButton * button)171 void WorkspaceSettingsDialog::buttonBoxClicked(
172     QAbstractButton* button) noexcept {
173   switch (mUi->buttonBox->buttonRole(button)) {
174     case QDialogButtonBox::RejectRole: {
175       reject();
176       break;
177     }
178 
179     case QDialogButtonBox::AcceptRole: {
180       saveSettings();
181       accept();
182       break;
183     }
184 
185     case QDialogButtonBox::ApplyRole: {
186       saveSettings();
187       break;
188     }
189 
190     case QDialogButtonBox::ResetRole: {
191       int answer = QMessageBox::question(
192           this, tr("Restore default settings"),
193           tr("Are you sure to reset all settings to their default values?\n\n"
194              "Attention: This will be applied immediately and cannot be "
195              "undone!"));
196       if (answer == QMessageBox::Yes) {
197         mSettings.restoreDefaults();
198         loadSettings();  // updating all widgets with the new values
199         saveSettings();  // save now since "cancel" does not revert!
200       }
201       break;
202     }
203 
204     default:
205       Q_ASSERT(false);
206       break;
207   }
208 }
209 
loadSettings()210 void WorkspaceSettingsDialog::loadSettings() noexcept {
211   // User Name
212   mUi->edtUserName->setText(mSettings.userName.get());
213 
214   // Application Locale
215   mUi->cbxAppLocale->setCurrentIndex(
216       mUi->cbxAppLocale->findData(mSettings.applicationLocale.get()));
217 
218   // Default Length Unit
219   mUi->cbxDefaultLengthUnit->clear();
220   foreach (const LengthUnit& unit, LengthUnit::getAllUnits()) {
221     mUi->cbxDefaultLengthUnit->addItem(unit.toStringTr(), unit.getIndex());
222   }
223   mUi->cbxDefaultLengthUnit->setCurrentIndex(
224       mSettings.defaultLengthUnit.get().getIndex());
225 
226   // Autosave Interval
227   mUi->spbAutosaveInterval->setValue(
228       mSettings.projectAutosaveIntervalSeconds.get());
229 
230   // Use OpenGL
231   mUi->cbxUseOpenGl->setChecked(mSettings.useOpenGl.get());
232 
233   // Library Locale Order
234   mLibLocaleOrderModel->setValues(mSettings.libraryLocaleOrder.get());
235 
236   // Library Norm Order
237   mLibNormOrderModel->setValues(mSettings.libraryNormOrder.get());
238 
239   // Repository URLs
240   mRepositoryUrlsModel->setValues(mSettings.repositoryUrls.get());
241 }
242 
saveSettings()243 void WorkspaceSettingsDialog::saveSettings() noexcept {
244   try {
245     // User Name
246     mSettings.userName.set(mUi->edtUserName->text().trimmed());
247 
248     // Application Locale
249     if (mUi->cbxAppLocale->currentIndex() >= 0) {
250       mSettings.applicationLocale.set(
251           mUi->cbxAppLocale->currentData().toString());
252     }
253 
254     // Default Length Unit
255     if (mUi->cbxDefaultLengthUnit->currentIndex() >= 0) {
256       mSettings.defaultLengthUnit.set(LengthUnit::fromIndex(
257           mUi->cbxDefaultLengthUnit->currentIndex()));  // can throw
258     }
259 
260     // Autosave Interval
261     mSettings.projectAutosaveIntervalSeconds.set(
262         mUi->spbAutosaveInterval->value());
263 
264     // Use OpenGL
265     mSettings.useOpenGl.set(mUi->cbxUseOpenGl->isChecked());
266 
267     // Library Locale Order
268     mSettings.libraryLocaleOrder.set(mLibLocaleOrderModel->getValues());
269 
270     // Library Norm Order
271     mSettings.libraryNormOrder.set(mLibNormOrderModel->getValues());
272 
273     // Repository URLs
274     mSettings.repositoryUrls.set(mRepositoryUrlsModel->getValues());
275 
276     mSettings.saveToFile();  // can throw
277   } catch (const Exception& e) {
278     QMessageBox::critical(this, tr("Error"), e.getMsg());
279   }
280 }
281 
282 /*******************************************************************************
283  *  End of File
284  ******************************************************************************/
285 
286 }  // namespace workspace
287 }  // namespace librepcb
288