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

us.ihmc.scs2.sessionVisualizer.jfx.SessionVisualizerIOTools Maven / Gradle / Ivy

package us.ihmc.scs2.sessionVisualizer.jfx;

import javafx.fxml.FXMLLoader;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.image.Image;
import javafx.scene.layout.Region;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;
import org.apache.commons.lang3.SystemUtils;
import us.ihmc.commons.nio.FileTools;
import us.ihmc.log.LogTools;
import us.ihmc.scs2.session.SessionIOTools;
import us.ihmc.scs2.sessionVisualizer.jfx.tools.JavaFXMissingTools;
import us.ihmc.scs2.sessionVisualizer.jfx.yoGraphic.YoGraphicFX2D;
import us.ihmc.scs2.sessionVisualizer.jfx.yoGraphic.YoGraphicFX3D;
import us.ihmc.scs2.sessionVisualizer.jfx.yoGraphic.YoGraphicFXItem;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.prefs.Preferences;

public class SessionVisualizerIOTools
{
   private static final ClassLoader classLoader = SessionVisualizerIOTools.class.getClassLoader();

   public static final Path SCS2_HOME = SessionIOTools.SCS2_HOME;
   public static final Path SCS2_CONFIGURATION_DEFAULT_PATH = SCS2_HOME.resolve("Configurations");

   static
   {
      try
      {
         FileTools.ensureDirectoryExists(SCS2_CONFIGURATION_DEFAULT_PATH);
      }
      catch (IOException e)
      {
         e.printStackTrace();
      }
   }

   public static final String scsConfigurationFileExtension = ".scs2";
   public static final String scsMainConfigurationFileExtension = ".scs2.main";
   public static final String yoChartGroupConfigurationFileExtension = ".scs2.chart";
   public static final String yoGraphicConfigurationFileExtension = SessionIOTools.yoGraphicConfigurationFileExtension;
   public static final String yoCompositeConfigurationFileExtension = ".scs2.yoComposite";
   public static final String yoEntryConfigurationFileExtension = ".scs2.yoEntry";
   public static final String yoSliderboardConfigurationFileExtension = ".scs2.yoSliderboard";
   public static final String yoVariableGroupConfigurationFileExtension = ".scs2.yoVariableGroup";
   public static final String yoEquationFileExtension = ".scs2.yoEquation";
   public static final String videoFileExtension = ".mp4";
   public static final ExtensionFilter scs2InfoFilter = new ExtensionFilter("SCS2 Info File", "*" + SessionIOTools.infoFileExtension);
   public static final ExtensionFilter scs2ConfigurationFilter = new ExtensionFilter("SCS2 Config File", "*" + scsConfigurationFileExtension);
   public static final ExtensionFilter yoChartGroupConfigurationFilter = new ExtensionFilter("SCS2 YoChartGroup File",
                                                                                             "*" + yoChartGroupConfigurationFileExtension);
   public static final ExtensionFilter yoGraphicConfigurationFilter = new ExtensionFilter("SCS2 YoGraphic File", "*" + yoGraphicConfigurationFileExtension);
   public static final ExtensionFilter yoCompositeConfigurationFilter = new ExtensionFilter("SCS2 YoComposite File",
                                                                                            "*" + yoCompositeConfigurationFileExtension);
   public static final ExtensionFilter yoEntryConfigurationFilter = new ExtensionFilter("SCS2 YoEntry File", "*" + yoEntryConfigurationFileExtension);
   public static final ExtensionFilter yoSliderboardConfigurationFilter = new ExtensionFilter("SCS2 YoSliderboard File",
                                                                                              "*" + yoSliderboardConfigurationFileExtension);
   public static final ExtensionFilter yoVariableGroupConfigurationFilter = new ExtensionFilter("SCS2 YoVariable Group File",
                                                                                                "*" + yoVariableGroupConfigurationFileExtension);
   public static final ExtensionFilter yoEquationFilter = new ExtensionFilter("SCS2 YoEquation File", "*" + yoEquationFileExtension);

