fileutils.cpp 8.95 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
Robert Loehning's avatar
Robert Loehning committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
Robert Loehning's avatar
Robert Loehning committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
Robert Loehning's avatar
Robert Loehning committed
7
**
hjk's avatar
hjk committed
8 9 10 11 12 13 14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
Robert Loehning's avatar
Robert Loehning committed
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22 23 24 25
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
Robert Loehning's avatar
Robert Loehning committed
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
Robert Loehning's avatar
Robert Loehning committed
29 30 31

#include "fileutils.h"

hjk's avatar
hjk committed
32
#include <coreplugin/coreconstants.h>
33
#include <coreplugin/documentmanager.h>
Robert Loehning's avatar
Robert Loehning committed
34
#include <coreplugin/icore.h>
35 36
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
hjk's avatar
hjk committed
37 38 39 40
#include <utils/consoleprocess.h>
#include <utils/hostosinfo.h>
#include <utils/qtcprocess.h>
#include <utils/unixutils.h>
Robert Loehning's avatar
Robert Loehning committed
41

hjk's avatar
hjk committed
42
#include <QApplication>
43 44 45
#include <QDir>
#include <QFileInfo>
#include <QMessageBox>
hjk's avatar
hjk committed
46 47
#include <QProcess>
#include <QPushButton>
48
#include <QWidget>
Robert Loehning's avatar
Robert Loehning committed
49

50 51 52 53
#if QT_VERSION < 0x050000
#include <QAbstractFileEngine>
#endif

hjk's avatar
hjk committed
54
using namespace Utils;
Robert Loehning's avatar
Robert Loehning committed
55

hjk's avatar
hjk committed
56
namespace Core {
Robert Loehning's avatar
Robert Loehning committed
57 58

// Show error with option to open settings.
hjk's avatar
hjk committed
59
static void showGraphicalShellError(QWidget *parent, const QString &app, const QString &error)
Robert Loehning's avatar
Robert Loehning committed
60 61 62 63 64 65 66 67 68
{
    const QString title = QApplication::translate("Core::Internal",
                                                  "Launching a file browser failed");
    const QString msg = QApplication::translate("Core::Internal",
                                                "Unable to start the file manager:\n\n%1\n\n").arg(app);
    QMessageBox mbox(QMessageBox::Warning, title, msg, QMessageBox::Close, parent);
    if (!error.isEmpty())
        mbox.setDetailedText(QApplication::translate("Core::Internal",
                                                     "'%1' returned the following error:\n\n%2").arg(app, error));
69
    QAbstractButton *settingsButton = mbox.addButton(Core::ICore::msgShowOptionsDialog(),
Robert Loehning's avatar
Robert Loehning committed
70 71
                                                     QMessageBox::ActionRole);
    mbox.exec();
hjk's avatar
hjk committed
72 73
    if (mbox.clickedButton() == settingsButton)
        ICore::showOptionsDialog(Constants::SETTINGS_CATEGORY_CORE, Constants::SETTINGS_ID_ENVIRONMENT);
Robert Loehning's avatar
Robert Loehning committed
74 75 76 77 78
}

void FileUtils::showInGraphicalShell(QWidget *parent, const QString &pathIn)
{
    // Mac, Windows support folder or file.
hjk's avatar
hjk committed
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
    if (HostOsInfo::isWindowsHost()) {
        const QString explorer = Environment::systemEnvironment().searchInPath(QLatin1String("explorer.exe"));
        if (explorer.isEmpty()) {
            QMessageBox::warning(parent,
                                 QApplication::translate("Core::Internal",
                                                         "Launching Windows Explorer Failed"),
                                 QApplication::translate("Core::Internal",
                                                         "Could not find explorer.exe in path to launch Windows Explorer."));
            return;
        }
        QStringList param;
        if (!QFileInfo(pathIn).isDir())
            param += QLatin1String("/select,");
        param += QDir::toNativeSeparators(pathIn);
        QProcess::startDetached(explorer, param);
    } else if (HostOsInfo::isMacHost()) {
        QStringList scriptArgs;
        scriptArgs << QLatin1String("-e")
                   << QString::fromLatin1("tell application \"Finder\" to reveal POSIX file \"%1\"")
                                         .arg(pathIn);
        QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs);
        scriptArgs.clear();
        scriptArgs << QLatin1String("-e")
                   << QLatin1String("tell application \"Finder\" to activate");
        QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs);
    } else {
        // we cannot select a file here, because no file browser really supports it...
        const QFileInfo fileInfo(pathIn);
        const QString folder = fileInfo.isDir() ? fileInfo.absoluteFilePath() : fileInfo.filePath();
        const QString app = UnixUtils::fileBrowser(ICore::settings());
        QProcess browserProc;
        const QString browserArgs = UnixUtils::substituteFileBrowserParameters(app, folder);
        bool success = browserProc.startDetached(browserArgs);
        const QString error = QString::fromLocal8Bit(browserProc.readAllStandardError());
        success = success && error.isEmpty();
        if (!success)
            showGraphicalShellError(parent, app, error);
Robert Loehning's avatar
Robert Loehning committed
116 117 118 119 120 121
    }
}

