How to "Reveal in Finder" or "Show in Explorer" with Qt

C++QtQt4

C++ Problem Overview


Is it possible to open a folder in Windows Explorer/OS X Finder and then select/highlight one file in that folder, and do it in a cross platform way? Right now, I do something like

QDesktopServices::openUrl( QUrl::fromLocalFile( path ) );

where path is a full path to folder I want to open. Obviously, this will just open the folder, and I'll have to track down the file I need manually. This is a bit of a problem when there are thousands of files in that folder.

If I make it a path to specific file in that folder, then that file is open with default application for that mime type, and that is not what I need. Instead, I need the functionality equivalent to "Reveal in Finder" or "Show in Explorer".

C++ Solutions


Solution 1 - C++

Qt Creator (source) has this functionality, it's trivial to copy it:

void FileUtils::showInGraphicalShell(QWidget *parent, const QString &pathIn)
{
    const QFileInfo fileInfo(pathIn);
    // Mac, Windows support folder or file.
    if (HostOsInfo::isWindowsHost()) {
        const FileName 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 (!fileInfo.isDir())
            param += QLatin1String("/select,");
        param += QDir::toNativeSeparators(fileInfo.canonicalFilePath());
        QProcess::startDetached(explorer.toString(), param);
    } else if (HostOsInfo::isMacHost()) {
        QStringList scriptArgs;
        scriptArgs << QLatin1String("-e")
                   << QString::fromLatin1("tell application \"Finder\" to reveal POSIX file \"%1\"")
                                         .arg(fileInfo.canonicalFilePath());
        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 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);
    }
}

Another, related blog post (with simpler code, I haven't tried it so I can't comment), is this.

Edit:

There is a bug in the original code when pathIn contains spaces on Windows. QProcess::startDetached will automatically quote a parameter if it contains spaces. However, Windows Explorer will not recognize a parameter wrapped in quotes, and will open the default location instead. Try it yourself in the Windows command line:

echo. > "C:\a file with space.txt"
:: The following works
C:\Windows\explorer.exe /select,C:\a file with space.txt  
:: The following does not work
C:\Windows\explorer.exe "/select,C:\a file with space.txt"

Thus,

QProcess::startDetached(explorer, QStringList(param));

is changed to

QString command = explorer + " " + param;
QProcess::startDetached(command);

Solution 2 - C++

Probably you can use QFileDialog::getOpenFileName to get the file name. The documentation is available here.. The above function will return the complete path including the file name and its extension if any..

Then you can give

QDesktopServices::openUrl(path);

to open the the file in its default appication, where the path will be the QString returned by QFileDialog::getOpenFileName.

Hope it helps..

Solution 3 - C++

Open file in windows explorer (not browser)

void OpenFileInExplorer()
{
   QString path = "C:/exampleDir/example.txt";

   QStringList args;

   args << "/select," << QDir::toNativeSeparators(path);

   QProcess *process = new QProcess(this);
   process->start("explorer.exe", args); 

}

Solution 4 - C++

Here is the code that I went with based on the inputs from a previous answer. This version does not depend on other methods in Qt Creator, accepts a file or directory, and has a fall back mode for error handling and other platforms:

void Util::showInFolder(const QString& path)
{
    QFileInfo info(path);
#if defined(Q_OS_WIN)
    QStringList args;
    if (!info.isDir())
        args << "/select,";
    args << QDir::toNativeSeparators(path);
    if (QProcess::startDetached("explorer", args))
        return;
#elif defined(Q_OS_MAC)
    QStringList args;
    args << "-e";
    args << "tell application \"Finder\"";
    args << "-e";
    args << "activate";
    args << "-e";
    args << "select POSIX file \"" + path + "\"";
    args << "-e";
    args << "end tell";
    args << "-e";
    args << "return";
    if (!QProcess::execute("/usr/bin/osascript", args))
        return;
#endif
    QDesktopServices::openUrl(QUrl::fromLocalFile(info.isDir()? path : info.path()));
}

Solution 5 - C++

This solution works on both Windows and Mac:

void showFileInFolder(const QString &path){
    #ifdef _WIN32    //Code for Windows
        QProcess::startDetached("explorer.exe", {"/select,", QDir::toNativeSeparators(path)});
    #elif defined(__APPLE__)    //Code for Mac
        QProcess::execute("/usr/bin/osascript", {"-e", "tell application \"Finder\" to reveal POSIX file \"" + path + "\""});
        QProcess::execute("/usr/bin/osascript", {"-e", "tell application \"Finder\" to activate"});
    #endif
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionnncView Question on Stackoverflow
Solution 1 - C++IvoView Answer on Stackoverflow
Solution 2 - C++liaKView Answer on Stackoverflow
Solution 3 - C++Mara BlackView Answer on Stackoverflow
Solution 4 - C++Dan DennedyView Answer on Stackoverflow
Solution 5 - C++Donald DuckView Answer on Stackoverflow