alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.windows;

import java.beans.*;
import org.openide.awt.StatusDisplayer;

import org.openide.util.*;

/** Simple support for an openable objects.
* Can be used either as an {@link org.openide.cookies.OpenCookie},
* {@link org.openide.cookies.ViewCookie}, or {@link org.openide.cookies.CloseCookie},
* depending on which cookies the subclass implements.
*
* @author Jaroslav Tulach
*/
public abstract class CloneableOpenSupport extends Object {
    /** the environment that provides connection to outside world */
    protected Env env;

    /** All opened editors on this file.
     * Warning: Treat this field like final.
     * Internally the instance is used as WeakListener
     * on Env validity changes.
     * Changing the instance in subclasses would lead to breaking
     * of that listening, thus to errorneous behaviour. */
    protected CloneableTopComponent.Ref allEditors;

    private static java.awt.Container container;

    /** New support for a given environment. 
    * @param env environment to take all date from/to
    */
    public CloneableOpenSupport(Env env) {
        this.env = env;

        Listener l = new Listener (env);
        this.allEditors = l;

        // attach property change listener to be informed about loosing validity
        env.addPropertyChangeListener (org.openide.util.WeakListeners.propertyChange (
                                           l, env
                                       ));
        // attach vetoable change listener to be cancel loosing validity when modified
        env.addVetoableChangeListener (org.openide.util.WeakListeners.vetoableChange (
                                           l, env
                                       ));
    }

    /** Opens and focuses or just focuses already opened
     * CloneableTopComponent.
     * 

Note: The actual processing of this method is scheduled into AWT thread * in case it is called from other than the AWT thread.

* @see org.openide.cookies.OpenCookie#open * @see #openCloneableTopComponent */ public void open () { //Bugfix #10688 open() is now run in AWT thread Mutex.EVENT.writeAccess (new Runnable () { public void run () { CloneableTopComponent editor = openCloneableTopComponent(); editor.requestActive(); } }); } /** Focuses existing component to view, or if none exists creates new. * The default implementation simply calls {@link #open}. * @see org.openide.cookies.ViewCookie#view */ public void view () { open (); } /** Focuses existing component to view, or if none exists creates new. * The default implementation simply calls {@link #open}. * @see org.openide.cookies.EditCookie#edit */ public void edit () { open (); } /** Closes all components. * @return true if every component is successfully closed or false if the user cancelled the request * @see org.openide.cookies.CloseCookie#close */ public boolean close () { return close (true); } /** Closes all opened windows. * @param ask true if we should ask user * @return true if sucesfully closed */ protected boolean close (final boolean ask) { if (allEditors.isEmpty ()) { return true; } //Bugfix #10688 close() is now run in AWT thread //also bugfix of 10714 - whole close (boolean) is run in AWT thread Boolean ret = (Boolean) Mutex.EVENT.writeAccess (new Mutex.Action () { public Object run () { //synchronized (allEditors) { synchronized (getLock()) { // user canceled the action if (ask && !canClose ()) { return Boolean.FALSE; } java.util.Enumeration en = allEditors.getComponents (); while (en.hasMoreElements ()) { TopComponent c = (TopComponent)en.nextElement (); if (!c.close ()) { return Boolean.FALSE; } } } return Boolean.TRUE; } }); return ret.booleanValue(); } /** Should test whether all data is saved, and if not, prompt the user * to save. * The default implementation returns true. * * @return true if everything can be closed */ protected boolean canClose () { return true; } /** Simply open for an editor. */ protected final CloneableTopComponent openCloneableTopComponent() { //synchronized (allEditors) { synchronized (getLock()) { CloneableTopComponent ret = allEditors.getArbitraryComponent (); if(ret != null) { ret.open(); return ret; } else { // no opened editor String msg = messageOpening (); if (msg != null) { StatusDisplayer.getDefault().setStatusText(msg); } CloneableTopComponent editor = createCloneableTopComponent (); editor.setReference (allEditors); editor.open(); msg = messageOpened (); if (msg == null) { msg = ""; // NOI18N } StatusDisplayer.getDefault().setStatusText(msg); return editor; } } } /** Creates lock object used in close and openCloneableTopComponent. */ private Object getLock() { if (container == null) { container = new java.awt.Container(); } return container.getTreeLock(); } /** A method to create a new component. Must be overridden in subclasses. * @return the cloneable top component for this support */ protected abstract CloneableTopComponent createCloneableTopComponent (); /** Message to display when an object is being opened. * @return the message or null if nothing should be displayed */ protected abstract String messageOpening (); /** Message to display when an object has been opened. * @return the message or null if nothing should be displayed */ protected abstract String messageOpened (); /** Abstract interface that is used by CloneableOpenSupport to * talk to outside world. */ public static interface Env extends java.io.Serializable { /** that is fired when the objects wants to mark itself as * invalid, so all components should be closed. */ public static final String PROP_VALID = "valid"; // NOI18N /** that is fired when the objects wants to mark itself modified * or not modified. */ public static final String PROP_MODIFIED = "modified"; // NOI18N /** Adds property listener. */ public void addPropertyChangeListener (PropertyChangeListener l); /** Removes property listener. */ public void removePropertyChangeListener (PropertyChangeListener l); /** Adds veto listener. */ public void addVetoableChangeListener (VetoableChangeListener l); /** Removes veto listener. */ public void removeVetoableChangeListener (VetoableChangeListener l); /** Test whether the support is in valid state or not. * It could be invalid after deserialization when the object it * referenced to does not exist anymore. * * @return true or false depending on its state */ public boolean isValid (); /** Test whether the object is modified or not. * @return true if the object is modified */ public boolean isModified (); /** Support for marking the environement modified. * @exception IOException if the environment cannot be marked modified * (for example when the file is readonly), when such exception * is the support should discard all previous changes */ public void markModified () throws java.io.IOException; /** Reverse method that can be called to make the environment * unmodified. */ public void unmarkModified (); /** Method that allows environment to find its * cloneable open support. */ public CloneableOpenSupport findCloneableOpenSupport (); } /** Property change & veto listener. To react to dispose/delete of * the data object. */ private static final class Listener extends CloneableTopComponent.Ref implements PropertyChangeListener, VetoableChangeListener, Runnable { /** generated Serialized Version UID */ static final long serialVersionUID = -1934890789745432531L; /** environment to use as connection to outside world */ private Env env; /** Constructor. */ public Listener (Env env) { this.env = env; } /** Getter for the associated CloneableOpenSupport * @return the support or null if none was found */ private CloneableOpenSupport support () { return env.findCloneableOpenSupport (); } public void propertyChange (PropertyChangeEvent ev) { if (Env.PROP_VALID.equals (ev.getPropertyName ())) { // do not check it if old value is not true if (Boolean.FALSE.equals (ev.getOldValue ())) return; Mutex.EVENT.readAccess (this); } } /** Closes the support in AWT thread. */ public void run () { // loosing validity CloneableOpenSupport os = support (); if (os != null) { // mark the object as not being modified, so nobody // will ask for save env.unmarkModified (); os.close (false); } } /** Forbids setValid (false) on data object when there is an * opened editor. * * @param ev PropertyChangeEvent */ public void vetoableChange (PropertyChangeEvent ev) throws PropertyVetoException { if (Env.PROP_VALID.equals (ev.getPropertyName ())) { // do not check it if old value is not true if (Boolean.FALSE.equals (ev.getOldValue ())) return; if (env.isModified ()) { // if the object is modified CloneableOpenSupport os = support (); if (os != null && !os.canClose ()) { // is modified and has not been sucessfully closed throw new PropertyVetoException ( // [PENDING] this is not a very good detail message! "", ev // NOI18N ); } } } } /** Resolvable to connect to the right data object. This * method is used for connectiong CloneableTopComponents via * their CloneableTopComponent.Ref */ public Object readResolve () { CloneableOpenSupport os = support (); if (os == null) { // problem! no replace!? return this; } // use the editor support's CloneableTopComponent.Ref return os.allEditors; } } }
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.