JavaFX Drag and Drop: accept only some file extensions - java

What i want to do:
when the user tries to drag and drop something into the window,he can do it only if the drag has file with extensions (.mp3,.ogg,.wav).If the files have not this extension the drop can't be done.I don't want links,etc...to be dropped.
For example accept only html is so easy as:
controller.setOnDragOver((over) -> {
Dragboard board = over.getDragboard();
if (board.hasHtml())
over.acceptTransferModes(TransferMode.LINK);
});
How can i add a filter for that?

You can use the getFiles method of DragBoard returned by getDragboard method of DragEvent in the event handler set in setOnDragOver of your Node or Scene to get the list of files currently dragged.
You can check the extensions in this list either using for example getExtension of Apache Commons IO or by implementing your own function to get the extension of a file. If the extension(s) of the file(s) of the dragboard does not match with the predefined extensions you can simply consume the DragEvent.
Example
In this example I have created a Stage with a VBox inside which accepts only files with extension of "jpg" and "png" to be dropped on it. If the drop was succesful it prints the absolute file path of the files.
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
VBox root = new VBox();
Scene scene = new Scene(root,400,400);
// Extensions that are valid to be drag-n-dropped
List<String> validExtensions = Arrays.asList("jpg", "png");
root.setOnDragOver(event -> {
// On drag over if the DragBoard has files
if (event.getGestureSource() != root && event.getDragboard().hasFiles()) {
// All files on the dragboard must have an accepted extension
if (!validExtensions.containsAll(
event.getDragboard().getFiles().stream()
.map(file -> getExtension(file.getName()))
.collect(Collectors.toList()))) {
event.consume();
return;
}
// Allow for both copying and moving
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
}
event.consume();
});
root.setOnDragDropped(event -> {
boolean success = false;
if (event.getGestureSource() != root && event.getDragboard().hasFiles()) {
// Print files
event.getDragboard().getFiles().forEach(file -> System.out.println(file.getAbsolutePath()));
success = true;
}
event.setDropCompleted(success);
event.consume();
});
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
// Method to to get extension of a file
private String getExtension(String fileName){
String extension = "";
int i = fileName.lastIndexOf('.');
if (i > 0 && i < fileName.length() - 1) //if the name is not empty
return fileName.substring(i + 1).toLowerCase();
return extension;
}
public static void main(String[] args) {
launch(args);
}
}

Related

JavaFX treeview top level works but sub-folders have wrong directory?

