Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jhotdraw.app.AbstractApplication Maven / Gradle / Ivy
/*
* @(#)AbstractApplication.java
*
* Copyright (c) 1996-2010 by the original authors of JHotDraw and all its
* contributors. All rights reserved.
*
* You may not use, copy or modify this file, except in compliance with the
* license agreement you entered into with the copyright holders. For details
* see accompanying license terms.
*/
package org.jhotdraw.app;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.awt.Container;
import java.awt.Window;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jhotdraw.beans.*;
import org.jhotdraw.gui.Worker;
import org.jhotdraw.util.*;
import java.util.prefs.*;
import javax.swing.*;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.jhotdraw.app.action.file.ClearRecentFilesMenuAction;
import org.jhotdraw.app.action.file.LoadDirectoryAction;
import org.jhotdraw.app.action.file.LoadFileAction;
import org.jhotdraw.app.action.file.LoadRecentFileAction;
import org.jhotdraw.app.action.file.OpenRecentFileAction;
import org.jhotdraw.gui.URIChooser;
import org.jhotdraw.util.prefs.PreferencesUtil;
/**
* This abstract class can be extended to implement an {@link Application}.
*
* {@code AbstractApplication} supports the command line parameter
* {@code -open filename} to open views for specific URI's upon launch of
* the application.
*
* @author Werner Randelshofer
* @version $Id: AbstractApplication.java 722 2010-11-26 08:49:25Z rawcoder $
*/
public abstract class AbstractApplication extends AbstractBean implements Application {
private LinkedList views = new LinkedList();
private Collection unmodifiableViews;
private boolean isEnabled = true;
protected ResourceBundleUtil labels;
protected ApplicationModel model;
private Preferences prefs;
@Nullable
private View activeView;
public final static String VIEW_COUNT_PROPERTY = "viewCount";
private LinkedList recentFiles = new LinkedList();
private final static int maxRecentFilesCount = 10;
private ActionMap actionMap;
private URIChooser openChooser;
private URIChooser saveChooser;
private URIChooser importChooser;
private URIChooser exportChooser;
/** Creates a new instance. */
public AbstractApplication() {
}
@Override
public void init() {
prefs = PreferencesUtil.userNodeForPackage((getModel() == null) ? getClass() : getModel().getClass());
int count = prefs.getInt("recentFileCount", 0);
for (int i = 0; i < count; i++) {
String path = prefs.get("recentFile." + i, null);
if (path != null) {
try {
recentFiles.add(new URI(path));
} catch (URISyntaxException ex) {
// Silently don't add this URI
}
}
}
}
@Override
public void start(List uris) {
if (uris.isEmpty()) {
final View v = createView();
add(v);
v.setEnabled(false);
show(v);
// Set the start view immediately active, so that
// ApplicationOpenFileAction picks it up on Mac OS X.
setActiveView(v);
v.execute(new Worker() {
@Override
public Object construct() {
v.clear();
return null;
}
@Override
public void finished() {
v.setEnabled(true);
}
});
} else {
for (final URI uri : uris) {
final View v = createView();
add(v);
v.setEnabled(false);
show(v);
// Set the start view immediately active, so that
// ApplicationOpenFileAction picks it up on Mac OS X.
setActiveView(v);
v.execute(new Worker() {
@Override
public Object construct() throws Exception {
v.read(uri, null);
return null;
}
@Override
public void finished() {
v.setURI(uri);
v.setEnabled(true);
}
});
}
}
}
@Override
public final View createView() {
View v = basicCreateView();
v.setActionMap(createViewActionMap(v));
return v;
}
@Override
public void setModel(ApplicationModel newValue) {
ApplicationModel oldValue = model;
model = newValue;
firePropertyChange("model", oldValue, newValue);
}
@Override
public ApplicationModel getModel() {
return model;
}
protected View basicCreateView() {
return model.createView();
}
/**
* Sets the active view. Calls deactivate on the previously
* active view, and then calls activate on the given view.
*
* @param newValue Active view, can be null.
*/
public void setActiveView(@Nullable View newValue) {
View oldValue = activeView;
if (activeView != null) {
activeView.deactivate();
}
activeView = newValue;
if (activeView != null) {
activeView.activate();
}
firePropertyChange(ACTIVE_VIEW_PROPERTY, oldValue, newValue);
}
/**
* Gets the active view.
*
* @return The active view can be null.
*/
@Override
@Nullable
public View getActiveView() {
return activeView;
}
@Override
public String getName() {
return model.getName();
}
@Override
public String getVersion() {
return model.getVersion();
}
@Override
public String getCopyright() {
return model.getCopyright();
}
@Override
public void stop() {
for (View p : new LinkedList(views())) {
dispose(p);
}
}
@Override
public void destroy() {
stop();
model.destroyApplication(this);
System.exit(0);
}
@Override
public void remove(View v) {
hide(v);
if (v == getActiveView()) {
setActiveView(null);
}
int oldCount = views.size();
views.remove(v);
v.setApplication(null);
firePropertyChange(VIEW_COUNT_PROPERTY, oldCount, views.size());
}
@Override
public void add(View v) {
if (v.getApplication() != this) {
int oldCount = views.size();
views.add(v);
v.setApplication(this);
v.init();
model.initView(this, v);
firePropertyChange(VIEW_COUNT_PROPERTY, oldCount, views.size());
}
}
protected abstract ActionMap createViewActionMap(View p);
@Override
public void dispose(View view) {
remove(view);
model.destroyView(this, view);
view.dispose();
}
@Override
public Collection views() {
if (unmodifiableViews == null) {
unmodifiableViews = Collections.unmodifiableCollection(views);
}
return unmodifiableViews;
}
@Override
public boolean isEnabled() {
return isEnabled;
}
@Override
public void setEnabled(boolean newValue) {
boolean oldValue = isEnabled;
isEnabled = newValue;
firePropertyChange("enabled", oldValue, newValue);
}
public Container createContainer() {
return new JFrame();
}
/** Launches the application.
*
* @param args This implementation supports the command-line parameter "-open"
* which can be followed by one or more filenames or URI's.
*/
@Override
public void launch(String[] args) {
configure(args);
// Get URI's from command line
final List uris = getOpenURIsFromMainArgs(args);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
init();
start(uris);
}
});
}
/** Parses the arguments to the main method and returns a list of URI's
* for which views need to be opened upon launch of the application.
*
* This implementation supports the command-line parameter "-open"
* which can be followed by one or more filenames or URI's.
*
* This method is invoked from the {@code Application.launch} method.
*
* @param args Arguments to the main method.
* @return A list of URI's parsed from the arguments. Returns an empty list
* if no URI's shall be opened.
*/
protected List getOpenURIsFromMainArgs(String[] args) {
LinkedList uris = new LinkedList();
for (int i = 0; i < args.length; ++i) {
if (args[i].equals("-open")) {
for (++i; i < args.length; ++i) {
if (args[i].startsWith("-")) {
break;
}
URI uri;
uri = new File(args[i]).toURI();
uris.add(uri);
}
}
}
return uris;
}
protected void initLabels() {
labels = ResourceBundleUtil.getBundle("org.jhotdraw.app.Labels");
}
@Override
public void configure(String[] args) {
}
@Override
public void removePalette(Window palette) {
}
@Override
public void addPalette(Window palette) {
}
@Override
public void removeWindow(Window window) {
}
@Override
public void addWindow(Window window, @Nullable View p) {
}
protected Action getAction(@Nullable View view, String actionID) {
return getActionMap(view).get(actionID);
}
/** Adds the specified action as a menu item to the supplied menu. */
protected void addAction(JMenu m, @Nullable View view, String actionID) {
addAction(m, getAction(view, actionID));
}
/** Adds the specified action as a menu item to the supplied menu. */
protected void addAction(JMenu m, Action a) {
if (a != null) {
if (m.getClientProperty("needsSeparator") == Boolean.TRUE) {
m.addSeparator();
m.putClientProperty("needsSeparator", null);
}
JMenuItem mi;
mi = m.add(a);
mi.setIcon(null);
mi.setToolTipText(null);
}
}
/** Adds the specified action as a menu item to the supplied menu. */
protected void addMenuItem(JMenu m, JMenuItem mi) {
if (mi != null) {
if (m.getClientProperty("needsSeparator") == Boolean.TRUE) {
m.addSeparator();
m.putClientProperty("needsSeparator", null);
}
m.add(mi);
}
}
/** Adds a separator to the supplied menu. The separator will only
be added, if the previous item is not a separator. */
protected void maybeAddSeparator(JMenu m) {
JPopupMenu pm = m.getPopupMenu();
if (pm.getComponentCount() > 0 //
&& !(pm.getComponent(pm.getComponentCount() - 1) instanceof JSeparator)) {
m.addSeparator();
}
}
@Override
public java.util.List getRecentURIs() {
return Collections.unmodifiableList(recentFiles);
}
@Override
public void clearRecentURIs() {
@SuppressWarnings("unchecked")
java.util.List oldValue = (java.util.List) recentFiles.clone();
recentFiles.clear();
prefs.putInt("recentFileCount", recentFiles.size());
firePropertyChange("recentFiles",
Collections.unmodifiableList(oldValue),
Collections.unmodifiableList(recentFiles));
}
@Override
public void addRecentURI(URI uri) {
@SuppressWarnings("unchecked")
java.util.List oldValue = (java.util.List) recentFiles.clone();
if (recentFiles.contains(uri)) {
recentFiles.remove(uri);
}
recentFiles.addFirst(uri);
if (recentFiles.size() > maxRecentFilesCount) {
recentFiles.removeLast();
}
prefs.putInt("recentFileCount", recentFiles.size());
int i = 0;
for (URI f : recentFiles) {
prefs.put("recentFile." + i, f.toString());
i++;
}
firePropertyChange("recentFiles", oldValue, 0);
firePropertyChange("recentFiles",
Collections.unmodifiableList(oldValue),
Collections.unmodifiableList(recentFiles));
}
protected JMenu createOpenRecentFileMenu(@Nullable View view) {
JMenuItem mi;
JMenu m;
m = new JMenu();
labels.configureMenu(m, //
(getAction(view, LoadFileAction.ID) != null || //
getAction(view, LoadDirectoryAction.ID) != null) ?//
"file.loadRecent" ://
"file.openRecent"//
);
m.setIcon(null);
m.add(getAction(view, ClearRecentFilesMenuAction.ID));
new OpenRecentMenuHandler(m, view);
return m;
}
/** Updates the menu items in the "Open Recent" file menu. */
private class OpenRecentMenuHandler implements PropertyChangeListener, Disposable {
private JMenu openRecentMenu;
private LinkedList openRecentActions = new LinkedList();
@Nullable
private View view;
public OpenRecentMenuHandler(JMenu openRecentMenu, @Nullable View view) {
this.openRecentMenu = openRecentMenu;
this.view = view;
if (view != null) {
view.addDisposable(this);
}
updateOpenRecentMenu();
addPropertyChangeListener(this);
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
if (name == "recentFiles") {
updateOpenRecentMenu();
}
}
/**
* Updates the "File > Open Recent" menu.
*/
protected void updateOpenRecentMenu() {
if (openRecentMenu.getItemCount() > 0) {
JMenuItem clearRecentFilesItem = (JMenuItem) openRecentMenu.getItem(
openRecentMenu.getItemCount() - 1);
openRecentMenu.remove(openRecentMenu.getItemCount() - 1);
// Dispose the actions and the menu items that are currently in the menu
for (Action action : openRecentActions) {
if (action instanceof Disposable) {
((Disposable) action).dispose();
}
}
openRecentActions.clear();
openRecentMenu.removeAll();
// Create new actions and add them to the menu
if (getAction(view, LoadFileAction.ID) != null || //
getAction(view, LoadDirectoryAction.ID) != null) {
for (URI f : getRecentURIs()) {
LoadRecentFileAction action = new LoadRecentFileAction(AbstractApplication.this, view, f);
openRecentMenu.add(action);
openRecentActions.add(action);
}
} else {
for (URI f : getRecentURIs()) {
OpenRecentFileAction action = new OpenRecentFileAction(AbstractApplication.this, f);
openRecentMenu.add(action);
openRecentActions.add(action);
}
}
if (getRecentURIs().size() > 0) {
openRecentMenu.addSeparator();
}
// Add a separator and the clear recent files item.
openRecentMenu.add(clearRecentFilesItem);
}
}
@Override
public void dispose() {
removePropertyChangeListener(this);
// Dispose the actions and the menu items that are currently in the menu
for (Action action : openRecentActions) {
if (action instanceof Disposable) {
((Disposable) action).dispose();
}
}
openRecentActions.clear();
}
}
@Override
public URIChooser getOpenChooser(View v) {
if (v == null) {
if (openChooser == null) {
openChooser = model.createOpenChooser(this, null);
List ruris = getRecentURIs();
if (ruris.size() > 0) {
try {
openChooser.setSelectedURI(ruris.get(0));
} catch (IllegalArgumentException e) {
// Ignore illegal values in recent URI list.
}
}
}
return openChooser;
} else {
URIChooser chooser = (URIChooser) v.getComponent().getClientProperty("openChooser");
if (chooser == null) {
chooser = model.createOpenChooser(this, v);
v.getComponent().putClientProperty("openChooser", chooser);
List ruris = getRecentURIs();
if (ruris.size() > 0) {
try {
chooser.setSelectedURI(ruris.get(0));
} catch (IllegalArgumentException e) {
// Ignore illegal values in recent URI list.
}
}
}
return chooser;
}
}
@Override
public URIChooser getSaveChooser(View v) {
if (v == null) {
if (saveChooser == null) {
saveChooser = model.createSaveChooser(this, null);
}
return saveChooser;
} else {
URIChooser chooser = (URIChooser) v.getComponent().getClientProperty("saveChooser");
if (chooser == null) {
chooser = model.createSaveChooser(this, v);
v.getComponent().putClientProperty("saveChooser", chooser);
try {
chooser.setSelectedURI(v.getURI());
} catch (IllegalArgumentException e) {
// ignore illegal values
}
}
return chooser;
}
}
@Override
public URIChooser getImportChooser(View v) {
if (v == null) {
if (importChooser == null) {
importChooser = model.createImportChooser(this, null);
}
return importChooser;
} else {
URIChooser chooser = (URIChooser) v.getComponent().getClientProperty("importChooser");
if (chooser == null) {
chooser = model.createImportChooser(this, v);
v.getComponent().putClientProperty("importChooser", chooser);
}
return chooser;
}
}
@Override
public URIChooser getExportChooser(View v) {
if (v == null) {
if (exportChooser == null) {
exportChooser = model.createExportChooser(this, null);
}
return exportChooser;
} else {
URIChooser chooser = (URIChooser) v.getComponent().getClientProperty("exportChooser");
if (chooser == null) {
chooser = model.createExportChooser(this, v);
v.getComponent().putClientProperty("exportChooser", chooser);
}
return chooser;
}
}
/**
* Sets the application-wide action map.
*/
public void setActionMap(ActionMap m) {
actionMap = m;
}
/**
* Gets the action map.
*/
@Override
public ActionMap getActionMap(@Nullable View v) {
return (v == null) ? actionMap : v.getActionMap();
}
}