/*
* This file is part of muCommander, http://www.mucommander.com
* Copyright (C) 2002-2016 Maxence Bernard
*
* muCommander is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* muCommander is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mucommander.desktop.windows;
import com.mucommander.commons.file.AbstractFile;
import com.mucommander.commons.file.protocol.local.LocalFile;
import com.mucommander.commons.file.protocol.local.SpecialWindowsLocation;
import com.mucommander.commons.file.util.Shell32;
import com.mucommander.commons.file.util.Shell32API;
import com.mucommander.desktop.DesktopManager;
import com.mucommander.desktop.QueuedTrash;
import java.io.IOException;
import java.util.List;
/**
* WindowsTrash is an <code>AbstractTrash</code> implementation for the <i>Microsoft Windows' Recycle Bin</i>.
*
* <p>Native methods in the Shell32 Windows API are used to access the Recycle Bin. There is an overhead associated with
* invoking those methods (via JNA), so for performance reasons, this trash is implemented as a {@link com.mucommander.desktop.QueuedTrash}
* in order to group calls to {@link #moveToTrash(com.mucommander.commons.file.AbstractFile)}.</p>
*
* @see WindowsTrashProvider
* @author Maxence Bernard
*/
public class WindowsTrash extends QueuedTrash {
//////////////////////////////////
// AbstractTrash implementation //
//////////////////////////////////
/**
* Implementation notes: returns <code>true</code> only for local files that are not archive entries.
*/
@Override
public boolean canMoveToTrash(AbstractFile file) {
return file.getTopAncestor() instanceof LocalFile;
}
/**
* Implementation notes: always returns <code>true</code>: {@link #empty()} is implemented.
*/
@Override
public boolean canEmpty() {
return true;
}
@Override
public boolean empty() {
return Shell32.isAvailable() && Shell32.getInstance().SHEmptyRecycleBin(null, null, Shell32API.SHERB_NOCONFIRMATION) == 0;
}
/**
* Implementation notes: always returns <code>false</code>.
*/
@Override
public boolean isTrashFile(AbstractFile file) {
// Quote from http://en.wikipedia.org/wiki/Recycle_Bin_(Windows):
// "The actual location of the Recycle Bin varies depending on the operating system and filesystem. On the older
// FAT filesystems (typically Windows 98 and prior), it is located in Drive:\RECYCLED. In the NTFS filesystem
// (Windows 2000, XP, NT) it can be found in Drive:\RECYCLER, with the exception of Windows Vista which stores
// it in the Drive:\$Recycle.Bin folder."
// => for the test to be accurate, we'd have to go thru the trouble of testing the kind of filesystem
// (FAT or NTFS) and the Windows version. It's a lot of work for little added value.
return false;
}
/**
* Implementation notes: returns the number of items for all Recycle Bins on all drives. This information is not
* available on certain versions of Windows such as <i>Windows 2000</i>.
*/
@Override
public int getItemCount() {
if(!Shell32.isAvailable())
return -1;
Shell32API.SHQUERYRBINFO queryRbInfo = new Shell32API.SHQUERYRBINFO();
// pszRootPath is null to retrieve the information for all Recycle Bins on all drives. Microsoft's documentation
// states that this fails on certain versions of Windows such as Windows 2000. If it does, we simply return -1.
int ret = Shell32.getInstance().SHQueryRecycleBin(
null,
queryRbInfo
);
return ret==0?(int)queryRbInfo.i64NumItems:-1;
}
/**
* Implementation notes: always returns <code>true</code>: {@link #open()} is implemented.
*/
@Override
public boolean canOpen() {
return true;
}
@Override
public void open() {
try {DesktopManager.openInFileManager(SpecialWindowsLocation.RECYCLE_BIN);}
catch(IOException e) {/* TODO: report error. */}
}
////////////////////////////////
// QueuedTrash implementation //
////////////////////////////////
@Override
protected boolean moveToTrash(List<AbstractFile> queuedFiles) {
if(!Shell32.isAvailable())
return false;
Shell32API.SHFILEOPSTRUCT fileop = new Shell32API.SHFILEOPSTRUCT();
fileop.wFunc = Shell32API.FO_DELETE;
fileop.fFlags = Shell32API.FOF_ALLOWUNDO| Shell32API.FOF_NOCONFIRMATION| Shell32API.FOF_SILENT;
int nbFiles = queuedFiles.size();
String[] paths = new String[nbFiles];
for(int i=0; i<nbFiles; i++) {
// Directories (and regular files) must not end with a trailing slash or the operation will fail.
paths[i] = queuedFiles.get(i).getAbsolutePath(false);
}
// The encodePaths method takes care of encoding the paths in a special way.
fileop.pFrom = fileop.encodePaths(paths);
return Shell32.getInstance().SHFileOperation(fileop) == 0;
}
}