   public static final ExtensionFilter videoExtensionFilter = new ExtensionFilter("MP4", "*" + videoFileExtension);

   private static final String CSS_FOLDER = "css/";
   private static final String FXML_FOLDER = "fxml/";
   private static final String ICONS_FOLDER = "icons/";
   private static final String IMAGES_FOLDER = "images/";
   private static final String SKYBOX_FOLDER = "skybox/";
   private static final String CONFIGURATION_FOLDER = "configuration/";
   private static final String YO_GRAPHIC_FOLDER = "yoGraphic/";
   private static final String SESSION_FOLDER = "session/";

   // CSS
   public static final URL GENERAL_STYLESHEET = getCSSResource("GeneralStylesheet");

   // Icon list:
   public static final Image SCS_ICON_IMAGE = loadIcon("scs-icon.png");
   public static final Image INVALID_ICON_IMAGE = loadIcon("invalid-icon.png");
   public static final Image VALID_ICON_IMAGE = loadIcon("valid-icon.png");
   public static final Image REMOTE_SESSION_IMAGE = loadIcon("viz-icon.png");
   public static final Image LOG_SESSION_IMAGE = loadIcon("log-icon.png");

   // FXML list:
   private static final String CHART = "chart/";
   private static final String YO_COMPOSITE = "yoComposite/";
   private static final String YO_COMPOSITE_CREATOR = YO_COMPOSITE + "creator/";
   private static final String YO_COMPOSITE_PATTERN = YO_COMPOSITE + "pattern/";
   private static final String YO_COMPOSITE_SEARCH = YO_COMPOSITE + "search/";
   private static final String YO_COMPOSITE_ENTRY = YO_COMPOSITE + "entry/";
   private static final String YO_GRAPHIC = "yoGraphic/";
   private static final String YO_GRAPHIC_2D = YO_GRAPHIC + "graphic2D/";
   private static final String YO_GRAPHIC_3D = YO_GRAPHIC + "graphic3D/";
   private static final String YO_GRAPHIC_GROUP = YO_GRAPHIC + "group/";
   private static final String YO_PIE_CHART = "yoPieChart/";
   private static final String YO_EDITOR = "editor/";
   private static final String YO_SLIDERBOARD = "yoSliderboard/";
   private static final String YO_SLIDERBOARD_BCF2000 = YO_SLIDERBOARD + "bcf2000/";
   private static final String YO_SLIDERBOARD_XTOUCHCOMPACT = YO_SLIDERBOARD + "xtouchcompact/";

