SWMMVis  6.0.0-alpha.4
Qt6/C++ GIS-based graphical user interface for the SWMMVis engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
fileopendialog.h
Go to the documentation of this file.
1
9#ifndef FILEOPENDIALOG_H
10#define FILEOPENDIALOG_H
11
12#include <QCryptographicHash>
13#include <QDir>
14#include <QFileDialog>
15#include <QFileInfo>
16#include <QRegularExpression>
17#include <QSettings>
18#include <QStringList>
19#include <initializer_list>
20
21namespace openswmmvis::ui
22{
23
24// Shared by open/import pickers. Keys describe file categories, never translated
25// captions, so one picker or locale cannot reset another type's remembered folder.
27{
28public:
35 static QString startDirectory(const QString &type, const QString &fallback = {})
36 {
37 if (type == QStringLiteral("models")) {
38 const QString preferred =
39 QSettings()
40 .value(QStringLiteral("SWMMVis/Preferences/General/ProjectOpenDirectory"))
41 .toString();
42 if (!preferred.isEmpty() && QFileInfo(preferred).isDir())
43 return preferred;
44 }
45 const QString saved = QSettings().value(settingKey(type)).toString();
46 if (!saved.isEmpty() && QFileInfo(saved).isDir())
47 return saved;
48 if (!fallback.isEmpty()) {
49 const QFileInfo candidate(fallback);
50 if (candidate.isDir())
51 return candidate.absoluteFilePath();
52 if (QFileInfo(candidate.absolutePath()).isDir())
53 return candidate.absolutePath();
54 }
55 return QDir::homePath();
56 }
57
64 static void rememberSelection(const QString &type, const QStringList &paths)
65 {
66 // A cancelled picker must not erase history. For multiple files, remember
67 // the last selected file's folder (normally all selections share a folder).
68 for (auto it = paths.crbegin(); it != paths.crend(); ++it) {
69 if (it->isEmpty())
70 continue;
71 const QFileInfo file(*it);
72 if (!file.isFile())
73 continue;
74 QSettings settings;
75 settings.setValue(settingKey(type), file.absolutePath());
76 settings.sync();
77 return;
78 }
79 }
80
93 static QString getOpenFileName(const QString &type, QWidget *parent = nullptr,
94 const QString &caption = {}, const QString &directory = {},
95 const QString &filter = {}, QString *selectedFilter = nullptr,
96 QFileDialog::Options options = {})
97 {
98 const QString path = QFileDialog::getOpenFileName(
99 parent, caption, startDirectory(type, directory), filter, selectedFilter, options);
100 rememberSelection(type, {path});
101 return path;
102 }
103
116 static QStringList getOpenFileNames(const QString &type, QWidget *parent = nullptr,
117 const QString &caption = {}, const QString &directory = {},
118 const QString &filter = {},
119 QString *selectedFilter = nullptr,
120 QFileDialog::Options options = {})
121 {
122 const QStringList paths = QFileDialog::getOpenFileNames(
123 parent, caption, startDirectory(type, directory), filter, selectedFilter, options);
124 rememberSelection(type, paths);
125 return paths;
126 }
127
128 // Generic engine/plugin path editors know their filters rather than a fixed
129 // category. Known types share the corresponding main-window picker history.
135 static QString typeForFilter(const QString &filter)
136 {
137 static const QRegularExpression pattern(QStringLiteral(R"(\*\.([\w.\-?*]+))"));
138 QStringList extensions;
139 auto matches = pattern.globalMatch(filter);
140 while (matches.hasNext())
141 extensions.append(matches.next().captured(1).toLower());
142 extensions.removeDuplicates();
143 extensions.sort();
144 const auto hasAny = [&extensions](std::initializer_list<const char *> types) {
145 for (const char *type : types)
146 if (extensions.contains(QString::fromLatin1(type)))
147 return true;
148 return false;
149 };
150 if (extensions.contains(QStringLiteral("2dm")))
151 return QStringLiteral("mesh");
152 if (extensions.contains(QStringLiteral("out")))
153 return QStringLiteral("results-1d");
154 if (hasAny({"h5", "hdf5"}))
155 return QStringLiteral("results-2d");
156 if (extensions.contains(QStringLiteral("inp")) ||
157 extensions.contains(QStringLiteral("oswp")))
158 return QStringLiteral("models");
159 if (extensions.contains(QStringLiteral("qml")) ||
160 extensions.contains(QStringLiteral("swmm-style.json")))
161 return QStringLiteral("styles");
162 if (hasAny({"tfw", "pgw", "jgw", "bpw", "wld"}))
163 return QStringLiteral("world-files");
164 if (hasAny({"tif", "tiff", "asc", "img", "vrt", "nc", "png", "jpg", "jpeg", "bmp"}))
165 return QStringLiteral("raster");
166 if (hasAny({"shp", "gpkg", "geojson", "gml", "kml", "fgb", "dxf"}))
167 return QStringLiteral("vector");
168 if (hasAny({"csv", "tsv", "txt", "dat", "tsf"}))
169 return QStringLiteral("timeseries");
170 if (extensions.isEmpty())
171 return QStringLiteral("other-files");
172 return QStringLiteral("filter-") +
173 QString::fromLatin1(
174 QCryptographicHash::hash(extensions.join(QLatin1Char(';')).toUtf8(),
175 QCryptographicHash::Sha256)
176 .toHex());
177 }
178
179private:
185 static QString settingKey(const QString &type)
186 {
187 return QStringLiteral("SWMMVis/FileOpenDirectories/") +
188 (type.isEmpty() ? QStringLiteral("other-files") : type);
189 }
190};
191
192} // namespace openswmmvis::ui
193#endif // FILEOPENDIALOG_H
Definition fileopendialog.h:27
static QString getOpenFileName(const QString &type, QWidget *parent=nullptr, const QString &caption={}, const QString &directory={}, const QString &filter={}, QString *selectedFilter=nullptr, QFileDialog::Options options={})
Open the standard modal file picker with per-category folder memory.
Definition fileopendialog.h:93
static QStringList getOpenFileNames(const QString &type, QWidget *parent=nullptr, const QString &caption={}, const QString &directory={}, const QString &filter={}, QString *selectedFilter=nullptr, QFileDialog::Options options={})
Open the standard modal file picker with per-category folder memory.
Definition fileopendialog.h:116
static QString typeForFilter(const QString &filter)
Map a filename filter to a shared category or deterministic extension-set key.
Definition fileopendialog.h:135
static QString startDirectory(const QString &type, const QString &fallback={})
Choose the most applicable existing directory for an open/import category.
Definition fileopendialog.h:35
static void rememberSelection(const QString &type, const QStringList &paths)
Persist the parent of the last nonempty selected regular file.
Definition fileopendialog.h:64
QString path
Populated by the worker only after its own successful atomic creation.
Definition extensiontimeseriesaccess.cpp:32
const char * extensions
Space-separated, no dots: "tif tiff".
Definition gdaldrivers.cpp:29
Definition openswmmvislayer.h:46
const ConstraintAuditOptions & options
Definition constraintaudit.cpp:34
int parent
Definition planning.cpp:199