I am trying to move files from a compressed archive to the native system (basycally, windows' eplorer) through drag and drop operations.
My only idea at this moment is to create a TransferHandler, which, when launched, will decompress the file in a temporary directory and set up that file as Transferable. Here is a snippet of code to make myself more clear:
private class FileTransferHandler extends TransferHandler {
protected Transferable createTransferable(JComponent c) {
List<File> files = new ArrayList<File>();
try {
File temp = createTempDirectory();
String path = temp.getAbsolutePath();
decompressTo(path);
files.add(new File(path));
} catch (Exception e) { e.printStackTrace(); };
return new FileTransferable(files);
}
public int getSourceActions(JComponent c) {
return COPY;
}
}
private class FileTransferable implements Transferable {
private List<File> files;
public FileTransferable(List<File> files) {
this.files = files;
}
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{ DataFlavor.javaFileListFlavor };
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(DataFlavor.javaFileListFlavor);
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (!isDataFlavorSupported(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return files;
}
}
(not valid anymore: The thing that puzzles me is that this way it somehow works: but only if after I release the mouse button I am not doing anything else.)
update: After more testing I observed that actually the file data is transferred from the temp directory to destination after I click in a zone that accepts that DataFlavor. If I click in a folder, the temp files are transferred to that folder. If I click in the console window, the path to the temp file appears in the console window.
So, if you please, I would like some pointers to direct me in the right way.
p.s.: the idea with decompressing to temp folder first came after observing that WinRar is doing the same thing.
p.p.s.: sorry if the question seems stupid, but I am mostly a web programmer just dabbling in desktop programming.
Well, this is apparently nearing the best results you can get.
I'll check your code when I have some time for it.
Related
I didn't change my code, but drag and drop recently stopped working to external applications (Firefox/Chrome browsers, dolphin, etc.) from a java Swing application running on Ubuntu. We think this may have changed after an Ubuntu upgrade.
The problem happens dropping onto Firefox/Google Chrome or onto file explorers on Ubuntu. The problem doesn't affect drag and drop within our Swing application.
When a drag is initiated, you can see the icon for dragging correctly shows, but when you drag over any of the drop locations, they show a red cancel type icon showing you can't drop there. Letting go of the mouse at that point does nothing in the java application code.
What needs to be changed in our java app to support what is expected? Drag and drop still works fine within the java app.
Here is the java code used to support a Transfer:
public static DataFlavor uriListFlavor; // initialized elsewhere as new DataFlavor("text/uri-list;class=java.lang.String");
JTable docsTable; // initialized elsewhere
docsTable.setTransferHandler(new DocTransferHandler());
//etc.
public static class DocTransferHandler extends TransferHandler {
DocTransferHandler() {
}
#Override
protected Transferable createTransferable(JComponent component) {
ArrayList<File> files = new ArrayList<>();
if (component instanceof JTable) {
JTable table = (JTable)component;
int[] rows = table.getSelectedRows();
for (int row : rows) {
String filePath = String.valueOf(table.getTModel().getValueAt(row, FILE_PATH_COLUMN));
String fileName = String.valueOf(table.getTModel().getValueAt(row, FILE_NAME_COLUMN));
files.add(new File(filePath+"/"+fileName));
}
}
return new Transferable() {
#Override
public DataFlavor[] getTransferDataFlavors() {
DataFlavor[] flavors = new DataFlavor[2];
flavors[0] = DataFlavor.javaFileListFlavor;
flavors[1] = uriListFlavor;
return flavors;
}
#Override
public boolean canImport(TransferSupport support) {
return (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor) || support.isDataFlavorSupported(uriListFlavor);
}
#Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (flavor.equals(CaseManagedDocs.uriListFlavor)) {
String uriList = "";
for (File file : files) {
uriList += file.toURI() + System.lineSeparator();
}
return uriList;
} else if (flavor.equals(DataFlavor.javaFileListFlavor)) {
return files;
}
throw new UnsupportedFlavorException(flavor);
}
};
}
I have a main GUI See image that is used to load and display (thumbnail) images.
I want to make it possible to drag&drop images on my Gui as well.
So I copied an example and put it in a class
public static class FileDragDropListener implements DropTargetListener {
#Override
public void drop(DropTargetDropEvent event) {
DragDropListener DDL = new DragDropListener();
// Accept copy drops
event.acceptDrop(DnDConstants.ACTION_COPY);
// Get the transfer which can provide the dropped item data
Transferable transferable = event.getTransferable();
// Get the data formats of the dropped item
DataFlavor[] flavors = transferable.getTransferDataFlavors();
// Loop through the flavors
for (DataFlavor flavor : flavors) {
try {
// If the drop items are files
if (flavor.isFlavorJavaFileListType()) {
// Get all of the dropped files
List <File> files = (List) transferable.getTransferData(flavor);
//logger.info("length of list {}", files.size());
File[] imgs = new File[files.size()];
int counter = 0;
// Loop them through
for (File file : files) {
// Print out the file path
logger.info("File path is: {}", file.getPath());
imgs[ counter ] = file;
counter++;
}
MyVariables.setSelectedFiles(imgs);
}
} catch (Exception e) {
// Print out the error stack
e.printStackTrace();
}
}
// Inform that the drop is complete
event.dropComplete(true);
}
}
This drag&drop as such works fine. The code:
// Print out the file path
logger.info("File path is: {}", file.getPath());
lists a row of file paths, which I dragged upon my Gui, in the console so drag&drop as such works fine with the files.
I use a setter/getter MyVariables.setSelectedFiles(imgs); to make this File[] available "everywhere".
My problem is now to get this File[] with image paths back in my Gui main class immediately after the drop, so I can update the left panel in my Gui. For that updating I have a method public void LoadImages that is used from many parts in my program, which also touches multiple Gui elements, so I can't make that one static. For that I created the setter/getter, but how do I listen in my main Gui thread for the event.dropComplete(true); to act on it.
I tried many things like Observers, listeners etc., but I always get the non static method cannot be be referenced from a static context.
I do understand that, but how do I get my Gui notified after the drop event has finished, so that it can pick up the data using the getter?
I finally solved it.
The above mentioned FileDragDropListener in my first post is not necessary at all.
When I start my Gui in the main method, I call the below mentioned method rootPanelDropListener.
Note: rootPanel is the name of my entire main screen JPanel.
MyVariables.setSelectedFiles(droppedFilesArray); is a setter I use to be able, in a later stage, to retrieve the data "everywhere" in my program.
loadImages("dropped files"); is the method that loads the images (obvious) and has 3 options: by directory, by selecting (multiple) files, or by dropping the files onto the Gui. Inside the loadimages I check on the parameter "dropped files", then using the getter for the dropped files like files = MyVariables.getSelectedFiles();
public void rootPanelDropListener() {
//Listen to drop events
rootPanel.setDropTarget(new DropTarget() {
public synchronized void drop(DropTargetDropEvent evt) {
try {
evt.acceptDrop(DnDConstants.ACTION_COPY);
List<File> droppedFiles = (List<File>)
evt.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
for (File file : droppedFiles) {
logger.debug("File path is: {}", file.getPath());
}
File[] droppedFilesArray = (File[]) droppedFiles.toArray(new File[droppedFiles.size()]);
MyVariables.setSelectedFiles(droppedFilesArray);
loadImages("dropped files");
} catch (Exception ex) {
ex.printStackTrace();
logger.error("Drag drop on rootpanel error {}", ex);
}
}
});
}
I'm trying to copy a file into the system's clipboard. As i found in the internet I'm trying to achieve this like this:
final List<File> files = new ArrayList<File>();
files.add(new File("pathToFile"));
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
new Transferable() {
#Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { DataFlavor.javaFileListFlavor };
}
#Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return DataFlavor.javaFileListFlavor.equals(flavor);
}
#Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return files;
}
}, null);
However after I run that code I'm not able fo paste the file from clipboard (tried on the desktop and in the system explorer). I have even tried to put in a sleep afterwards because I have read that the JVM must be running in order to be ablke to paste that clipboard content but it didn't work for me.
Nevertheless Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null); is returning the respective file I copied into clipboard.
One thing that I did find out was that Toolkit.getDefaultToolkit().getSystemClipboard().isDataFlavorAvailable(DataFlavor.javaFileListFlavor); returns false. Does that mean that the clipboard does not support files? That wouldn't make sense as I am able to copy paste files in the explorer using Ctlr+C and Ctrl+V.
I don't know if it's important but I'm running my tests under Linux Mint.
Can anyone explain to me why I can't paste that copied file or how I have to copy it in order to be able to paste it via Ctrl+V system wide?
You can use Terminal Command
String[] args = new String[] {"/bin/bash", "-c","Your command at terminal", "with", "args"};
Process proc = new ProcessBuilder(args).start();
I have some trouble with the Windows Explorer.
My Application starts the download of a file and puts it into the system clipboard meanwhile. If the User now pastes the file at some place of the Windows Explorer, the file isn't having its real size, but the size depending on the progress of the download.
Does somebody have an idea of how I could advise the Explorer to wait until the download has finished and copy the file to the target directory afterwards?
I also tried to "tunnel" the file over the loopback Interface using the local SMB server but it didnt help unfortunately...
Thanks in advance
Downloading the file and calling the paste to clipboard method:
new Thread(new Runnable() {
#Override
public void run() {
final String where = getText();
int selectedRows[] = CustomJTableModel.table.getSelectedRows();
List<File> fileList = new ArrayList<File>();
for( int i=0; selectedRows.length>i; i++ ) {
// Build the relative file/folder path
String fileName = (String)table.getValueAt(table.getSelectedRow(), 0);
final String value = buildPath(where, fileName);
new Thread(new Runnable() {
#Override
public void run() {
staticNetworkDaemon.getFile(value, where);
}
}).start();
fileList.add(new File("\\\\127.0.0.1\\r$\\downloaded" + value.replace("/", "\\")));
}
setClipboardFile(fileList);
}
}).start();
Copying the file to the clipboard:
public static void setClipboardFile(final List<File> files) {
Transferable trans = new Transferable() {
List<File> fileList = new ArrayList<File>();
public DataFlavor[] getTransferDataFlavors() {
for( File f: files ) {
fileList.add(f);
}
return new DataFlavor[] { DataFlavor.javaFileListFlavor };
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return DataFlavor.javaFileListFlavor.equals(flavor);
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (isDataFlavorSupported(flavor))
return fileList;
throw new UnsupportedFlavorException(flavor);
}
};
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(trans, null);
}
What you're doing is simply wrong. Don't put something in the clipboard unless it's ready to be pasted -- you're breaking the contract that you should be following when using the clipboard.
Maybe my answer is a little bit simplistic, but why not simply wait until the file is completely downloaded before setting it in the clipboard? What about using something like a Future to wait for it, then set it in the clipboard.
This...
fileList.add(new File("\\\\127.0.0.1\\r$\\downloaded" + value.replace("/", "\\")))
Is so wrong as to be mind boggling. You only want to add the where to the fileList but only AFTER it has been successfully downloaded.
Once the file has been downloaded, only then do you want to add it to the clipboard.
The creation of your Transferable is also a "little" troubling, the Transferable should make a copy of the File List the moment it is created, this prevents the List from been modified before it is used, which could change the results
In languages like C++ or Delphi it is possible to put to clipboard IDataObject object. IDataObject object can contain absolutely different formats. If your can paste IDataObject with CFSTR_FILEDESCRIPTOR and CFSTR_FILECONTENTS formats to clipboard your problem will be solved.
When shell requests files from clipboard it checks for CF_HDROP, CF_IDLIST, CF_FILEDESCRIPTORW/CF_FILEDESCRIPTORA or CF_FILENAMEW/CF_FILENAMEA formats. And if clipboard contains CF_FILEDESCRIPTOR format only shell will use this format for file transfer.
CF_FILEDESCRIPTOR format contains names, attributes and dates of files. CF_FILECONTENTS format contains IStream of file. And you are absolutely free to create any implementation of IStream object. When shell call IStream.Read and request the part of file which is already downloaded just return this part of file. But when shell call IStream.Read and request the part of file which is not downloaded yet - just wait and after the part is downloaded return it.
I need to retrieve a list of all files of a certain type on my internal and external storage. I found this (-> List all of one file type on Android device?) example, but it's very mp3 specific.
My app creates a .zip file which is renamed to the extension *.message
Another activity should display a list of all available .message files, from which the user can choose one to open it.
Does anyone has an idea how to begin?
Thanks!
To obtain a list of files with a specific extension you can use File.list() with a FilenameFilter. For example:
File dir = new File(".");
String[] names = dir.list(
new FilenameFilter()
{
public boolean accept(File dir, String name)
{
return name.endsWith(".message");
}
});
Note that the returned strings are file names only, they do not contain the full path.
Here it is
File root = new File(globalVar.recordDir);
{
try {
if (root.listFiles().length > 0) {
for (File file : root.listFiles()) {
if (file.getName().endsWith(".mp3")) {
//DO somthings with it
}
}
}
} else {
}
} catch (Exception e) {
}
}