   // YoComposite resources:
   public static final String DEFAULT_YO_COMPOSITE_PATTERNS_FILE = "DefaultYoCompositePatterns" + yoCompositeConfigurationFileExtension;
   public static final URL YO_COMPOSITE_PATTERN_EDITOR_PANE_URL = getFXMLResource(YO_COMPOSITE_PATTERN, "YoCompositePatternEditorPane");
   public static final URL YO_COMPOSITE_PATTERN_PROPERTY_WINDOW_URL = getFXMLResource(YO_COMPOSITE_PATTERN, "YoCompositePatternPropertyWindow");
   public static final URL YO_COMPOSITE_AND_EQUATION_EDITOR_WINDOW_URL = getFXMLResource(YO_COMPOSITE_CREATOR, "YoCompositeAndEquationEditorWindow");
   public static final URL YO_COMPOSITE_CREATOR_DIALOG_URL = getFXMLResource(YO_COMPOSITE_CREATOR, "YoCompositeCreatorDialog");
   public static final URL YO_EQUATION_EDITOR_PANE_URL = getFXMLResource(YO_COMPOSITE_CREATOR, "YoEquationEditorPane");
   public static final URL YO_EQUATION_EDITOR_HELP_PANE_URL = getFXMLResource(YO_COMPOSITE_CREATOR, "YoEquationEditorHelpPane");
   public static final URL YO_COMPOSITE_SEARCH_PANEL_URL = getFXMLResource(YO_COMPOSITE_SEARCH, "YoCompositeSearchPane");
   public static final URL YO_SEARCH_TAB_PANE_URL = getFXMLResource(YO_COMPOSITE_SEARCH, "YoSearchTabPane");
   public static final URL YO_ENTRY_LIST_VIEW_URL = getFXMLResource(YO_COMPOSITE_ENTRY, "YoEntryListView");
   public static final URL YO_REGISTRY_STATISTICS_URL = getFXMLResource("YoRegistryStatisticsPane");
   // YoGraphic resources:
   public static final URL GRAPHIC_2D_CROSS_URL = getYoGraphicResource("cross.svg");
   public static final URL GRAPHIC_2D_PLUS_URL = getYoGraphicResource("plus.svg");
   public static final URL GRAPHIC_2D_CIRCLE_URL = getYoGraphicResource("circle.svg");
   public static final URL GRAPHIC_2D_CIRCLE_CROSS_URL = getYoGraphicResource("circle_cross.svg");
   public static final URL GRAPHIC_2D_CIRCLE_PLUS_URL = getYoGraphicResource("circle_plus.svg");
   public static final URL GRAPHIC_2D_DIAMOND_URL = getYoGraphicResource("diamond.svg");
   public static final URL GRAPHIC_2D_DIAMOND_PLUS_URL = getYoGraphicResource("diamond_plus.svg");
   public static final URL GRAPHIC_2D_SQUARE_URL = getYoGraphicResource("square.svg");
   public static final URL GRAPHIC_2D_SQUARE_CROSS_URL = getYoGraphicResource("square_cross.svg");
   public static final Path GRAPHIC_2D_CUSTOM_GRAPHICS = Paths.get(SCS2_HOME.toString(), "yoGraphic");
   public static final URL GRAPHIC_3D_SPHERE_URL = getYoGraphicResource("sphere.stl");
   public static final URL GRAPHIC_3D_CUBE_URL = getYoGraphicResource("cube.stl");
   public static final URL GRAPHIC_3D_TETRAHEDRON_URL = getYoGraphicResource("tetrahedron.stl");
   public static final URL GRAPHIC_3D_ICOSAHEDRON_URL = getYoGraphicResource("icosahedron.stl");
   public static final Path GRAPHIC_3D_CUSTOM_GRAPHICS = Paths.get(SCS2_HOME.toString(), "yoGraphic");
   // YoSliderboard resources:
   public static final URL YO_SLIDERBOARD_BCF2000_WINDOW_URL = getFXMLResource(YO_SLIDERBOARD_BCF2000, "YoBCF2000SliderboardWindow");
   public static final URL YO_SLIDERBOARD_XTOUCHCOMPACT_WINDOW_URL = getFXMLResource(YO_SLIDERBOARD_XTOUCHCOMPACT, "YoXTouchCompactSliderboardWindow");
   public static final URL YO_MULTI_SLIDERBOARD_WINDOW_URL = getFXMLResource(YO_SLIDERBOARD, "YoMultiSliderboardWindow");

   public static final URL MAIN_WINDOW_URL = getFXMLResource("MainWindow");
   public static final URL SECONDARY_WINDOW_URL = getFXMLResource("SecondaryWindow");

   public static final URL SIDE_PANE_URL = getFXMLResource("SidePane");
   public static final URL USER_SIDE_PANE_URL = getFXMLResource("UserSidePane");
   public static final URL ABOUT_WINDOW_URL = getFXMLResource("AboutWindow");
   public static final URL VIDEO_PREVIEW_PANE_URL = getFXMLResource("VideoRecordingPreviewPane");
   public static final URL SESSION_DATA_EXPORT_STAGE_URL = getFXMLResource("SessionDataExportStage");
   public static final URL SESSION_VARIABLE_FILTER_PANE_URL = getFXMLResource("SessionVariableFilterPane");
   public static final URL PLOTTER2D_OPTIONS_STAGE_URL = getFXMLResource(YO_GRAPHIC, "Plotter2DOptionsStage");
   public static final URL CAMERA3D_OPTIONS_PANE_URL = getFXMLResource("camera/Camera3DOptionsPane");

   public static final URL YO_PIE_CHART_WINDOW_URL = getFXMLResource(YO_PIE_CHART, "YoPieChartWindow");

   public static final URL CHART_PANEL_FXML_URL = getFXMLResource(CHART, "YoChartPanel");
   public static final URL CHART_GROUP_PANEL_URL = getFXMLResource(CHART, "YoChartGroupPanel");
   public static final URL CHART_GROUP_MODEL_EDITOR_PANE_URL = getFXMLResource(CHART, "YoChartGroupModelEditorPane");
   public static final URL CHART_IDENTIFIER_EDITOR_PANE_URL = getFXMLResource(CHART, "YoChartIdentifierEditorPane");
   public static final URL CHART_OPTION_DIALOG_URL = getFXMLResource(CHART, "YoChartOptionDialog");
   public static final URL CHART_VARIABLE_OPTION_PANE_URL = getFXMLResource(CHART, "YoChartVariableOptionPane");
   public static final URL CHART_BASELINE_EDITOR_PANE_URL = getFXMLResource(CHART, "YoChartBaselineEditorPane");

   public static final URL YO_GRAPHIC_ITEM_CREATOR_URL = getFXMLResource(YO_GRAPHIC, "YoGraphicItemCreatorDialog");
   public static final URL YO_GRAPHIC_PROPERTY_URL = getFXMLResource(YO_GRAPHIC, "YoGraphicPropertyWindow");
   public static final URL YO_COMPOSITE_EDITOR_URL = getFXMLResource(YO_EDITOR, "YoCompositeEditorPane");
   public static final URL SIMPLE_COLOR_EDITOR_PANE_URL = getFXMLResource(YO_EDITOR, "SimpleColorEditorPane");
   public static final URL YO_COLOR_RGBA_EDITOR_PANE_URL = getFXMLResource(YO_EDITOR, "YoColorRGBAEditorPane");
   public static final URL YO_COLOR_RGBA_SINGLE_EDITOR_PANE_URL = getFXMLResource(YO_EDITOR, "YoColorRGBASingleEditorPane");
   public static final URL YO_GRAPHIC_ROBOT_COLLISIONS_BUTTON_URL = getFXMLResource(YO_GRAPHIC, "YoGraphicRobotCollisionsToggleButton");
   public static final URL YO_GRAPHIC_TERRAIN_COLLISIONS_BUTTON_URL = getFXMLResource(YO_GRAPHIC, "YoGraphicTerrainCollisionsToggleButton");
   public static final URL YO_GRAPHIC_ROBOT_MASS_PROPERTIES_BUTTON_URL = getFXMLResource(YO_GRAPHIC, "YoGraphicRobotMassPropertiesToggleButton");

   // Session resources:
   public static final URL REMOTE_SESSION_MANAGER_PANE_FXML_URL = getFXMLResource(SESSION_FOLDER, "RemoteSessionManagerPane");
   public static final URL REMOTE_SESSION_INFO_PANE_FXML_URL = getFXMLResource(SESSION_FOLDER, "YoClientInformationPane");
   public static final URL LOG_SESSION_MANAGER_PANE_FXML_URL = getFXMLResource(SESSION_FOLDER, "LogSessionManagerPane");
   public static final URL LOG_CROP_PROGRESS_PANE_FXML_URL = getFXMLResource(SESSION_FOLDER, "LogCropProgressPane");
   public static final URL MCAP_LOG_SESSION_MANAGER_PANE_FXML_URL = getFXMLResource(SESSION_FOLDER, "MCAPLogSessionManagerPane");

   // Cloudy Crown Skybox
   public static final String SKYBOX_CLOUDY_FOLDER = "cloudy/";
   public static final Image SKYBOX_TOP_IMAGE = loadSkyboxImage(SKYBOX_CLOUDY_FOLDER + "Up.png");
   public static final Image SKYBOX_BOTTOM_IMAGE = loadSkyboxImage(SKYBOX_CLOUDY_FOLDER + "Down.png");
   public static final Image SKYBOX_LEFT_IMAGE = loadSkyboxImage(SKYBOX_CLOUDY_FOLDER + "Left.png");
   public static final Image SKYBOX_RIGHT_IMAGE = loadSkyboxImage(SKYBOX_CLOUDY_FOLDER + "Right.png");
   public static final Image SKYBOX_FRONT_IMAGE = loadSkyboxImage(SKYBOX_CLOUDY_FOLDER + "Front.png");
   public static final Image SKYBOX_BACK_IMAGE = loadSkyboxImage(SKYBOX_CLOUDY_FOLDER + "Back.png");

