Skip to content
Snippets Groups Projects
Commit aa3abaec authored by Hallvard Trætteberg's avatar Hallvard Trætteberg
Browse files

Fjernet generell File-meny (#4)

parent e013b049
No related branches found
No related tags found
No related merge requests found
Showing
with 96 additions and 811 deletions
package fxutil.doc;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
/**
* Incomplete implementation of **IDocumentStorage**, to simplify implementing ones for specific
* document and location types. The main missing methods are for getting and setting the current
* document, creating an empty one and creating an **InputStream** from a location.
*
* @author hal
*
* @param <D> the document type
* @param <L> the location type
*/
public abstract class AbstractDocumentStorageImpl<D, L>
implements IDocumentStorage<L>, IDocumentPersistence<D, L> {
private L documentLocation = null;
@Override
public L getDocumentLocation() {
return documentLocation;
}
@Override
public void setDocumentLocation(final L documentLocation) {
final L oldDocumentLocation = this.documentLocation;
this.documentLocation = documentLocation;
fireDocumentLocationChanged(oldDocumentLocation);
}
protected void setDocumentAndLocation(final D document, final L documentLocation) {
setDocument(document);
setDocumentLocation(documentLocation);
}
/**
* Returns the current document.
*
* @return the current document
*/
protected abstract D getDocument();
/**
* Sets the current document.
*
* @param document the new document
*/
protected abstract void setDocument(D document);
//
private final Collection<IDocumentStorageListener<L>> documentListeners =
new ArrayList<IDocumentStorageListener<L>>();
@Override
public void addDocumentStorageListener(
final IDocumentStorageListener<L> documentStorageListener) {
documentListeners.add(documentStorageListener);
}
@Override
public void removeDocumentStorageListener(
final IDocumentStorageListener<L> documentStorageListener) {
documentListeners.remove(documentStorageListener);
}
protected void fireDocumentLocationChanged(final L oldDocumentLocation) {
for (final IDocumentStorageListener<L> documentStorageListener : documentListeners) {
documentStorageListener.documentLocationChanged(documentLocation, oldDocumentLocation);
}
}
protected void fireDocumentChanged(final D oldDocument) {
for (final IDocumentStorageListener<L> documentListener : documentListeners) {
if (documentListener instanceof IDocumentListener) {
((IDocumentListener<D, L>) documentListener).documentChanged(getDocument(), oldDocument);
}
}
}
/**
* Creates a new and empty document.
*
* @return
*/
protected abstract D createDocument();
@Override
public void newDocument() {
setDocumentAndLocation(createDocument(), null);
}
/**
* Creates an InputStream from a location.
*
* @param location the location
* @return the location's InputStream
* @throws IOException when the InputStream cannot be created
*/
protected abstract InputStream toInputStream(L location) throws IOException;
protected InputStream toInputStream(final File location) throws IOException {
return new FileInputStream(location);
}
protected InputStream toInputStream(final URL location) throws IOException {
return location.openStream();
}
protected InputStream toInputStream(final URI location) throws IOException {
return toInputStream(location.toURL());
}
@Override
public void openDocument(final L storage) throws IOException {
try (InputStream input = toInputStream(storage)) {
setDocumentAndLocation(loadDocument(input), storage);
} catch (final Exception e) {
throw new IOException(e);
}
}
@Override
public void saveDocument() throws IOException {
try {
saveDocument(getDocument(), getDocumentLocation());
} catch (final Exception e) {
throw new IOException(e);
}
}
public void saveDocumentAs(final L documentLocation) throws IOException {
final L oldDocumentLocation = getDocumentLocation();
setDocumentLocation(documentLocation);
try {
saveDocument();
} catch (final IOException e) {
setDocumentLocation(oldDocumentLocation);
throw e;
}
}
public void saveCopyAs(final L documentLocation) throws Exception {
saveDocument(getDocument(), documentLocation);
}
}
package fxutil.doc;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextInputDialog;
import javafx.stage.FileChooser;
public class FileMenuController {
private IDocumentStorage<File> documentStorage;
public void setDocumentStorage(final IDocumentStorage<File> documentStorage) {
this.documentStorage = documentStorage;
if (importMenu != null) {
importMenu.setDisable(documentStorage.getDocumentImporters().isEmpty());
}
}
@FXML
public void handleNewAction() {
documentStorage.newDocument();
}
private final List<File> recentFiles = new ArrayList<File>();
@FXML
private Menu recentMenu;
protected void updateRecentMenu(final File file) {
recentFiles.remove(file);
recentFiles.add(0, file);
recentMenu.getItems().clear();
for (final File recentFile : recentFiles) {
final MenuItem menuItem = new MenuItem();
menuItem.setText(recentFile.toString());
menuItem.setOnAction(event -> handleOpenAction(event));
recentMenu.getItems().add(menuItem);
}
}
private FileChooser fileChooser;
FileChooser getFileChooser() {
if (fileChooser == null) {
fileChooser = new FileChooser();
}
return fileChooser;
}
@FXML
public void handleOpenAction(final ActionEvent event) {
File selection = null;
if (event.getSource() instanceof MenuItem) {
final File file = new File(((MenuItem) event.getSource()).getText());
if (file.exists()) {
selection = file;
}
}
if (selection == null) {
final FileChooser fileChooser = getFileChooser();
selection = fileChooser.showOpenDialog(null);
}
if (selection != null) {
handleOpenAction(selection);
}
}
void handleOpenAction(final File selection) {
try {
documentStorage.openDocument(selection);
updateRecentMenu(selection);
} catch (final IOException e) {
showExceptionDialog("Oops, problem when opening " + selection, e);
}
}
private void showExceptionDialog(final String message) {
final Alert alert = new Alert(AlertType.ERROR, message, ButtonType.CLOSE);
alert.showAndWait();
}
private void showExceptionDialog(final String message, final Exception e) {
showExceptionDialog(message + ": " + e.getLocalizedMessage());
}
private void showSaveExceptionDialog(final File location, final Exception e) {
showExceptionDialog("Oops, problem saving to " + location, e);
}
@FXML
public void handleSaveAction() {
if (documentStorage.getDocumentLocation() == null) {
handleSaveAsAction();
} else {
try {
documentStorage.saveDocument();
} catch (final IOException e) {
showSaveExceptionDialog(documentStorage.getDocumentLocation(), e);
}
}
}
@FXML
public void handleSaveAsAction() {
final FileChooser fileChooser = getFileChooser();
final File selection = fileChooser.showSaveDialog(null);
handleSaveAsAction(selection);
}
void handleSaveAsAction(final File selection) {
final File oldStorage = documentStorage.getDocumentLocation();
try {
documentStorage.setDocumentLocation(selection);
documentStorage.saveDocument();
} catch (final IOException e) {
showSaveExceptionDialog(documentStorage.getDocumentLocation(), e);
documentStorage.setDocumentLocation(oldStorage);
}
}
@FXML
public void handleSaveCopyAsAction() {
final FileChooser fileChooser = getFileChooser();
final File selection = fileChooser.showSaveDialog(null);
handleSaveCopyAsAction(selection);
}
void handleSaveCopyAsAction(final File selection) {
final File oldStorage = documentStorage.getDocumentLocation();
try {
documentStorage.setDocumentLocation(selection);
documentStorage.saveDocument();
} catch (final IOException e) {
showSaveExceptionDialog(selection, e);
} finally {
documentStorage.setDocumentLocation(oldStorage);
}
}
@FXML
private Menu importMenu;
@FXML
public void handleFileImportAction() {
final FileChooser fileChooser = getFileChooser();
final File selection = fileChooser.showOpenDialog(null);
// String path = selection.getPath();
// int pos = path.lastIndexOf('.');
// String ext = (pos > 0 ? path.substring(pos + 1) : null);
handleFileImportAction(selection);
}
void handleFileImportAction(final File selection) {
for (final IDocumentImporter importer : documentStorage.getDocumentImporters()) {
try (InputStream input = new FileInputStream(selection)) {
importer.importDocument(input);
break;
} catch (final Exception e) {
}
}
}
private TextInputDialog inputDialog;
@FXML
public void handleUrlImportAction() {
if (inputDialog == null) {
inputDialog = new TextInputDialog();
}
inputDialog.setTitle("Import from URL");
inputDialog.setHeaderText("Enter URL to import from");
inputDialog.setContentText("Enter URL: ");
// https://developer.garmin.com/downloads/connect-api/sample_file.gpx
while (true) {
final Optional<String> result = inputDialog.showAndWait();
if (!result.isPresent()) {
break;
}
try {
if (handleUrlImportAction(new URL(result.get()))) {
break;
}
inputDialog.setHeaderText("Problems reading it...");
inputDialog.setContentText("Enter another URL: ");
} catch (final MalformedURLException e1) {
inputDialog.setContentText("Enter a valid URL: ");
}
}
}
boolean handleUrlImportAction(final URL url) {
for (final IDocumentImporter importer : documentStorage.getDocumentImporters()) {
try (InputStream input = url.openStream()) {
importer.importDocument(input);
return true;
} catch (final Exception e) {
System.err.println(e.getMessage());
}
}
return false;
}
}
package fxutil.doc;
import java.io.IOException;
import java.io.InputStream;
/**
* An interface with a method for importing domain data from a location. The main use is supporting
* an **import** action in a **File** menu.
*
* @author hal
*
*/
public interface IDocumentImporter {
/**
* Loads a document from the input stream and sets it as the current document.
*
* @param inputStream the document to import
* @throws IOException when the document cannot imported
*/
public void importDocument(InputStream inputStream) throws IOException;
}
package fxutil.doc;
/**
* Listener interface for the (contents of) the (current) document of an IDocumentStorage, e.g. when
* an **open** action is performed.
*
* @author hal
*
* @param <D> the document type
* @param <L> the location type
*/
public interface IDocumentListener<D, L> extends IDocumentStorageListener<L> {
/**
* Notifies that the current document has changed.
*
* @param document the new document
* @param oldDocument the previous document
*/
public void documentChanged(D document, D oldDocument);
}
package fxutil.doc;
import java.io.InputStream;
/**
* An interface with a method for loading and returning a document (domain data container) from an
* InputStream. This allows various ways of loading or importing domain data, with different sources
* and formats.
*
* @author hal
*
* @param <D> the document type
*/
public interface IDocumentLoader<D> {
/**
* Loads and returns a new document from an InputStream
*
* @param inputStream the InputStream to load from
* @return the loaded document
* @throws Exception when the document couldn't be loaded
*/
public D loadDocument(InputStream inputStream) throws Exception;
}
package fxutil.doc;
public interface IDocumentPersistence<D, L> extends IDocumentLoader<D>, IDocumentSaver<D, L> {
}
package fxutil.doc;
/**
* An interface with a method for saving a document (domain data container) to a location. This
* allows various ways of saving or exporting domain data, to different locations and formats.
*
* @author hal
*
* @param <D> the document type
* @param <L> the location type
*/
public interface IDocumentSaver<D, L> {
/**
* Saves the provided document to the provided location
*
* @param document the document to save
* @param documentLocation the location to save to
* @throws Exception when the document couldn't be saved
*/
public void saveDocument(D document, L documentLocation) throws Exception;
}
package fxutil.doc;
import java.io.IOException;
import java.util.Collection;
/**
* An interface with the methods necessary for supporting the standard File menu actions. The class
* representing the document (domain data container) is implicit in the implementation of this
* interface. The interface includes methods for getting and setting the location and creating,
* opening and saving the (current) document.
*
* @author hal
*
* @param <L> The type of the location, typically java.io.File.
*/
public interface IDocumentStorage<L> {
/**
* Returns the current location (of the current document).
*
* @return the current location
*/
public L getDocumentLocation();
/**
* Sets the current location (of the current document), can be used by a save-as action.
*
* @param documentLocation the new document location
*/
public void setDocumentLocation(L documentLocation);
/**
* Adds an IDocumentStorageListener that will be notified when the current location changes.
*
* @param documentStorageListener the listener to add
*/
public void addDocumentStorageListener(IDocumentStorageListener<L> documentStorageListener);
/**
* Removes an IDocumentStorageListener.
*
* @param documentStorageListener the listener to remove
*/
public void removeDocumentStorageListener(IDocumentStorageListener<L> documentStorageListener);
/**
* Creates a new documents and sets it as the current one, can be used by a new action.
*/
public void newDocument();
/**
* Loads a documents from the provided location and sets it as the current one, can be used by an
* open action.
*/
public void openDocument(L documentLocation) throws IOException;
/**
* Saves the current document (to the current location), can be used by a save action.
*/
public void saveDocument() throws IOException;
/**
* Returns the set of IDocumentImporters, can be used by an import action.
*
* @return
*/
public Collection<IDocumentImporter> getDocumentImporters();
}
package fxutil.doc;
/**
* Listener interface for the (current) location of the (current) document of an IDocumentStorage,
* e.g. when a **save-as** action is performed.
*
* @author hal
*
* @param <L> the document location type
*/
public interface IDocumentStorageListener<L> {
/**
* Notifies that the current document location has changed.
*
* @param documentLocation the new document location
* @param oldDocumentLocation the previous document location
*/
public void documentLocationChanged(L documentLocation, L oldDocumentLocation);
}
package fxutil.doc;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Collections;
public abstract class SimpleJsonFileStorageImpl<T> extends AbstractDocumentStorageImpl<T, File>
implements IDocumentStorage<File> {
private T document;
private final ObjectMapper objectMapper;
private final Class<T> documentClass;
public SimpleJsonFileStorageImpl(final Class<T> documentClass) {
this.documentClass = documentClass;
final SimpleModule module = new SimpleModule();
configureJacksonModule(module);
objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
}
protected abstract void configureJacksonModule(final SimpleModule module);
@Override
public T loadDocument(final InputStream inputStream) throws Exception {
return objectMapper.readValue(inputStream, documentClass);
}
@Override
public void saveDocument(final T document, final File documentLocation) throws Exception {
try (OutputStream outputStream = new FileOutputStream(documentLocation, false)) {
objectMapper.writeValue(outputStream, document);
}
}
@Override
public Collection<IDocumentImporter> getDocumentImporters() {
return Collections.emptyList();
}
@Override
public T getDocument() {
return document;
}
@Override
public void setDocument(final T document) {
final T oldDocument = this.document;
this.document = document;
fireDocumentChanged(oldDocument);
}
@Override
protected T createDocument() {
try {
return documentClass.getDeclaredConstructor().newInstance();
} catch (final Exception e) {
throw new RuntimeException("Exception when instantiating " + documentClass, e);
}
}
}
package simpleex.ui;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import fxmapcontrol.Location;
import fxmapcontrol.MapBase;
import fxmapcontrol.MapItemsControl;
import fxmapcontrol.MapNode;
import fxmapcontrol.MapProjection;
import fxutil.doc.FileMenuController;
import fxutil.doc.IDocumentListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Optional;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ListView;
import javafx.scene.control.Slider;
import javafx.stage.FileChooser;
import simpleex.core.LatLong;
import simpleex.core.LatLongs;
import simpleex.json.LatLongDeserializer;
import simpleex.json.LatLongSerializer;
import simpleex.json.LatLongsDeserializer;
import simpleex.json.LatLongsSerializer;
public class FxAppController extends FileMenuController
implements IDocumentListener<LatLongs, File> {
public class FxAppController {
private final LatLongsStorage latLongsStorage;
private LatLongs latLongs;
public FxAppController() {
latLongsStorage = new LatLongsStorage();
latLongsStorage.addDocumentStorageListener(this);
latLongs = new LatLongs();
}
public LatLongs getLatLongs() {
return latLongsStorage.getDocument();
return latLongs;
}
// to make it testable
public void setLatLongs(final LatLongs latLongs) {
latLongsStorage.setDocument(latLongs);
this.latLongs = latLongs;
updateLocationViewList(0);
}
......@@ -57,12 +69,10 @@ public class FxAppController extends FileMenuController
@FXML
private void initialize() {
// fileMenuController.
setDocumentStorage(latLongsStorage);
// map stuff
// mapView.getChildren().add(MapTileLayer.getOpenStreetMapLayer());
zoomSlider.valueProperty()
.addListener((prop, oldValue, newValue) -> mapView.setZoomLevel(zoomSlider.getValue()));
.addListener((prop, oldValue, newValue) -> mapView.setZoomLevel(zoomSlider.getValue()));
zoomSlider.setValue(8);
markersParent = new MapItemsControl<MapNode>();
mapView.getChildren().add(markersParent);
......@@ -72,7 +82,7 @@ public class FxAppController extends FileMenuController
draggableMarkerController = new DraggableNodeController(Optional.of(this::handleMarkerDragged));
// the location list
locationListView.getSelectionModel().selectedIndexProperty()
.addListener((prop, oldValue, newValue) -> updateMapMarker(true));
.addListener((prop, oldValue, newValue) -> updateMapMarker(true));
}
private void handleMapDragged(final Node node, final double dx, final double dy) {
......@@ -155,14 +165,68 @@ public class FxAppController extends FileMenuController
}
}
// IDocumentListener
// File menu items
@Override
public void documentLocationChanged(final File documentLocation,
final File oldDocumentLocation) {}
private FileChooser fileChooser;
@Override
public void documentChanged(final LatLongs document, final LatLongs oldDocument) {
updateLocationViewList(0);
private FileChooser getFileChooser() {
if (fileChooser == null) {
fileChooser = new FileChooser();
}
return fileChooser;
}
@FXML
void handleOpenAction(final ActionEvent event) {
final FileChooser fileChooser = getFileChooser();
final File selection = fileChooser.showOpenDialog(null);
if (selection != null) {
try (InputStream input = new FileInputStream(selection) ){
setLatLongs(getObjectMapper().readValue(input, LatLongs.class));
} catch (final IOException e) {
showExceptionDialog("Oops, problem when opening " + selection, e);
}
}
}
private ObjectMapper objectMapper;
public ObjectMapper getObjectMapper() {
if (objectMapper == null) {
final SimpleModule module = new SimpleModule();
module.addSerializer(LatLong.class, new LatLongSerializer());
module.addSerializer(LatLongs.class, new LatLongsSerializer());
module.addDeserializer(LatLong.class, new LatLongDeserializer());
module.addDeserializer(LatLongs.class, new LatLongsDeserializer());
objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
}
return objectMapper;
}
private void showExceptionDialog(final String message) {
final Alert alert = new Alert(AlertType.ERROR, message, ButtonType.CLOSE);
alert.showAndWait();
}
private void showExceptionDialog(final String message, final Exception e) {
showExceptionDialog(message + ": " + e.getLocalizedMessage());
}
private void showSaveExceptionDialog(final File location, final Exception e) {
showExceptionDialog("Oops, problem saving to " + location, e);
}
@FXML
void handleSaveAction() {
final FileChooser fileChooser = getFileChooser();
final File selection = fileChooser.showSaveDialog(null);
if (selection != null ) {
try (OutputStream outputStream = new FileOutputStream(selection, false)) {
getObjectMapper().writeValue(outputStream, getLatLongs());
} catch (final IOException e) {
showSaveExceptionDialog(selection, e);
}
}
}
}
package simpleex.ui;
import fxutil.doc.AbstractDocumentStorageImpl;
import fxutil.doc.IDocumentImporter;
import fxutil.doc.IDocumentLoader;
import fxutil.doc.IDocumentPersistence;
import fxutil.doc.IDocumentStorage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
import simpleex.core.LatLongs;
public class LatLongsApp {
private LatLongs latLongs = null;
private final IDocumentPersistence<LatLongs, File> documentPersistence =
new IDocumentPersistence<LatLongs, File>() {
@Override
public LatLongs loadDocument(final InputStream inputStream) throws Exception {
// TODO
return null;
}
@Override
public void saveDocument(final LatLongs document, final File documentLocation)
throws Exception {
try (OutputStream output = new FileOutputStream(documentLocation)) {
// TODO
}
}
};
private final AbstractDocumentStorageImpl<LatLongs, File> documentStorage =
new AbstractDocumentStorageImpl<LatLongs, File>() {
@Override
protected LatLongs getDocument() {
return latLongs;
}
@Override
protected void setDocument(final LatLongs document) {
final LatLongs oldDocument = getDocument();
LatLongsApp.this.latLongs = document;
fireDocumentChanged(oldDocument);
}
@Override
protected LatLongs createDocument() {
return new LatLongs();
}
@Override
protected InputStream toInputStream(final File storage) throws IOException {
return new FileInputStream(storage);
}
@Override
public LatLongs loadDocument(final InputStream inputStream) throws Exception {
return documentPersistence.loadDocument(inputStream);
}
@Override
public void saveDocument(final LatLongs document, final File documentLocation)
throws Exception {
documentPersistence.saveDocument(document, documentLocation);
}
@Override
public Collection<IDocumentImporter> getDocumentImporters() {
return documentLoaders.stream().map(loader -> new IDocumentImporter() {
@Override
public void importDocument(final InputStream inputStream) throws IOException {
try {
setDocumentAndLocation(loader.loadDocument(inputStream), null);
} catch (final Exception e) {
throw new IOException(e);
}
}
}).collect(Collectors.toList());
}
};
public IDocumentStorage<File> getDocumentStorage() {
return documentStorage;
}
private final Collection<IDocumentLoader<LatLongs>> documentLoaders = Arrays.asList();
public Iterable<IDocumentLoader<LatLongs>> getDocumentLoaders() {
return documentLoaders;
}
}
package simpleex.ui;
import com.fasterxml.jackson.databind.module.SimpleModule;
import fxutil.doc.IDocumentStorage;
import fxutil.doc.SimpleJsonFileStorageImpl;
import java.io.File;
import simpleex.core.LatLong;
import simpleex.core.LatLongs;
import simpleex.json.LatLongDeserializer;
import simpleex.json.LatLongSerializer;
import simpleex.json.LatLongsDeserializer;
import simpleex.json.LatLongsSerializer;
public class LatLongsStorage extends SimpleJsonFileStorageImpl<LatLongs>
implements IDocumentStorage<File> {
public LatLongsStorage() {
super(LatLongs.class);
}
@Override
protected void configureJacksonModule(final SimpleModule module) {
module.addSerializer(LatLong.class, new LatLongSerializer());
module.addSerializer(LatLongs.class, new LatLongsSerializer());
module.addDeserializer(LatLong.class, new LatLongDeserializer());
module.addDeserializer(LatLongs.class, new LatLongsDeserializer());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.SeparatorMenuItem?>
<Menu xmlns:fx="http://javafx.com/fxml" text="File" fx:controller="fxutil.doc.FileMenuController">
<items>
<MenuItem text="New" accelerator="Meta+N" onAction="#handleNewAction"/>
<MenuItem text="Open..." accelerator="Meta+O" onAction="#handleOpenAction"/>
<Menu fx:id="recentMenu" text="Open Recent"/>
<SeparatorMenuItem/>
<MenuItem text="Save" accelerator="Meta+S" onAction="#handleSaveAction"/>
<MenuItem text="Save As..." onAction="#handleSaveAsAction"/>
<MenuItem text="Save Copy As..." onAction="#handleSaveCopyAsAction"/>
<SeparatorMenuItem/>
<Menu fx:id="importMenu" text="Import">
<MenuItem text="File..." onAction="#handleFileImportAction"/>
<MenuItem text="URL..." onAction="#handleUrlImportAction"/>
</Menu>
</items>
</Menu>
......@@ -24,7 +24,12 @@
<VBox>
<MenuBar >
<menus>
<fx:include fx:id="fileMenu" source="FileMenu.fxml"/>
<Menu text="File">
<items>
<MenuItem text="Open..." accelerator="Meta+O" onAction="#handleOpenAction"/>
<MenuItem text="Save" accelerator="Meta+S" onAction="#handleSaveAction"/>
</items>
</Menu>
</menus>
</MenuBar>
</VBox>
......
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.SeparatorMenuItem?>
<Menu xmlns:fx="http://javafx.com/fxml" text="File" fx:controller="fxutil.doc.FileMenuController">
<items>
<MenuItem text="New" accelerator="Meta+N" onAction="#handleNewAction"/>
<MenuItem text="Open..." accelerator="Meta+O" onAction="#handleOpenAction"/>
<Menu fx:id="recentMenu" text="Open Recent"/>
<SeparatorMenuItem/>
<MenuItem text="Save" accelerator="Meta+S" onAction="#handleSaveAction"/>
<MenuItem text="Save As..." onAction="#handleSaveAsAction"/>
<MenuItem text="Save Copy As..." onAction="#handleSaveCopyAsAction"/>
<SeparatorMenuItem/>
<Menu fx:id="importMenu" text="Import">
<MenuItem text="File..." onAction="#handleFileImportAction"/>
<MenuItem text="URL..." onAction="#handleUrlImportAction"/>
</Menu>
</items>
</Menu>
......@@ -24,7 +24,12 @@
<VBox>
<MenuBar >
<menus>
<fx:include fx:id="fileMenu" source="FileMenu.fxml"/>
<Menu text="File">
<items>
<MenuItem text="Open..." accelerator="Meta+O" onAction="#handleOpenAction"/>
<MenuItem text="Save" accelerator="Meta+S" onAction="#handleSaveAction"/>
</items>
</Menu>
</menus>
</MenuBar>
</VBox>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment