All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tinymediamanager.ui.components.NativeFileChooser Maven / Gradle / Ivy

/*
 * Copyright 2012 - 2019 Manuel Laggner
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.tinymediamanager.ui.components;

import java.awt.Component;
import java.awt.HeadlessException;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.filechooser.FileSystemView;

/**
 * This class is used to build an abstraction for the JFileChooser to use a native component whenever possible (JavaFX File Dialog if available)
 *
 * @author Manuel Laggner
 */
public class NativeFileChooser extends JFileChooser {
  private static final long   serialVersionUID = 1713280883666050112L;
  public static final boolean JAVAFX_AVAILABLE = isJavaFXAvailable();
  private JFXFileChooser      fileChooser;
  private JFXDirectoryChooser directoryChooser;
  private List          currentFiles;
  private File                currentFile;

  private static boolean isJavaFXAvailable() {
    try {
      Class.forName("javafx.stage.FileChooser");
      // set an option to do not close JFX environment too early
      Class clazz = Class.forName("javafx.application.Platform");
      Method method = clazz.getMethod("setImplicitExit", boolean.class);
      method.invoke(null, Boolean.FALSE);
      // no exception till here; initialize the JavaFX environment
      Class.forName("javafx.embed.swing.JFXPanel").newInstance();
      return true;
    }
    catch (Exception e) {
      return false;
    }
  }

  public NativeFileChooser() {
    initFxFileChooser(null);
  }

  public NativeFileChooser(String currentDirectoryPath) {
    super(currentDirectoryPath);
    initFxFileChooser(new File(currentDirectoryPath));
  }

  public NativeFileChooser(File currentDirectory) {
    super(currentDirectory);
    initFxFileChooser(currentDirectory);
  }

  public NativeFileChooser(FileSystemView fsv) {
    super(fsv);
    initFxFileChooser(fsv.getDefaultDirectory());
  }

  public NativeFileChooser(File currentDirectory, FileSystemView fsv) {
    super(currentDirectory, fsv);
    initFxFileChooser(currentDirectory);
  }

  public NativeFileChooser(String currentDirectoryPath, FileSystemView fsv) {
    super(currentDirectoryPath, fsv);
    initFxFileChooser(new File(currentDirectoryPath));
  }

  @Override
  public int showOpenDialog(Component parent) throws HeadlessException {
    // try to invoke the File/DirectoryDialog of JavaFX
    if (JAVAFX_AVAILABLE) {
      try {
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        Runnable runnable = () -> {
          if (isDirectorySelectionEnabled()) {
            currentFile = directoryChooser.showDialog();
          }
          else {
            if (isMultiSelectionEnabled()) {
              currentFiles = fileChooser.showOpenMultipleDialog();
            }
            else {
              currentFile = fileChooser.showOpenDialog();
            }
          }
          countDownLatch.countDown();
        };

        Class clazz = Class.forName("javafx.application.Platform");
        Method method = clazz.getMethod("runLater", Runnable.class);
        method.invoke(null, runnable);
        countDownLatch.await();

        if (isMultiSelectionEnabled()) {
          if (currentFiles != null) {
            return JFileChooser.APPROVE_OPTION;
          }
          else {
            return JFileChooser.CANCEL_OPTION;
          }
        }
        else {
          if (currentFile != null) {
            return JFileChooser.APPROVE_OPTION;
          }
          else {
            return JFileChooser.CANCEL_OPTION;
          }
        }
      }
      catch (Exception ignored) {
      }
    }

    // we're still here - show the JFileChooser as fallback
    return super.showOpenDialog(parent);
  }

  @Override
  public int showSaveDialog(Component parent) throws HeadlessException {
    if (!JAVAFX_AVAILABLE) {
      return super.showSaveDialog(parent);
    }

    final CountDownLatch countDownLatch = new CountDownLatch(1);
    Runnable runnable = () -> {
      // parent.setEnabled(false);
      if (isDirectorySelectionEnabled()) {
        currentFile = directoryChooser.showDialog();
      }
      else {
        currentFile = fileChooser.showSaveDialog();
      }
      countDownLatch.countDown();
      // parent.setEnabled(true);
    };

    try {
      Class clazz = Class.forName("javafx.application.Platform");
      Method method = clazz.getMethod("runLater", Runnable.class);
      method.invoke(null, runnable);
      countDownLatch.await();
    }
    catch (InterruptedException ex) {
      throw new RuntimeException(ex);
    }
    catch (Exception e) {
      return JFileChooser.CANCEL_OPTION;
    }

    if (currentFile != null) {
      return JFileChooser.APPROVE_OPTION;
    }
    else {
      return JFileChooser.CANCEL_OPTION;
    }
  }

  @Override
  public int showDialog(Component parent, String approveButtonText) throws HeadlessException {
    if (!JAVAFX_AVAILABLE) {
      return super.showDialog(parent, approveButtonText);
    }
    return showOpenDialog(parent);
  }

  @Override
  public File[] getSelectedFiles() {
    if (!JAVAFX_AVAILABLE) {
      return super.getSelectedFiles();
    }
    if (currentFiles == null) {
      return null;
    }
    return currentFiles.toArray(new File[currentFiles.size()]);
  }