   // SCS 1 Skybox
   public static final String SKYBOX_SCS1_FOLDER = "brightSky/";
   public static final Image SCS1_SKYBOX_TOP_IMAGE = loadSkyboxImage(SKYBOX_SCS1_FOLDER + "Up.bmp");
   public static final Image SCS1_SKYBOX_BOTTOM_IMAGE = loadSkyboxImage(SKYBOX_SCS1_FOLDER + "Down.bmp");
   public static final Image SCS1_SKYBOX_LEFT_IMAGE = loadSkyboxImage(SKYBOX_SCS1_FOLDER + "Left.bmp");
   public static final Image SCS1_SKYBOX_RIGHT_IMAGE = loadSkyboxImage(SKYBOX_SCS1_FOLDER + "Right.bmp");
   public static final Image SCS1_SKYBOX_FRONT_IMAGE = loadSkyboxImage(SKYBOX_SCS1_FOLDER + "Front.bmp");
   public static final Image SCS1_SKYBOX_BACK_IMAGE = loadSkyboxImage(SKYBOX_SCS1_FOLDER + "Back.bmp");

   public static void addSCSIconToDialog(Dialog dialog)
   {
      addSCSIconToWindow(dialog.getDialogPane().getScene().getWindow());
   }

   public static void addSCSIconToWindow(Window window)
   {
      if (window instanceof Stage)
      {
         ((Stage) window).getIcons().add(SCS_ICON_IMAGE);
      }
   }

   public static URL getCSSResource(String filename)
   {
      return classLoader.getResource(CSS_FOLDER + filename + ".css");
   }

   public static URL getFXMLResource(String filename)
   {
      return classLoader.getResource(FXML_FOLDER + filename + ".fxml");
   }

   public static URL getFXMLResource(String location, String filename)
   {
      return classLoader.getResource(FXML_FOLDER + location + filename + ".fxml");
   }

   public static InputStream getYoGraphicFXIconResource(Class yoGraphicFXType)
   {
      if (yoGraphicFXType == null)
         return null;

      return getIconResource(YO_GRAPHIC_FOLDER + yoGraphicFXType.getSimpleName() + ".png");
   }

   public static FXMLLoader getYoGraphicFXEditorFXMLLoader(Class yoGraphicFXType)
   {
      String location = null;
      if (YoGraphicFX2D.class.isAssignableFrom(yoGraphicFXType))
         location = YO_GRAPHIC_2D;
      else if (YoGraphicFX3D.class.isAssignableFrom(yoGraphicFXType))
         location = YO_GRAPHIC_3D;
      else
         throw new IllegalArgumentException("Unhandled graphic type: " + yoGraphicFXType.getSimpleName());

      URL fxmlResource = getFXMLResource(location, yoGraphicFXType.getSimpleName() + "EditorPane");
      Objects.requireNonNull(fxmlResource, "Could not find FXML resource for " + yoGraphicFXType.getSimpleName());
      return new FXMLLoader(fxmlResource);
   }

   public static FXMLLoader getYoGraphicFXGroupEditorFXMLLoader(Class yoGraphicFXType)
   {
      String location = null;
      if (YoGraphicFX2D.class.isAssignableFrom(yoGraphicFXType))
         location = YO_GRAPHIC_GROUP + "graphic2D/";
      else if (YoGraphicFX3D.class.isAssignableFrom(yoGraphicFXType))
         location = YO_GRAPHIC_GROUP + "graphic3D/";
      else
         throw new IllegalArgumentException("Unhandled graphic type: " + yoGraphicFXType.getSimpleName());

      URL fxmlResource = getFXMLResource(location, yoGraphicFXType.getSimpleName() + "GroupEditorPane");
      Objects.requireNonNull(fxmlResource, "Could not find FXML resource for grouped " + yoGraphicFXType.getSimpleName());
      return new FXMLLoader(fxmlResource);
   }

