/*
* Created on 26.02.2007
*
*/
package org.jdesktop.swingx.appframework;
import java.awt.Component;
import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.RootPaneContainer;
import org.jdesktop.application.ApplicationContext;
import org.jdesktop.application.SessionStorage;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.swingx.JXFrame;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.JXTaskPane;
import org.jdesktop.swingx.appframework.XProperties.XTableProperty;
import org.jdesktop.swingx.appframework.XProperties.XTaskPaneProperty;
import org.jdesktop.swingx.search.SearchFactory;
public abstract class SingleXFrameApplication extends SingleFrameApplication {
private static final Logger logger = Logger.getLogger(SingleXFrameApplication.class.getName());
/**
* {@inheritDoc} <p>
*
* Overridden to force a JXFrame as main frame and inject SwingX specific
* session properties.
*
*/
@Override
protected void initialize(String[] args) {
// <snip>SwingX special
injectSessionProperties();
customizeSwingXContext();
setMainFrame(createXMainFrame());
// </snip>
}
/**
* Hook to configure SwingX related global state.
* Here: sets SearchFactory. <p>
* PENDING: okay to do on the EDT?
*/
protected void customizeSwingXContext() {
SearchFactory.setInstance(new AppSearchFactory());
}
public void prepareDialog(JDialog c, boolean visible) {
if (c == null) {
throw new IllegalArgumentException("null JDialog");
}
if (!hadBeenPrepared(c)) {
prepareWindow(c);
}
if (visible) {
c.setVisible(true);
}
}
/**
* Checks and returns whether the given RootPaneContainer already has
* been prepared. As a side-effect, the container is marked as prepared
* (wrong place?)
*
* @param c
* @return
*/
private boolean hadBeenPrepared(RootPaneContainer c) {
JComponent rootPane = c.getRootPane();
// These initializations are only done once
Object k = "SingleFrameApplication.initRootPaneContainer";
boolean prepared = Boolean.TRUE.equals(rootPane.getClientProperty(k));
if (!prepared) {
rootPane.putClientProperty(k, Boolean.TRUE);
}
return prepared;
}
/**
* Prepares the given window. Injects properties from app context.
* Restores session state if appropriate. Registers listeners to try and
* track session state.
*
* @param root
*/
protected void prepareWindow(Window root) {
configureWindow(root);
// If the window's size doesn't appear to have been set, do it
if ((root.getWidth() == 0) || (root.getHeight() == 0)) {
root.pack();
if (!root.isLocationByPlatform()) {
Component owner = (root != getMainFrame()) ? getMainFrame()
: null;
root.setLocationRelativeTo(owner); // center the window
}
}
// Restore session state
String filename = sessionFilename(root);
if (filename != null) {
try {
ApplicationContext ac = getContext();
ac.getSessionStorage().restore(root, filename);
} catch (Exception e) {
logger.log(Level.WARNING, "couldn't restore sesssion", e);
}
}
root.addWindowListener(getDialogListener());
}
private WindowListener getDialogListener() {
return new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
saveSession(e.getWindow());
}
@Override
public void windowClosed(WindowEvent e) {
saveSession(e.getWindow());
}
};
}
/**
* Save session state for the component hierarchy rooted by the mainFrame.
* SingleFrameApplication subclasses that override shutdown need to remember
* call {@code super.shutdown()}.
*/
@Override
protected void shutdown() {
List<Window> windows = new ArrayList<Window>();
windows.add(getMainFrame());
for (int i = 0; i < getMainFrame().getOwnedWindows().length; i++) {
windows.add(getMainFrame().getOwnedWindows()[i]);
}
for (Window window : windows) {
saveSession(window);
}
}
private String sessionFilename(Window window) {
if (window == null) {
return null;
}
else {
String name = window.getName();
return (name == null) ? null : name + ".session.xml";
}
}
private void saveSession(Window window) {
String filename = sessionFilename(window);
if (filename != null) {
ApplicationContext appContext = getContext();
try {
appContext.getSessionStorage().save(window, filename);
}
catch (IOException e) {
logger.log(Level.WARNING, "couldn't save sesssion", e);
} catch (SecurityException e) {
logger.log(Level.WARNING, "couldn't save sesssion", e);
}
}
}
/**
* Deletes the session state by deleting the file. Useful during development
* when restoring to old state is not always the desired behaviour.
* Pending: this is incomplete, deletes the mainframe state only.
*/
protected void deleteSessionState() {
ApplicationContext context = getContext();
try {
context.getLocalStorage().deleteFile("mainFrame.session.xml");
} catch (IOException e) {
logger.log(Level.WARNING, "couldn't delete sesssion", e);
} catch (SecurityException e) {
logger.log(Level.WARNING, "couldn't delete sesssion", e);
}
}
protected JXFrame createXMainFrame() {
JXFrame xFrame = createXFrame();
xFrame.setName("mainFrame");
// PENDING JW: how-to set app icon?
return xFrame;
}
protected JXFrame createXFrame() {
return new JXFrame();
}
/**
* Registers SwingX specific Properties for session storage. <p>
*/
protected void injectSessionProperties() {
SessionStorage storage = getContext().getSessionStorage();
storage.putProperty(JXTable.class, new XTableProperty());
storage.putProperty(JXTaskPane.class, new XTaskPaneProperty());
new XProperties().registerPersistenceDelegates();
}
}