void FileUtils::openTerminal(const QString &path)
{
    // Get terminal application
hjk's avatar
hjk committed
122
    QString terminalEmulator;
Robert Loehning's avatar
Robert Loehning committed
123
    QStringList args;
124 125
    const OsType hostOs = HostOsInfo::hostOs();
    if (hostOs == OsTypeWindows) {
Friedemann Kleint's avatar
Friedemann Kleint committed
126
        terminalEmulator = ConsoleProcess::defaultTerminalEmulator();
127
    } else if (hostOs == OsTypeMac) {
hjk's avatar
hjk committed
128 129 130
        terminalEmulator = ICore::resourcePath()
            + QLatin1String("/scripts/openTerminal.command");
    } else {
131
        args = QtcProcess::splitArgs(ConsoleProcess::terminalEmulator(ICore::settings()), hostOs);
hjk's avatar
hjk committed
132 133 134 135
        terminalEmulator = args.takeFirst();
        args.append(QString::fromLocal8Bit(qgetenv("SHELL")));
    }

Robert Loehning's avatar
Robert Loehning committed
136 137 138 139 140 141 142 143
    // Launch terminal with working directory set.
    const QFileInfo fileInfo(path);
    const QString pwd = QDir::toNativeSeparators(fileInfo.isDir() ?
                                                 fileInfo.absoluteFilePath() :
                                                 fileInfo.absolutePath());
    QProcess::startDetached(terminalEmulator, args, pwd);
}

144 145 146 147 148
QString FileUtils::msgFindInDirectory()
{
    return QApplication::translate("Core::Internal", "Find in This Directory...");
}

Robert Loehning's avatar
Robert Loehning committed
149 150
QString FileUtils::msgGraphicalShellAction()
{
hjk's avatar
hjk committed
151 152 153 154
    if (HostOsInfo::isWindowsHost())
        return QApplication::translate("Core::Internal", "Show in Explorer");
    if (HostOsInfo::isMacHost())
        return QApplication::translate("Core::Internal", "Show in Finder");
Eike Ziller's avatar
Eike Ziller committed
155
    return QApplication::translate("Core::Internal", "Show Containing Folder");
Robert Loehning's avatar
Robert Loehning committed
156 157 158 159
}

QString FileUtils::msgTerminalAction()
{
hjk's avatar
hjk committed
160 161
    if (HostOsInfo::isWindowsHost())
        return QApplication::translate("Core::Internal", "Open Command Prompt Here");
Eike Ziller's avatar
Eike Ziller committed
162
    return QApplication::translate("Core::Internal", "Open Terminal Here");
Robert Loehning's avatar
Robert Loehning committed
163
}
164

165 166 167
void FileUtils::removeFile(const QString &filePath, bool deleteFromFS)
{
    // remove from version control
hjk's avatar
hjk committed
168
    VcsManager::promptToDelete(filePath);
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183

    // remove from file system
    if (deleteFromFS) {
        QFile file(filePath);

        if (file.exists()) {
            // could have been deleted by vc
            if (!file.remove())
                QMessageBox::warning(ICore::mainWindow(),
                    QApplication::translate("Core::Internal", "Deleting File Failed"),
                    QApplication::translate("Core::Internal", "Could not delete file %1.").arg(filePath));
        }
    }
}

184 185 186
static inline bool fileSystemRenameFile(const QString &orgFilePath,
                                        const QString &newFilePath)
{
187
#if QT_VERSION < 0x050000
Aurindam Jana's avatar
Aurindam Jana committed
188
    QAbstractFileEngine *fileEngine = QAbstractFileEngine::create(orgFilePath); // Due to QTBUG-3570
189 190 191
    if (!fileEngine->caseSensitive() && orgFilePath.compare(newFilePath, Qt::CaseInsensitive) == 0)
        return fileEngine->rename(newFilePath);
#endif
192 193
    // QTBUG-3570 is also valid for Qt 5 but QAbstractFileEngine is now in a private header file and
    // the symbol is not exported.
194 195 196 197 198 199 200 201 202
    return QFile::rename(orgFilePath, newFilePath);
}

bool FileUtils::renameFile(const QString &orgFilePath, const QString &newFilePath)
{
    if (orgFilePath == newFilePath)
        return false;

    QString dir = QFileInfo(orgFilePath).absolutePath();
hjk's avatar
hjk committed
203
    IVersionControl *vc = VcsManager::findVersionControlForDirectory(dir);
204 205

    bool result = false;
hjk's avatar
hjk committed
206
    if (vc && vc->supportsOperation(IVersionControl::MoveOperation))
207 208 209 210 211 212 213 214 215
        result = vc->vcsMove(orgFilePath, newFilePath);
    if (!result) // The moving via vcs failed or the vcs does not support moving, fall back
        result = fileSystemRenameFile(orgFilePath, newFilePath);
    if (result) {
        // yeah we moved, tell the filemanager about it
        Core::DocumentManager::renamedFile(orgFilePath, newFilePath);
    }
    return result;
}
hjk's avatar
hjk committed
216 217

} // namespace Core