   public static InputStream getIconResource(String iconNameWithExtension)
   {
      return classLoader.getResourceAsStream(ICONS_FOLDER + iconNameWithExtension);
   }

   public static InputStream getImageResource(String imageNameWithExtension)
   {
      return classLoader.getResourceAsStream(IMAGES_FOLDER + imageNameWithExtension);
   }

   public static InputStream getSkyboxResource(String skyboxNameWithExtension)
   {
      return classLoader.getResourceAsStream(SKYBOX_FOLDER + skyboxNameWithExtension);
   }

   public static InputStream getConfigurationResource(String filenameWithExtension)
   {
      return classLoader.getResourceAsStream(CONFIGURATION_FOLDER + filenameWithExtension);
   }

   public static URL getYoGraphicResource(String filenameWithExtension)
   {
      return classLoader.getResource(YO_GRAPHIC_FOLDER + filenameWithExtension);
   }

   public static URL getYoGraphicResource(String location, String filenameWithExtension)
   {
      return classLoader.getResource(YO_GRAPHIC_FOLDER + location + filenameWithExtension);
   }

   public static Image loadIcon(String iconNameWithExtension)
   {
      return createImage(iconNameWithExtension, () -> getIconResource(iconNameWithExtension));
   }

   public static Image loadImage(String imageNameWithExtension)
   {
      return createImage(imageNameWithExtension, () -> getImageResource(imageNameWithExtension));
   }

   public static Image loadSkyboxImage(String skyboxImageNameWithExtension)
   {
      return createImage(skyboxImageNameWithExtension, () -> getSkyboxResource(skyboxImageNameWithExtension));
   }

   public static Image createImage(String name, Supplier isSupplier)
   {
      for (int i = 0; i < 3; i++)
      {
         try (InputStream is = isSupplier.get())
         {
            Image image = new Image(is);

            if (image.getWidth() != 0.0)
               return image;

            LogTools.error("Failed to load image {}, retrying.", name);
         }
         catch (IOException e)
         {
            e.printStackTrace();
         }
      }
      return null;
   }

   public static File scs2ConfigurationOpenFileDialog(Window owner)
   {
      return showOpenDialog(owner, "Load SCS2 Configuration", scs2ConfigurationFilter);
   }

   public static File scs2ConfigurationSaveFileDialog(Window owner)
   {
      return showSaveDialog(owner, "Save SCS2 Configuration", scs2ConfigurationFilter);
   }

   public static File yoChartConfigurationOpenFileDialog(Window owner)
   {
      return showOpenDialog(owner, "Load YoChartGroup", yoChartGroupConfigurationFilter);
   }

   public static File yoChartConfigurationSaveFileDialog(Window owner)
   {
      return showSaveDialog(owner, "Save YoChartGroup", yoChartGroupConfigurationFilter);
   }

   public static File yoGraphicConfigurationOpenFileDialog(Window owner)
   {
      return showOpenDialog(owner, "Load YoGraphic", yoGraphicConfigurationFilter);
   }

   public static File yoGraphicConfigurationSaveFileDialog(Window owner)
   {
      return showSaveDialog(owner, "Save YoGraphic", yoGraphicConfigurationFilter);
   }

   public static File yoCompositeConfigurationOpenFileDialog(Window owner)
   {
      return showOpenDialog(owner, "Load YoComposite", yoCompositeConfigurationFilter);
   }

   public static File yoCompositeConfigurationSaveFileDialog(Window owner)
   {
      return showSaveDialog(owner, "Save YoComposite", yoCompositeConfigurationFilter);
   }

   public static File yoEntryConfigurationOpenFileDialog(Window owner)
   {
      return showOpenDialog(owner, "Load YoEntry", yoEntryConfigurationFilter);
   }

