QFile: add supportsMoveToTrash()

[ChangeLog][QtCore][QFile] Added supportsMoveToTrash() to check if Qt
supports moving files to trash in the current OS.

Fixes: QTBUG-127580
Change-Id: Ifb754f0e28774c20aa7cfffd17e6c951ffd9d9ff
Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
This commit is contained in:
Thiago Macieira 2024-07-29 13:34:21 -07:00 committed by Ahmad Samir
parent 6faf18aceb
commit 17d1d577c9
7 changed files with 91 additions and 21 deletions

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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.

View File

@ -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<QString>("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