From 656c8691f17550b64e2e711ff8509e5053585c8d Mon Sep 17 00:00:00 2001
From: Tobias Hunger <tobias.hunger@nokia.com>
Date: Thu, 23 Sep 2010 11:06:12 +0200
Subject: [PATCH] PathChooser: Make use of the environment

 * Expand environment arguments
 * Introduce new kind: ExistingCommand
 * Use PATH to look up ExistingCommand

Reviewed-by: dt
---
 src/libs/utils/pathchooser.cpp | 86 +++++++++++++++++++++++++++-------
 src/libs/utils/pathchooser.h   |  9 +++-
 2 files changed, 76 insertions(+), 19 deletions(-)

diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp
index db6a0129fe..0b121a63d4 100644
--- a/src/libs/utils/pathchooser.cpp
+++ b/src/libs/utils/pathchooser.cpp
@@ -30,6 +30,7 @@
 #include "pathchooser.h"
 
 #include "basevalidatinglineedit.h"
+#include "environment.h"
 #include "qtcassert.h"
 
 #include <QtCore/QDebug>
@@ -54,6 +55,7 @@
 namespace Utils {
 
 // ------------------ PathValidatingLineEdit
+
 class PathValidatingLineEdit : public BaseValidatingLineEdit
 {
 public:
@@ -79,10 +81,14 @@ bool PathValidatingLineEdit::validate(const QString &value, QString *errorMessag
 }
 
 // ------------------ PathChooserPrivate
-struct PathChooserPrivate
+
+class PathChooserPrivate
 {
+public:
     PathChooserPrivate(PathChooser *chooser);
 
+    QString expandedPath(const QString &path) const;
+
     QHBoxLayout *m_hLayout;
     PathValidatingLineEdit *m_lineEdit;
     PathChooser::Kind m_acceptingKind;
@@ -90,6 +96,7 @@ struct PathChooserPrivate
     QString m_dialogFilter;
     QString m_initialBrowsePathOverride;
     QString m_baseDirectory;
+    Environment m_environment;
 };
 
 PathChooserPrivate::PathChooserPrivate(PathChooser *chooser) :
@@ -99,6 +106,24 @@ PathChooserPrivate::PathChooserPrivate(PathChooser *chooser) :
 {
 }
 
+QString PathChooserPrivate::expandedPath(const QString &input) const
+{
+    QString path = QDir::fromNativeSeparators(input);
+    if (m_environment.size() > 0)
+        return m_environment.expandVariables(path);
+
+    if (path.isEmpty() || m_acceptingKind == PathChooser::Command)
+        return path;
+
+    if (m_acceptingKind == PathChooser::ExistingCommand)
+        return m_environment.searchInPath(path, QStringList() << m_baseDirectory);
+
+    if (!m_baseDirectory.isEmpty() && QFileInfo(path).isRelative())
+        return QFileInfo(m_baseDirectory + QLatin1Char('/') + path).absoluteFilePath();
+
+    return path;
+}
+
 PathChooser::PathChooser(QWidget *parent) :
     QWidget(parent),
     m_d(new PathChooserPrivate(this))
@@ -119,6 +144,8 @@ PathChooser::PathChooser(QWidget *parent) :
 
     setLayout(m_d->m_hLayout);
     setFocusProxy(m_d->m_lineEdit);
+
+    setEnvironment(Environment::systemEnvironment());
 }
 
 PathChooser::~PathChooser()
@@ -153,15 +180,20 @@ void PathChooser::setBaseDirectory(const QString &directory)
     m_d->m_baseDirectory = directory;
 }
 
+void PathChooser::setEnvironment(const Utils::Environment &env)
+{
+    m_d->m_environment = env;
+}
+
+
 QString PathChooser::path() const
 {
-    const QString path = m_d->m_lineEdit->text();
-    if (!m_d->m_baseDirectory.isEmpty()
-            && QFileInfo(path).isRelative()
-            && !path.isEmpty())
-        return QFileInfo(m_d->m_baseDirectory + QLatin1Char('/') + path).absoluteFilePath();
-    else
-        return QDir::fromNativeSeparators(path);
+    return m_d->expandedPath(QDir::fromNativeSeparators(m_d->m_lineEdit->text()));
+}
+
+QString PathChooser::rawPath() const
+{
+    return QDir::fromNativeSeparators(m_d->m_lineEdit->text());
 }
 
 void PathChooser::setPath(const QString &path)