   public static File yoEntryConfigurationSaveFileDialog(Window owner)
   {
      return showSaveDialog(owner, "Save YoEntry", yoEntryConfigurationFilter);
   }

   public static File yoSliderboardConfigurationOpenFileDialog(Window owner)
   {
      return showOpenDialog(owner, "Load YoSliderboard", yoSliderboardConfigurationFilter);
   }

   public static File yoSliderboardConfigurationSaveFileDialog(Window owner)
   {
      return showSaveDialog(owner, "Save YoSliderboard", yoSliderboardConfigurationFilter);
   }

   public static File yoVariableGroupConfigurationOpenFileDialog(Window owner)
   {
      return showOpenDialog(owner, "Load YoVariable Group", yoVariableGroupConfigurationFilter);
   }

   public static File yoVariableGroupConfigurationSaveFileDialog(Window owner)
   {
      return showSaveDialog(owner, "Save YoVariable Group", yoVariableGroupConfigurationFilter);
   }

   public static File yoEquationOpenFileDialog(Window owner)
   {
      return showOpenDialog(owner, "Load YoEquation", yoEquationFilter);
   }

   public static File yoEquationSaveFileDialog(Window owner)
   {
      return showSaveDialog(owner, "Save YoEquation", yoEquationFilter);
   }

   public static File videoExportSaveFileDialog(Window owner)
   {
      return showSaveDialog(owner, "Save Video", videoExtensionFilter, "video");
   }

   public static File showSaveDialog(Window owner, String title, ExtensionFilter extensionFilter)
   {
      return showSaveDialog(owner, title, extensionFilter, "filePath");
   }

   public static File showSaveDialog(Window owner, String title, ExtensionFilter extensionFilter, String pathKey)
   {
      List extensions = extensionFilter != null ? extensionFilter.getExtensions() : Collections.emptyList();
      boolean hasExtension = !extensions.isEmpty();

      FileChooser fileChooser = fileChooser(title, extensionFilter, pathKey);
      if (hasExtension && !SystemUtils.IS_OS_WINDOWS)
         fileChooser.setInitialFileName(extensions.get(0));

      boolean usePhantomStage = owner == null;
      if (usePhantomStage)
      {
         owner = getPhantomStage();
      }

      File result = fileChooser.showSaveDialog(owner);

      if (result == null)
         return null;

      if (hasExtension)
      {
         // FIXME: This is to address what seems to be a bug with the FileChooser on Windows.
         // When saving, if you select a file with the same extension, then modify the name, the FileChooser will append the file extension another time.
         String filename = result.getName();
         boolean containsExtension = false;

         for (int i = 0; i < extensions.size(); i++)
         {
            String extension = extensions.get(i);
            if (extension.charAt(0) == '*')
               extension = extension.substring(1);

            int firstIndexOfExtension = filename.indexOf(extension);

            if (firstIndexOfExtension == -1)
            {
               continue;
            }
            else
            {
               containsExtension = true;

               if (firstIndexOfExtension == filename.length() - extension.length())
               {
                  break;
               }
               else
               {
                  String newFilename = filename.substring(0, firstIndexOfExtension) + extension;
                  result = new File(result.getParentFile(), newFilename);
                  // No need to worry if the file already exists, it would have caused a prompt in the FileChooser.
                  break;
               }
            }
         }

         // FIXME: This is to address what seems to be a bug with the FileChooser on Linux.
         // When saving, the filename is not guaranteed to contain the file extension.
         if (!containsExtension)
         {
            String newFilename = filename + extensions.get(0).replace("*", "");
            result = new File(result.getParentFile(), newFilename);
            if (result.exists())
            { // On Linux, this case is not covered by the FileChooser, we need to manually display a confirmation

               Alert alert = new Alert(AlertType.WARNING, result.getName() + " already exists.\nDo you want to replace it?", ButtonType.YES, ButtonType.NO);
               alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
               alert.initOwner(owner);
               alert.setTitle("Confirm Save As");
               JavaFXMissingTools.centerDialogInOwner(alert);
               Optional confirmation = alert.showAndWait();

               if (!confirmation.isPresent() || confirmation.get() == ButtonType.NO)
                  return null;
            }
         }
      }

      setDefaultFilePath(pathKey, result);

      return result;
   }

