1 /*
2 
3 Pencil2D - Traditional Animation Software
4 Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5 Copyright (C) 2012-2020 Matthew Chiawen Chang
6 
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; version 2 of the License.
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 */
17 
18 #include "filespage.h"
19 
20 #include <QSettings>
21 #include <QStandardPaths>
22 
23 #include "errordialog.h"
24 #include "filemanager.h"
25 #include "pencilerror.h"
26 #include "presetdialog.h"
27 
28 #include "ui_filespage.h"
29 
FilesPage()30 FilesPage::FilesPage()
31     : ui(new Ui::FilesPage)
32 {
33     ui->setupUi(this);
34 
35     initPreset();
36 
37     connect(ui->addPreset, &QPushButton::clicked, this, &FilesPage::addPreset);
38     connect(ui->removePreset, &QPushButton::clicked, this, &FilesPage::removePreset);
39     connect(ui->setDefaultPreset, &QPushButton::clicked, this, &FilesPage::setDefaultPreset);
40     connect(ui->askPresetRbtn, &QRadioButton::toggled, this, &FilesPage::askForPresetChange);
41     connect(ui->loadLastActiveRbtn, &QRadioButton::toggled, this, &FilesPage::loadMostRecentChange);
42     connect(ui->loadDefaultPresetRbtn, &QRadioButton::toggled, this, &FilesPage::loadDefaultPreset);
43     connect(ui->presetListWidget, &QListWidget::itemChanged, this, &FilesPage::presetNameChanged);
44 
45     auto spinBoxValueChange = static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged);
46     connect(ui->autosaveCheckBox, &QCheckBox::stateChanged, this, &FilesPage::autoSaveChange);
47     connect(ui->autosaveNumberBox, spinBoxValueChange, this, &FilesPage::autoSaveNumberChange);
48 }
49 
~FilesPage()50 FilesPage::~FilesPage()
51 {
52     delete ui;
53 }
54 
initPreset()55 void FilesPage::initPreset()
56 {
57     mPresetDir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
58     mPresetDir.mkpath("presets");
59     mPresetDir.cd("presets");
60 
61     mPresetSettings = new QSettings(mPresetDir.filePath("presets.ini"), QSettings::IniFormat, this);
62 
63     QListWidgetItem* defaultItem = new QListWidgetItem("Blank");
64     defaultItem->setData(Qt::UserRole, 0);
65     ui->presetListWidget->addItem(defaultItem);
66 
67     bool ok = true;
68     for (const QString& key : mPresetSettings->allKeys())
69     {
70         int index = key.toInt(&ok);
71         if (!ok || index == 0 || !mPresetDir.exists(QString("%1.pclx").arg(index))) continue;
72 
73         mMaxPresetIndex = qMax(index, mMaxPresetIndex);
74 
75         QString name = mPresetSettings->value(key).toString();
76         if (name.isEmpty())
77             continue;
78 
79         QListWidgetItem* item = new QListWidgetItem(name);
80         item->setFlags(item->flags() | Qt::ItemIsEditable);
81         item->setData(Qt::UserRole, index);
82         ui->presetListWidget->addItem(item);
83     }
84 }
85 
addPreset()86 void FilesPage::addPreset()
87 {
88     int newPresetIndex = mMaxPresetIndex + 1;
89 
90     // 1. save the current object to the preset folder
91     FileManager fm(this);
92     Status st = fm.save(mManager->object(), PresetDialog::getPresetPath(newPresetIndex));
93     if (!st.ok())
94     {
95         ErrorDialog errorDialog(st.title(),
96                                 st.description().append(tr("<br><br>Error: your preset may not have saved successfully. "
97                                                            "If you believe that this error is an issue with Pencil2D, please create a new issue at:"
98                                                            "<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>"
99                                                            "Please include the following details in your issue:")), st.details().html());
100         errorDialog.exec();
101         return;
102     }
103 
104     // 2. update the preset ini
105     QString presetName = QString("Preset %1").arg(newPresetIndex);
106     mPresetSettings->setValue(QString::number(newPresetIndex), presetName);
107     mMaxPresetIndex = newPresetIndex;
108 
109     // 3. update the list widget
110     QListWidgetItem* newItem = new QListWidgetItem(presetName);
111     newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
112     newItem->setData(Qt::UserRole, newPresetIndex);
113     ui->presetListWidget->addItem(newItem);
114 
115     ui->presetListWidget->scrollToBottom();
116     ui->presetListWidget->editItem(newItem);
117 }
118 
removePreset()119 void FilesPage::removePreset()
120 {
121     if (ui->presetListWidget->count() <= 1) { return; }
122     if (ui->presetListWidget->selectedItems().empty()) { return; }
123 
124     // 1. Remove the items from list widget
125     QList<QListWidgetItem*> itemsToRemove = ui->presetListWidget->selectedItems();
126     for (QListWidgetItem* item : itemsToRemove)
127     {
128         ui->presetListWidget->removeItemWidget(item);
129     }
130 
131     // 2. Delete preset pclx files
132     for (QListWidgetItem* item : itemsToRemove)
133     {
134         int index = item->data(Qt::UserRole).toInt();
135         QFile presetFile(PresetDialog::getPresetPath(index));
136         presetFile.remove();
137     }
138 
139     // 3. Delete items from the ini settings
140     for (QListWidgetItem* item : itemsToRemove)
141     {
142         int index = item->data(Qt::UserRole).toInt();
143         mPresetSettings->remove(QString::number(index));
144     }
145 
146     // 4. check if the default preset has been deleted
147     int prevDefaultIndex = mManager->getInt(SETTING::DEFAULT_PRESET);
148     for (QListWidgetItem* item : itemsToRemove)
149     {
150         int index = item->data(Qt::UserRole).toInt();
151         if (index == prevDefaultIndex)
152         {
153             mManager->set(SETTING::DEFAULT_PRESET, 0);
154         }
155     }
156 
157     // 5. delete items
158     for (QListWidgetItem* item : itemsToRemove)
159     {
160         delete item;
161     }
162     updateValues();
163 }
164 
setDefaultPreset()165 void FilesPage::setDefaultPreset()
166 {
167     bool ok = true;
168 
169     QListWidgetItem* newDefaultPresetItem = ui->presetListWidget->currentItem();
170     if (newDefaultPresetItem)
171     {
172         int newDefaultIndex = newDefaultPresetItem->data(Qt::UserRole).toInt(&ok);
173         Q_ASSERT(ok);
174 
175         mManager->set(SETTING::DEFAULT_PRESET, newDefaultIndex);
176         updateValues();
177     }
178 }
179 
presetNameChanged(QListWidgetItem * item)180 void FilesPage::presetNameChanged(QListWidgetItem* item)
181 {
182     // Remove characters that may be problematic for ini files
183     item->setText(item->text().remove(QChar('@')).remove(QChar('/')).remove(QChar('\\')));
184 
185     bool ok = true;
186     int index = item->data(Qt::UserRole).toInt(&ok);
187     Q_ASSERT(ok);
188     mPresetSettings->setValue(QString::number(index), item->text());
189 }
190 
updateValues()191 void FilesPage::updateValues()
192 {
193     bool ok = true;
194     int defaultPresetIndex = mManager->getInt(SETTING::DEFAULT_PRESET);
195 
196     for (int i = 0; i < ui->presetListWidget->count(); i++)
197     {
198         QListWidgetItem* item = ui->presetListWidget->item(i);
199         int presetIndex = item->data(Qt::UserRole).toInt(&ok);
200 
201         bool isDefault = presetIndex == defaultPresetIndex;
202 
203         QFont font = item->font();
204         font.setBold(isDefault); // Bold text for the default item
205         item->setFont(font);
206 
207         QBrush backgroundBrush = (isDefault) ? palette().light() : palette().window();
208         item->setBackground(backgroundBrush);
209     }
210     ui->autosaveCheckBox->setChecked(mManager->isOn(SETTING::AUTO_SAVE));
211     ui->autosaveNumberBox->setValue(mManager->getInt(SETTING::AUTO_SAVE_NUMBER));
212     ui->askPresetRbtn->setChecked(mManager->isOn(SETTING::ASK_FOR_PRESET));
213     ui->loadDefaultPresetRbtn->setChecked(mManager->isOn(SETTING::LOAD_DEFAULT_PRESET));
214     ui->loadLastActiveRbtn->setChecked(mManager->isOn(SETTING::LOAD_MOST_RECENT));
215 }
216 
askForPresetChange(int b)217 void FilesPage::askForPresetChange(int b)
218 {
219     mManager->set(SETTING::ASK_FOR_PRESET, b != Qt::Unchecked);
220 }
221 
loadMostRecentChange(int b)222 void FilesPage::loadMostRecentChange(int b)
223 {
224     mManager->set(SETTING::LOAD_MOST_RECENT, b != Qt::Unchecked);
225 }
226 
loadDefaultPreset(int b)227 void FilesPage::loadDefaultPreset(int b)
228 {
229     mManager->set(SETTING::LOAD_DEFAULT_PRESET, b != Qt::Unchecked);
230 }
231 
autoSaveChange(int b)232 void FilesPage::autoSaveChange(int b)
233 {
234     mManager->set(SETTING::AUTO_SAVE, b != Qt::Unchecked);
235 }
236 
autoSaveNumberChange(int number)237 void FilesPage::autoSaveNumberChange(int number)
238 {
239     mManager->set(SETTING::AUTO_SAVE_NUMBER, number);
240 }
241