Question

Is there a Qt function to move files to Recycle Bin instead of truly deleting them, for OSes that support it, or do I need to use OS-specific code?

Was it helpful?

Solution

Since Qt 5.15.0 Alpha, this method has been added, which should be what you were looking for.

bool QFile::moveToTrash()

The corresponding code changes can be found here.

(This issue is old and the corresponding Bugreport at https://bugreports.qt.io/browse/QTBUG-47703 has already been posted, but I currently lack the reputation to comment, and found this to be a useful information.)

OTHER TIPS

Qt doesnt provide a MoveToTrash. Here's a part of my code

for Windows

#ifdef Q_OS_WIN32

#include "windows.h"

void MoveToTrashImpl( QString file ){
    QFileInfo fileinfo( file );
    if( !fileinfo.exists() )
        throw OdtCore::Exception( "File doesnt exists, cant move to trash" );
    WCHAR from[ MAX_PATH ];
    memset( from, 0, sizeof( from ));
    int l = fileinfo.absoluteFilePath().toWCharArray( from );
    Q_ASSERT( 0 <= l && l < MAX_PATH );
    from[ l ] = '\0';
    SHFILEOPSTRUCT fileop;
    memset( &fileop, 0, sizeof( fileop ) );
    fileop.wFunc = FO_DELETE;
    fileop.pFrom = from;
    fileop.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
    int rv = SHFileOperation( &fileop );
    if( 0 != rv ){
        qDebug() << rv << QString::number( rv ).toInt( 0, 8 );
        throw OdtCore::Exception( "move to trash failed" );
    }
}
#endif

and for Linux

#ifdef Q_OS_LINUX

bool TrashInitialized = false;
QString TrashPath;
QString TrashPathInfo;
QString TrashPathFiles;

void MoveToTrashImpl( QString file ){
    #ifdef QT_GUI_LIB
        if( !TrashInitialized ){
            QStringList paths;
            const char* xdg_data_home = getenv( "XDG_DATA_HOME" );
            if( xdg_data_home ){
                qDebug() << "XDG_DATA_HOME not yet tested";
                QString xdgTrash( xdg_data_home );
                paths.append( xdgTrash + "/Trash" );
            }
            QString home = QStandardPaths::writableLocation( QStandardPaths::HomeLocation );
            paths.append( home + "/.local/share/Trash" );
            paths.append( home + "/.trash" );
            foreach( QString path, paths ){
                if( TrashPath.isEmpty() ){
                    QDir dir( path );
                    if( dir.exists() ){
                        TrashPath = path;
                    }
                }
            }
            if( TrashPath.isEmpty() )
                throw Exception( "Cant detect trash folder" );
            TrashPathInfo = TrashPath + "/info";
            TrashPathFiles = TrashPath + "/files";
            if( !QDir( TrashPathInfo ).exists() || !QDir( TrashPathFiles ).exists() )
                throw Exception( "Trash doesnt looks like FreeDesktop.org Trash specification" );
            TrashInitialized = true;
        }
        QFileInfo original( file );
        if( !original.exists() )
            throw Exception( "File doesnt exists, cant move to trash" );
        QString info;
        info += "[Trash Info]\nPath=";
        info += original.absoluteFilePath();
        info += "\nDeletionDate=";
        info += QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm:ss.zzzZ");
        info += "\n";
        QString trashname = original.fileName();
        QString infopath = TrashPathInfo + "/" + trashname + ".trashinfo";
        QString filepath = TrashPathFiles + "/" + trashname;
        int nr = 1;
        while( QFileInfo( infopath ).exists() || QFileInfo( filepath ).exists() ){
            nr++;
            trashname = original.baseName() + "." + QString::number( nr );
            if( !original.completeSuffix().isEmpty() ){
                trashname += QString( "." ) + original.completeSuffix();
            }
            infopath = TrashPathInfo + "/" + trashname + ".trashinfo";
            filepath = TrashPathFiles + "/" + trashname;
        }
        QDir dir;
        if( !dir.rename( original.absoluteFilePath(), filepath ) ){
            throw Exception( "move to trash failed" );
        }
        File infofile;
        infofile.createUtf8( infopath, info );
    #else
        Q_UNUSED( file );
        throw Exception( "Trash in server-mode not supported" );
    #endif
}
#endif

There is no API yet.

https://bugreports.qt.io/browse/QTBUG-181

The issue is closed and the fix version is: Some future release

Edit: A new issue has been opened at https://bugreports.qt.io/browse/QTBUG-47703.

Edit Apparently it is now done in 5.15.0 Alpha bool QFile::moveToTrash()

I think that there is no cross-platform way. Simple moving files to "trash" location will not give effect, because user may switch off this possibility.

Maybe, this url will help: http://www.hardcoded.net/articles/send-files-to-trash-on-all-platforms.htm

I'm relatively certain that there is no Qt API that wraps this for all supported platforms. That means, unfortunately, that you will have to write platform-specific code.

I don't know anything about where/how Linux distributions store deleted files, and I imagine that it probably varies depending on which file manager you're using. I believe that moving files to a ~/.Trash folder is the standard way of doing it, but I'm not sure if this is reliable. For example, in the case of files stored on external volumes.

Things are a bit easier on Mac OS X, where there is a supported API to do this: FSMoveObjectToTrashSync, provided by Core Services. At least, that's how I remember you're supposed to do it. The documentation claims that this method is now deprecated in OS X 10.8. I have no idea what the recommended alternative is.

As a Windows programmer, I think that platform is much easier. :-) The basic solution is to call the SHFileOperation function:

