diff --git a/core/src/main/java/dk/gtz/graphedit/model/ModelEditorSettings.java b/core/src/main/java/dk/gtz/graphedit/model/ModelEditorSettings.java index f3b410ba..ea059ac4 100644 --- a/core/src/main/java/dk/gtz/graphedit/model/ModelEditorSettings.java +++ b/core/src/main/java/dk/gtz/graphedit/model/ModelEditorSettings.java @@ -4,8 +4,9 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Optional; -import dk.gtz.graphedit.util.PlatformUtils; +import dk.gtz.graphedit.util.EditorActions; import dk.gtz.graphedit.viewmodel.ViewModelEditorSettings; /** @@ -23,6 +24,7 @@ * @param showTraceToasts When true, will display toasts on logger.trace calls * @param lastOpenedProject Filepath to the last opened graphedit project file * @param recentProjects List of filepaths that have been recently opened + * @param disabledPlugins List of plugin filepaths that are disabled */ public record ModelEditorSettings( double gridSizeX, @@ -36,13 +38,14 @@ public record ModelEditorSettings( boolean showErrorToasts, boolean showTraceToasts, String lastOpenedProject, - List recentProjects) { + List recentProjects, + List disabledPlugins) { /** * Constructs a ModelEditorSettings instance with default values. */ public ModelEditorSettings() { - this(20.0d, 20.0d, true, false, true, false, true, true, true, false, "", new ArrayList<>()); + this(20.0d, 20.0d, true, false, true, false, true, true, true, false, "", new ArrayList<>(), new ArrayList<>()); } /** @@ -61,7 +64,9 @@ public ModelEditorSettings(ViewModelEditorSettings viewmodel) { viewmodel.showErrorToasts().get(), viewmodel.showTraceToasts().get(), viewmodel.lastOpenedProject().get(), - new ArrayList(viewmodel.recentProjects().get())); + new ArrayList(viewmodel.recentProjects().get()), + new ArrayList(viewmodel.disabledPlugins().get()) + ); } /** @@ -70,13 +75,6 @@ public ModelEditorSettings(ViewModelEditorSettings viewmodel) { * @return The OS-specific file path to editor settings */ public static Path getEditorSettingsFile() { - if(PlatformUtils.isWindows()) - return Path.of(System.getenv("AppData") + File.separator + "graphedit-settings.json"); - var userHome = System.getProperty("user.home"); - if(PlatformUtils.isMac()) - userHome += "/Library/Application Support/Graphedit/"; - else - userHome += "/.local/graphedit/"; - return Path.of(userHome + "graphedit-settings.json"); + return Path.of(EditorActions.getConfigDir() + File.separator + "graphedit-settings.json"); } } diff --git a/core/src/main/java/dk/gtz/graphedit/spi/IPlugin.java b/core/src/main/java/dk/gtz/graphedit/spi/IPlugin.java index ea560db9..4c967951 100644 --- a/core/src/main/java/dk/gtz/graphedit/spi/IPlugin.java +++ b/core/src/main/java/dk/gtz/graphedit/spi/IPlugin.java @@ -17,6 +17,14 @@ public interface IPlugin { */ String getName(); + /** + * Get a general description of this plugin + * @return A description of what kinds of utilities this plugin provides + */ + default String getDescription() { + return ""; + } + /** * Event called when the plugin is initialized. * At this point, most things are registered in {@link DI}. diff --git a/core/src/main/java/dk/gtz/graphedit/spi/IPluginsContainer.java b/core/src/main/java/dk/gtz/graphedit/spi/IPluginsContainer.java index 3f4e4865..b74586c1 100644 --- a/core/src/main/java/dk/gtz/graphedit/spi/IPluginsContainer.java +++ b/core/src/main/java/dk/gtz/graphedit/spi/IPluginsContainer.java @@ -49,4 +49,10 @@ public interface IPluginsContainer { * @return The underlying collection of plugins */ Collection getPlugins(); + + /** + * Get a collection of plugins filtered such that it only contains the enabled plugins + * @return A collection of the enabled plugins + */ + Collection getEnabledPlugins(); } diff --git a/core/src/main/java/dk/gtz/graphedit/util/EditorActions.java b/core/src/main/java/dk/gtz/graphedit/util/EditorActions.java index 265e3171..099ea5a0 100644 --- a/core/src/main/java/dk/gtz/graphedit/util/EditorActions.java +++ b/core/src/main/java/dk/gtz/graphedit/util/EditorActions.java @@ -587,4 +587,13 @@ public static ModelProjectResource createNewModel(String modelName) { var exampleGraph = new ModelGraph("", exampleVertices, exampleEdges); return new ModelProjectResource(exampleMetaData, exampleGraph); } + + public static String getConfigDir() { + if(PlatformUtils.isWindows()) + return String.join(File.separator, System.getenv("AppData"), "graphedit").toString(); + var userHome = System.getProperty("user.home"); + if(PlatformUtils.isMac()) + return String.join(File.separator, userHome, "Library", "Application Support", "Graphedit"); + return String.join(File.separator, userHome, ".local", "graphedit"); + } } diff --git a/core/src/main/java/dk/gtz/graphedit/view/SidePanelController.java b/core/src/main/java/dk/gtz/graphedit/view/SidePanelController.java index 33bdc5c3..4656746b 100644 --- a/core/src/main/java/dk/gtz/graphedit/view/SidePanelController.java +++ b/core/src/main/java/dk/gtz/graphedit/view/SidePanelController.java @@ -7,6 +7,7 @@ import dk.gtz.graphedit.spi.IPlugin; import dk.gtz.graphedit.spi.IPluginPanel; import dk.gtz.graphedit.spi.IPluginsContainer; +import dk.gtz.graphedit.viewmodel.ViewModelEditorSettings; import dk.yalibs.yadi.DI; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; @@ -39,13 +40,14 @@ public SidePanelController() { @FXML private void initialize() { var plugins = DI.get(IPluginsContainer.class); + var settings = DI.get(ViewModelEditorSettings.class); if(plugins.getPlugins().isEmpty()) { logger.warn("No plugins are loaded, cannot show sidepanel"); return; } left.setSpacing(20); left.setPadding(new Insets(15)); - for(var plugin : plugins.getPlugins()) { + for(var plugin : plugins.getEnabledPlugins()) { try { initializePluginTab(plugin); } catch(Exception e) { diff --git a/core/src/main/java/dk/gtz/graphedit/viewmodel/ViewModelEditorSettings.java b/core/src/main/java/dk/gtz/graphedit/viewmodel/ViewModelEditorSettings.java index a4be2097..c232e642 100644 --- a/core/src/main/java/dk/gtz/graphedit/viewmodel/ViewModelEditorSettings.java +++ b/core/src/main/java/dk/gtz/graphedit/viewmodel/ViewModelEditorSettings.java @@ -40,7 +40,8 @@ public record ViewModelEditorSettings( BooleanProperty showErrorToasts, BooleanProperty showTraceToasts, StringProperty lastOpenedProject, - ListProperty recentProjects) { + ListProperty recentProjects, + ListProperty disabledPlugins) { /** * Construct a new instance @@ -59,9 +60,13 @@ public ViewModelEditorSettings(ModelEditorSettings settings) { settings.showErrorToasts(), settings.showTraceToasts(), settings.lastOpenedProject(), + new SimpleListProperty(FXCollections.observableArrayList()), new SimpleListProperty(FXCollections.observableArrayList()) ); - this.recentProjects.addAll(settings.recentProjects()); + if(settings.recentProjects() != null) + this.recentProjects.addAll(settings.recentProjects()); + if(settings.disabledPlugins() != null) + this.disabledPlugins.addAll(settings.disabledPlugins()); } /** @@ -91,7 +96,8 @@ public ViewModelEditorSettings( boolean showErrorToasts, boolean showTraceToasts, String lastOpenedProject, - List recentProjects) { + List recentProjects, + List disabledPlugins) { this( new SimpleDoubleProperty(gridSizeX), new SimpleDoubleProperty(gridSizeY), @@ -104,8 +110,10 @@ public ViewModelEditorSettings( new SimpleBooleanProperty(showErrorToasts), new SimpleBooleanProperty(showTraceToasts), new SimpleStringProperty(lastOpenedProject), + new SimpleListProperty(FXCollections.observableArrayList()), new SimpleListProperty(FXCollections.observableArrayList()) ); this.recentProjects.addAll(recentProjects); + this.disabledPlugins.addAll(disabledPlugins); } } diff --git a/graphedit/src/main/java/dk/gtz/graphedit/Args.java b/graphedit/src/main/java/dk/gtz/graphedit/Args.java index 1f24b120..a2ab5732 100644 --- a/graphedit/src/main/java/dk/gtz/graphedit/Args.java +++ b/graphedit/src/main/java/dk/gtz/graphedit/Args.java @@ -5,7 +5,7 @@ import com.beust.jcommander.Parameter; -import dk.gtz.graphedit.util.PlatformUtils; +import dk.gtz.graphedit.util.EditorActions; public class Args { @Parameter(names = { "-h", "--help" }, description = "Show this message") @@ -13,15 +13,5 @@ public class Args { @Parameter(names = { "-v", "--verbosity" }, description = "Set verbosity level") public String verbosity = "INFO"; @Parameter(names = { "-P", "--plugin-dir" }, description = "Set directory to look for plugins in") - public List pluginDirs = List.of("plugins", String.join(File.separator, configDir(), "plugins")); - - private static String configDir() { - if(PlatformUtils.isWindows()) - return String.join(File.separator, System.getenv("AppData"), "graphedit").toString(); - var userHome = System.getProperty("user.home"); - if(PlatformUtils.isMac()) - return String.join(File.separator, userHome, "Library", "Application Support", "Graphedit"); - return String.join(File.separator, userHome, ".local", "graphedit"); - } + public List pluginDirs = List.of("plugins", String.join(File.separator, EditorActions.getConfigDir(), "plugins")); } - diff --git a/graphedit/src/main/java/dk/gtz/graphedit/Main.java b/graphedit/src/main/java/dk/gtz/graphedit/Main.java index fd80aae5..32a686d6 100644 --- a/graphedit/src/main/java/dk/gtz/graphedit/Main.java +++ b/graphedit/src/main/java/dk/gtz/graphedit/Main.java @@ -10,9 +10,11 @@ import dk.gtz.graphedit.serialization.IModelSerializer; import dk.gtz.graphedit.serialization.JacksonModelSerializer; import dk.gtz.graphedit.spi.IPluginsContainer; +import dk.gtz.graphedit.util.EditorActions; import dk.gtz.graphedit.view.GraphEditApplication; import dk.gtz.graphedit.viewmodel.LanguageServerCollection; import dk.gtz.graphedit.viewmodel.SyntaxFactoryCollection; +import dk.gtz.graphedit.viewmodel.ViewModelEditorSettings; import dk.yalibs.yadi.DI; public class Main { @@ -32,29 +34,34 @@ public static void main(String[] argv) throws Exception { return; } - DI.add(IModelSerializer.class, new JacksonModelSerializer()); - var loader = new PluginLoader(args.pluginDirs, DI.get(IModelSerializer.class)).loadPlugins(); var factories = new SyntaxFactoryCollection(); var servers = new LanguageServerCollection(); DI.add(SyntaxFactoryCollection.class, factories); DI.add(LanguageServerCollection.class, servers); + DI.add(IModelSerializer.class, new JacksonModelSerializer()); + var editorSettings = EditorActions.loadEditorSettings(); + DI.add(ViewModelEditorSettings.class, editorSettings); + + var loader = new PluginLoader(args.pluginDirs, DI.get(IModelSerializer.class)).loadPlugins(); DI.add(IPluginsContainer.class, loader.getLoadedPlugins()); - for(var plugin : loader.getLoadedPlugins().getPlugins()) + for(var plugin : loader.getLoadedPlugins().getEnabledPlugins()) { plugin.onInitialize(); - for(var plugin : loader.getLoadedPlugins().getPlugins()) { + } + for(var plugin : loader.getLoadedPlugins().getEnabledPlugins()) { try { factories.add(plugin.getSyntaxFactories()); } catch (Exception e) { logger.error("could not load syntax factories for plugin: {}", plugin.getName(), e); } } - for(var plugin : loader.getLoadedPlugins().getPlugins()) { + for(var plugin : loader.getLoadedPlugins().getEnabledPlugins()) { try { servers.add(plugin.getLanguageServers()); } catch (Exception e) { logger.error("could not load language servers for plugin: {}", plugin.getName(), e); } } + if(servers.isEmpty()) logger.warn("No language servers loaded. Expect a very simple experience"); if(factories.isEmpty()) diff --git a/graphedit/src/main/java/dk/gtz/graphedit/plugins/ObservableSetPluginsContainer.java b/graphedit/src/main/java/dk/gtz/graphedit/plugins/ObservableSetPluginsContainer.java index 93d601ad..cf37981f 100644 --- a/graphedit/src/main/java/dk/gtz/graphedit/plugins/ObservableSetPluginsContainer.java +++ b/graphedit/src/main/java/dk/gtz/graphedit/plugins/ObservableSetPluginsContainer.java @@ -2,17 +2,20 @@ import java.util.List; import java.util.Optional; - import dk.gtz.graphedit.spi.IPlugin; import dk.gtz.graphedit.spi.IPluginsContainer; +import dk.gtz.graphedit.viewmodel.ViewModelEditorSettings; +import dk.yalibs.yadi.DI; import javafx.collections.ObservableSet; import javafx.collections.FXCollections; public class ObservableSetPluginsContainer implements IPluginsContainer { private final ObservableSet plugins; + private final ViewModelEditorSettings settings; public ObservableSetPluginsContainer() { plugins = FXCollections.observableSet(); + settings = DI.get(ViewModelEditorSettings.class); } @Override @@ -53,5 +56,9 @@ public Optional get(String name) { public ObservableSet getPlugins() { return plugins; } -} + @Override + public List getEnabledPlugins() { + return plugins.stream().filter(p -> !settings.disabledPlugins().contains(p.getName())).toList(); + } +} diff --git a/graphedit/src/main/java/dk/gtz/graphedit/view/GraphEditApplication.java b/graphedit/src/main/java/dk/gtz/graphedit/view/GraphEditApplication.java index c27143ba..a3d344d9 100644 --- a/graphedit/src/main/java/dk/gtz/graphedit/view/GraphEditApplication.java +++ b/graphedit/src/main/java/dk/gtz/graphedit/view/GraphEditApplication.java @@ -34,7 +34,6 @@ import dk.gtz.graphedit.tool.VertexDeleteTool; import dk.gtz.graphedit.tool.VertexDragMoveTool; import dk.gtz.graphedit.tool.ViewTool; -import dk.gtz.graphedit.util.EditorActions; import dk.gtz.graphedit.util.IObservableUndoSystem; import dk.gtz.graphedit.util.MouseTracker; import dk.gtz.graphedit.util.ObservableStackUndoSystem; @@ -119,7 +118,6 @@ private void setupApplication() { DI.add(LintContainer.class, new LintContainer()); ObservableList selectedElementsList = FXCollections.observableArrayList(); DI.add("selectedElements", selectedElementsList); - DI.add(ViewModelEditorSettings.class, EditorActions.loadEditorSettings()); } private void setupLSPs(LanguageServerCollection servers, File projectFile, IBufferContainer buffers, LintContainer lints) { @@ -172,7 +170,7 @@ private void loadProject() throws Exception { var settings = DI.get(ViewModelEditorSettings.class); var projectFilePath = Path.of(settings.lastOpenedProject().get()); if(!projectFilePath.toFile().exists()) - throw new Exception("not a valid project file path, will load temp project " + projectFilePath.toString()); + throw new Exception("project file path does not exist '" + projectFilePath.toString() + "', loading tmp project instead"); var project = DI.get(IModelSerializer.class).deserializeProject(projectFilePath.toFile()); DI.add(ViewModelProject.class, new ViewModelProject(project, Optional.of(projectFilePath.toFile().getParent()))); setupLSPs(DI.get(LanguageServerCollection.class), projectFilePath.toFile(), DI.get(IBufferContainer.class), DI.get(LintContainer.class)); @@ -235,6 +233,8 @@ private void setupLogging() { @Override public void stop() { logger.trace("shutting down..."); + if(lspThreads == null) + return; for(var lspThread : lspThreads) { logger.trace("interrupting lsp thread {}", lspThread.getName()); lspThread.interrupt(); diff --git a/std/src/main/java/dk/gtz/graphedit/plugins/LintPanel.java b/std/src/main/java/dk/gtz/graphedit/plugins/LintPanel.java index cff54934..b428aabd 100644 --- a/std/src/main/java/dk/gtz/graphedit/plugins/LintPanel.java +++ b/std/src/main/java/dk/gtz/graphedit/plugins/LintPanel.java @@ -8,19 +8,18 @@ import javafx.scene.Node; public class LintPanel implements IPluginPanel { - @Override public String getTooltip() { - return "Lints"; + return "Lints"; } @Override public Node getIcon() { - return new FontIcon(BootstrapIcons.STARS); + return new FontIcon(BootstrapIcons.STARS); } @Override public Node getPanel() { - return new LintPanelController(); + return new LintPanelController(); } } diff --git a/std/src/main/java/dk/gtz/graphedit/plugins/PluginManagementPanel.java b/std/src/main/java/dk/gtz/graphedit/plugins/PluginManagementPanel.java new file mode 100644 index 00000000..c9e10bf5 --- /dev/null +++ b/std/src/main/java/dk/gtz/graphedit/plugins/PluginManagementPanel.java @@ -0,0 +1,25 @@ +package dk.gtz.graphedit.plugins; + +import org.kordamp.ikonli.bootstrapicons.BootstrapIcons; +import org.kordamp.ikonli.javafx.FontIcon; + +import dk.gtz.graphedit.plugins.view.PluginManagementPanelController; +import dk.gtz.graphedit.spi.IPluginPanel; +import javafx.scene.Node; + +public class PluginManagementPanel implements IPluginPanel { + @Override + public String getTooltip() { + return "Plugins"; + } + + @Override + public Node getIcon() { + return new FontIcon(BootstrapIcons.PLUG); + } + + @Override + public Node getPanel() { + return new PluginManagementPanelController(); + } +} diff --git a/std/src/main/java/dk/gtz/graphedit/plugins/StandardPlugin.java b/std/src/main/java/dk/gtz/graphedit/plugins/StandardPlugin.java index c22a11cc..4fdf9830 100644 --- a/std/src/main/java/dk/gtz/graphedit/plugins/StandardPlugin.java +++ b/std/src/main/java/dk/gtz/graphedit/plugins/StandardPlugin.java @@ -18,6 +18,27 @@ public String getName() { return "Standard"; } + @Override + public String getDescription() { + return """ + Standard plugin. Provides all the basics. Be careful disabling this. + + Syntaxes provided: + - LTS + - Petrinet + - Simple + + Language Servers provided: + - lts-ls (Example language server for LTS syntax) + + Panels provided: + - Files panel + - Syntax Element Property Editor panel + - Lint Inspector panel + - Plugin panel + """; + } + @Override public List getSyntaxFactories() throws Exception { return List.of( @@ -31,7 +52,8 @@ public List getPanels() throws Exception { return List.of( new ProjectFilesViewPanel(), new InspectorPanel(), - new LintPanel()); + new LintPanel(), + new PluginManagementPanel()); } @Override diff --git a/std/src/main/java/dk/gtz/graphedit/plugins/view/PluginManagementPanelController.java b/std/src/main/java/dk/gtz/graphedit/plugins/view/PluginManagementPanelController.java new file mode 100644 index 00000000..67692eb3 --- /dev/null +++ b/std/src/main/java/dk/gtz/graphedit/plugins/view/PluginManagementPanelController.java @@ -0,0 +1,84 @@ +package dk.gtz.graphedit.plugins.view; + +import org.kordamp.ikonli.bootstrapicons.BootstrapIcons; +import org.kordamp.ikonli.javafx.FontIcon; + +import atlantafx.base.controls.Tile; +import atlantafx.base.controls.ToggleSwitch; +import atlantafx.base.theme.Styles; +import dk.gtz.graphedit.spi.IPlugin; +import dk.gtz.graphedit.spi.IPluginsContainer; +import dk.gtz.graphedit.util.EditorActions; +import dk.gtz.graphedit.view.IRestartableApplication; +import dk.gtz.graphedit.viewmodel.ViewModelEditorSettings; +import dk.yalibs.yadi.DI; +import javafx.geometry.Insets; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.ToolBar; +import javafx.scene.control.Tooltip; +import javafx.scene.layout.VBox; +import javafx.stage.PopupWindow.AnchorLocation; + +public class PluginManagementPanelController extends VBox { + private final VBox container; + private final ScrollPane scrollPane; + private final ViewModelEditorSettings settings; + private final IPluginsContainer plugins; + + public PluginManagementPanelController() { + settings = DI.get(ViewModelEditorSettings.class); + plugins = DI.get(IPluginsContainer.class); + container = new VBox(); + container.setSpacing(10); + container.setPadding(new Insets(10)); + scrollPane = new ScrollPane(container); + scrollPane.setFitToWidth(true); + getChildren().add(getToolbar()); + getChildren().add(scrollPane); + initializePluginsList(); + } + + private Node getToolbar() { + var saveButton = new Button(null, new FontIcon(BootstrapIcons.HDD)); + saveButton.getStyleClass().addAll(Styles.BUTTON_ICON); + var saveTip = new Tooltip("Save Settings"); + saveTip.setAnchorLocation(AnchorLocation.WINDOW_TOP_LEFT); + saveTip.setPrefWidth(200); + saveTip.setWrapText(true); + saveButton.setTooltip(saveTip); + saveButton.setOnAction(e -> EditorActions.saveEditorSettings(settings)); + + var reloadButton = new Button(null, new FontIcon(BootstrapIcons.POWER)); + reloadButton.getStyleClass().addAll(Styles.BUTTON_ICON); + var reloadTip = new Tooltip("Reload Editor"); + reloadTip.setAnchorLocation(AnchorLocation.WINDOW_TOP_LEFT); + reloadTip.setPrefWidth(200); + reloadTip.setWrapText(true); + reloadButton.setTooltip(reloadTip); + reloadButton.setOnAction(e -> DI.get(IRestartableApplication.class).restart()); + return new ToolBar(saveButton, reloadButton); + } + + private void initializePluginsList() { + for(var plugin : plugins.getPlugins()) + container.getChildren().add(getPluginEntry(plugin)); + } + + private Node getPluginEntry(IPlugin plugin) { + var result = new Tile(plugin.getName(), ""); + var enabledThingy = new ToggleSwitch(); + enabledThingy.setSelected(!settings.disabledPlugins().contains(plugin.getName())); + enabledThingy.selectedProperty().addListener((e,o,n) -> { + if(n) + settings.disabledPlugins().remove(plugin.getName()); + else + settings.disabledPlugins().add(plugin.getName()); + }); + result.setAction(enabledThingy); + result.setActionHandler(enabledThingy::fire); + result.setTooltip(new Tooltip(plugin.getDescription())); + return result; + } +} diff --git a/std/src/main/java/dk/gtz/graphedit/plugins/view/ProjectFilesViewController.java b/std/src/main/java/dk/gtz/graphedit/plugins/view/ProjectFilesViewController.java index 75621c34..887a449c 100644 --- a/std/src/main/java/dk/gtz/graphedit/plugins/view/ProjectFilesViewController.java +++ b/std/src/main/java/dk/gtz/graphedit/plugins/view/ProjectFilesViewController.java @@ -18,10 +18,8 @@ import atlantafx.base.theme.Tweaks; import dk.gtz.graphedit.logging.Toast; import dk.gtz.graphedit.serialization.IMimeTypeChecker; -import dk.gtz.graphedit.serialization.IModelSerializer; import dk.gtz.graphedit.util.EditorActions; import dk.gtz.graphedit.util.PlatformUtils; -import dk.gtz.graphedit.viewmodel.IBufferContainer; import dk.gtz.graphedit.viewmodel.ViewModelProject; import dk.yalibs.yadi.DI; import javafx.application.Platform; @@ -51,8 +49,6 @@ public String toString() { private static Logger logger = LoggerFactory.getLogger(ProjectFilesViewController.class); private ViewModelProject openProject; - private IModelSerializer serializer; - private IBufferContainer openBuffers; private TreeView fileTree; private WatchService watchService; private SimpleBooleanProperty useGitignoreMatcher; @@ -69,8 +65,6 @@ public ProjectFilesViewController() { private void initialize() { isGitInstalled = PlatformUtils.isProgramInstalled("git"); openProject = DI.get(ViewModelProject.class); - serializer = DI.get(IModelSerializer.class); - openBuffers = DI.get(IBufferContainer.class); useGitignoreMatcher = new SimpleBooleanProperty(true); useGrapheditIgnoreMatcher = new SimpleBooleanProperty(true); showHiddenFiles = new SimpleBooleanProperty(false);