@@ -188,8 +220,13 @@ void PathChooser::slotBrowse()
         newPath = QFileDialog::getExistingDirectory(this,
                 makeDialogTitle(tr("Choose Directory")), predefined);
         break;
-    case PathChooser::File: // fall through
+    case PathChooser::ExistingCommand:
     case PathChooser::Command:
+        newPath = QFileDialog::getOpenFileName(this,
+                makeDialogTitle(tr("Choose Executable")), predefined,
+                m_d->m_dialogFilter);
+        break;
+    case PathChooser::File: // fall through
         newPath = QFileDialog::getOpenFileName(this,
                 makeDialogTitle(tr("Choose File")), predefined,
                 m_d->m_dialogFilter);
@@ -239,21 +276,31 @@ QString PathChooser::errorMessage() const
 
 bool PathChooser::validatePath(const QString &path, QString *errorMessage)
 {
-    if (path.isEmpty()) {
+    QString expandedPath = m_d->expandedPath(path);
+
+    QString displayPath = expandedPath;
+    if (expandedPath.isEmpty())
+        //: Selected path is not valid:
+        displayPath = tr("<not valid>");
+
+    *errorMessage = tr("Full path: <b>%1</b>").arg(QDir::toNativeSeparators(expandedPath));
+
+    if (expandedPath.isEmpty()) {
         if (errorMessage)
             *errorMessage = tr("The path must not be empty.");
         return false;
     }
 
-    const QFileInfo fi(path);
+    const QFileInfo fi(expandedPath);
 
     // Check if existing
     switch (m_d->m_acceptingKind) {
     case PathChooser::Directory: // fall through
-    case PathChooser::File:
+    case PathChooser::File: // fall through
+    case PathChooser::ExistingCommand:
         if (!fi.exists()) {
             if (errorMessage)
-                *errorMessage = tr("The path '%1' does not exist.").arg(path);
+                *errorMessage = tr("The path '%1' does not exist.").arg(QDir::toNativeSeparators(expandedPath));
             return false;
         }
         break;
@@ -268,7 +315,7 @@ bool PathChooser::validatePath(const QString &path, QString *errorMessage)
     case PathChooser::Directory:
         if (!fi.isDir()) {
             if (errorMessage)
-                *errorMessage = tr("The path '%1' is not a directory.").arg(path);
+                *errorMessage = tr("The path <b>%1</b> is not a directory.").arg(QDir::toNativeSeparators(expandedPath));
             return false;
         }
         break;
@@ -276,14 +323,19 @@ bool PathChooser::validatePath(const QString &path, QString *errorMessage)
     case PathChooser::File:
         if (!fi.isFile()) {
             if (errorMessage)
-                *errorMessage = tr("The path '%1' is not a file.").arg(path);
+                *errorMessage = tr("The path <b>%1</b> is not a file.").arg(QDir::toNativeSeparators(expandedPath));
             return false;
         }
         break;
 
+    case PathChooser::ExistingCommand:
+        if (!fi.isFile() || !fi.isExecutable()) {
+            if (errorMessage)
+                *errorMessage = tr("The path <b>%1</b> is not a executable file.").arg(QDir::toNativeSeparators(expandedPath));
+            return false;
+        }
+
     case PathChooser::Command:
-        // TODO do proper command validation
-        // i.e. search $PATH for a matching file
         break;
 
     case PathChooser::Any:
diff --git a/src/libs/utils/pathchooser.h b/src/libs/utils/pathchooser.h
index 9d2b1a2097..ae7d9fe600 100644
--- a/src/libs/utils/pathchooser.h
+++ b/src/libs/utils/pathchooser.h
@@ -42,7 +42,8 @@ QT_END_NAMESPACE
 
 namespace Utils {
 
-struct PathChooserPrivate;
+class Environment;
+class PathChooserPrivate;
 
 /**
  * A control that let's the user choose a path, consisting of a QLineEdit and
@@ -67,7 +68,8 @@ public:
     enum Kind {
         Directory,
         File,
-        Command,
+        ExistingCommand, // A command that must exist at the time of selection
+        Command, // A command that may or may not exist at the time of selection (e.g. result of a build)
         Any
     };
 
@@ -87,10 +89,13 @@ public:
     QString errorMessage() const;
 
     QString path() const;
+    QString rawPath() const; // The raw unexpanded input.
 
     QString baseDirectory() const;
     void setBaseDirectory(const QString &directory);
 
+    void setEnvironment(const Utils::Environment &env);
+
     /** Returns the suggested label title when used in a form layout. */
     static QString label();
 
-- 
GitLab