This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git
The following commit(s) were added to refs/heads/master by this push:
new 4848fadf6 CAY-2948 Modeler: use native FileDialog on Mac
4848fadf6 is described below
commit 4848fadf62efc9ad35d5e356f7d2f368c863c059
Author: Andrus Adamchik <[email protected]>
AuthorDate: Sat May 23 12:41:07 2026 -0400
CAY-2948 Modeler: use native FileDialog on Mac
---
RELEASE-NOTES.txt | 1 +
.../org/apache/cayenne/modeler/Application.java | 7 ++
.../cayenne/modeler/platform/UIInitializer.java | 10 ++
.../platform/mac/MacFileChooserFactory.java | 121 +++++++++++++++++++++
.../modeler/platform/mac/MacUIInitializer.java | 7 +-
.../modeler/pref/adapters/FileChooserPrefs.java | 42 +++++--
.../filechooser/FileChooserFactory.java} | 29 +++--
.../toolkit/filechooser/JFileChooserFactory.java | 82 ++++++++++++++
.../modeler/ui/action/ImportDataMapAction.java | 20 +---
.../modeler/ui/action/ImportEOModelAction.java | 102 ++++-------------
.../cayenne/modeler/ui/action/ProjectOpener.java | 89 ++++-----------
.../modeler/ui/dbgen/DBGeneratorOptionsDialog.java | 16 +--
.../modeler/ui/dbmerge/MergerOptionsDialog.java | 22 +---
.../preferences/classpath/ClasspathPrefsPanel.java | 36 +++---
.../editor/datamap/cgen/CgenConfigPanel.java | 19 +---
15 files changed, 352 insertions(+), 251 deletions(-)
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index d1ae3bafb..03c7bba2c 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -45,6 +45,7 @@ CAY-2943 CayenneModeler MCP: open_project tool
CAY-2945 CayenneModeler universal "main"
CAY-2946 Claude Code "plugin" for agentic coding with Cayenne
CAY-2947 Merge "cayenne-commitlog" into the core
+CAY-2948 Modeler: use native FileDialog on Mac
Bug Fixes:
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Application.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Application.java
index a2ece0876..de844a0c0 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Application.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Application.java
@@ -31,6 +31,7 @@ import org.apache.cayenne.di.Injector;
import org.apache.cayenne.modeler.dbconnector.DBConnectors;
import org.apache.cayenne.modeler.log.ModelerLogFactory;
import org.apache.cayenne.modeler.platform.UIInitializer;
+import org.apache.cayenne.modeler.toolkit.filechooser.FileChooserFactory;
import org.apache.cayenne.modeler.pref.adapters.ClasspathPrefs;
import org.apache.cayenne.modeler.pref.adapters.DBConnectorPrefs;
import org.apache.cayenne.modeler.pref.adapters.GeneralPrefs;
@@ -88,6 +89,7 @@ public class Application {
private final Injector injector;
private final UIInitializer platformInit;
+ private final FileChooserFactory fileChooserFactory;
private final ModelerClassLoader classLoader;
private final PrefsLocator prefsLocator;
private final PrefsManager prefsManager;
@@ -102,6 +104,7 @@ public class Application {
public Application(Injector injector, UIInitializer platformInit, CliArgs
cli) {
this.injector = injector;
this.platformInit = platformInit;
+ this.fileChooserFactory = platformInit.fileChooserFactory();
this.cli = cli;
this.classLoader = new ModelerClassLoader();
@@ -143,6 +146,10 @@ public class Application {
return platformInit;
}
+ public FileChooserFactory getFileChooserFactory() {
+ return fileChooserFactory;
+ }
+
public ConfigurationNodeParentGetter getConfigurationNodeParentGetter() {
return injector.getInstance(ConfigurationNodeParentGetter.class);
}
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/UIInitializer.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/UIInitializer.java
index a544193e9..cc299d637 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/UIInitializer.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/UIInitializer.java
@@ -19,6 +19,8 @@
package org.apache.cayenne.modeler.platform;
import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.modeler.toolkit.filechooser.FileChooserFactory;
+import org.apache.cayenne.modeler.toolkit.filechooser.JFileChooserFactory;
/**
* A base callback for platform-specific Modeler initialization.
@@ -38,4 +40,12 @@ public interface UIInitializer {
*/
default void afterFrameCreated(Application app) {
}
+
+ /**
+ * Returns the platform-appropriate {@link FileChooserFactory}. Defaults
to Swing's
+ * {@code JFileChooser}; overridden on macOS to use the native {@code
FileDialog}.
+ */
+ default FileChooserFactory fileChooserFactory() {
+ return new JFileChooserFactory();
+ }
}
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/mac/MacFileChooserFactory.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/mac/MacFileChooserFactory.java
new file mode 100644
index 000000000..5b636b82b
--- /dev/null
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/mac/MacFileChooserFactory.java
@@ -0,0 +1,121 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * https://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.apache.cayenne.modeler.platform.mac;
+
+import org.apache.cayenne.modeler.toolkit.filechooser.FileChooserFactory;
+
+import javax.swing.SwingUtilities;
+import javax.swing.filechooser.FileFilter;
+import java.awt.Component;
+import java.awt.FileDialog;
+import java.awt.Frame;
+import java.awt.Window;
+import java.io.File;
+import java.io.FilenameFilter;
+
+/**
+ * {@link FileChooserFactory} implementation backed by the native OS {@link
FileDialog}.
+ * On macOS this delegates to NSOpenPanel / NSSavePanel, providing Quick Look
preview,
+ * Spotlight search, and the standard Finder sidebar.
+ *
+ * <p>Directory picking requires {@code
apple.awt.fileDialogForDirectories=true} to be set
+ * as a global JVM property before Swing starts (set by {@code
MacUIInitializer}).
+ */
+public class MacFileChooserFactory extends FileChooserFactory {
+
+ private static final String DIRS_DIALOG_PROPERTY =
"apple.awt.fileDialogForDirectories";
+
+ @Override
+ public File openFile(Component parent, String title, File initialDir,
FileFilter filter) {
+ Frame frame = toFrame(parent);
+ String titleStr = title != null ? title : "";
+ FilenameFilter fnFilter = filter != null
+ ? (dir, name) -> filter.accept(new File(dir, name))
+ : null;
+
+ File startDir = initialDir;
+ while (true) {
+ FileDialog fd = new FileDialog(frame, titleStr, FileDialog.LOAD);
+ if (startDir != null) {
+ fd.setDirectory(startDir.getAbsolutePath());
+ }
+ if (fnFilter != null) {
+ fd.setFilenameFilter(fnFilter);
+ }
+ fd.setVisible(true);
+
+ String file = fd.getFile();
+ if (file == null) {
+ return null; // canceled
+ }
+ File selected = new File(fd.getDirectory(), file);
+ if (selected.isFile()) {
+ return selected;
+ }
+ // User selected a directory (possible when
apple.awt.fileDialogForDirectories=true);
+ // re-show starting inside it so they can navigate to a file.
+ startDir = selected;
+ }
+ }
+
+ @Override
+ public File saveFile(Component parent, String title, File initialDir,
String defaultName) {
+ FileDialog fd = new FileDialog(toFrame(parent), title != null ? title
: "", FileDialog.SAVE);
+ if (initialDir != null) {
+ fd.setDirectory(initialDir.getAbsolutePath());
+ }
+ if (defaultName != null) {
+ fd.setFile(defaultName);
+ }
+ fd.setVisible(true);
+ String file = fd.getFile();
+ return file != null ? new File(fd.getDirectory(), file) : null;
+ }
+
+ @Override
+ public File openDirectory(Component parent, String title, File initialDir)
{
+ // Toggle the property only for the duration of this modal dialog.
+ // FileDialog is EDT-blocking, so no other dialog can run concurrently.
+ System.setProperty(DIRS_DIALOG_PROPERTY, "true");
+ try {
+ FileDialog fd = new FileDialog(toFrame(parent), title != null ?
title : "", FileDialog.LOAD);
+ if (initialDir != null) {
+ fd.setDirectory(initialDir.getAbsolutePath());
+ }
+ fd.setVisible(true);
+ String file = fd.getFile();
+ // getFile() returns the selected directory name; getDirectory()
is its parent.
+ return file != null ? new File(fd.getDirectory(), file) : null;
+ } finally {
+ System.clearProperty(DIRS_DIALOG_PROPERTY);
+ }
+ }
+
+ private static Frame toFrame(Component c) {
+ Window w = SwingUtilities.getWindowAncestor(c);
+ while (w != null) {
+ if (w instanceof Frame f) {
+ return f;
+ }
+ w = w.getOwner();
+ }
+ return null;
+ }
+}
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/mac/MacUIInitializer.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/mac/MacUIInitializer.java
index 09f272939..b48796f10 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/mac/MacUIInitializer.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/mac/MacUIInitializer.java
@@ -21,6 +21,7 @@ package org.apache.cayenne.modeler.platform.mac;
import org.apache.cayenne.modeler.Application;
import org.apache.cayenne.modeler.service.action.GlobalActions;
import org.apache.cayenne.modeler.platform.UIInitializer;
+import org.apache.cayenne.modeler.toolkit.filechooser.FileChooserFactory;
import org.apache.cayenne.modeler.ui.action.AboutAction;
import org.apache.cayenne.modeler.ui.action.ConfigurePreferencesAction;
import org.apache.cayenne.modeler.ui.action.ExitAction;
@@ -40,7 +41,6 @@ public class MacUIInitializer implements UIInitializer {
System.setProperty("apple.awt.application.name", "CayenneModeler");
// override some default styles and colors, assuming that Aqua theme
will be used
-
Color lightGrey = new Color(0xEEEEEE);
Color darkGrey = new Color(225, 225, 225);
Border darkBorder = BorderFactory.createLineBorder(darkGrey);
@@ -91,6 +91,11 @@ public class MacUIInitializer implements UIInitializer {
UIManager.put("MenuItem.selectionForeground", Color.BLACK);
}
+ @Override
+ public FileChooserFactory fileChooserFactory() {
+ return new MacFileChooserFactory();
+ }
+
@Override
public void afterFrameCreated(Application app) {
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/FileChooserPrefs.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/FileChooserPrefs.java
index 119ea52d4..1a339f489 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/FileChooserPrefs.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/FileChooserPrefs.java
@@ -22,6 +22,9 @@ package org.apache.cayenne.modeler.pref.adapters;
import org.apache.cayenne.modeler.pref.PreferenceAdapter;
import javax.swing.JFileChooser;
+import java.awt.FileDialog;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
import java.io.File;
import java.util.prefs.Preferences;
@@ -34,24 +37,47 @@ public final class FileChooserPrefs extends
PreferenceAdapter {
}
public void bind(JFileChooser chooser) {
- File startDir = resolveExistingDirectory(prefs.get(PATH_PROPERTY,
null));
+ File startDir = loadDir();
if (startDir != null) {
chooser.setCurrentDirectory(startDir);
}
-
chooser.addActionListener(e -> {
if (JFileChooser.APPROVE_SELECTION.equals(e.getActionCommand())) {
- File selected = chooser.getSelectedFile();
- if (selected != null) {
- prefs.put(PATH_PROPERTY,
- selected.isFile()
- ?
selected.getParentFile().getAbsolutePath()
- : selected.getAbsolutePath());
+ saveDir(chooser.getSelectedFile());
+ }
+ });
+ }
+
+ public void bind(FileDialog dialog) {
+ File startDir = loadDir();
+ if (startDir != null) {
+ dialog.setDirectory(startDir.getAbsolutePath());
+ }
+ dialog.addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentHidden(ComponentEvent e) {
+ String file = dialog.getFile();
+ String dir = dialog.getDirectory();
+ if (file != null && dir != null) {
+ prefs.put(PATH_PROPERTY, dir);
}
}
});
}
+ public File loadDir() {
+ return resolveExistingDirectory(prefs.get(PATH_PROPERTY, null));
+ }
+
+ public void saveDir(File f) {
+ if (f != null) {
+ prefs.put(PATH_PROPERTY,
+ f.isFile()
+ ? f.getParentFile().getAbsolutePath()
+ : f.getAbsolutePath());
+ }
+ }
+
private static File resolveExistingDirectory(String path) {
if (path == null) {
return null;
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/UIInitializer.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/filechooser/FileChooserFactory.java
similarity index 51%
copy from
modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/UIInitializer.java
copy to
modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/filechooser/FileChooserFactory.java
index a544193e9..0362c73cb 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/platform/UIInitializer.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/filechooser/FileChooserFactory.java
@@ -16,26 +16,31 @@
* specific language governing permissions and limitations
* under the License.
****************************************************************/
-package org.apache.cayenne.modeler.platform;
-import org.apache.cayenne.modeler.Application;
+package org.apache.cayenne.modeler.toolkit.filechooser;
+
+import javax.swing.filechooser.FileFilter;
+import java.awt.Component;
+import java.io.File;
/**
- * A base callback for platform-specific Modeler initialization.
+ * Platform-specific factory for file and directory chooser dialogs.
+ * Implementations may use either a native OS dialog or Swing's JFileChooser.
*/
-public interface UIInitializer {
+public abstract class FileChooserFactory {
+
+ /**
+ * Shows a file-open dialog and returns the selected file, or {@code null}
if canceled.
+ */
+ public abstract File openFile(Component parent, String title, File
initialDir, FileFilter filter);
/**
- * Sets platform-specific system properties and initializes the
application look and feel.
- * Called before AWT/Swing is touched, so implementations may set
properties that AWT reads
- * only during its own init (e.g. {@code apple.awt.application.name})
before installing the L&F.
+ * Shows a file-save dialog and returns the selected file, or {@code null}
if canceled.
*/
- default void beforeSwingLaunch() {
- }
+ public abstract File saveFile(Component parent, String title, File
initialDir, String defaultName);
/**
- * Updates default frame menus according to the platform specifics.
+ * Shows a directory-selection dialog and returns the selected directory,
or {@code null} if canceled.
*/
- default void afterFrameCreated(Application app) {
- }
+ public abstract File openDirectory(Component parent, String title, File
initialDir);
}
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/filechooser/JFileChooserFactory.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/filechooser/JFileChooserFactory.java
new file mode 100644
index 000000000..9d8e89efb
--- /dev/null
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/filechooser/JFileChooserFactory.java
@@ -0,0 +1,82 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * https://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.apache.cayenne.modeler.toolkit.filechooser;
+
+import javax.swing.JFileChooser;
+import javax.swing.filechooser.FileFilter;
+import java.awt.Component;
+import java.io.File;
+
+/**
+ * {@link FileChooserFactory} implementation backed by Swing's {@link
JFileChooser}.
+ */
+public class JFileChooserFactory extends FileChooserFactory {
+
+ @Override
+ public File openFile(Component parent, String title, File initialDir,
FileFilter filter) {
+ JFileChooser chooser = new JFileChooser();
+ chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+ if (title != null) {
+ chooser.setDialogTitle(title);
+ }
+ if (initialDir != null) {
+ chooser.setCurrentDirectory(initialDir);
+ }
+ if (filter != null) {
+ chooser.addChoosableFileFilter(filter);
+ chooser.setFileFilter(filter);
+ }
+ return chooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION
+ ? chooser.getSelectedFile()
+ : null;
+ }
+
+ @Override
+ public File saveFile(Component parent, String title, File initialDir,
String defaultName) {
+ JFileChooser chooser = new JFileChooser();
+ if (title != null) {
+ chooser.setDialogTitle(title);
+ }
+ if (initialDir != null) {
+ chooser.setCurrentDirectory(initialDir);
+ }
+ if (defaultName != null) {
+ chooser.setSelectedFile(new File(defaultName));
+ }
+ return chooser.showSaveDialog(parent) == JFileChooser.APPROVE_OPTION
+ ? chooser.getSelectedFile()
+ : null;
+ }
+
+ @Override
+ public File openDirectory(Component parent, String title, File initialDir)
{
+ JFileChooser chooser = new JFileChooser();
+ chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ if (title != null) {
+ chooser.setDialogTitle(title);
+ }
+ if (initialDir != null) {
+ chooser.setCurrentDirectory(initialDir);
+ }
+ return chooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION
+ ? chooser.getSelectedFile()
+ : null;
+ }
+}
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/ImportDataMapAction.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/ImportDataMapAction.java
index 0a0408659..9246c236d 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/ImportDataMapAction.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/ImportDataMapAction.java
@@ -35,7 +35,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
-import java.awt.*;
+import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.io.File;
import java.net.URL;
@@ -98,19 +98,9 @@ public class ImportDataMapAction extends AppAction {
}
protected File selectDataMap(Frame f) {
-
- JFileChooser chooser = new JFileChooser();
- chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
-
- new
FileChooserPrefs(app.getPrefsManager().uiNode("importDataMap/lastDir")).bind(chooser);
-
- chooser.addChoosableFileFilter(FileFilters.getDataMapFilter());
-
- int status = chooser.showDialog(f, "Select DataMap");
- if (status == JFileChooser.APPROVE_OPTION) {
- return chooser.getSelectedFile();
- }
-
- return null;
+ FileChooserPrefs prefs = new
FileChooserPrefs(app.getPrefsManager().uiNode("importDataMap/lastDir"));
+ File selected = app.getFileChooserFactory().openFile(f, "Select
DataMap", prefs.loadDir(), FileFilters.getDataMapFilter());
+ prefs.saveDir(selected);
+ return selected;
}
}
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/ImportEOModelAction.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/ImportEOModelAction.java
index 916d203c2..cf0ef10ba 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/ImportEOModelAction.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/ImportEOModelAction.java
@@ -58,9 +58,7 @@ import org.apache.cayenne.wocompat.EOModelProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.swing.*;
import javax.swing.filechooser.FileFilter;
-import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.File;
import java.net.URL;
@@ -77,11 +75,11 @@ public class ImportEOModelAction extends AppAction {
private static final Logger LOGGER =
LoggerFactory.getLogger(ImportEOModelAction.class);
+ private static final FileFilter eomodelFilter = new EOModelFileFilter();
+
private final Map<String, String> adaptersByEofPlugin;
private final Map<String, String> adaptersByDriver;
- private JFileChooser eoModelChooser;
-
public ImportEOModelAction(Application application) {
super(application, "Import EOModel");
@@ -125,34 +123,27 @@ public class ImportEOModelAction extends AppAction {
* Allows user to select an EOModel, then imports it as a DataMap.
*/
protected void importEOModel() {
- JFileChooser fileChooser = getEOModelChooser();
- int status = fileChooser.showOpenDialog(app.getFrame());
-
- if (status == JFileChooser.APPROVE_OPTION) {
-
- File file = fileChooser.getSelectedFile().getParentFile();
-
- DataMap currentMap = getProjectSession().getSelectedDataMap();
-
- try {
- URL url = file.toURI().toURL();
-
- EOModelProcessor processor = new EOModelProcessor();
-
- // load DataNode if we are not merging with an existing map
- if (currentMap == null) {
- loadDataNode(processor.loadModeIndex(url));
- }
+ FileChooserPrefs prefs = new
FileChooserPrefs(app.getPrefsManager().uiNode("importEOModel/lastDir"));
+ File selected = app.getFileChooserFactory().openFile(app.getFrame(),
"Select EOModel", prefs.loadDir(), eomodelFilter);
+ if (selected == null) {
+ return;
+ }
+ prefs.saveDir(selected);
- // load DataMap
- DataMap map = processor.loadEOModel(url);
- addDataMap(map, currentMap);
+ File file = selected.getParentFile();
+ DataMap currentMap = getProjectSession().getSelectedDataMap();
- } catch (Exception ex) {
- LOGGER.info("EOModel Loading Exception", ex);
- new ErrorDialog(app, "Import EOModel Error", ex).open();
+ try {
+ URL url = file.toURI().toURL();
+ EOModelProcessor processor = new EOModelProcessor();
+ if (currentMap == null) {
+ loadDataNode(processor.loadModeIndex(url));
}
-
+ DataMap map = processor.loadEOModel(url);
+ addDataMap(map, currentMap);
+ } catch (Exception ex) {
+ LOGGER.info("EOModel Loading Exception", ex);
+ new ErrorDialog(app, "Import EOModel Error", ex).open();
}
}
@@ -306,59 +297,6 @@ public class ImportEOModelAction extends AppAction {
}
}
- /**
- * Returns EOModel chooser.
- */
- public JFileChooser getEOModelChooser() {
-
- if (eoModelChooser == null) {
- eoModelChooser = new EOModelChooser("Select EOModel");
- }
-
- new
FileChooserPrefs(app.getPrefsManager().uiNode("importEOModel/lastDir")).bind(eoModelChooser);
-
- return eoModelChooser;
- }
-
- /**
- * Custom file chooser that will pop up again if an invalid file is
selected.
- */
- static class EOModelChooser extends JFileChooser {
-
- static final FileFilter eomodelFilter = new EOModelFileFilter();
-
- private JDialog cachedDialog;
-
- public EOModelChooser(String title) {
- super.setFileFilter(eomodelFilter);
- super.setDialogTitle(title);
- super.setFileSelectionMode(JFileChooser.FILES_ONLY);
- }
-
- public int showOpenDialog(Component parent) {
- int status = super.showOpenDialog(parent);
- if (status != JFileChooser.APPROVE_OPTION) {
- cachedDialog = null;
- return status;
- }
-
- File file = this.getSelectedFile();
- if (file.isFile() && eomodelFilter.accept(file)) {
- cachedDialog = null;
- return JFileChooser.APPROVE_OPTION;
- }
-
- return this.showOpenDialog(parent);
- }
-
- protected JDialog createDialog(Component parent) throws
HeadlessException {
- if (cachedDialog == null) {
- cachedDialog = super.createDialog(parent);
- }
- return cachedDialog;
- }
- }
-
static final class EOModelFileFilter extends FileFilter {
static final String EOM_SUFFIX = ".eomodeld";
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/ProjectOpener.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/ProjectOpener.java
index 01d4fb85c..32d49032e 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/ProjectOpener.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/ProjectOpener.java
@@ -24,21 +24,20 @@ import
org.apache.cayenne.configuration.DataChannelDescriptor;
import org.apache.cayenne.modeler.Application;
import org.apache.cayenne.modeler.pref.adapters.RecentProjectsPrefs;
import org.apache.cayenne.modeler.ui.project.overwrite.OverwriteDialog;
+import org.apache.cayenne.modeler.toolkit.filechooser.FileChooserFactory;
import org.apache.cayenne.modeler.toolkit.filechooser.FileFilters;
import org.apache.cayenne.project.Project;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.swing.*;
-import javax.swing.filechooser.FileFilter;
import java.io.File;
import java.util.List;
/**
- * File chooser panel used to select a directory to store project files.
+ * Helper that shows file-chooser dialogs for opening and saving Cayenne
projects.
*/
-class ProjectOpener extends JFileChooser {
+class ProjectOpener {
private static final Logger LOGGER =
LoggerFactory.getLogger(ProjectOpener.class);
@@ -46,94 +45,52 @@ class ProjectOpener extends JFileChooser {
* Selects a directory to store the project.
*/
public File newProjectDir(Application application, Project p) {
- if (p != null) {
- StringBuilder nameProject = new StringBuilder("cayenne");
- if (((DataChannelDescriptor) p.getRootNode()).getName() != null) {
- nameProject.append("-").append(((DataChannelDescriptor)
p.getRootNode()).getName());
- }
- nameProject.append(".xml");
- // configure for application project
- return newProjectDir(nameProject.toString(),
FileFilters.getApplicationFilter(), application);
- } else {
+ if (p == null) {
throw new CayenneRuntimeException("Null project.");
}
- }
- private File newProjectDir(String location, FileFilter filter, Application
application) {
- // configure dialog
- setDialogTitle("Select Project Directory");
- setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
- setCurrentDirectory(getDefaultStartDir(application));
-
- // preselect current directory
- if (getCurrentDirectory() != null) {
- setSelectedFile(getCurrentDirectory());
+ StringBuilder nameProject = new StringBuilder("cayenne");
+ if (((DataChannelDescriptor) p.getRootNode()).getName() != null) {
+ nameProject.append("-").append(((DataChannelDescriptor)
p.getRootNode()).getName());
}
+ nameProject.append(".xml");
- // configure filters
- resetChoosableFileFilters();
- // allow users to see directories with cayenne.xml files
- addChoosableFileFilter(filter);
-
- File selectedDir;
+ FileChooserFactory factory = application.getFileChooserFactory();
+ File startDir = getDefaultStartDir(application);
while (true) {
- int status = showDialog(application.getFrame(), "Select");
- selectedDir = getSelectedFile();
- if (status != JFileChooser.APPROVE_OPTION || selectedDir == null) {
+ File selectedDir = factory.openDirectory(application.getFrame(),
"Select Project Directory", startDir);
+ if (selectedDir == null) {
LOGGER.info("Save canceled.");
return null;
}
- // normalize selection
- LOGGER.info("Selected: " + selectedDir);
- if (!selectedDir.isDirectory()) {
- selectedDir = getSelectedFile().getParentFile();
- }
-
- // check for overwrite
- File projectFile = new File(selectedDir, location);
+ LOGGER.info("Selected: {}", selectedDir);
+ File projectFile = new File(selectedDir, nameProject.toString());
if (projectFile.exists()) {
OverwriteDialog dialog = new OverwriteDialog(projectFile,
application.getFrame());
dialog.show();
-
if (dialog.shouldOverwrite()) {
- break;
+ return selectedDir;
} else if (!dialog.shouldSelectAnother()) {
- // canceled
return null;
}
+ // else loop again
} else {
- break;
+ return selectedDir;
}
}
-
- return selectedDir;
}
/**
- * Runs a dialog to open Cayenne project.
+ * Runs a dialog to open a Cayenne project.
*/
public File openProjectFile(Application application) {
-
- // configure dialog
- setDialogTitle("Select Project File");
- setFileSelectionMode(JFileChooser.FILES_ONLY);
- setCurrentDirectory(getDefaultStartDir(application));
-
- // configure filters
- resetChoosableFileFilters();
- addChoosableFileFilter(FileFilters.getApplicationFilter());
-
- // default to App projects
- setFileFilter(FileFilters.getApplicationFilter());
-
- int status = showOpenDialog(application.getFrame());
- if (status != JFileChooser.APPROVE_OPTION) {
- return null;
- }
-
- return getSelectedFile();
+ return application.getFileChooserFactory().openFile(
+ application.getFrame(),
+ "Select Project File",
+ getDefaultStartDir(application),
+ FileFilters.getApplicationFilter());
}
private File getDefaultStartDir(Application application) {
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsDialog.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsDialog.java
index 520e13b05..318676d51 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsDialog.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsDialog.java
@@ -42,7 +42,6 @@ import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
-import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
@@ -350,25 +349,16 @@ public class DBGeneratorOptionsDialog extends
ProjectDialog {
}
private void storeSQLAction() {
- JFileChooser fc = new JFileChooser();
- fc.setDialogType(JFileChooser.SAVE_DIALOG);
- fc.setDialogTitle("Save SQL Script");
-
File projectDir = new File(app
.getFrame().getProjectSession().project()
.getConfigurationResource()
.getURL()
.getPath());
- fc.setCurrentDirectory(projectDir);
- if (fc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
+ File file = app.getFileChooserFactory().saveFile(this, "Save SQL
Script", projectDir, null);
+ if (file != null) {
refreshGeneratorAction();
- try {
- File file = fc.getSelectedFile();
- FileWriter fw = new FileWriter(file);
- PrintWriter pw = new PrintWriter(fw);
+ try (FileWriter fw = new FileWriter(file); PrintWriter pw = new
PrintWriter(fw)) {
pw.print(textForSQL);
- pw.flush();
- pw.close();
} catch (IOException ex) {
reportError("Error Saving SQL", ex);
}
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbmerge/MergerOptionsDialog.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbmerge/MergerOptionsDialog.java
index 8593087ee..5bad5ae0e 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbmerge/MergerOptionsDialog.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbmerge/MergerOptionsDialog.java
@@ -61,7 +61,6 @@ import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import javax.swing.Box;
import javax.swing.JButton;
-import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
@@ -359,24 +358,13 @@ public class MergerOptionsDialog extends ProjectDialog {
}
private void storeSQLAction() {
- JFileChooser fc = new JFileChooser();
- fc.setDialogType(JFileChooser.SAVE_DIALOG);
- fc.setDialogTitle("Save SQL Script");
-
- Resource projectDir =
app.getFrame().getProjectSession().project().getConfigurationResource();
- if (projectDir != null) {
- fc.setCurrentDirectory(new File(projectDir.getURL().getPath()));
- }
-
- if (fc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
+ Resource configRes =
app.getFrame().getProjectSession().project().getConfigurationResource();
+ File initialDir = configRes != null ? new
File(configRes.getURL().getPath()) : null;
+ File file = app.getFileChooserFactory().saveFile(this, "Save SQL
Script", initialDir, null);
+ if (file != null) {
refreshSQLAction();
- try {
- File file = fc.getSelectedFile();
- FileWriter fw = new FileWriter(file);
- PrintWriter pw = new PrintWriter(fw);
+ try (FileWriter fw = new FileWriter(file); PrintWriter pw = new
PrintWriter(fw)) {
pw.print(textForSQL);
- pw.flush();
- pw.close();
} catch (IOException ex) {
reportError("Error Saving SQL", ex);
}
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/ClasspathPrefsPanel.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/ClasspathPrefsPanel.java
index 9aacfa88b..34bb4d619 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/ClasspathPrefsPanel.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/classpath/ClasspathPrefsPanel.java
@@ -33,12 +33,10 @@ import
org.apache.cayenne.modeler.toolkit.filechooser.FileFilters;
import javax.swing.BorderFactory;
import javax.swing.JButton;
-import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
-import javax.swing.filechooser.FileFilter;
import javax.swing.table.AbstractTableModel;
import java.awt.BorderLayout;
import java.io.File;
@@ -99,10 +97,8 @@ public class ClasspathPrefsPanel extends AppPanel {
JButton addMvnButton = new JButton("Get From Maven Central");
JButton deleteEntryButton = new JButton("Delete");
- addJarButton.addActionListener(e ->
- chooseClassEntry(FileFilters.getExtensionFileFilter("jar",
"JAR Files"), "Select JAR File.", JFileChooser.FILES_ONLY));
- addDirButton.addActionListener(e ->
- chooseClassEntry(null, "Select Java Class Directory.",
JFileChooser.DIRECTORIES_ONLY));
+ addJarButton.addActionListener(e -> chooseJarEntry());
+ addDirButton.addActionListener(e -> chooseDirEntry());
addMvnButton.addActionListener(e ->
new MavenDependencyDialog(app,
SwingUtilities.getWindowAncestor(this), this).open());
deleteEntryButton.addActionListener(e -> removeEntryClicked());
@@ -133,24 +129,18 @@ public class ClasspathPrefsPanel extends AppPanel {
add(outer.getPanel(), BorderLayout.CENTER);
}
- private void chooseClassEntry(FileFilter filter, String title, int
selectionMode) {
- JFileChooser chooser = new JFileChooser();
- chooser.setFileSelectionMode(selectionMode);
- chooser.setDialogType(JFileChooser.OPEN_DIALOG);
- chooser.setAcceptAllFileFilterUsed(true);
-
- new
FileChooserPrefs(app.getPrefsManager().uiNode("classpath/lastDir")).bind(chooser);
- if (filter != null) {
- chooser.addChoosableFileFilter(filter);
- chooser.setFileFilter(filter);
- }
- chooser.setDialogTitle(title);
-
- File selected = null;
- if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
- selected = chooser.getSelectedFile();
- }
+ private void chooseJarEntry() {
+ FileChooserPrefs prefs = new
FileChooserPrefs(app.getPrefsManager().uiNode("classpath/lastDir"));
+ File selected = app.getFileChooserFactory().openFile(
+ this, "Select JAR File.", prefs.loadDir(),
FileFilters.getExtensionFileFilter("jar", "JAR Files"));
+ prefs.saveDir(selected);
+ entryAdded(selected);
+ }
+ private void chooseDirEntry() {
+ FileChooserPrefs prefs = new
FileChooserPrefs(app.getPrefsManager().uiNode("classpath/lastDir"));
+ File selected = app.getFileChooserFactory().openDirectory(this,
"Select Java Class Directory.", prefs.loadDir());
+ prefs.saveDir(selected);
entryAdded(selected);
}
diff --git
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/cgen/CgenConfigPanel.java
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/cgen/CgenConfigPanel.java
index 61ba591c1..50ae2d49c 100644
---
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/cgen/CgenConfigPanel.java
+++
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/cgen/CgenConfigPanel.java
@@ -397,21 +397,12 @@ public class CgenConfigPanel extends ProjectPanel {
private void selectOutputFolderAction() {
String currentDir = outputFolder.getText();
+ File initialDir = !Util.isEmptyString(currentDir)
+ ? new File(currentDir)
+ : CgenOps.baseDir(session).toFile();
- JFileChooser chooser = new JFileChooser();
- chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- chooser.setDialogType(JFileChooser.OPEN_DIALOG);
-
- if (!Util.isEmptyString(currentDir)) {
- chooser.setCurrentDirectory(new File(currentDir));
- } else {
- chooser.setCurrentDirectory(CgenOps.baseDir(session).toFile());
- }
-
- int result = chooser.showOpenDialog(this);
- if (result == JFileChooser.APPROVE_OPTION) {
- File selected = chooser.getSelectedFile();
-
+ File selected = app.getFileChooserFactory().openDirectory(this,
"Select Output Folder", initialDir);
+ if (selected != null) {
String path = selected.getAbsolutePath();
outputFolder.setText(path);
applyOutputFolder(path);