All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jaxx.runtime.swing.session.SwingSession Maven / Gradle / Ivy

There is a newer version: 3.0-alpha-6
Show newest version
/*
 * #%L
 * Graphical Widget
 * 
 * $Id: SwingSession.java 2782 2014-02-04 07:12:14Z tchemit $
 * $HeadURL: https://nuiton.org/svn/jaxx/tags/jaxx-2.8.2/jaxx-runtime/src/main/java/jaxx/runtime/swing/session/SwingSession.java $
 * %%
 * Copyright (C) 2004 - 2010 CodeLutin
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as 
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */
package jaxx.runtime.swing.session;


import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdesktop.swingx.JXTable;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.*;
import java.io.*;
import java.util.*;

/**
 * Use to store and restore position and size of application. Default supported widgets
 * are:
 * 
  • java.awt.Window (and subclasses) *
  • javax.swing.JTabbedPane (and subclasses) *
  • javax.swing.JSplitPane (and subclasses) *
  • org.jdesktop.swingx.JXTable (and subclasses) *
  • javax.swing.JTable (and subclasses) * * * usage: *
  • create SwingSession object *
  • add component that you want save *
  • explicite call to save * * You can use same SwingSession for multiple window but in this case you must * have setName for each window with different name, otherwize there are * collision between window component and result is undetermisitic * * This code is partialy inspired from http://kenai.com/projects/bsaf/pages/Home * project. This project is under LGPL v2.1 license. We can't reuse directly this * library because to many fields and methods are private and we can't implements * it and modify some behavior. * * @author poussin * @author kmorin * @version $Revision: 2782 $ * @since 2.5.16 * * Last update: $Date: 2014-02-04 08:12:14 +0100 (Tue, 04 Feb 2014) $ * by : $Author: tchemit $ */ public class SwingSession { private static final Log log = LogFactory.getLog(SwingSession.class); protected File file; protected boolean autoSave; protected Set registeredComponent = Sets.newIdentityHashSet(); /** State object registered to get and set State. * key: class of component managed by the state; value: the state*/ protected Map stateManager = Maps.newHashMap(); /** state of all component added with add method. * key: path of compoenent; value: State */ protected Map states; public SwingSession(File file, boolean autoSave) { this(file, autoSave, Maps.newHashMap()); } public SwingSession(File file, boolean autoSave, Map additionalStates) { this.file = file; this.autoSave = autoSave; stateManager.put(Window.class, new WindowState()); stateManager.put(JTable.class, new JTableState()); stateManager.put(JTabbedPane.class, new JTabbedPaneState()); stateManager.put(JSplitPane.class, new JSplitPaneState()); stateManager.put(JXTable.class, new JXTableSwingSessionState()); stateManager.putAll(additionalStates); states = loadStates(file); if (states == null) { states = Maps.newHashMap(); } } @Override protected void finalize() throws Throwable { save(); super.finalize(); } /* If an exception occurs in the XMLEncoder/Decoder, we want * to throw an IOException. The exceptionThrow listener method * doesn't throw a checked exception so we just set a flag * here and check it when the encode/decode operation finishes */ static private class AbortExceptionListener implements ExceptionListener { public Exception exception = null; @Override public void exceptionThrown(Exception e) { if (exception == null) { exception = e; } } } /* There are some (old) Java classes that aren't proper beans. Rectangle * is one of these. When running within the secure sandbox, writing a * Rectangle with XMLEncoder causes a security exception because * DefaultPersistenceDelegate calls Field.setAccessible(true) to gain * access to private fields. This is a workaround for that problem. * A bug has been filed, see JDK bug ID 4741757 */ private static class RectanglePD extends DefaultPersistenceDelegate { public RectanglePD() { super(new String[]{"x", "y", "width", "height"}); } @Override protected Expression instantiate(Object oldInstance, Encoder out) { Rectangle oldR = (Rectangle) oldInstance; Object[] constructorArgs = new Object[]{ oldR.x, oldR.y, oldR.width, oldR.height }; return new Expression(oldInstance, oldInstance.getClass(), "new", constructorArgs); } } public void save() { updateState(); AbortExceptionListener el = new AbortExceptionListener(); ByteArrayOutputStream bst = new ByteArrayOutputStream(); XMLEncoder e = null; /* Buffer the XMLEncoder's output so that decoding errors don't * cause us to trash the current version of the specified file. */ try { e = new XMLEncoder(bst); e.setPersistenceDelegate(Rectangle.class, new RectanglePD()); e.setExceptionListener(el); e.writeObject(states); } finally { if (e != null) { e.close(); } } if (el.exception != null) { log.warn("save failed \"" + file + "\"", el.exception); } else { OutputStream ost = null; try { ost = new FileOutputStream(file); ost.write(bst.toByteArray()); } catch (IOException eee) { log.warn("save failed \"" + file + "\"", eee); } finally { if (ost != null) { try { ost.close(); } catch (IOException eee) { log.warn("can't close properly \"" + file + "\"", eee); } } } } } /** * Loads the states from the file */ public Map loadStates(File file) { Map result = null; if (file.exists()) { XMLDecoder d = null; try { InputStream ist = new FileInputStream(file); d = new XMLDecoder(ist); AbortExceptionListener eee = new AbortExceptionListener(); d.setExceptionListener(eee); Object bean = d.readObject(); if (eee.exception != null) { log.warn("load failed \"" + file + "\"", eee.exception); } else { result = (Map) bean; } } catch (IOException eee) { log.warn("load failed \"" + file + "\"", eee); } finally { if (d != null) { d.close(); } } } return result; } public void updateState() { walkThrowComponent("", registeredComponent, new SaveStateAction()); } public void add(Component c) { add(c, false); } public void add(final Component c, boolean replace) { if (c == null) { return; } final String cName = getComponentName(c); Object existingComponent = CollectionUtils.find(registeredComponent, new Predicate() { @Override public boolean evaluate(Object o) { Component comp = (Component) o; String compName = getComponentName(comp); return c.getClass().equals(comp.getClass()) && cName.equals(compName); } }); if (existingComponent != null) { if (replace) { if (log.isDebugEnabled()) { log.debug("replacing the component fir path /" + cName); } remove((Component) existingComponent); } else { log.warn(String.format( "Component already added %s(%s)", c.getClass(), c.getName())); return; } } registeredComponent.add(c); walkThrowComponent("", Collections.singleton(c), new RestoreStateAction()); } /** * Remove component from component to save * @param c */ public void remove(Component c) { registeredComponent.remove(c); } protected String getComponentName(Component c) { String name = c.getName(); if (name == null) { int n = c.getParent().getComponentZOrder(c); if (n >= 0) { Class clazz = c.getClass(); name = clazz.getSimpleName(); if (name.length() == 0) { name = "Anonymous" + clazz.getSuperclass().getSimpleName(); } name = name + n; } else { // Implies that the component tree is changing // while we're computing the path. Punt. log.warn("Couldn't compute pathname for " + c); } } return name; } public State getStateManager(Class clazz) { State result = null; while (result == null && clazz != null) { result = stateManager.get(clazz); clazz = clazz.getSuperclass(); } return result; } public void addToStateManager(Class component, State state) { stateManager.put(component, state); } public State getStates(String path) { return states.get(path); } public void setStates(String path, State state) { this.states.put(path, state); } protected void walkThrowComponent( String path, Collection roots, Action action) { for (Component root : roots) { if (root != null) { String pathname = path + "/" + getComponentName(root); State state = getStateManager(root.getClass()); if (state != null) { action.doAction(this, pathname, root); } if (root instanceof Container) { Component[] children = ((Container) root).getComponents(); if ((children != null) && (children.length > 0)) { walkThrowComponent(pathname, Arrays.asList(children), action); } } if (root instanceof JFrame) { Component[] children = ((JFrame) root).getContentPane().getComponents(); if ((children != null) && (children.length > 0)) { walkThrowComponent(pathname, Arrays.asList(children), action); } } } } } public static interface Action { public void doAction(SwingSession session, String path, Component c); } public static class SaveStateAction implements Action { @Override public void doAction(SwingSession session, String path, Component c) { State manager = session.getStateManager(c.getClass()); State state = manager.getState(c); session.setStates(path, state); } } public static class RestoreStateAction implements Action { @Override public void doAction(SwingSession session, String path, Component c) { State manager = session.getStateManager(c.getClass()); State state = session.getStates(path); if (state != null) { manager.setState(c, state); } } } }




  • © 2015 - 2025 Weber Informatics LLC | Privacy Policy