KSeExpr 6.0.0.0
ExprFileDialog.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2011-2019 Disney Enterprises, Inc.
2// SPDX-License-Identifier: LicenseRef-Apache-2.0
3// SPDX-FileCopyrightText: 2020 L. E. Segovia <amy@amyspark.me>
4// SPDX-License-Identifier: GPL-3.0-or-later
5
6// NOTE: This is based on Dan's paint3d FileDialog
7
8#include "ExprFileDialog.h"
9
10#include <QMenu>
11#include <QPalette>
12#include <QTimer>
13#include <QToolButton>
14#include <QUrl>
15#include <array>
16#include <iostream>
17
18using std::max;
19using std::min;
20
21static const std::array<const char *, 21> folder_fav = {"17 16 4 1", "# c #000000", ". c None", "a c #ffff98", "b c #cc0000", ".................", ".................",
22 "...#####.........", "..#aaaaa#........", ".###############.", ".#aaaaaaaaaaaaa#.", ".#aaaa##a##aaaa#.", ".#aaa#bb#bb#aaa#.", ".#aaa#bbbbb#aaa#.",
23 ".#aaa#bbbbb#aaa#.", ".#aaaa#bbb#aaaa#.", ".#aaaaa#b#aaaaa#.", ".#aaaaaa#aaaaaa#.", ".#aaaaaaaaaaaaa#.", ".###############.", "................."};
24
25void ExprPreviewWidget::makePreview(const QString &path)
26{
27 QFileInfo fi(path);
28
29 if (fi.isDir()) {
30 QString s = fi.absoluteFilePath() + QString::fromLatin1("/preview.tif");
31 if (!QFile::exists(s))
32 s = fi.absoluteFilePath() + QString::fromLatin1("/preview.png");
33 if (!QFile::exists(s))
34 _pm->setPixmap(QPixmap()); // nothing to preview
35
36 QPixmap pix(s);
37 if (!pix.isNull())
38 _pm->setPixmap(pix);
39 else
40 _pm->setPixmap(QPixmap());
41 } else if (fi.exists()) {
42 QImage img(fi.absoluteFilePath());
43 if (!img.isNull())
44 _pm->setPixmap(QPixmap::fromImage(img.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
45 else
46 _pm->setPixmap(QPixmap());
47 } else
48 _pm->setPixmap(QPixmap());
49 _pm->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
50}
51
53 : QWidget(parent)
54{
55 _pm = new QLabel(this);
56 _pm->setFrameStyle(QFrame::StyledPanel);
57 _pm->setBackgroundRole(QPalette::Base);
58 _pm->setAutoFillBackground(true);
59 auto *layout = new QVBoxLayout;
60 layout->setSpacing(0);
61 layout->setContentsMargins({});
62 layout->addWidget(_pm);
63 setLayout(layout);
64}
65
67 : QFileDialog(parent)
68{
69 // QStringList pathlist(QString(globals.startpath.c_str()));
70 // addLookInEntries(pathlist);
71
72 // disconnect broken return press handling (mishandles new directory names)
73 QList<QLineEdit *> lineedits = findChildren<QLineEdit *>();
74 if (!lineedits.empty())
75 _nameEdit = (QLineEdit *)lineedits.at(0);
76 if (_nameEdit) {
77 _nameEdit->disconnect(SIGNAL(returnPressed()));
78 connect(_nameEdit, SIGNAL(returnPressed()), SLOT(editReturnPress()));
79 }
80
81 // connect custom ok clicked handler
82 QList<QPushButton *> myWidgets = findChildren<QPushButton *>();
83 for (auto *const item : myWidgets) {
84 if (item->text().contains(tr("Open")))
85 _okButton = item;
86 }
87 if (_okButton)
88 connect(_okButton, SIGNAL(clicked()), SLOT(handleOk()));
89
90 connect(this, SIGNAL(currentChanged(const QString &)), this, SLOT(selChanged(const QString &)));
91
92 // don't create missing directories by default
93 _favDir = QString();
94 _temppath = QString();
95
96 setMinimumWidth(680);
97 resize(840, 440);
98}
99
101{
102 if (fileMode() != QFileDialog::Directory)
103 return;
104 QString entry = _nameEdit->text();
105 if (entry.isEmpty())
106 return;
107
108 // create directory if needed
109 if (_createDir) {
110 QDir d(directory());
111 if (!d.exists(entry)) {
112 if (d.mkdir(entry)) {
113 _temppath = directory().absolutePath();
114 setDirectory(_temppath + QLatin1Char('/') + entry);
115 _nameEdit->setText(QString());
116 if (_okButton)
117 _okButton->animateClick(); // retry click to accept entry
118
119 QTimer::singleShot(200, this, SLOT(resetDir()));
120 }
121 }
122 }
123}
124
126{
127 if (!_nameEdit)
128 return;
129
130 QString str = _nameEdit->text();
131 if (str.contains(QLatin1Char('/'))) {
132 QDir d;
133 if (d.cd(str)) {
134 setDirectory(str);
135 _nameEdit->setText(QString());
136 } else {
137 int slashcount = str.count(QLatin1Char('/'));
138
139 QString foundDir;
140 for (int i = 0; i < slashcount; i++) {
141 QString section = str.section(QLatin1Char('/'), 0, i);
142 if (d.cd(section))
143 foundDir = section;
144 }
145 if (foundDir.length()) {
146 setDirectory(foundDir);
147 QString remainder = str.right(str.length() - (foundDir.length() + 1));
148 _nameEdit->setText(remainder);
149 }
150
151 if (d.cd(str))
152 setDirectory(str);
153 }
154 } else if (fileMode() == QFileDialog::Directory)
155 handleOk();
156 else
157 accept();
158}
159
160void ExprFileDialog::addFavoritesButton(const QString &dirname, const QString &linkname, const QString &linkdir)
161{
162 auto *layout = findChild<QGridLayout *>(QString::fromLatin1("gridLayout"));
163 if (!layout)
164 return;
165
166 QDir d;
167
168 std::string favlocation = getenv("HOME");
169 favlocation += "/paint3d/favorites/";
170
171 QString dirpath = QString::fromStdString(favlocation);
172 if (!d.cd(dirpath))
173 d.mkpath(dirpath);
174 dirpath += dirname;
175 if (!d.cd(dirpath))
176 d.mkpath(dirpath);
177
178 if (!(linkdir.isEmpty() || linkname.isEmpty())) {
179 if (!QFile::exists(dirpath + linkname))
180 QFile::link(linkdir, dirpath + linkname);
181 }
182
183 _favDir = dirpath;
184
185 static QPixmap folderFav(folder_fav.data());
186 auto *fav = new QToolButton(this);
187 fav->setFixedSize(18, 18);
188 fav->setIcon(folderFav);
189 fav->setToolTip(tr("Favorites"));
190
191 layout->addWidget(fav, 0, 3);
192
193 connect(fav, SIGNAL(clicked()), SLOT(gotoFavorites()));
194}
195
197{
198 if (!_favDir.isEmpty())
199 setDirectory(_favDir);
200}
201
202void ExprFileDialog::addLookInEntries(const QStringList &paths)
203{
204 if (paths.isEmpty())
205 return;
206
207 QStringList h = history();
208 for (const auto &it : paths) {
209 if (!h.contains(it))
210 h.push_back(it);
211 }
212 setHistory(h);
213}
214
216{
217 _lookInList = history();
218}
219
221{
222 setHistory(_lookInList);
223}
224
225static QStringList makeFiltersList(const QString &filter)
226{
227 if (filter.isEmpty())
228 return QStringList();
229
230 int i = filter.indexOf(QString::fromLatin1(";;"), 0);
231 QString sep = QString::fromLatin1(";;");
232 if (i == -1) {
233 if (filter.indexOf(QString::fromLatin1("\n"), 0) != -1) {
234 sep = QString::fromLatin1("\n");
235 i = filter.indexOf(sep, 0);
236 }
237 }
238
239 return filter.split(sep);
240}
241
242QString ExprFileDialog::getOpenFileName(const QString &caption, const QString &startWith, const QString &filter)
243{
244 if (!filter.isEmpty()) {
245 QStringList filters = makeFiltersList(filter);
246 setNameFilters(filters);
247 }
248
249 if (!startWith.isEmpty())
250 setDirectory(startWith);
251 if (!caption.isNull())
252 setWindowTitle(caption);
253 setFileMode(QFileDialog::ExistingFile);
254 setAcceptMode(QFileDialog::AcceptOpen);
255 selectFile(QString());
256
257 QString result;
258 if (exec() == QDialog::Accepted) {
259 result = selectedFiles().first();
260 _workingDirectory = directory().absolutePath();
261 }
262 resetPreview();
263
264 return result;
265}
266
267QStringList ExprFileDialog::getOpenFileNames(const QString &caption, const QString &startWith, const QString &filter)
268{
269 if (!filter.isEmpty()) {
270 QStringList filters = makeFiltersList(filter);
271 setNameFilters(filters);
272 }
273
274 if (!startWith.isEmpty())
275 setDirectory(startWith);
276 if (!caption.isNull())
277 setWindowTitle(caption);
278 setFileMode(QFileDialog::ExistingFiles);
279 setAcceptMode(QFileDialog::AcceptOpen);
280 selectFile(QString());
281
282 QString result;
283 QStringList lst;
284 if (exec() == QDialog::Accepted) {
285 lst = selectedFiles();
286 _workingDirectory = directory().absolutePath();
287 }
288 resetPreview();
289
290 return lst;
291}
292
293QString ExprFileDialog::getExistingDirectory(const QString &caption, const QString &startWith, const QString &filter)
294{
295 if (!filter.isEmpty()) {
296 QStringList filters = makeFiltersList(filter);
297 setNameFilters(filters);
298 }
299
300 if (!startWith.isEmpty())
301 setDirectory(startWith);
302 if (!caption.isNull())
303 setWindowTitle(caption);
304 setFileMode(QFileDialog::Directory);
305 selectFile(QString());
306
307 QString result;
308 if (exec() == QDialog::Accepted) {
309 result = selectedFiles().first();
310 _workingDirectory = directory().absolutePath();
311 }
312 resetPreview();
313
314 return result;
315}
316
317QString ExprFileDialog::getExistingOrNewDirectory(const QString &caption, const QString &startWith, const QString &filter)
318{
319 _createDir = true;
320 QString result = getExistingDirectory(caption, startWith, filter);
321 _createDir = false;
322 resetPreview();
323 return result;
324}
325
326QString ExprFileDialog::getSaveFileName(const QString &caption, const QString &startWith, const QString &filter)
327{
328 if (!filter.isEmpty()) {
329 QStringList filters = makeFiltersList(filter);
330 setNameFilters(filters);
331 }
332
333 if (!startWith.isEmpty())
334 setDirectory(startWith);
335 if (!caption.isNull())
336 setWindowTitle(caption);
337 setFileMode(QFileDialog::AnyFile);
338 setAcceptMode(QFileDialog::AcceptSave);
339 selectFile(QString());
340
341 QString result;
342 if (exec() == QDialog::Accepted) {
343 result = selectedFiles().first();
344 _workingDirectory = directory().absolutePath();
345 }
346 resetPreview();
347
348 return result;
349}
350
352{
353 auto *layout = findChild<QGridLayout *>(QString::fromLatin1("gridLayout"));
354 if (!layout)
355 return;
356
357 _pw = new ExprPreviewWidget(this);
358 _pw->setFixedWidth(160);
359 _pw->setMinimumHeight(160);
360 layout->addWidget(_pw, 1, 3);
361}
362
364{
365 if (_pw)
366 _pw->reset();
367}
368
369void ExprFileDialog::addCheckBox(const QString &s)
370{
371 auto *layout = findChild<QGridLayout *>(QString::fromLatin1("gridLayout"));
372 if (!layout)
373 return;
374
375 _cb = new QCheckBox(s, this);
376 _cb->setChecked(false);
377
378 layout->addWidget(_cb, 4, _combo ? 2 : 0);
379}
380
382{
383 if (!_cb)
384 return false;
385 return _cb->isChecked();
386}
387
389{
390 if (_cb)
391 _cb->show();
392}
393
395{
396 if (_cb)
397 _cb->hide();
398}
399
400void ExprFileDialog::addComboBox(const QString &s, const QStringList &sl)
401{
402 auto *layout = findChild<QGridLayout *>(QString::fromLatin1("gridLayout"));
403 if (!layout)
404 return;
405
406 _combolabel = new QLabel(s, this);
407 _combolabel->setFixedWidth(58);
408 _combo = new QComboBox(this);
409 _combo->setEditable(true);
410 _combo->setFixedWidth(160);
411 for (const auto &it : sl)
412 _combo->addItem(it);
413
414 int rownum = layout->rowCount();
415 layout->addWidget(_combo, rownum, 1);
416 layout->addWidget(_combolabel, rownum, 0);
417}
418
420{
421 if (_combo)
422 _combo->show();
423 if (_combolabel)
424 _combolabel->show();
425}
426
428{
429 if (_combo)
430 _combo->hide();
431 if (_combolabel)
432 _combolabel->hide();
433}
434
435void ExprFileDialog::selChanged(const QString &path)
436{
437 if (_pw)
438 _pw->makePreview(path);
439}
440
441void ExprFileDialog::setButtonName(const QString &str)
442{
443 if (_okButton)
444 _okButton->setText(str);
445}
446
448{
449 QList<QUrl> urls = sidebarUrls();
450 QUrl url = QUrl::fromLocalFile(s);
451 if (url.isValid() && QFile::exists(s)) {
452 urls.push_back(url);
453 setSidebarUrls(urls);
454 }
455}
static QStringList makeFiltersList(const QString &filter)
static const std::array< const char *, 21 > folder_fav
QString _workingDirectory
QStringList getOpenFileNames(const QString &caption=QString(), const QString &startWith=QString(), const QString &filter=QString())
QString getExistingDirectory(const QString &caption=QString(), const QString &startWith=QString(), const QString &filter=QString())
QString getExistingOrNewDirectory(const QString &caption=QString(), const QString &startWith=QString(), const QString &filter=QString())
void addLookInEntries(const QStringList &paths)
void addFavoritesButton(const QString &dirname, const QString &linkname, const QString &linkdir)
ExprPreviewWidget * _pw
QComboBox * _combo
QLabel * _combolabel
void setButtonName(const QString &str)
void addComboBox(const QString &s, const QStringList &sl)
void addSidebarShortcut(const QString &s)
void addCheckBox(const QString &s)
QString getSaveFileName(const QString &caption=QString(), const QString &startWith=QString(), const QString &filter=QString())
QLineEdit * _nameEdit
std::atomic< bool > _createDir
QStringList _lookInList
QPushButton * _okButton
ExprFileDialog(QWidget *parent=nullptr)
QCheckBox * _cb
QString getOpenFileName(const QString &caption=QString(), const QString &startWith=QString(), const QString &filter=QString())
void selChanged(const QString &path)
void makePreview(const QString &path)
ExprPreviewWidget(QWidget *parent)