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.
Related
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 would like to be able to display a list of files showing only the file name not the whole file path.
Currently I have a list of files. When I click one of these files the listener passes this to a method out of scope which loads the file.
This means if I was to just pass it a list of just file names it would no longer work as my listener requires a full file path. I do not have any ideas as to how I would go about both storing a list of filenames whilst simultaneously linking them to the full file path.
Happy to answer any questions you may have. Many thanks,
Note: the small for loop shows how I could potentially extract the filename from the file path, but I am not currently doing anything with it at this time. It's just an example to show you how far I have gotten.
public void GetFilesFromFolder(String dirName) throws IOException {
File dir = new File(dirName);
File[] files = dir.listFiles((File dir1, String filename) -> filename.endsWith(".mp3"));
String[] fileName = new String[files.length];
int x = 0;
for (File file : files) {
String fileTemp = file.toString();
fileTemp = fileTemp.substring(fileTemp.lastIndexOf("\\" + 1));
System.out.println(fileTemp);
fileName[x] = fileTemp;
System.out.println(fileName[x]);
x++;
}
observableList.clear();
observableList.addAll(files);
}
public void SetFileListView() throws IOException {
listView.setItems(null);
}
public VBox listStack() throws IOException {
vbox = new VBox();
vbox.getChildren().add(listView);
listView.setItems(observableList);
listView.setMinHeight(500);
MusicDataModel mdm = MainView.getMainView().musicDataModel;
MusicDataViewController mdv = MainView.getMainView().musicDataViewController;
listView.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends File> observable, File oldValue, File newValue) -> {
try {
mdm.load(newValue.toString());
mdv.SetValues();
} catch (UnsupportedTagException | InvalidDataException | IOException | NotSupportedException ex) {
Logger.getLogger(FileListView.class.getName()).log(Level.SEVERE, null, ex);
}
});
return vbox;
}
Populate the list view with Files, as you currently do, and use a cell factory on the list view to change the way the file is displayed:
listView.setCellFactory(lv -> new ListCell<File>() {
#Override
protected void updateItem(File file, boolean empty) {
super.updateItem(file, empty);
setText(file == null ? null : file.getName());
}
});
This will ensure each cell in the list view displays only the file name (the last component of the file's full path), though it still retains the File instance as its data (so you can still get the selected File, etc).
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) {
}
}
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.