diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index 73b90d2544d..74b89d986c2 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -452,6 +452,22 @@ QFile::remove(const QString &fileName) return QFile(fileName).remove(); } +/*! + \since 6.9 + + Returns \c true if Qt supports moving files to a trash (recycle bin) in the + current operating system using the moveToTrash() function, \c false + otherwise. Note that this function returning \c true does not imply + moveToTrash() will succeed. In particular, this function does not check if + the user has disabled the functionality in their settings. + + \sa moveToTrash() +*/ +bool QFile::supportsMoveToTrash() +{ + return QFileSystemEngine::supportsMoveFileToTrash(); +} + /*! \since 5.15 @@ -479,9 +495,12 @@ QFile::remove(const QString &fileName) themselves mount points). //! [move-to-trash-common] - \note On systems where the system API doesn't report the location of the file in the - trash, fileName() will be set to the null string once the file has been moved. On - systems that don't have a trash can, this function always returns false. + \note On systems where the system API doesn't report the location of the + file in the trash, fileName() will be set to the null string once the file + has been moved. On systems that don't have a trash can, this function + always returns \c false (see supportsMoveToTrash()). + + \sa supportsMoveToTrash(), remove(), QDir::remove() */ bool QFile::moveToTrash() diff --git a/src/corelib/io/qfile.h b/src/corelib/io/qfile.h index 058b2fa2363..9c6f600bae7 100644 --- a/src/corelib/io/qfile.h +++ b/src/corelib/io/qfile.h @@ -210,6 +210,7 @@ public: } #endif // QT_CONFIG(cxx17_filesystem) + static bool supportsMoveToTrash() Q_DECL_PURE_FUNCTION; bool moveToTrash(); static bool moveToTrash(const QString &fileName, QString *pathInTrash = nullptr); #ifdef Q_QDOC diff --git a/src/corelib/io/qfilesystemengine_mac.mm b/src/corelib/io/qfilesystemengine_mac.mm index d4d7a9ee920..a0dc83321e4 100644 --- a/src/corelib/io/qfilesystemengine_mac.mm +++ b/src/corelib/io/qfilesystemengine_mac.mm @@ -20,6 +20,16 @@ QT_BEGIN_NAMESPACE Using Finder would also play the trash sound, which we don't want either in such a core API; applications that want that can play the sound themselves. */ +//static +bool QFileSystemEngine::supportsMoveFileToTrash() +{ +#ifdef Q_OS_MACOS // desktop macOS has a trash can + return true; +#else // watch, tv, iOS don't have a trash can + return false; +#endif +} + //static bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source, QFileSystemEntry &newLocation, QSystemError &error) diff --git a/src/corelib/io/qfilesystemengine_p.h b/src/corelib/io/qfilesystemengine_p.h index 814915407ea..621ee7a0ee8 100644 --- a/src/corelib/io/qfilesystemengine_p.h +++ b/src/corelib/io/qfilesystemengine_p.h @@ -127,6 +127,7 @@ public: static bool createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error); static bool copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error); + static bool supportsMoveFileToTrash(); static bool moveFileToTrash(const QFileSystemEntry &source, QFileSystemEntry &newLocation, QSystemError &error); static bool renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error); static bool renameOverwriteFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error); diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 3be4873f4d6..c7df9ca8c4c 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -1184,6 +1184,12 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy // see qfilesystemengine_mac.mm #elif defined(QT_BOOTSTRAPPED) || !defined(AT_FDCWD) // bootstrapped tools don't need this, and we don't want QStorageInfo +//static +bool QFileSystemEngine::supportsMoveFileToTrash() +{ + return false; +} + //static bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &, QFileSystemEntry &, QSystemError &error) @@ -1195,6 +1201,11 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &, QFileSystemEnt /* Implementing as per https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html */ +//static +bool QFileSystemEngine::supportsMoveFileToTrash() +{ + return true; +} namespace { struct FreeDesktopTrashOperation diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index bdcac20dd32..15764b28798 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -1772,6 +1772,12 @@ bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError & return ret; } +//static +bool QFileSystemEngine::supportsMoveFileToTrash() +{ + return true; +} + /* If possible, we use the IFileOperation implementation, which allows us to determine the location of the object in the trash. diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 2748df5e7ba..379b2fd179e 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -287,6 +287,7 @@ private slots: void reuseQFile(); + void supportsMoveToTrash(); void moveToTrash_data(); void moveToTrash(); void moveToTrashDuplicateName(); @@ -3969,6 +3970,27 @@ void tst_QFile::reuseQFile() } } +void tst_QFile::supportsMoveToTrash() +{ + // enforce the result according to our current implementation details +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) + // Windows and macOS: definitely supported + QVERIFY(QFile::supportsMoveToTrash()); +#elif defined(Q_OS_DARWIN) + // Other Darwin platforms: not supported + // (though Apple docs say trashItemAtURL is supported) + QVERIFY(!QFile::supportsMoveToTrash()); +#elif defined(Q_OS_ANDROID) + // Android: not supported (we get EACCES even for $HOME files) + QVERIFY(!QFile::supportsMoveToTrash()); +#elif !defined(AT_FDCWD) + // Unix platforms without the POSIX atfile support: not supported + QVERIFY(!QFile::supportsMoveToTrash()); +#else + QVERIFY(QFile::supportsMoveToTrash()); +#endif +} + void tst_QFile::moveToTrash_data() { QTest::addColumn("source"); @@ -4025,9 +4047,9 @@ void tst_QFile::moveToTrash_data() void tst_QFile::moveToTrash() { -#if defined(Q_OS_ANDROID) or defined(Q_OS_WEBOS) or defined(Q_OS_VXWORKS) - QSKIP("This platform doesn't implement a trash bin"); -#endif + if (!QFile::supportsMoveToTrash()) + QSKIP("This platform doesn't implement a trash bin"); + QFETCH(QString, source); QFETCH(bool, create); QFETCH(bool, result); @@ -4127,9 +4149,9 @@ void tst_QFile::moveToTrash() void tst_QFile::moveToTrashDuplicateName() { -#if defined(Q_OS_ANDROID) || defined(Q_OS_WEBOS) || defined(Q_OS_VXWORKS) - QSKIP("This platform doesn't implement a trash bin"); -#endif + if (!QFile::supportsMoveToTrash()) + QSKIP("This platform doesn't implement a trash bin"); + QString origFileName = []() { QTemporaryFile temp(QDir::homePath() + "/tst_qfile.moveToTrashOpenFile.XXXXXX"); temp.setAutoRemove(false); @@ -4182,9 +4204,9 @@ void tst_QFile::moveToTrashOpenFile_data() void tst_QFile::moveToTrashOpenFile() { -#if defined(Q_OS_ANDROID) || defined(Q_OS_WEBOS) || defined(Q_OS_VXWORKS) - QSKIP("This platform doesn't implement a trash bin"); -#endif + if (!QFile::supportsMoveToTrash()) + QSKIP("This platform doesn't implement a trash bin"); + QFETCH(bool, useStatic); QFETCH(bool, success); const QByteArrayView contents = "Hello, World\n"; @@ -4242,9 +4264,9 @@ void tst_QFile::moveToTrashOpenFile() void tst_QFile::moveToTrashSymlinkToFile() { -#if defined(Q_OS_ANDROID) || defined(Q_OS_WEBOS) || defined(Q_OS_VXWORKS) - QSKIP("This platform doesn't implement a trash bin"); -#endif + if (!QFile::supportsMoveToTrash()) + QSKIP("This platform doesn't implement a trash bin"); + QTemporaryFile temp(QDir::homePath() + "/tst_qfile.moveToTrashSymlinkFile.XXXXXX"); QVERIFY2(temp.open(), "Failed to create temporary file: " + temp.errorString().toLocal8Bit()); @@ -4281,9 +4303,9 @@ void tst_QFile::moveToTrashSymlinkToDirectory_data() void tst_QFile::moveToTrashSymlinkToDirectory() { -#if defined(Q_OS_ANDROID) || defined(Q_OS_WEBOS) || defined(Q_OS_VXWORKS) - QSKIP("This platform doesn't implement a trash bin"); -#endif + if (!QFile::supportsMoveToTrash()) + QSKIP("This platform doesn't implement a trash bin"); + QFETCH(bool, appendSlash); QTemporaryDir temp(QDir::homePath() + "/tst_qfile.moveToTrashSymlinkDir.XXXXXX"); QVERIFY2(temp.isValid(), "Failed to create temporary dir: " + temp.errorString().toLocal8Bit()); @@ -4315,9 +4337,9 @@ void tst_QFile::moveToTrashSymlinkToDirectory() void tst_QFile::moveToTrashXdgSafety() { -#if defined(Q_OS_VXWORKS) - QSKIP("This platform doesn't implement a trash bin"); -#endif + if (!QFile::supportsMoveToTrash()) + QSKIP("This platform doesn't implement a trash bin"); + #if defined(Q_OS_WIN) || defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID) || defined(Q_OS_WEBOS) QSKIP("This test is specific to XDG Unix systems"); #else