I am trying to build a text editor for my first program project. I have the treeview on the left side and the tabpane on the right. There is a textarea on the tab. My intent is to display the contents of the file that is selected in the treeview, if it is a file, to the textarea. Sounds simple enough right?
I have been trying all day to get this to work and I can not figure it out. Something is wrong and it is beyond my skill level.
Any advice is appreciated. Thank you to all you help make this a fantastic educational platform!
import javafx.beans.value.ChangeListener
import javafx.beans.value.ObservableValue
import javafx.fxml.FXML
import javafx.fxml.Initializable
import javafx.scene.control.Tab
import javafx.scene.control.TabPane
import javafx.scene.control.TextArea
import javafx.scene.control.TreeItem
import javafx.scene.control.TreeView
import javafx.scene.control.cell.TextFieldTreeCell
import javafx.stage.FileChooser
import javafx.stage.Window
class Controller implements Initializable{
#FXML
TextArea inputSpace
#FXML
Tab tabName
#FXML
TabPane tabPane
#FXML
TreeView fileTree
void openAndSetTab(File file) throws FileNotFoundException{
if(file.canRead()){
def openFile = new Tab()
tabPane.getTabs().add(openFile)
//set file name to tab title
def dotPosition = file.name.indexOf('.')
def fileName = file.name.substring(0,dotPosition)
openFile.text = fileName
//add file data to text area
def inputArea = new TextArea()
openFile.setContent(inputArea)
def data = file?.getText()
inputArea.setText(data)
//bring to front
openFile.getTabPane().getSelectionModel().select(openFile)
}else{
println('Cannot read...')
println(file.absolutePath)
}
}
void openFile() {
//get file
def chooser = new FileChooser()
def file = chooser.showOpenDialog(Window.getResource('Main.java') as Window)
openAndSetTab(file)
}
/**
* save text data to file
* and set title of tab
*/
void saveFile() {
FileChooser chooser = new FileChooser()
def data = inputSpace.text
def file = chooser.showSaveDialog(Window.getResource('Main.java') as Window)
if(data != null){
file.text = ''
file << data
}
//set tab title to saved file name
int dotPosition = file.name.indexOf('.')
def fileName = file.name.substring(0,dotPosition)
tabName.text = fileName
}
/**
* stackoverflow.com Answer
* https://stackoverflow.com/questions/38278601/javafx-treeview-directory-listing
* answered Jul 9 '16 at 6:46
* Author: fabian
* Original was using CheckBoxTreeItem, I updated code to my needs
* #param inputDirectoryLocation
*/
void displayTreeView(String inputDirectoryLocation) {
def tree = new GetTree()
// Creates the root item.
TreeItem<String> rootItem = new TreeItem<>(inputDirectoryLocation)
// Hides the root item of the tree view.
fileTree.setShowRoot(false)
// Creates the cell factory.
fileTree.setCellFactory(TextFieldTreeCell.forTreeView())
// Get a list of files.
def fileInputDirectoryLocation = new File(inputDirectoryLocation)
List<File> fileList = fileInputDirectoryLocation.listFiles()
// create tree
for (File file : fileList) {
tree.createTree(file, rootItem)
}
fileTree.setRoot(rootItem)
}
#Override
void initialize(URL url, ResourceBundle resourceBundle) {
displayTreeView(System.getProperty('user.dir'))
fileTree.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TreeItem>() {
#Override
void changed(ObservableValue<? extends TreeItem> observableValue, TreeItem treeItem, TreeItem t1) {
def file = new File(t1.value.toString())
if(file.isFile()){
openAndSetTab(file)
}
}
})
}
}
I added the groovy jar to the classpath so that's why it looks wired. It't the superset of java. Love using it. What am I doing wrong?
The GetTree class is as follows,
import javafx.scene.control.TreeItem
/**
* stackoverflow.com Answer
* https://stackoverflow.com/questions/38278601/javafx-treeview-directory-listing
* answered Jul 9 '16 at 6:46
* Author: fabian
* Original was using CheckBoxTreeItem, I updated code to my needs
*/
class GetTree {
static void createTree(File file, TreeItem<String> parent) {
if (file.isDirectory()) {
TreeItem<String> treeItem = new TreeItem<>(file.getName())
parent.getChildren().add(treeItem)
for (File f : file.listFiles()) {
createTree(f, treeItem)
}
} else{//must be a file
parent.getChildren().add(new TreeItem<>(file.getName()))
}
}
}
Projects folder is
tetragrammaton
.idea
-sub-directories.here
out
-sub-directories.here
src
sub-directories.here
testing.txt
TetraGrammaton.iml
The only files that open in the textarea that is on the tab, is the 2 files, testing.txt and TetraGrammaton.iml. The other directories open upon clicking but do not open in the textarea.

How to use Java 8 `Files.find` method?

