KSeExpr  4.0.4.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 
18 using std::max;
19 using std::min;
20 
21 static 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 
25 void 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->setMargin(0);
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::DirectoryOnly)
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::DirectoryOnly)
155  handleOk();
156  else
157  accept();
158 }
159 
160 void 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 
202 void 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 
225 static 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 
242 QString 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 
267 QStringList 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 
293 QString 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::DirectoryOnly);
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 
317 QString 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 
326 QString 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 
369 void 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 
400 void 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 
435 void ExprFileDialog::selChanged(const QString &path)
436 {
437  if (_pw)
438  _pw->makePreview(path);
439 }
440 
441 void 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 restoreLookInEntries()
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)
double max(double x, double y)
Definition: ExprBuiltins.h:74
double min(double x, double y)
Definition: ExprBuiltins.h:78