#include <Windows.h>   // general Windows header file
#include <ShellAPI.h>  // for shell functions, like SHFileOperation
#include <string>      // (or use QString)

void RecycleFileOnWindows()
{
   std::wstring path = L"C:\\Users\\Administrator\\Documents\\deleteme.txt";
   path.append(1, L'\0');        // path string must be double nul-terminated

   SHFILEOPSTRUCT shfos = {};
   shfos.hwnd   = nullptr;       // handle to window that will own generated windows, if applicable
   shfos.wFunc  = FO_DELETE;
   shfos.pFrom  = path.c_str();
   shfos.pTo    = nullptr;       // not used for deletion operations
   shfos.fFlags = FOF_ALLOWUNDO; // use the recycle bin

   const int retVal = SHFileOperation(&shfos);
   if (retVal != 0)
   {
      // The operation failed...
      if (shfos.fAnyOperationsAborted)
      {
         // ...but that's because the user canceled.
         MessageBox(nullptr, L"Operation was canceled", nullptr, MB_OK | MB_ICONINFORMATION);
      }
      else
      {
         // ...for one of the other reasons given in the documentation.
         MessageBox(nullptr, L"Operation failed", nullptr, MB_OK | MB_ICONERROR);
      }
   }
}

There are also flags that you can set to customize confirmation, error reporting, and other behavior. The linked documentation contains all the details you need to build upon this basic example.

On Windows Vista and later, the SHFileOperation function has been superseded by the methods provided by the IFileOperation interface. If you're targeting only these later versions of Windows, you should prefer to use this interface. Otherwise, SHFileOperation will continue to work fine.

if(QSysInfo::kernelType()=="linux")
{
    QDateTime currentTime(QDateTime::currentDateTime());    // save System time

    QString trashFilePath=QDir::homePath()+"/.local/share/Trash/files/";    // trash file path contain delete files
    QString trashInfoPath=QDir::homePath()+"/.local/share/Trash/info/";     // trash info path contain delete files information

    // create file format for trash info file----- START
    QFile infoFile(trashInfoPath+FileName.completeBaseName()+"."+FileName.completeSuffix()+".trashinfo");     //filename+extension+.trashinfo //  create file information file in /.local/share/Trash/info/ folder

    infoFile.open(QIODevice::ReadWrite);

    QTextStream stream(&infoFile);         // for write data on open file

    stream<<"[Trash Info]"<<endl;
    stream<<"Path="+QString(QUrl::toPercentEncoding(FileName.absoluteFilePath(),"~_-./"))<<endl;     // convert path string in percentage decoding scheme string
    stream<<"DeletionDate="+currentTime.toString("yyyy-MM-dd")+"T"+currentTime.toString("hh:mm:ss")<<endl;      // get date and time format YYYY-MM-DDThh:mm:ss

    infoFile.close();

    // create info file format of trash file----- END

    QDir file;
    file.rename(FileName.absoluteFilePath(),trashFilePath+FileName.completeBaseName()+"."+FileName.completeSuffix());  // rename(file old path, file trash path)



}

Trash files in linux exist /home/user_name/.local/share/Trash/files/ directory but it also require info file for each trash file which exist in /home/user_name/.local/share/Trash/info/ directory. when we want to move file into trash, actually move file into /home/user_name/.local/share/Trash/files/ directory and create info file in /home/user_name/.local/share/Trash/info/ directory. inside .trashinfo format use percentage decoding scheme for set file path where file existed, info file also contain time and date of deletion.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top