/* * 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-2004 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.core.spi.multiview; import javax.swing.Action; /** * instances of this class describe the MultiViewElement's state when the component is * about to be closed. (See MultiViewElement.canCloseElement()) */ public final class CloseOperationState { public final static String ID_CLOSE_OK = "safe"; //NOI18N /** * Singleton instance of a close operation state, to be used whenever MultiViewElement is in consistent state * and can be safely closed. */ public static final CloseOperationState STATE_OK = MultiViewFactory.createSafeCloseState(); private boolean canClose; private String id; private Action proceedAction; private Action discardAction; CloseOperationState(boolean close, String warningId, Action proceed, Action discard) { canClose = close; proceedAction = proceed; discardAction = discard; id = warningId; } /** * The return value denotes wheather the MultiViewElement can be closed or not. */ public boolean canClose() { return canClose; } /** * A preferably unique id of the reason why the element cannot be closed. * CloseOperationHandler implementation can use it when deciding about UI shown or action taken. */ public String getCloseWarningID() { return id; } /** * Action is used when user wants to complete the closing of the component without loosing changed data. * Used by CloseOperationHandler. */ public Action getProceedAction() { return proceedAction; } /** * Action is used when user wants to complete the closing of the component and discard any changes. * Used by CloseOperationHandler. */ public Action getDiscardAction() { return discardAction; } } /* * 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-2004 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.core.spi.multiview; /** * Handles closing of the MultiView component globally. Each opened MultiViewElement * creates a CloseOperationState instance to notify the environment of it's internal state. * * @author Milos Kleint */ public interface CloseOperationHandler { /** * Perform the closeOperation on the opened elements in the multiview topcomponent. * Can resolve by itself just based on the states of the elements or ask the user for * the decision. * @param elements - CloseOperationState instances of MultiViewElements that cannot be * closed and require resolution. * @returns true if component can be close, false if it shall remain opened. */ boolean resolveCloseOperation(CloseOperationState[] elements); } Index: MultiViewElement.java =================================================================== RCS file: /cvs/core/multiview/src/org/netbeans/core/spi/multiview/Attic/MultiViewElement.java,v retrieving revision 1.1.2.3 retrieving revision 1.1.2.4 diff -c -r1.1.2.3 -r1.1.2.4 *** MultiViewElement.java 26 Apr 2004 13:13:07 -0000 1.1.2.3 --- MultiViewElement.java 28 Apr 2004 07:20:30 -0000 1.1.2.4 *************** *** 30,55 **** /** Returns Swing visual representation of this multi view element. Should be relatively fast * and always return the same component. */ ! public JComponent getVisualRepresentation (); /** * Returns the visual component with the multi view element's toolbar.Should be relatively fast as it's called * everytime the current perspective is switched. */ ! public JComponent getToolbarRepresentation (); /** Gets the actions which will appear in the popup menu of this component. *

Subclasses are encouraged to use add the default TopComponent actions to * the array of their own. These are accessible by calling MultiViewElementCallback.createDefaultActions() * @return array of actions for this component */ ! public Action[] getActions(); /** * Lookup for the MultiViewElement. Will become part of the TopComponent's lookup. * @return the lookup to use when the MultiViewElement is active. */ ! public Lookup getLookup(); /** Called only when enclosing multi view top component was closed before and --- 30,55 ---- /** Returns Swing visual representation of this multi view element. Should be relatively fast * and always return the same component. */ ! JComponent getVisualRepresentation (); /** * Returns the visual component with the multi view element's toolbar.Should be relatively fast as it's called * everytime the current perspective is switched. */ ! JComponent getToolbarRepresentation (); /** Gets the actions which will appear in the popup menu of this component. *

Subclasses are encouraged to use add the default TopComponent actions to * the array of their own. These are accessible by calling MultiViewElementCallback.createDefaultActions() * @return array of actions for this component */ ! Action[] getActions(); /** * Lookup for the MultiViewElement. Will become part of the TopComponent's lookup. * @return the lookup to use when the MultiViewElement is active. */ ! Lookup getLookup(); /** Called only when enclosing multi view top component was closed before and *************** *** 57,86 **** * provide subclasses information about multi view TopComponent's life cycle. * Subclasses will usually perform initializing tasks here. */ ! public void componentOpened(); /** Called only when multi view top component was closed. The intent is * to provide subclasses information about TopComponent's life cycle. * Subclasses will usually perform cleaning tasks here. */ ! public void componentClosed(); /** Called when this MultiViewElement is about to be shown. * That can happen when switching the current perspective/view or when the topcomonent itself is shown for the first time. */ ! public void componentShowing(); /** Called when this MultiViewElement was hidden. This happens when other view replaces this one as the selected view or * when the whole topcomponent gets hidden (eg. when user selects anothe topcomponent in the current mode). */ ! public void componentHidden(); /** Called when this multi view element is activated. * This happens when the parent window of this component gets focus * (and this component is the preferred one in it), or when * this component is selected in its window (and its window was already focused). */ ! public void componentActivated (); /** Called when this multi view element is deactivated. * This happens when the parent window of this component loses focus --- 57,86 ---- * provide subclasses information about multi view TopComponent's life cycle. * Subclasses will usually perform initializing tasks here. */ ! void componentOpened(); /** Called only when multi view top component was closed. The intent is * to provide subclasses information about TopComponent's life cycle. * Subclasses will usually perform cleaning tasks here. */ ! void componentClosed(); /** Called when this MultiViewElement is about to be shown. * That can happen when switching the current perspective/view or when the topcomonent itself is shown for the first time. */ ! void componentShowing(); /** Called when this MultiViewElement was hidden. This happens when other view replaces this one as the selected view or * when the whole topcomponent gets hidden (eg. when user selects anothe topcomponent in the current mode). */ ! void componentHidden(); /** Called when this multi view element is activated. * This happens when the parent window of this component gets focus * (and this component is the preferred one in it), or when * this component is selected in its window (and its window was already focused). */ ! void componentActivated (); /** Called when this multi view element is deactivated. * This happens when the parent window of this component loses focus *************** *** 88,94 **** * or when this component loses preference in the parent window * (and the parent window is focussed). */ ! public void componentDeactivated (); /** * UndoRedo support, --- 88,94 ---- * or when this component loses preference in the parent window * (and the parent window is focussed). */ ! void componentDeactivated (); /** * UndoRedo support, *************** *** 96,102 **** * * @return undoable edit for this component, null if not implemented. */ ! public UndoRedo getUndoRedo(); /** --- 96,102 ---- * * @return undoable edit for this component, null if not implemented. */ ! UndoRedo getUndoRedo(); /** *************** *** 104,113 **** * the element from the description. Same applies for deserialization of MultiViewTopComponent. * Implementors shall not attempt to serialize the passed instance. */ ! public void setMultiViewCallback (MultiViewElementCallback callback); ! //MK - how is this supposed to work? who and when will call it? ! // public void removeActionRequestObserver (); } --- 104,119 ---- * the element from the description. Same applies for deserialization of MultiViewTopComponent. * Implementors shall not attempt to serialize the passed instance. */ ! void setMultiViewCallback (MultiViewElementCallback callback); ! /** ! * Element decides if it can be safely closed. The element shall just return a value ! * (created by MultiViewFactory.createCloseState() factory method), ! * not open any UI, that is a semantical difference from TopComponent.canClose(). ! * The CloseOperationHandler is the centralized place to show dialogs to the user. ! * In cases when the element is consistent, just return CloseOperationState.STATE_OK. ! */ ! CloseOperationState canCloseElement(); } Index: MultiViewFactory.java =================================================================== RCS file: /cvs/core/multiview/src/org/netbeans/core/spi/multiview/Attic/MultiViewFactory.java,v retrieving revision 1.1.2.2 retrieving revision 1.1.2.4 diff -c -r1.1.2.2 -r1.1.2.4 *** MultiViewFactory.java 26 Apr 2004 07:01:15 -0000 1.1.2.2 --- MultiViewFactory.java 28 Apr 2004 13:12:45 -0000 1.1.2.4 *************** *** 13,25 **** --- 13,37 ---- package org.netbeans.core.spi.multiview; + import java.awt.BorderLayout; + import java.awt.event.ActionEvent; import java.io.Serializable; + import java.util.ArrayList; + import java.util.Collection; + import java.util.Iterator; + import javax.swing.AbstractAction; import javax.swing.Action; + import javax.swing.JButton; import javax.swing.JComponent; + import javax.swing.JLabel; + import javax.swing.JList; import javax.swing.JPanel; + import javax.swing.JScrollPane; import javax.swing.JToolBar; import javax.swing.text.Document; import org.netbeans.core.multiview.MultiViewTopComponent; + import org.openide.DialogDisplayer; + import org.openide.NotifyDescriptor; import org.openide.text.CloneableEditor; import org.openide.text.NbDocument; import org.openide.util.Lookup; *************** *** 36,41 **** --- 48,60 ---- */ public final static MultiViewElement BLANK_ELEMENT = new Blank(); + /** + * a utility noop action instance to be used when no special handling is + * required in createUnsafeCloseState() method. + */ + public final static Action NOOP_CLOSE_ACTION = new NoopAction(); + + /** Factory class, no instances. */ private MultiViewFactory () { *************** *** 44,60 **** /** Creates and returns new instance of top component with * multi views */ public static TopComponent createMultiView (MultiViewDescription[] descriptions, MultiViewDescription defaultDesc) { ! // PENDING - data context of MVTC? if (descriptions == null) return null; MultiViewTopComponent tc = new MultiViewTopComponent(); tc.setMultiViewDescriptions(descriptions, defaultDesc); return tc; } ! // public static MultiViewElement createElement(CloneableEditor editor) { ! // //TODO ! // return null; ! // } private static final class Blank implements MultiViewElement, Serializable { --- 63,109 ---- /** Creates and returns new instance of top component with * multi views */ public static TopComponent createMultiView (MultiViewDescription[] descriptions, MultiViewDescription defaultDesc) { ! return createMultiView(descriptions, defaultDesc, createDefaultCloseOpHandler()); ! } ! ! /** Creates and returns new instance of top component with ! * multi views. ! * @param CloseOperationHandler handles closing of the multiview component. ! */ ! public static TopComponent createMultiView (MultiViewDescription[] descriptions, MultiViewDescription defaultDesc, ! CloseOperationHandler closeHandler) { if (descriptions == null) return null; + if (closeHandler == null) closeHandler = createDefaultCloseOpHandler(); MultiViewTopComponent tc = new MultiViewTopComponent(); tc.setMultiViewDescriptions(descriptions, defaultDesc); + tc.setCloseOperationHandler(closeHandler); return tc; } ! /** ! * Utility method for MultiViewElements to create a CloseOperationState instance that ! * informs the environment that the MVElement is ok to be closed. ! */ ! ! static CloseOperationState createSafeCloseState() { ! return new CloseOperationState(true, CloseOperationState.ID_CLOSE_OK, NOOP_CLOSE_ACTION, NOOP_CLOSE_ACTION); ! } ! ! /** ! * Utility method for MultiViewElements to create a CloseOperationState instance ! * that warns about possible data loss. Corrective actions can be defined. ! */ ! ! public static CloseOperationState createUnsafeCloseState(String warningId, Action proceedAction, Action discardAction) { ! return new CloseOperationState(false, ! (warningId == null ? "" : warningId), ! (proceedAction == null ? NOOP_CLOSE_ACTION : proceedAction), ! (discardAction == null ? NOOP_CLOSE_ACTION : discardAction)); ! } ! ! static CloseOperationHandler createDefaultCloseOpHandler() { ! return new DefaultCloseHandler(); ! } private static final class Blank implements MultiViewElement, Serializable { *************** *** 104,170 **** public void setMultiViewCallback(MultiViewElementCallback callback) { } - public boolean canClose() { - return true; - } public org.openide.awt.UndoRedo getUndoRedo() { return null; } } ! ! // private static final class EditorElement implements MultiViewElement, Serializable { ! // private CloneableEditor editor; ! // private transient JComponent bar; ! // ! // public EditorElement(CloneableEditor edit) { ! // editor = edit; ! // } ! // ! // public JComponent getToolbarRepresentation() { ! // Document doc = editor.getEditorPane().getDocument(); ! // if (doc instanceof NbDocument.CustomToolbar) { ! // if (bar == null) { ! // bar = ((NbDocument.CustomToolbar)doc).createToolbar(editor.getEditorPane()); ! // } ! // return bar; // } ! // return null; ! // } ! // ! // public javax.swing.JComponent getVisualRepresentation() { ! // return editor; ! // } ! // ! // public void componentActivated() { ! // } ! // ! // public void componentClosed() { ! // } ! // ! // public void componentDeactivated() { ! // } ! // ! // public void componentHidden() { ! // } ! // ! // public void componentOpened() { ! // } ! // ! // public void componentShowing() { // } ! // ! // public Action[] getActions() { ! // return editor.getActions(); ! // } ! // ! // public Lookup getLookup() { ! // return editor.getLookup(); ! // } ! // ! // public void setMultiViewCallback(org.netbeans.core.spi.multiview.MultiViewElementCallback callback) { ! // } ! // ! // } } --- 153,254 ---- public void setMultiViewCallback(MultiViewElementCallback callback) { } public org.openide.awt.UndoRedo getUndoRedo() { return null; } + public CloseOperationState canCloseElement() { + return CloseOperationState.STATE_OK; + } + } ! ! /** ! * default simple implementation of the close handler. ! */ ! private static final class DefaultCloseHandler implements CloseOperationHandler, Serializable { ! private static final long serialVersionUID =-3126744916624172427L; ! ! public boolean resolveCloseOperation(CloseOperationState[] elements) { ! if (elements != null) { ! boolean canBeClosed = true; ! Collection badOnes = new ArrayList(); ! for (int i = 0; i < elements.length; i++) { ! if (!elements[i].canClose()) { ! badOnes.add(elements[i]); ! canBeClosed = false; ! } ! } ! if (!canBeClosed) { ! //TODO SHOW dialog here. ! throw new IllegalStateException("Cannot close component. Some of the elements require close operation handling. See MultiViewFactory.createMultiView()"); ! // Object[] options = new Object[] { ! // new JButton("Proceed"), ! // new JButton("Discard"), ! // new JButton("Cancel") ! // }; ! // NotifyDescriptor desc = new NotifyDescriptor(createPanel(badOnes), "Cannot close component.", ! // NotifyDescriptor.DEFAULT_OPTION, NotifyDescriptor.WARNING_MESSAGE, ! // options, options[0]); ! // Object retVal = DialogDisplayer.getDefault().notify(desc); ! // if (retVal == options[0]) { ! // // do proceed. ! // Iterator it = badOnes.iterator(); ! // while (it.hasNext()) { ! // Action act = ((CloseOperationState)it.next()).getProceedAction(); ! // if (act != null) { ! // act.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "proceed")); ! // } ! // } ! // } else if (retVal == options[1]) { ! // // do discard ! // Iterator it = badOnes.iterator(); ! // while (it.hasNext()) { ! // Action act = ((CloseOperationState)it.next()).getDiscardAction(); ! // if (act != null) { ! // act.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "discard")); ! // } ! // } ! // } else { ! // // was cancel.. ! // return false; ! // } ! } ! } ! return true; ! } ! ! // private JPanel createPanel(Collection elems) { ! // JPanel panel = new JPanel(); ! // panel.setLayout(new BorderLayout()); ! // JLabel lbl = new JLabel("Cannot safely close component for following reasons:"); ! // panel.add(lbl, BorderLayout.NORTH); ! // JScrollPane pane = new JScrollPane(); ! // String[] warnings = new String[elems.size()]; ! // int index = 0; ! // Iterator it = elems.iterator(); ! // while (it.hasNext()) { ! // CloseOperationState state = (CloseOperationState)it.next(); ! // warnings[index] = state.getCloseWarningMessage(); ! // index = index + 1; // } ! // JList list = new JList(warnings); ! // pane.setViewportView(list); ! // panel.add(pane); ! // return panel; // } ! } ! ! /** ! * just a default noon action to put into the closeoperation state. ! */ ! private static final class NoopAction extends AbstractAction { ! ! public void actionPerformed(java.awt.event.ActionEvent e) { ! // do nothing ! } ! ! } ! }