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

org.openide.text.EditorSupport Maven / Gradle / Ivy

Go to download

The NetBeans Platform is a generic base for desktop applications. It provides the services common to almost all large desktop applications: window management, menus, settings and storage, an update manager, and file access. Get a head start by reusing these standard components, allowing you to concentrate fully on your application's business logic.

The newest version!
/*
 *                 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.text;

import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.io.*;
import java.util.*;

import javax.swing.JEditorPane;
import javax.swing.text.*;
import javax.swing.event.ChangeListener;
import org.openide.ErrorManager;

import org.openide.awt.UndoRedo;
import org.openide.actions.*;
import org.openide.cookies.EditorCookie;
import org.openide.cookies.OpenCookie;
import org.openide.cookies.CloseCookie;
import org.openide.cookies.SaveCookie;
import org.openide.cookies.PrintCookie;
import org.openide.filesystems.*;
import org.openide.loaders.*;
import org.openide.nodes.NodeAdapter;
import org.openide.windows.*;
import org.openide.util.Task;
import org.openide.util.actions.SystemAction;
import org.openide.nodes.NodeListener;
import org.openide.nodes.Node;

/** Support for associating an editor and a Swing {@link Document} to a data object.
 * Can be assigned as a cookie to any editable data object.
 * Then this data object will be capable of being opened in an editor, and there will be ways of retrieving and acting upon the Swing document which is editing it.
*
* @author Jaroslav Tulach
* @deprecated Use DataEditorSupport instead
*/
public class EditorSupport extends OpenSupport
implements EditorCookie.Observable, OpenCookie, CloseCookie, PrintCookie {
    /** Common name for editor mode.
     * @deprecated Use {@link org.openide.text.CloneableEditorSupport#EDITOR_MODE} instead.
     */
    public static final String EDITOR_MODE = CloneableEditorSupport.EDITOR_MODE;

    /** @deprecated no longer used */
    protected String modifiedAppendix = " *"; // NOI18N
    
    /** The flag saying if we should listen to the document modifications */
    private boolean listenToModifs = true;
    
    /** delegating support */
    private Del del;

    /** Support an existing loader entry. The file is taken from the
    * entry and is updated if the entry is moved or renamed.
    * @param entry entry to create instance from
    */
    public EditorSupport(MultiDataObject.Entry entry) {
        super(entry, new DelEnv(entry.getDataObject()));

        del = new Del (
            entry.getDataObject (),
            (DelEnv)env,
            allEditors
        );
    }
    
    /** Message to display when an object is being opened.
    * @return the message or null if nothing should be displayed
    */
    protected String messageOpening () {
        return del.superMessageOpening ();
    }
    
    /** Message to display when an object has been opened.
    * @return the message or null if nothing should be displayed
    */
    protected String messageOpened () {
        return del.superMessageOpened ();
    }

    /** Constructs message that should be displayed when the data object
    * is modified and is being closed.
    *
    * @return text to show to the user
    */
    protected String messageSave () {
        return del.superMessageSave ();
    }
    
    /** Constructs message that should be used to name the editor component.
    *
    * @return name of the editor
    */
    protected String messageName () {
        return del.superMessageName ();
    }
    
    /** Text to use as tooltip for component.
    *
    * @return text to show to the user
    */
    protected String messageToolTip () {
        return del.superMessageToolTip ();
    }
    
    
    /** Updates titles of all editors.
    */
    protected void updateTitles () {
        del.superUpdateTitles ();
    }
    

    /* A method to create a new component. Overridden in subclasses.
    * @return the {@link Editor} for this support
    */
    protected CloneableTopComponent createCloneableTopComponent () {
        // initializes the document if not initialized
        prepareDocument ();

        DataObject obj = findDataObject ();
        Editor editor = new Editor (obj);
        return editor;
    }

    /** Create an undo/redo manager.
    * This manager is then attached to the document, and listens to
    * all changes made in it.
    * 

* The default implementation simply uses UndoRedo.Manager. * * @return the undo/redo manager */ protected UndoRedo.Manager createUndoRedoManager () { return del.superUndoRedoManager (); } /** Passes the actual opening to internal delegate support. * Overrides superclass method. */ public void open() { del.open(); } // editor cookie ....................................................................... /** Closes all opened editors (if the user agrees) and * flushes content of the document to the file. * * @return false if the operation is cancelled */ public boolean close () { return del.close (); } /** Closes the editor, asks if necessary. * @param ask true if we should ask the user * @return true if succesfully closed */ protected boolean close (boolean ask) { return del.superClose (ask); } /** Load the document into memory. This is done * in different thread. A task for the thread is returned * so anyone may test whether the loading has been finished * or is still in process. * * @return task for control over loading */ public synchronized Task prepareDocument () { return del.prepareDocument (); } /** Get the document associated with this cookie. * It is an instance of Swing's {@link StyledDocument} but it should * also understand the NetBeans {@link org.openide.text.NbDocument#GUARDED} to * prevent certain lines from being edited by the user. *

* If the document is not loaded the method blocks until * it is. * * @return the styled document for this cookie that * understands the guarded attribute * @exception IOException if the document could not be loaded */ public StyledDocument openDocument () throws IOException { return del.openDocument (); } /** Get the document. This method may be called before the document initialization * (prepareTask) * has been completed, in such a case the document must not be modified. * @return document or null if it is not yet loaded */ public StyledDocument getDocument () { return del.getDocument (); } /** Test whether the document is in memory, or whether loading is still in progress. * @return true if document is loaded */ public boolean isDocumentLoaded() { return del.isDocumentLoaded (); } /** Save the document in this thread. * Create 'orig' document for the case that the save would fail. * @exception IOException on I/O error */ public void saveDocument () throws IOException { del.superSaveDocument (); } /** * Actually write file data to an output stream from an editor kit's document. * Called during a file save by {@link #saveDocument}. *

The default implementation just calls {@link EditorKit#write(OutputStream, Document, int, int) EditorKit.write(...)}. * Subclasses could override this to provide support for persistent guard blocks, for example. * @param doc the document to write from * @param kit the associated editor kit * @param stream the open stream to write to * @throws IOException if there was a problem writing the file * @throws BadLocationException should not normally be thrown * @see #loadFromStreamToKit */ protected void saveFromKitToStream (StyledDocument doc, EditorKit kit, OutputStream stream) throws IOException, BadLocationException { del.superSaveFromKitToStream (doc, kit, stream); } /** Test whether the document is modified. * @return true if the document is in memory and is modified; * otherwise false */ public boolean isModified () { return del.isModified (); } /** Finds data object the entry belongs to. * @return data object or null */ protected MultiDataObject findDataObject () { return entry.getDataObject (); } /** Create a position reference for the given offset. * The position moves as the document is modified and * reacts to closing and opening of the document. * * @param offset the offset to create position at * @param bias the Position.Bias for new creating position. * @return position reference for that offset */ public final PositionRef createPositionRef (int offset, Position.Bias bias) { return del.createPositionRef (offset, bias); } /** Get the line set for all paragraphs in the document. * @return positions of all paragraphs on last save */ public Line.Set getLineSet () { return del.getLineSet (); } // other public methods ................................................................ /** * Set the MIME type for the document. * @param s the new MIME type */ public void setMIMEType (String s) { del.setMIMEType (s); } /** @deprecated has no effect */ public void setActions (SystemAction[] actions) { } /** Creates editor kit for this source. * @return editor kit */ protected EditorKit createEditorKit () { return del.superCreateEditorKit (); } /** Utility method which enables or disables listening to modifications * on asociated document. *

* Could be useful if we have to modify document, but do not want the * Save and Save All actions to be enabled/disabled automatically. * Initially modifications are listened to. * @param listenToModifs whether to listen to modifications */ public void setModificationListening (final boolean listenToModifs) { this.listenToModifs = listenToModifs; } /** Adds a listener for status changes. An event is fired * when the document is moved or removed from memory. * @param l new listener */ public void addChangeListener (ChangeListener l) { del.addChangeListener (l); } /** Removes a listener for status changes. * @param l listener to remove */ public void removeChangeListener (ChangeListener l) { del.removeChangeListener (l); } public final void addPropertyChangeListener(java.beans.PropertyChangeListener l) { del.addPropertyChangeListener (l); } public final void removePropertyChangeListener(java.beans.PropertyChangeListener l) { del.removePropertyChangeListener (l); } /** The implementation of @see org.openide.cookies.PrintCookie#print() method. */ public void print() { del.print (); } /** * Actually read file data into an editor kit's document from an input stream. * Called during a file load by {@link #prepareDocument}. *

The default implementation just calls {@link EditorKit#read(InputStream, Document, int) EditorKit.read(...)}. * Subclasses could override this to provide support for persistent guard blocks, for example. * @param doc the document to read into * @param stream the open stream to read from * @param kit the associated editor kit * @throws IOException if there was a problem reading the file * @throws BadLocationException should not normally be thrown * @see #saveFromKitToStream */ protected void loadFromStreamToKit (StyledDocument doc, InputStream stream, EditorKit kit) throws IOException, BadLocationException { del.superLoadFromStreamToKit (doc, stream, kit); } /** Reload the document in response to external modification. * @see #reloadDocumentTask */ protected void reloadDocument() { reloadDocumentTask ().waitFinished (); } /** Starts reloading of document. Could not be named reloadDocument, * because of backward compatibility. * * @return task one can listen on when reloading the document */ protected Task reloadDocumentTask () { return del.superReloadDocument (); } /** Forcibly create one editor component. Then set the caret * to the given position. * @param pos where to place the caret * @return always non-null editor */ protected Editor openAt(PositionRef pos) { CloneableEditorSupport.Pane p = del.openAt (pos, -1); if (p instanceof Editor) { return (Editor)p; } java.awt.Component c = p.getEditorPane(); for (;;) { if (c instanceof Editor) { return (Editor)c; } c = c.getParent(); } } /** Should test whether all data is saved, and if not, prompt the user * to save. * * @return true if everything can be closed */ protected boolean canClose () { return del.superCanClose (); } /* List of all JEditorPane's opened by this editor support. * The first item in the array should represent the component * that is currently selected or has been selected lastly. * * @return array of panes or null if no pane is opened. * In no case empty array is returned. */ public JEditorPane[] getOpenedPanes () { return del.getOpenedPanes (); } /** Notification method called when the document become unmodified. * Called after save or after reload of document. */ protected void notifyUnmodified () { EditorSupport.this.modifySaveCookie (false); del.superNotifyUnmodified (); } /** Overrides the super method to add a save cookie if the * document has been marked modified. * * @return true if the environment accepted being marked as modified * or false if it refused it and the document should still be unmodified */ protected boolean notifyModified () { if (del.superNotifyModified ()) { EditorSupport.this.modifySaveCookie (true); return true; } else { return false; } } /** Called when the document is closed and released from memory. */ protected void notifyClosed() { del.superNotifyClosed (); } /** Utility method to extract EditorSupport from Del instance. * @param ces cloneable editor support * @return EditorSupport * @exception ClassCastException if the variables do not match */ static EditorSupport extract (CloneableEditorSupport ces) { EditorSupport.Del del = (Del)ces; return del.es (); } /** Modifies the save cookie, if necessary * @param add true if we should add the cookie */ final void modifySaveCookie (boolean add) { if (listenToModifs) { if (add) { ((EntryEnv)env).addSaveCookie (); } else { ((EntryEnv)env).removeSaveCookie (); } } } /** Cloneable top component to hold the editor kit. */ public static class Editor extends CloneableEditor { /** data object to work with */ protected DataObject obj; static final long serialVersionUID =-185739563792410059L; /** For externalization of subclasses only */ public Editor () { super(); } /** Constructor * @param obj data object we belong to. The appropriate editor support is * acquired as the DataObject's EditorSupport.class cookie. */ public Editor (DataObject obj) { this(obj, (EditorSupport)obj.getCookie(EditorSupport.class)); } /** Constructor * @param obj data object we belong to. * @param support editor support to use. */ public Editor (DataObject obj, EditorSupport support) { super (support.del); this.obj = obj; } /* Deserialize this top component. * @param in the stream to deserialize from */ public void readExternal (ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); Object ces = cloneableEditorSupport (); if (ces instanceof Del) { obj = ((Del)ces).getDataObjectHack2 (); } } } // end of Editor inner class /** Special implementation of CloneableEditorSupport that is used * by all methods of EditorSupport to delegate on it. */ private final class Del extends DataEditorSupport implements EditorCookie.Observable { /** Listener on node changes. */ private NodeListener nodeL; /** Constrcutor. Takes environemnt and ref object to replace * the default one */ public Del ( DataObject obj, CloneableEditorSupport.Env env, CloneableTopComponent.Ref ref ) { super (obj, env); this.allEditors = ref; } /** Getter */ public final EditorSupport es () { return EditorSupport.this; } protected void notifyUnmodified () { EditorSupport.this.notifyUnmodified (); } protected boolean notifyModified () { return EditorSupport.this.notifyModified (); } protected void notifyClosed() { EditorSupport.this.notifyClosed (); } final void superNotifyUnmodified () { super.notifyUnmodified (); } final boolean superNotifyModified () { return super.notifyModified (); } final void superNotifyClosed() { // #28256(#27645) Unregisters lisntening on node // when all components closed. nodeL = null; super.notifyClosed (); } protected CloneableEditor createCloneableEditor() { if (true) throw new IllegalStateException ("Do not call!"); CloneableTopComponent ctc = createCloneableTopComponent(); if(ctc instanceof Editor) { return (CloneableEditor)ctc; } else { return new Editor(getDataObject()); } } protected Pane createPane () { CloneableTopComponent ctc = createCloneableTopComponent(); if(ctc instanceof Editor) { return (CloneableEditor)ctc; } else { Pane pan = (Pane)ctc.getClientProperty("CloneableEditorSupport.Pane"); if (pan != null) { return pan; } if (ctc instanceof Pane) { return (Pane)ctc; } return new Editor(getDataObject()); } } // // Messages // protected String messageToolTip() { return EditorSupport.this.messageToolTip (); } protected String messageName() { return EditorSupport.this.messageName (); } protected String messageOpening() { return EditorSupport.this.messageOpening (); } protected String messageOpened() { return EditorSupport.this.messageOpened (); } protected String messageSave() { return EditorSupport.this.messageSave (); } protected void updateTitles () { EditorSupport.this.updateTitles (); } final String superMessageToolTip() { return super.messageToolTip (); } final String superMessageName() { return super.messageName (); } final String superMessageOpening() { return super.messageOpening (); } final String superMessageOpened() { return super.messageOpened (); } final String superMessageSave() { return super.messageSave (); } final void superUpdateTitles () { super.updateTitles (); } // // close // protected boolean close(boolean ask) { return EditorSupport.this.close (ask); } protected boolean superClose(boolean ask) { return super.close (ask); } /** Overrides superclass method. Delegates the creation * of component to enclosing class and adds initializing of * editor component. */ protected CloneableTopComponent createCloneableTopComponent() { CloneableTopComponent ctc = EditorSupport.this.createCloneableTopComponent (); if(ctc instanceof CloneableEditor) { initializeCloneableEditor((CloneableEditor)ctc); } return ctc; } /** Overrides superclass method. Initializes editor component. */ protected void initializeCloneableEditor (CloneableEditor editor) { DataObject obj = getDataObject(); if(obj.isValid()) { org.openide.nodes.Node ourNode = obj.getNodeDelegate(); editor.setActivatedNodes(new org.openide.nodes.Node[] {ourNode}); editor.setIcon(ourNode.getIcon (java.beans.BeanInfo.ICON_COLOR_16x16)); NodeListener nl = new DataNodeListener(editor); ourNode.addNodeListener(org.openide.nodes.NodeOp.weakNodeListener (nl, ourNode)); nodeL = nl; } } // // Stream manipulation // final void superLoadFromStreamToKit( StyledDocument doc,InputStream stream,EditorKit kit ) throws IOException, BadLocationException { super.loadFromStreamToKit (doc, stream, kit); } protected void loadFromStreamToKit( StyledDocument doc,InputStream stream,EditorKit kit ) throws IOException, BadLocationException { EditorSupport.this.loadFromStreamToKit (doc, stream, kit); } protected void superSaveFromKitToStream( StyledDocument doc,EditorKit kit,OutputStream stream ) throws IOException, BadLocationException { super.saveFromKitToStream (doc, kit, stream); } protected void saveFromKitToStream( StyledDocument doc,EditorKit kit,OutputStream stream ) throws IOException, BadLocationException { EditorSupport.this.saveFromKitToStream (doc, kit, stream); } protected Task reloadDocument () { return EditorSupport.this.reloadDocumentTask (); } final Task superReloadDocument () { return super.reloadDocument (); } public void saveDocument() throws IOException { EditorSupport.this.saveDocument(); } final void superSaveDocument() throws IOException { super.saveDocument(); } final UndoRedo.Manager superUndoRedoManager() { return super.createUndoRedoManager (); } // // Undo manager // protected UndoRedo.Manager createUndoRedoManager() { return EditorSupport.this.createUndoRedoManager (); } // // Editor kit // EditorKit superCreateEditorKit() { return super.createEditorKit (); } protected EditorKit createEditorKit() { return EditorSupport.this.createEditorKit (); } /* protected StyledDocument createStyledDocument(EditorKit kit) { return EditorSupport.this.createStyledDocument (kit); } */ // // canClose // final boolean superCanClose() { return super.canClose (); } protected boolean canClose() { return EditorSupport.this.canClose (); } /** Class which supports listening on node delegate. */ private final class DataNodeListener extends NodeAdapter { /** Asociated editor */ private final CloneableEditor editor; DataNodeListener (CloneableEditor editor) { this.editor = editor; } public void propertyChange (java.beans.PropertyChangeEvent ev) { if (Node.PROP_DISPLAY_NAME.equals(ev.getPropertyName())) { updateTitles(); } if (Node.PROP_ICON.equals(ev.getPropertyName())) { final DataObject obj = getDataObject(); if (obj.isValid()) { org.openide.util.Mutex.EVENT.writeAccess(new Runnable() { public void run() { editor.setIcon(obj.getNodeDelegate().getIcon ( java.beans.BeanInfo.ICON_COLOR_16x16)); } }); } } } } // End of DataNodeListener class. } /** Implementation of the default Environment for EditorSupport */ private static class EntryEnv extends DataEditorSupport.Env implements SaveCookie { /** generated Serialized Version UID */ static final long serialVersionUID = 354528097109874355L; /** Constructor. * @param obj this support should be associated with */ public EntryEnv (MultiDataObject obj) { super (obj); } /** Getter for file associated with this environment. * @return the file input/output operation should be performed on */ protected FileObject getFile () { return getDataObject ().getPrimaryFile (); } /** Locks the file. * @return the lock on the file getFile () * @exception IOException if the file cannot be locked */ protected FileLock takeLock () throws IOException { return ((MultiDataObject)getDataObject ()).getPrimaryEntry ().takeLock (); } /** Gives notification that the DataObject was changed. * @param ev PropertyChangeEvent */ public void propertyChange(PropertyChangeEvent ev) { if (DataObject.PROP_PRIMARY_FILE.equals(ev.getPropertyName())) { changeFile (); } if (DataObject.PROP_NAME.equals(ev.getPropertyName())) { EditorSupport es = (EditorSupport)getDataObject ().getCookie ( EditorSupport.class ); if (es != null) { es.updateTitles (); } } super.propertyChange (ev); } /** Invoke the save operation. * @throws IOException if the object could not be saved */ public void save() throws java.io.IOException { // Do not use findCloneableOpenSupport; it will not work if the // DataObject has both an EditorSupport and an OpenSupport attached // at once. EditorSupport es = (EditorSupport)getDataObject ().getCookie (EditorSupport.class); if (es == null) throw new IOException ("no EditorSupport found on this data object"); // NOI18N else es.saveDocument (); } /* void clearSaveCookie() { DataObject dataObj = findDataObject(); // remove save cookie (if save was succesfull) dataObj.setModified(false); releaseFileLock(); } */ /** Adds save cookie to the DO. */ final void addSaveCookie() { DataObject dataObj = getDataObject (); // add Save cookie to the data object if (dataObj instanceof MultiDataObject) { if (dataObj.getCookie(SaveCookie.class) == null) { getCookieSet((MultiDataObject)dataObj).add(this); } } } /** Removes save cookie from the DO. */ final void removeSaveCookie() { DataObject dataObj = getDataObject (); // add Save cookie to the data object if (dataObj instanceof MultiDataObject) { if (dataObj.getCookie(SaveCookie.class) == this) { getCookieSet((MultiDataObject)dataObj).remove(this); } } } // UGLY private static java.lang.reflect.Method getCookieSetMethod = null; private static final org.openide.nodes.CookieSet getCookieSet (MultiDataObject obj) { try { if (getCookieSetMethod == null) { getCookieSetMethod = MultiDataObject.class.getDeclaredMethod ("getCookieSet", new Class[] { }); // NOI18N getCookieSetMethod.setAccessible (true); } return (org.openide.nodes.CookieSet) getCookieSetMethod.invoke (obj, new Object[] { }); } catch (Exception e) { ErrorManager.getDefault().notify(e); return new org.openide.nodes.CookieSet (); } } /** Method that allows environment to find its * cloneable open support. * @return the support or null if the environemnt is not in valid * state and the CloneableOpenSupport cannot be found for associated * data object */ public CloneableOpenSupport findCloneableOpenSupport() { CloneableOpenSupport s = super.findCloneableOpenSupport (); if (s != null) { return s; } EditorSupport es = (EditorSupport)getDataObject ().getCookie (EditorSupport.class); if (es != null) { return es.del; } else { return null; } } } // end of EntryEnv /** Environment for delegating object. */ private static final class DelEnv extends EntryEnv { /** generated Serialized Version UID */ static final long serialVersionUID = 174320972368471234L; public DelEnv (MultiDataObject obj) { super (obj); } /** Finds delegating environment for this editor object. */ public CloneableOpenSupport findCloneableOpenSupport() { // Svata: is this really needed ? EditorSupport does not implement CloneableOpenSupport anyway. CloneableOpenSupport o = super.findCloneableOpenSupport (); if (o instanceof EditorSupport) { EditorSupport es = (EditorSupport)o; return es.del; } return o; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy