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 "filedialog.h"
19 
20 #include <QSettings>
21 #include <QFileInfo>
22 #include <QFileDialog>
23 
24 #include "fileformat.h"
25 #include "pencildef.h"
26 
getOpenFileName(QWidget * parent,FileType fileType,const QString & caption)27 QString FileDialog::getOpenFileName(QWidget* parent, FileType fileType, const QString& caption)
28 {
29     QString strInitialFilePath = getLastOpenPath(fileType);
30     QString strFilter = openFileFilters(fileType);
31     QString strSelectedFilter = getFilterForFile(strFilter, strInitialFilePath);
32 
33     QString filePath = QFileDialog::getOpenFileName(parent,
34                                                     caption.isEmpty() ? openDialogCaption(fileType) : caption,
35                                                     strInitialFilePath,
36                                                     strFilter,
37                                                     strSelectedFilter.isNull() ? nullptr : &strSelectedFilter);
38     if (!filePath.isEmpty())
39     {
40         setLastOpenPath(fileType, filePath);
41     }
42 
43     return filePath;
44 }
45 
getOpenFileNames(QWidget * parent,FileType fileType,const QString & caption)46 QStringList FileDialog::getOpenFileNames(QWidget* parent, FileType fileType, const QString& caption)
47 {
48     QString strInitialFilePath = getLastOpenPath(fileType);
49     QString strFilter = openFileFilters(fileType);
50     QString strSelectedFilter = getFilterForFile(strFilter, strInitialFilePath);
51 
52     QStringList filePaths = QFileDialog::getOpenFileNames(parent,
53                                                           caption.isEmpty() ? openDialogCaption(fileType) : caption,
54                                                           strInitialFilePath,
55                                                           strFilter,
56                                                           strSelectedFilter.isNull() ? nullptr : &strSelectedFilter);
57     if (!filePaths.isEmpty() && !filePaths.first().isEmpty())
58     {
59         setLastOpenPath(fileType, filePaths.first());
60     }
61 
62     return filePaths;
63 }
64 
getSaveFileName(QWidget * parent,FileType fileType,const QString & caption)65 QString FileDialog::getSaveFileName(QWidget* parent, FileType fileType, const QString& caption)
66 {
67     QString strInitialFilePath = getLastSavePath(fileType);
68     QString strFilter = saveFileFilters(fileType);
69     QString strSelectedFilter = getFilterForFile(strFilter, strInitialFilePath);
70 
71     QString filePath = QFileDialog::getSaveFileName(parent,
72                                                     caption.isEmpty() ? saveDialogCaption(fileType) : caption,
73                                                     strInitialFilePath,
74                                                     strFilter,
75                                                     strSelectedFilter.isNull() ? nullptr : &strSelectedFilter);
76 
77     if (filePath.isEmpty()) { return QString(); }
78 
79     setLastSavePath(fileType, filePath);
80 
81     QFileInfo info(filePath);
82     if (info.suffix().isEmpty() && strSelectedFilter.isEmpty())
83     {
84         filePath += addDefaultExtensionSuffix(fileType);
85     }
86 
87     return filePath;
88 }
89 
addDefaultExtensionSuffix(const FileType fileType)90 QString FileDialog::addDefaultExtensionSuffix(const FileType fileType)
91 {
92     switch (fileType)
93     {
94     case FileType::ANIMATION: return PFF_DEFAULT_PROJECT_EXT;
95     case FileType::IMAGE: return PFF_DEFAULT_IMAGE_EXT;
96     case FileType::IMAGE_SEQUENCE: return PFF_DEFAULT_IMAGE_SEQ_EXT;
97     case FileType::GIF: return PFF_DEFAULT_ANIMATED_EXT;
98     case FileType::PALETTE: return PFF_DEFAULT_PALETTE_EXT;
99     default:
100         return "";
101     }
102 }
103 
getLastOpenPath(FileType fileType)104 QString FileDialog::getLastOpenPath(FileType fileType)
105 {
106     QSettings setting(PENCIL2D, PENCIL2D);
107     setting.beginGroup("LastOpenPath");
108 
109     return setting.value(toSettingKey(fileType), QDir::homePath()).toString();
110 }
111 
setLastOpenPath(FileType fileType,const QString & openPath)112 void FileDialog::setLastOpenPath(FileType fileType, const QString& openPath)
113 {
114     QSettings setting(PENCIL2D, PENCIL2D);
115     setting.beginGroup("LastOpenPath");
116 
117     setting.setValue(toSettingKey(fileType), QFileInfo(openPath).absolutePath());
118 }
119 
getLastSavePath(FileType fileType)120 QString FileDialog::getLastSavePath(FileType fileType)
121 {
122     QSettings setting(PENCIL2D, PENCIL2D);
123     setting.beginGroup("LastSavePath");
124 
125     return setting.value(toSettingKey(fileType),
126                          QDir::homePath() + "/" + defaultFileName(fileType)).toString();
127 }
128 
setLastSavePath(FileType fileType,const QString & savePath)129 void FileDialog::setLastSavePath(FileType fileType, const QString& savePath)
130 {
131     QSettings setting(PENCIL2D, PENCIL2D);
132     setting.beginGroup("LastSavePath");
133 
134     setting.setValue(toSettingKey(fileType), savePath);
135 }
136 
openDialogCaption(FileType fileType)137 QString FileDialog::openDialogCaption(FileType fileType)
138 {
139     switch (fileType)
140     {
141     case FileType::ANIMATION: return tr("Open animation");
142     case FileType::IMAGE: return tr("Import image");
143     case FileType::IMAGE_SEQUENCE: return tr("Import image sequence");
144     case FileType::GIF: return tr("Import Animated GIF");
145     case FileType::MOVIE: return tr("Import movie");
146     case FileType::SOUND: return tr("Import sound");
147     case FileType::PALETTE: return tr("Open palette");
148     }
149     return "";
150 }
151 
saveDialogCaption(FileType fileType)152 QString FileDialog::saveDialogCaption(FileType fileType)
153 {
154     switch (fileType)
155     {
156     case FileType::ANIMATION: return tr("Save animation");
157     case FileType::IMAGE: return tr("Export image");
158     case FileType::IMAGE_SEQUENCE: return tr("Export image sequence");
159     case FileType::GIF: return tr("Export Animated GIF");
160     case FileType::MOVIE: return tr("Export movie");
161     case FileType::SOUND: return tr("Export sound");
162     case FileType::PALETTE: return tr("Export palette");
163     }
164     return "";
165 }
166 
openFileFilters(FileType fileType)167 QString FileDialog::openFileFilters(FileType fileType)
168 {
169     switch (fileType)
170     {
171     case FileType::ANIMATION: return PFF_OPEN_PROJECT_EXT_FILTER;
172     case FileType::IMAGE: return PFF_IMAGE_FILTER;
173     case FileType::IMAGE_SEQUENCE: return PFF_IMAGE_SEQ_FILTER;
174     case FileType::GIF: return PFF_GIF_EXT_FILTER;
175     case FileType::MOVIE: return PFF_MOVIE_EXT;
176     case FileType::SOUND: return PFF_SOUND_EXT_FILTER;
177     case FileType::PALETTE: return PFF_PALETTE_EXT_FILTER;
178     }
179     return "";
180 }
181 
saveFileFilters(FileType fileType)182 QString FileDialog::saveFileFilters(FileType fileType)
183 {
184     switch (fileType)
185     {
186     case FileType::ANIMATION: return PFF_SAVE_PROJECT_EXT_FILTER;
187     case FileType::IMAGE: return "";
188     case FileType::IMAGE_SEQUENCE: return "";
189     case FileType::GIF: return QString("%1 (*.gif)").arg(tr("Animated GIF"));
190     case FileType::MOVIE: return "MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng)";
191     case FileType::SOUND: return "";
192     case FileType::PALETTE: return PFF_PALETTE_EXT_FILTER;
193     }
194     return "";
195 }
196 
getFilterForFile(const QString & filters,QString filePath)197 QString FileDialog::getFilterForFile(const QString& filters, QString filePath)
198 {
199     if (!filePath.contains("."))
200     {
201         return QString();
202     }
203     QString fileExt = filePath.remove(0, filePath.lastIndexOf(".")).prepend("*");
204 
205     QStringList filtersSplit = filters.split(";;");
206     for (const QString& filter : filtersSplit)
207     {
208         int start = filter.indexOf("(");
209         int end = filter.indexOf(")");
210         if (start < 0 || end < 0)
211         {
212             continue;
213         }
214         start++;
215         QStringList filterExts = filter.mid(start, end - start).split(" ");
216         if (filterExts.contains(fileExt))
217         {
218             return filter.trimmed();
219         }
220     }
221 
222     return QString();
223 }
224 
defaultFileName(FileType fileType)225 QString FileDialog::defaultFileName(FileType fileType)
226 {
227     switch (fileType)
228     {
229     case FileType::ANIMATION: return tr("MyAnimation.pclx");
230     case FileType::IMAGE:
231     case FileType::IMAGE_SEQUENCE: return tr("untitled.png");
232     case FileType::GIF: return tr("untitled.gif");
233     case FileType::MOVIE: return tr("untitled.mp4");
234     case FileType::SOUND: return tr("untitled.wav");
235     case FileType::PALETTE: return tr("untitled.xml");
236     }
237     return "";
238 }
239 
toSettingKey(FileType fileType)240 QString FileDialog::toSettingKey(FileType fileType)
241 {
242     switch (fileType)
243     {
244     case FileType::ANIMATION: return "Animation";
245     case FileType::IMAGE: return "Image";
246     case FileType::IMAGE_SEQUENCE: return "ImageSequence";
247     case FileType::GIF: return "Animated GIF";
248     case FileType::MOVIE: return "Movie";
249     case FileType::SOUND: return "Sound";
250     case FileType::PALETTE: return "Palette";
251     }
252     return "";
253 }
254