I am trying to write an app to use Files.find method in it.
Below program works perfectly :
package ehsan;
/* I have removed imports for code brevity */
public class Main {
public static void main(String[] args) throws IOException {
Path p = Paths.get("/home/ehsan");
final int maxDepth = 10;
Stream<Path> matches = Files.find(p,maxDepth,(path, basicFileAttributes) -> String.valueOf(path).endsWith(".txt"));
matches.map(path -> path.getFileName()).forEach(System.out::println);
}
}
This works fine and gives me a list of files ending with .txt ( aka text files ) :
hello.txt
...
But below program does not show anything :
package ehsan;
public class Main {
public static void main(String[] args) throws IOException {
Path p = Paths.get("/home/ehsan");
final int maxDepth = 10;
Stream<Path> matches = Files.find(p,maxDepth,(path, basicFileAttributes) -> path.getFileName().equals("workspace"));
matches.map(path -> path.getFileName()).forEach(System.out::println);
}
}
But it does not show anything :(
Here is my home folder hiearchy (ls result) :
blog Projects
Desktop Public
Documents Templates
Downloads The.Purge.Election.Year.2016.HC.1080p.HDrip.ShAaNiG.mkv
IdeaProjects The.Purge.Election.Year.2016.HC.1080p.HDrip.ShAaNiG.mkv.aria2
Music Videos
Pictures workspace
So whats going wrong with path.getFileName().equals("workspace")?
Path.getFilename() does not return a String, but a Path object, do this:
getFilename().toString().equals("workspace")
Use the following and look at the console. Maybe none of your files contains workspace in it
Files.find(p,maxDepth,(path, basicFileAttributes) -> {
if (String.valueOf(path).equals("workspace")) {
System.out.println("FOUND : " + path);
return true;
}
System.out.println("\tNOT VALID : " + path);
return false;
});

SWT file drop: identify folders

Code
I'm trying to add drop functionality to my program so users can drag and drop files from Windows. Therefore I implemented the SWT DropTargetListener interface and added a SWT DropTarget to my SWT control.
public class MyFileDrop implements DropTargetListener {
public MyFileDrop(final Control control) {
addDropTarget(control);
}
private void addDropTarget(final Control control) {
final DropTarget dropTarget = new DropTarget(control, DND.DROP_COPY | DND.DROP_DEFAULT);
dropTarget.setTransfer(new Transfer[] { FileTransfer.getInstance() });
dropTarget.addDropListener(this);
}
#Override
public void drop(final DropTargetEvent event) {
String[] fileNames = (String[]) event.data;
for (final String fileName : fileNames) {
System.out.println(fileName);
}
}
// other DropTargetListener methods [...]
}
If I drag and drop a folder from Windows Explorer to my control, the folder name gets printed out. But all files inside that dropped folder aren't listed.
Example
folder1
- subfile1.png
- subfile2.exe
file1.png
file2.exe
If I select folder1, file1 and file2 and drag and drop it to my program, this is the output:
path/to/folder1
path/to/file1.png
path/to/file2.exe
Questions
Why aren't the files inside the folder dropped to the program? How can I archive that these files are also dropped?
How can I set the files apart from the folder?
Regards winklerrr
Code
So this is my solution
#Override
public void drop(DropTargetEvent event) {
String[] fileNames = (String[]) event.data;
for (String fileName : fileNames) {
final File file = new File(fileName);
if (file.isDirectory()) {
Collection<File> subFiles = FileUtils.listFiles(file, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
for (File subFile : subFiles) {
System.out.println(subFile.getAbsolutePath());
}
} else {
System.out.println(file.getAbsolutePath());
}
}
}
I used the FileUtils from the commons-io package.
Example
folder1
- subfile1.png
- subfile2.exe
file1.png
file2.exe
With the new code, this is now the output:
path/to/folder1/subfile1.png
path/to/folder1/subfile2.exe
path/to/file1.png
path/to/file2.exe
Answers
How can I archive that these files are also dropped?
FileUtils.listFiles(File, IOFileFilter, IOFileFilter)
How can I set the files apart from the folder?
File.isDirectory()

WebView not showing anything

I have a pretty simple application that lists rows from a database in a tableview. When the user clicks on a row in that list, the application grabs the XML column from that row, and is supposed to display it in a WebView in the same window. Everything other than actually displaying the XML works fine. I've been beating my head on this for a while, but I'm not getting anywhere. Here's the code that the listener calls:
#FXML
private void showXML(QueryRow row) {
String msg = "";
try {
msg = mainApp.getMsg(row.getID().get());
} catch (SQLException e) {
e.printStackTrace();
}
final String fm = msg;
System.out.println(msg);
//tb.setText(msg);
webEngine = webView.getEngine();
// webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
//
// public void changed(ObservableValue ov, State oldState, State newState) {
//
// if (newState == Worker.State.SUCCEEDED) {
// System.out.println("inside");
// webEngine.load(fm);
// //stage.setTitle(webEngine.getLocation());
// }
//
// }
// });
System.out.println("Go baby go!");
webEngine.load(fm);
}
What am I missing?
If you want to load XML and fm is not link then you should probably use
webEngine.loadContent(fm);
/**
* Loads the given HTML content directly. This method is useful when you have an HTML
* String composed in memory, or loaded from some system which cannot be reached via
* a URL (for example, the HTML text may have come from a database). As with
* {#link #load(String)}, this method is asynchronous.
*/
public void loadContent(String content) {
loadContent(content, "text/html");
}
But this will not make xml visible, so if you want your xml to be displayed, you have to put it in some default html page. Something like this:
https://gist.github.com/jewelsea/1463485
or simple way:
webEngine.loadContent(
<textarea readonly style='width:100%; height:100%'>"+ fm +"</textarea>")
Ok, I just tested a little bit. text/html is the correct way, but you need to do some work on your xml data: You have to escape the XML entities (I use commons-lang3 StringEscapeUtils for that) and then wrap all in a preformatted html string:
public class JavaFXTest extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Test to display XML");
BorderPane content = new BorderPane();
WebView webView = new WebView();
WebEngine webEngine = webView.getEngine();
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<tag1>\n <tag2>hello</tag2>\n</tag1>";
String escaped = StringEscapeUtils.escapeHtml4(xml);
String html = "<html><head></head><body><pre>" + escaped + "</pre></body>";
webEngine.loadContent(html, "text/html");
content.setCenter(webView);
primaryStage.setScene(new Scene(content, 400, 300));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
This produces the following window:
Addition: You might need to do some pretty printing on the xml before escaping; I just used hard coded line breaks and spaces.

How to hook into the internal Eclipse browser?

For my eclipse plugin I want to track every URL that is opened with the internal (and if possible also external) Eclipse browser.
So far I use
org.eclipse.swt.browser.Browser;
and
addLocationListener(...)
But I would prefer that it works also for the internal Eclipse browser. How can I achieve that?
One possible solution for the Eclipse Internal Browser would be to create an eclipse plugin that registers an IStartup extension. In your earlyStartup() method you would register an IPartListener on the workbenchPage. Then when the internal browser part is created, you will receive a callback with a reference to the WebBrowserEditor (or WebBrowserView). Since there is no direct API you will have to hack a bit and use reflection to grab the internal SWT Browser instance. Once you have that, you can add your location listener.
Sometimes during early startup there is no active Workbench window yet so you have to loop through all existing workbench windows (usually just one) and each of their workbench pages to add part listeners also.
Here is the snippet of code for the earlyStartup() routine. Note that I have omitted any cleanup of listeners during dispose for windows/pages so that still needs to be done.
//Add this code to an IStartup.earlyStartup() method
final IPartListener partListener = new IPartListener() {
#Override
public void partOpened(IWorkbenchPart part) {
if (part instanceof WebBrowserEditor)
{
WebBrowserEditor editor = (WebBrowserEditor) part;
try {
Field webBrowser = editor.getClass().getDeclaredField("webBrowser");
webBrowser.setAccessible(true);
BrowserViewer viewer = (BrowserViewer)webBrowser.get(editor);
Field browser = viewer.getClass().getDeclaredField("browser");
browser.setAccessible(true);
Browser swtBrowser = (Browser) browser.get(viewer);
swtBrowser.addLocationListener(new LocationListener() {
#Override
public void changed(LocationEvent event) {
System.out.println(event.location);
}
});
} catch (Exception e) {
}
}
else if (part instanceof WebBrowserView)
{
WebBrowserView view = (WebBrowserView) part;
try {
Field webBrowser = editor.getClass().getDeclaredField("viewer");
webBrowser.setAccessible(true);
BrowserViewer viewer = (BrowserViewer)webBrowser.get(view);
Field browser = viewer.getClass().getDeclaredField("browser");
browser.setAccessible(true);
Browser swtBrowser = (Browser) browser.get(viewer);
swtBrowser.addLocationListener(new LocationListener() {
#Override
public void changed(LocationEvent event) {
System.out.println(event.location);
}
});
} catch (Exception e) {
}
}
}
...
};
final IPageListener pageListener = new IPageListener() {
#Override
public void pageOpened(IWorkbenchPage page) {
page.addPartListener(partListener);
}
...
};
final IWindowListener windowListener = new IWindowListener() {
#Override
public void windowOpened(IWorkbenchWindow window) {
window.addPageListener(pageListener);
}
...
};
IWorkbenchWindow activeWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (activeWindow != null)
{
IWorkbenchPage activePage = activeWindow.getActivePage();
if (activePage != null)
{
activePage.addPartListener(partListener);
}
else
{
activeWindow.addPageListener(pageListener);
}
}
else
{
for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows())
{
for (IWorkbenchPage page : window.getPages()) {
page.addPartListener(partListener);
}
window.addPageListener(pageListener);
}
PlatformUI.getWorkbench().addWindowListener(windowListener);
}
One last detail about this code snippet is that it requires a dependency on the org.eclipse.ui.browser plugin to have access to the WebBrowserEditor class.

Categories