  @Override
  public File getSelectedFile() {
    if (!JAVAFX_AVAILABLE) {
      return super.getSelectedFile();
    }
    return currentFile;
  }

  @Override
  public void setSelectedFiles(File[] selectedFiles) {
    if (!JAVAFX_AVAILABLE) {
      super.setSelectedFiles(selectedFiles);
      return;
    }
    if (selectedFiles == null || selectedFiles.length == 0) {
      currentFiles = null;
    }
    else {
      setSelectedFile(selectedFiles[0]);
      currentFiles = new ArrayList<>(Arrays.asList(selectedFiles));
    }
  }

  @Override
  public void setSelectedFile(File file) {
    if (!JAVAFX_AVAILABLE) {
      super.setSelectedFile(file);
      return;
    }
    currentFile = file;
    if (file != null) {
      if (file.isDirectory()) {
        fileChooser.setInitialDirectory(file.getAbsoluteFile());

        if (directoryChooser != null) {
          directoryChooser.setInitialDirectory(file.getAbsoluteFile());
        }
      }
      else if (file.isFile()) {
        fileChooser.setInitialDirectory(file.getParentFile());
        fileChooser.setInitialFileName(file.getName());

        if (directoryChooser != null) {
          directoryChooser.setInitialDirectory(file.getParentFile());
        }
      }
      else {
        // okay, no dir and no file - just get the filename out of it
        if (directoryChooser == null) {
          fileChooser.setInitialFileName(file.getName());
        }
      }
    }
  }

  @Override
  public void setFileSelectionMode(int mode) {
    super.setFileSelectionMode(mode);
    if (!JAVAFX_AVAILABLE) {
      return;
    }
    if (mode == DIRECTORIES_ONLY) {
      if (directoryChooser == null) {
        try {
          directoryChooser = new JFXDirectoryChooser();
        }
        catch (Exception e) {
          return;
        }
      }
      setSelectedFile(currentFile); // Set file again, so directory chooser will be affected by it
      setDialogTitle(getDialogTitle());
    }
  }

  @Override
  public void setDialogTitle(String dialogTitle) {
    if (!JAVAFX_AVAILABLE) {
      super.setDialogTitle(dialogTitle);
      return;
    }
    fileChooser.setTitle(dialogTitle);
    if (directoryChooser != null) {
      directoryChooser.setTitle(dialogTitle);
    }
  }

  @Override
  public String getDialogTitle() {
    if (!JAVAFX_AVAILABLE) {
      return super.getDialogTitle();
    }
    return fileChooser.getTitle();
  }

  @Override
  public void changeToParentDirectory() {
    if (!JAVAFX_AVAILABLE) {
      super.changeToParentDirectory();
      return;
    }
    File parentDir = fileChooser.getInitialDirectory().getParentFile();
    if (parentDir.isDirectory()) {
      fileChooser.setInitialDirectory(parentDir);
      if (directoryChooser != null) {
        directoryChooser.setInitialDirectory(parentDir);
      }
    }
  }

  @Override
  public void addChoosableFileFilter(FileFilter filter) {
    super.addChoosableFileFilter(filter);
    if (!JAVAFX_AVAILABLE || filter == null) {
      return;
    }
    if (filter.getClass().equals(FileNameExtensionFilter.class)) {
      FileNameExtensionFilter f = (FileNameExtensionFilter) filter;

      List ext = new ArrayList<>();
      for (String extension : f.getExtensions()) {
        ext.add(extension.replaceAll("^\\*?\\.?(.*)$", "*.$1"));
      }
      fileChooser.addExtensionFilter(f.getDescription(), ext);
    }
  }

  @Override
  public void setAcceptAllFileFilterUsed(boolean bool) {
    boolean differs = isAcceptAllFileFilterUsed() ^ bool;
    super.setAcceptAllFileFilterUsed(bool);
    if (!JAVAFX_AVAILABLE) {
      return;
    }
    if (differs) {
      if (bool) {
        fileChooser.addExtensionFilter("All files", Collections.singletonList("*.*"));
      }
      else {
        // ToDo
        // for (Iterator it = fileChooser.getExtensionFilters().iterator(); it.hasNext();) {
        // FileChooser.ExtensionFilter filter = it.next();
        // if (filter.getExtensions().contains("*.*")) {
        // it.remove();
        // }
        // }
      }
    }
  }

  @Override
  public void setCurrentDirectory(File dir) {
    if (fileChooser != null) {
      fileChooser.setInitialDirectory(dir);
    }
    else if (directoryChooser != null) {
      directoryChooser.setInitialDirectory(dir);
    }
    else {
      super.setCurrentDirectory(dir);
    }
  }

  private void initFxFileChooser(File currentFile) {
    if (JAVAFX_AVAILABLE) {
      try {
        fileChooser = new JFXFileChooser();
        this.currentFile = currentFile;
        if (currentFile != null) {
          setSelectedFile(currentFile);
        }
      }
      catch (Exception ignored) {
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy