dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
pathchooser.cpp
Go to the documentation of this file.
1 
13 /*
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  * for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, see <http://www.gnu.org/licenses/>
26  */
27 
28 #include "pathchooser.h"
29 
30 #include "basevalidatinglineedit.h"
31 #include "hostosinfo.h"
32 #include "qtcassert.h"
33 
34 #include <QtCore/QDebug>
35 #include <QtCore/QDir>
36 #include <QtCore/QFileInfo>
37 #include <QtCore/QSettings>
38 
39 #include <QDesktopServices>
40 #include <QStandardPaths>
41 #include <QFileDialog>
42 #include <QHBoxLayout>
43 #include <QLineEdit>
44 #include <QToolButton>
45 #include <QPushButton>
46 
47 /*static*/ const char * const Utils::PathChooser::browseButtonLabel =
48 #ifdef Q_OS_MAC
49  QT_TRANSLATE_NOOP("Utils::PathChooser", "Choose...");
50 #else
51  QT_TRANSLATE_NOOP("Utils::PathChooser", "Browse...");
52 #endif
53 
54 namespace Utils {
55 
56 // ------------------ PathValidatingLineEdit
58 {
59 public:
60  explicit PathValidatingLineEdit(PathChooser *chooser, QWidget *parent = nullptr);
61 
62 protected:
63  virtual bool validate(const QString &value, QString *errorMessage) const;
64 
65 private:
66  PathChooser *m_chooser;
67 };
68 
70  BaseValidatingLineEdit(parent),
71  m_chooser(chooser)
72 {
73  QTC_ASSERT(chooser, return);
74 }
75 
76 bool PathValidatingLineEdit::validate(const QString &value, QString *errorMessage) const
77 {
78  return m_chooser->validatePath(value, errorMessage);
79 }
80 
81 // ------------------ PathChooserPrivate
83 {
85 
86  QHBoxLayout *m_hLayout;
88  PathChooser::Kind m_acceptingKind;
90  QString m_dialogFilter;
92 };
93 
95  m_hLayout(new QHBoxLayout),
96  m_lineEdit(new PathValidatingLineEdit(chooser)),
97  m_acceptingKind(PathChooser::Directory)
98 {
99 }
100 
101 PathChooser::PathChooser(QWidget *parent) :
102  QWidget(parent),
103  m_d(new PathChooserPrivate(this))
104 {
105 
106  m_d->m_hLayout->setContentsMargins(0, 0, 0, 0);
107 
108  connect(m_d->m_lineEdit, SIGNAL(validReturnPressed()), this, SIGNAL(returnPressed()));
109  connect(m_d->m_lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(changed(QString)));
110  connect(m_d->m_lineEdit, SIGNAL(validChanged()), this, SIGNAL(validChanged()));
111  connect(m_d->m_lineEdit, SIGNAL(validChanged(bool)), this, SIGNAL(validChanged(bool)));
112  connect(m_d->m_lineEdit, SIGNAL(editingFinished()), this, SIGNAL(editingFinished()));
113 
114  m_d->m_lineEdit->setMinimumWidth(50);
115  m_d->m_hLayout->addWidget(m_d->m_lineEdit);
116  m_d->m_hLayout->setSizeConstraint(QLayout::SetMinimumSize);
117 
118  addButton(tr(browseButtonLabel), this, SLOT(slotBrowse()));
119 
120  setLayout(m_d->m_hLayout);
121  setFocusProxy(m_d->m_lineEdit);
122 }
123 
124 PathChooser::~PathChooser()
125 {
126  delete m_d;
127 }
128 
129 void PathChooser::addButton(const QString &text, QObject *receiver, const char *slotFunc)
130 {
131 #ifdef Q_OS_MAC
132  QPushButton *button = new QPushButton;
133 #else
134  QToolButton *button = new QToolButton;
135 #endif
136  button->setText(text);
137  connect(button, SIGNAL(clicked()), receiver, slotFunc);
138  m_d->m_hLayout->addWidget(button);
139 }
140 
141 QAbstractButton *PathChooser::buttonAtIndex(int index) const
142 {
143  return findChildren<QAbstractButton*>().at(index);
144 }
145 
146 QString PathChooser::path() const
147 {
148  return m_d->m_lineEdit->text();
149 }
150 
151 void PathChooser::setPath(const QString &path)
152 {
153  m_d->m_lineEdit->setText(QDir::toNativeSeparators(path));
154 }
155 
156 void PathChooser::slotBrowse()
157 {
158  emit beforeBrowsing();
159 
160  QString predefined = path();
161  if ((predefined.isEmpty() || !QFileInfo(predefined).isDir())
162  && !m_d->m_initialBrowsePathOverride.isNull()) {
163  predefined = m_d->m_initialBrowsePathOverride;
164  if (!QFileInfo(predefined).isDir())
165  predefined.clear();
166  }
167 
168  if (predefined.startsWith(":"))
169  predefined.clear();
170 
171  // Prompt for a file/dir
172  QString dialogTitle;
173  QString newPath;
174  switch (m_d->m_acceptingKind) {
175  case PathChooser::Directory:
176  newPath = QFileDialog::getExistingDirectory(this,
177  makeDialogTitle(tr("Choose a directory")), predefined);
178  break;
179 
180  case PathChooser::File: // fall through
181  case PathChooser::Command:
182  newPath = QFileDialog::getOpenFileName(this,
183  makeDialogTitle(tr("Choose a file")), predefined,
184  m_d->m_dialogFilter);
185  break;
186 
187  default:
188  ;
189  }
190 
191  // Delete trailing slashes unless it is "/"|"\\", only
192  if (!newPath.isEmpty()) {
193  newPath = QDir::toNativeSeparators(newPath);
194  if (newPath.size() > 1 && newPath.endsWith(QDir::separator()))
195  newPath.truncate(newPath.size() - 1);
196  setPath(newPath);
197  }
198 
199  emit browsingFinished();
200 }
201 
202 bool PathChooser::isValid() const
203 {
204  return m_d->m_lineEdit->isValid();
205 }
206 
207 QString PathChooser::errorMessage() const
208 {
209  return m_d->m_lineEdit->errorMessage();
210 }
211 
212 bool PathChooser::validatePath(const QString &path, QString *errorMessage)
213 {
214  if (path.isEmpty()) {
215  if (errorMessage)
216  *errorMessage = tr("The path must not be empty.");
217  return false;
218  }
219 
220  const QFileInfo fi(path);
221  const bool isDir = fi.isDir();
222 
223  // Check if existing
224  switch (m_d->m_acceptingKind) {
225  case PathChooser::Directory: // fall through
226  case PathChooser::File:
227  if (!fi.exists()) {
228  if (errorMessage)
229  *errorMessage = tr("The path '%1' does not exist.").arg(path);
230  return false;
231  }
232  break;
233 
234  case PathChooser::Command: // fall through
235  default:
236  ;
237  }
238 
239  // Check expected kind
240  switch (m_d->m_acceptingKind) {
241  case PathChooser::Directory:
242  if (!isDir) {
243  if (errorMessage)
244  *errorMessage = tr("The path '%1' is not a directory.").arg(path);
245  return false;
246  }
247  break;
248 
249  case PathChooser::File:
250  if (isDir) {
251  if (errorMessage)
252  *errorMessage = tr("The path '%1' is not a file.").arg(path);
253  return false;
254  }
255  break;
256 
257  case PathChooser::Command:
258  // TODO do proper command validation
259  // i.e. search $PATH for a matching file
260  break;
261 
262  default:
263  ;
264  }
265 
266  return true;
267 }
268 
269 QString PathChooser::label()
270 {
271  return tr("Path:");
272 }
273 
274 QString PathChooser::homePath()
275 {
276  // Return 'users/<name>/Documents' on Windows, since Windows explorer
277  // does not let people actually display the contents of their home
278  // directory. Alternatively, create a QtCreator-specific directory?
280  return QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
281  return QDir::homePath();
282 }
283 
284 void PathChooser::setExpectedKind(Kind expected)
285 {
286  m_d->m_acceptingKind = expected;
287 }
288 
289 PathChooser::Kind PathChooser::expectedKind() const
290 {
291  return m_d->m_acceptingKind;
292 }
293 
294 void PathChooser::setPromptDialogTitle(const QString &title)
295 {
296  m_d->m_dialogTitleOverride = title;
297 }
298 
299 QString PathChooser::promptDialogTitle() const
300 {
301  return m_d->m_dialogTitleOverride;
302 }
303 
304 void PathChooser::setPromptDialogFilter(const QString &filter)
305 {
306  m_d->m_dialogFilter = filter;
307 }
308 
309 QString PathChooser::promptDialogFilter() const
310 {
311  return m_d->m_dialogFilter;
312 }
313 
314 void PathChooser::setInitialBrowsePathBackup(const QString &path)
315 {
316  m_d->m_initialBrowsePathOverride = path;
317 }
318 
319 QString PathChooser::makeDialogTitle(const QString &title)
320 {
321  if (m_d->m_dialogTitleOverride.isNull())
322  return title;
323  else
324  return m_d->m_dialogTitleOverride;
325 }
326 
327 } // namespace Utils
PathValidatingLineEdit(PathChooser *chooser, QWidget *parent=nullptr)
Definition: pathchooser.cpp:69
virtual bool validate(const QString &value, QString *errorMessage) const
Definition: pathchooser.cpp:76
PathChooser::Kind m_acceptingKind
Definition: pathchooser.cpp:88
QT_TRANSLATE_NOOP("Utils::PathChooser","Browse...")
PathValidatingLineEdit * m_lineEdit
Definition: pathchooser.cpp:87
PathChooserPrivate(PathChooser *chooser)
Definition: pathchooser.cpp:94
void setPath(const QString &)
static bool isWindowsHost()
Definition: hostosinfo.h:56