   public static File showOpenDialog(Window owner, String title, ExtensionFilter extensionFilter)
   {
      return showOpenDialog(owner, title, extensionFilter, "filePath");
   }

   public static File showOpenDialog(Window owner, String title, ExtensionFilter extensionFilter, String pathKey)
   {
      return showOpenDialog(owner, title, Collections.singletonList(extensionFilter), pathKey);
   }

   public static File showOpenDialog(Window owner, String title, Collection extensionFilters, String pathKey)
   {
      FileChooser fileChooser = fileChooser(title, extensionFilters, pathKey);

      boolean usePhantomStage = owner == null;
      if (usePhantomStage)
      {
         owner = getPhantomStage();
         getPhantomStage().show();
      }

      File result = fileChooser.showOpenDialog(owner);
      if (result != null)
         setDefaultFilePath(pathKey, result);

      return result;
   }

   private static Stage phantomStage = null;

   private static Stage getPhantomStage()
   {
      if (phantomStage == null)
      {
         Stage stage = new Stage();
         addSCSIconToWindow(stage);
         stage.initStyle(StageStyle.UNDECORATED);
         stage.setX(stage.getX() - 0.5 * stage.getWidth());
         stage.setY(stage.getY() - 0.5 * stage.getHeight());
         stage.setWidth(0);
         stage.setHeight(0);
         stage.show();
         phantomStage = stage;
      }
      return phantomStage;
   }

   private static FileChooser fileChooser(String title, ExtensionFilter extensionFilter, String pathKey)
   {
      return fileChooser(title, Collections.singletonList(extensionFilter), pathKey);
   }

   private static FileChooser fileChooser(String title, Collection extensionFilters, String pathKey)
   {
      FileChooser fileChooser = new FileChooser();
      fileChooser.setTitle(title);
      fileChooser.setInitialDirectory(getDefaultFilePath(pathKey));
      fileChooser.getExtensionFilters().addAll(extensionFilters);
      return fileChooser;
   }

   /**
    * Returns the file that was last opened or saved to.
    *
    * @return the most-recently-used file.
    */
   public static File getDefaultFilePath()
   {
      return getDefaultFilePath("filePath");
   }

   public static File getDefaultFilePath(String key)
   {
      if (key == null)
         key = "filePath";

      Preferences prefs = Preferences.userNodeForPackage(SessionVisualizerIOTools.class);
      String filePath = prefs.get(key, null);

      if (filePath != null && Files.isDirectory(Paths.get(filePath)))
         return new File(filePath);
      else
         return null;
   }

   /**
    * Stores the given file's path as the most-recently-used path. The path is persisted across program
    * runs.
    *
    * @param file the file
    */
   public static void setDefaultFilePath(File file)
   {
      setDefaultFilePath("filePath", file);
   }

   public static void setDefaultFilePath(String key, File file)
   {
      Preferences prefs = Preferences.userNodeForPackage(SessionVisualizerIOTools.class);
      if (file != null)
      {
         if (!file.isDirectory())
            file = file.getParentFile();

         prefs.put(key, file.getAbsolutePath());
      }
   }

   /**
    * Opens the given URI in the user's default browser.
    *
    * @param uri the URI to open
    * @return {@code true} if the URI was successfully opened, {@code false} otherwise.
    */
   public static boolean openWebpage(URI uri)
   {
      Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
      if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE))
      {
         try
         {
            desktop.browse(uri);
            return true;
         }
         catch (Exception e)
         {
            e.printStackTrace();
         }
      }
      return false;
   }

   /**
    * Opens the given URL in the user's default browser.
    *
    * @param url the URL to open
    * @return {@code true} if the URL was successfully opened, {@code false} otherwise.
    */
   public static boolean openWebpage(URL url)
   {
      try
      {
         return openWebpage(url.toURI());
      }
      catch (URISyntaxException e)
      {
         e.printStackTrace();
      }
      return false;
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy