+
+ EditorContextDispatcher
class added.
+
+
+
+
+
+
+ EditorContextDispatcher
class added, in order to simplify the access to current
+ active elements in the IDE (like current FileObject and editor pane) and
+ to make the events dispatching more efficient - reduce the number of listeners on context switching.
+ EditorContextDispatcher
allows registration of listeners based on files MIME type, therefore
+ listeners obtain change events only when context change concerns a file of the given MIME type.
+
+
+
+
+
+
+
diff -r 766e8327016d spi.debugger.ui/manifest.mf
--- a/spi.debugger.ui/manifest.mf Fri Jun 06 19:28:24 2008 +0200
+++ b/spi.debugger.ui/manifest.mf Fri Jun 13 11:53:44 2008 +0200
@@ -2,6 +2,6 @@ OpenIDE-Module: org.netbeans.spi.debugge
OpenIDE-Module: org.netbeans.spi.debugger.ui/1
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/debugger/ui/Bundle.properties
OpenIDE-Module-Layer: org/netbeans/modules/debugger/resources/mf-layer.xml
-OpenIDE-Module-Specification-Version: 2.12
+OpenIDE-Module-Specification-Version: 2.13
OpenIDE-Module-Provides: org.netbeans.spi.debugger.ui
OpenIDE-Module-Install: org/netbeans/modules/debugger/ui/DebuggerModule.class
diff -r 766e8327016d spi.debugger.ui/nbproject/project.xml
--- a/spi.debugger.ui/nbproject/project.xml Fri Jun 06 19:28:24 2008 +0200
+++ b/spi.debugger.ui/nbproject/project.xml Fri Jun 13 11:53:44 2008 +0200
@@ -98,6 +98,14 @@ made subject to such option by the copyr
org.openide.loaders
diff -r 766e8327016d spi.debugger.ui/src/org/netbeans/spi/debugger/ui/EditorContextDispatcher.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/spi.debugger.ui/src/org/netbeans/spi/debugger/ui/EditorContextDispatcher.java Fri Jun 13 11:53:44 2008 +0200
@@ -0,0 +1,627 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2008 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.spi.debugger.ui;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.swing.JEditorPane;
+import javax.swing.text.Caret;
+import javax.swing.text.StyledDocument;
+
+import org.openide.cookies.EditorCookie;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileStateInvalidException;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectNotFoundException;
+import org.openide.text.Line;
+import org.openide.text.NbDocument;
+import org.openide.util.Lookup;
+import org.openide.util.LookupEvent;
+import org.openide.util.LookupListener;
+import org.openide.util.RequestProcessor;
+import org.openide.util.Utilities;
+import org.openide.util.WeakListeners;
+import org.openide.windows.TopComponent;
+
+/**
+ * Dispatcher of context-related events and provider of active elements in the IDE.
+ *
+ * This class tracks the changes of the selected file and active editor and re-fires
+ * the changes to registered listeners. The listeners can register based on
+ * a MIME type of files which they are interested in. This prevents from unnecessary
+ * activity of debugging actions when the context is switched among unrelated files.
+ *
+ *
The EditorContextDispatcher provides convenient access to currently selected
+ * elements and recently selected elements in the GUI.
+ *
+ *
Typical usage:
+ * Attach a listener based on file MIME type. The usage of WeakListeners is
+ * preferred, unless the listener can be removed explicitely.
+ *
+ * EditorContextDispatcher.getDefault().addPropertyChangeListener("<MIME type>",
+ * WeakListeners.propertyChange(dispatchListener, EditorContextDispatcher.getDefault()));
+ *
+ * Then use getCurrent*()
methods to find the currently selected
+ * elements in the IDE.
+ * If recently selected elements are desired, use getMostRecent*()
+ * methods. They provide current elements if available, or elements that were
+ * current the last time.
+ *
+ *
+ * @author Martin Entlicher
+ * @since 2.13
+ */
+public final class EditorContextDispatcher {
+
+ /**
+ * Name of property fired when the current file changes.
+ */
+ public static final String PROP_FILE = "file"; // NOI18N
+ /**
+ * Name of property fired when the current editor changes.
+ */
+ public static final String PROP_EDITOR = "editor"; // NOI18N
+
+ private static EditorContextDispatcher context;
+
+ /**
+ * Get the default instance of EditorContextDispatcher.
+ * @return The EditorContextDispatcher
+ */
+ public static synchronized EditorContextDispatcher getDefault() {
+ if (context == null) {
+ context = new EditorContextDispatcher();
+ }
+ return context;
+ }
+
+
+ private final RequestProcessor refreshProcessor;
+ private final Lookup.Result resFileObject;
+ private final Lookup.Result resEditorCookie;
+ private final PropertyChangeListener tcListener;
+
+ private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+ private final Map pcsByMIMEType = new HashMap();
+
+ private String lastFiredMIMEType = null;
+ private Map lastMIMETypeEvents = new HashMap();
+
+ private String currentURL;
+ private FileObject currentFile = null;
+ private EditorCookie currentEditorCookie = null;
+ private JEditorPane currentOpenedPane = null;
+
+ // Most recent in editor:
+ private Reference mostRecentFileRef = new WeakReference(null);
+ private Reference mostRecentEditorCookieRef = new WeakReference(null);
+ private Reference mostRecentOpenedPaneRef = new WeakReference(null);
+
+ private EditorContextDispatcher() {
+ refreshProcessor = new RequestProcessor("Refresh Editor Context", 1); // NOI18N
+
+ resFileObject = Utilities.actionsGlobalContext().lookupResult(FileObject.class);
+ resFileObject.addLookupListener(new EditorLookupListener(FileObject.class));
+
+ resEditorCookie = Utilities.actionsGlobalContext().lookupResult(EditorCookie.class);
+ resEditorCookie.addLookupListener(new EditorLookupListener(EditorCookie.class));
+
+ tcListener = new EditorLookupListener(TopComponent.class);
+ TopComponent.getRegistry ().addPropertyChangeListener (WeakListeners.propertyChange(
+ tcListener, TopComponent.getRegistry()));
+ }
+
+ /**
+ * Get the current active file.
+ * @return The current file or null
when there is no active file.
+ */
+ public synchronized FileObject getCurrentFile() {
+ return currentFile;
+ }
+
+ /**
+ * Get the String representation of URL of the current active file.
+ * @return The String representation of URL of the current active file or
+ * an empty String when there is no active file.
+ */
+ public synchronized String getCurrentURLAsString() {
+ if (currentURL == null) {
+ FileObject fo = getCurrentFile();
+ if (fo != null) {
+ try {
+ currentURL = fo.getURL().toString ();
+ } catch (FileStateInvalidException ex) {}
+ }
+ if (currentURL == null) {
+ currentURL = ""; // NOI18N
+ }
+ }
+ return currentURL;
+ }
+
+ /**
+ * Get the {@link org.openide.cookies.EditorCookie} of currently edited file.
+ * @return The current {@link org.openide.cookies.EditorCookie} or
+ * null
when there is no currently edited file.
+ */
+ private synchronized EditorCookie getCurrentEditorCookie() {
+ if (currentOpenedPane != null) {
+ return currentEditorCookie;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the {@link javax.swing.JEditorPane} of currently edited file.
+ * @return The current {@link javax.swing.JEditorPane} or
+ * null
when there is no currently edited file.
+ */
+ public synchronized JEditorPane getCurrentEditor() {
+ return currentOpenedPane;
+ }
+
+ /**
+ * Get the line number of the caret in the current editor.
+ * @return the line number or -1
when there is no current editor.
+ */
+ public int getCurrentLineNumber() {
+ EditorCookie e = getCurrentEditorCookie ();
+ if (e == null) return -1;
+ JEditorPane ep = getCurrentEditor ();
+ if (ep == null) return -1;
+ StyledDocument d = e.getDocument ();
+ if (d == null) return -1;
+ Caret caret = ep.getCaret ();
+ if (caret == null) return -1;
+ int ln = NbDocument.findLineNumber (
+ d,
+ caret.getDot ()
+ );
+ return ln + 1;
+ }
+
+ /**
+ * Get the line of the caret in the current editor.
+ * @return the line or null
when there is no current editor.
+ */
+ public Line getCurrentLine() {
+ EditorCookie e = getCurrentEditorCookie ();
+ if (e == null) return null;
+ JEditorPane ep = getCurrentEditor ();
+ if (ep == null) return null;
+ StyledDocument d = e.getDocument ();
+ if (d == null) return null;
+ Caret caret = ep.getCaret ();
+ if (caret == null) return null;
+ int lineNumber = NbDocument.findLineNumber(d, caret.getDot());
+ Line.Set lineSet = e.getLineSet();
+ try {
+ assert lineSet != null : e;
+ return lineSet.getCurrent(lineNumber);
+ } catch (IndexOutOfBoundsException ex) {
+ return null;
+ }
+ }
+
+ /**
+ * Get the most recent active file. This returns the active file if there's
+ * one, or a file, that was most recently active.
+ * @return The most recent file or null
when there was no recent
+ * active file.
+ */
+ public synchronized FileObject getMostRecentFile() {
+ return mostRecentFileRef.get();
+ }
+
+ /**
+ * Get the String representation of URL of the most recent active file.
+ * @return The String representation of URL of the most recent file or
+ * an empty String when there was no recent active file.
+ */
+ public synchronized String getMostRecentURLAsString() {
+ FileObject fo = getMostRecentFile();
+ if (fo != null) {
+ try {
+ return fo.getURL().toString ();
+ } catch (FileStateInvalidException ex) {}
+ }
+ return ""; // NOI18N
+ }
+
+ private synchronized EditorCookie getMostRecentEditorCookie() {
+ if (getMostRecentEditor() != null) {
+ return mostRecentEditorCookieRef.get();
+ } else {
+ return null;
+ }
+ }
+
+ public synchronized JEditorPane getMostRecentEditor() {
+ return mostRecentOpenedPaneRef.get();
+ }
+
+ /**
+ * Get the line number of the caret in the most recent editor.
+ * This returns the current line number in the current editor if there's one,
+ * or a line number of the caret in the editor, that was most recently active.
+ * @return the line number or -1
when there was no recent active editor.
+ */
+ public int getMostRecentLineNumber() {
+ EditorCookie e = getMostRecentEditorCookie ();
+ if (e == null) return -1;
+ JEditorPane ep = getMostRecentEditor ();
+ if (ep == null) return -1;
+ StyledDocument d = e.getDocument ();
+ if (d == null) return -1;
+ Caret caret = ep.getCaret ();
+ if (caret == null) return -1;
+ int ln = NbDocument.findLineNumber (
+ d,
+ caret.getDot ()
+ );
+ return ln + 1;
+ }
+
+ /**
+ * Get the line of the caret in the most recent editor.
+ * This returns the current line in the current editor if there's one,
+ * or a line of the caret in the editor, that was most recently active.
+ * @return the line or null
when there was no recent active editor.
+ */
+ public Line getMostRecentLine() {
+ EditorCookie e = getMostRecentEditorCookie ();
+ if (e == null) return null;
+ JEditorPane ep = getMostRecentEditor ();
+ if (ep == null) return null;
+ StyledDocument d = e.getDocument ();
+ if (d == null) return null;
+ Caret caret = ep.getCaret ();
+ if (caret == null) return null;
+ int lineNumber = NbDocument.findLineNumber(d, caret.getDot());
+ Line.Set lineSet = e.getLineSet();
+ try {
+ return lineSet.getCurrent(lineNumber);
+ } catch (IndexOutOfBoundsException ex) {
+ return null;
+ }
+ }
+
+ /**
+ * Add a PropertyChangeListener to this context dispatcher.
+ * It's strongly suggested to use {@link #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)}
+ * instead, if possible, for performance reasons.
+ * @param l The PropertyChangeListener
+ */
+ public void addPropertyChangeListener(PropertyChangeListener l) {
+ pcs.addPropertyChangeListener(l);
+ }
+
+ /**
+ * Remove a PropertyChangeListener from this context dispatcher.
+ * @param l The PropertyChangeListener
+ */
+ public void removePropertyChangeListener(PropertyChangeListener l) {
+ pcs.removePropertyChangeListener(l);
+ // Also remove the listener from all MIME types
+ synchronized (pcsByMIMEType) {
+ Set MIMETypes = new HashSet(pcsByMIMEType.keySet());
+ for (String MIMEType : MIMETypes) {
+ PropertyChangeSupport pcs = pcsByMIMEType.get(MIMEType);
+ pcs.removePropertyChangeListener(l);
+ if (pcs.getPropertyChangeListeners().length == 0) {
+ pcsByMIMEType.remove(MIMEType);
+ }
+ }
+ }
+ }
+
+ /**
+ * Add a PropertyChangeListener to this context dispatcher to be notified
+ * about changes of files with a specified MIME type.
+ * @param MIMEType The MIME type to report changes for
+ * @param l The PropertyChangeListener
+ */
+ public void addPropertyChangeListener(String MIMEType, PropertyChangeListener l) {
+ PropertyChangeSupport pcs;
+ synchronized (pcsByMIMEType) {
+ pcs = pcsByMIMEType.get(MIMEType);
+ if (pcs == null) {
+ pcs = new PropertyChangeSupport(this);
+ pcsByMIMEType.put(MIMEType, pcs);
+ }
+ }
+ pcs.addPropertyChangeListener(l);
+ }
+
+ /*public void removePropertyChangeListener(String MIMEType, PropertyChangeListener l) {
+ PropertyChangeSupport pcs;
+ synchronized (pcsByMIMEType) {
+ pcs = pcsByMIMEType.get(MIMEType);
+ if (pcs == null) {
+ return ;
+ }
+ }
+ pcs.removePropertyChangeListener(l);
+ }*/
+
+ private void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
+ //System.err.println("EditorContextDispatcher.firePropertyChange("+propertyName+", "+oldValue+", "+newValue+")");
+ pcs.firePropertyChange(propertyName, oldValue, newValue);
+ }
+
+ private void firePropertyChange(PropertyChangeEvent evt, String preferredMIMEType) {
+ //System.err.println("EditorContextDispatcher.firePropertyChange("+evt.getPropertyName()+", "+evt.getOldValue()+", "+evt.getNewValue()+")");
+ pcs.firePropertyChange(evt);
+ if (PROP_FILE.equals(evt.getPropertyName())) {
+ // Retrieve the files MIME types and fire to appropriate MIME type listeners:
+ FileObject oldFile = (FileObject) evt.getOldValue();
+ FileObject newFile = (FileObject) evt.getNewValue();
+ String oldMIMEType = (oldFile != null) ? oldFile.getMIMEType() : null;
+ String newMIMEType = (newFile != null) ? newFile.getMIMEType() : null;
+ PropertyChangeSupport pcsMIMEOld = null, pcsMIMENew = null;
+ PropertyChangeEvent evtOld = null, evtNew = null;
+ synchronized (pcsByMIMEType) {
+ if (oldMIMEType != null && oldMIMEType.equals(newMIMEType)) {
+ pcsMIMEOld = pcsByMIMEType.get(oldMIMEType);
+ evtOld = evt;
+ //System.err.println("EditorContextDispatcher.fireMIMETypeChange("+oldMIMEType+", "+evt.getPropertyName()+", "+evt.getOldValue()+", "+evt.getNewValue()+")");
+ } else {
+ if (oldMIMEType != null) {
+ pcsMIMEOld = pcsByMIMEType.get(oldMIMEType);
+ if (pcsMIMEOld != null) {
+ evtOld = new PropertyChangeEvent(evt.getSource(),
+ evt.getPropertyName(),
+ evt.getOldValue(),
+ null);
+ }
+ //System.err.println("EditorContextDispatcher.fireMIMETypeChange("+oldMIMEType+", "+evt.getPropertyName()+", "+evt.getOldValue()+", null)");
+ }
+ if (newMIMEType != null) {
+ pcsMIMENew = pcsByMIMEType.get(newMIMEType);
+ if (pcsMIMENew != null) {
+ evtNew = new PropertyChangeEvent(evt.getSource(),
+ evt.getPropertyName(),
+ null,
+ evt.getNewValue());
+ }
+ //System.err.println("EditorContextDispatcher.fireMIMETypeChange("+newMIMEType+", "+evt.getPropertyName()+", null, "+evt.getNewValue()+")");
+ }
+ }
+ }
+ if (pcsMIMEOld != null) {
+ pcsMIMEOld.firePropertyChange(evtOld);
+ }
+ if (pcsMIMENew != null) {
+ pcsMIMENew.firePropertyChange(evtNew);
+ }
+ // Now check, whether the MIME type has changed and whether we should
+ // fire non-file change events with 'null' new values to listeners
+ // registered for a particular MIME type:
+ if (oldMIMEType != null && !oldMIMEType.equals(newMIMEType) && pcsMIMEOld != null) {
+ String lastMIMEType;
+ Map lastEvents;
+ synchronized (this) {
+ lastMIMEType = lastFiredMIMEType;
+ lastEvents = new HashMap(lastMIMETypeEvents);
+ if (lastMIMEType != null && lastMIMEType.equals(oldMIMEType)) {
+ lastFiredMIMEType = null;
+ lastMIMETypeEvents.clear();
+ } else {
+ lastEvents = null;
+ }
+ }
+ if (lastEvents != null) {
+ for (String property : lastEvents.keySet()) {
+ pcsMIMEOld.firePropertyChange(property, lastEvents.get(property), null);
+ }
+ }
+ }
+ } else {
+ PropertyChangeSupport pcsMIME = null;
+ if (preferredMIMEType != null) {
+ synchronized (pcsByMIMEType) {
+ pcsMIME = pcsByMIMEType.get(preferredMIMEType);
+ }
+ if (pcsMIME != null) {
+ pcsMIME.firePropertyChange(evt);
+ }
+ }
+ //System.err.println("EditorContextDispatcher.fireMIMETypeChange("+preferredMIMEType+", "+evt.getPropertyName()+", "+evt.getOldValue()+", "+evt.getNewValue()+")");
+ synchronized (this) {
+ if (pcsMIME != null) {
+ lastFiredMIMEType = preferredMIMEType;
+ lastMIMETypeEvents.put(evt.getPropertyName(), evt.getNewValue());
+ } else {
+ lastFiredMIMEType = null;
+ lastMIMETypeEvents.clear();
+ }
+ }
+ }
+ }
+
+ private class EditorLookupListener extends Object implements LookupListener, PropertyChangeListener {
+
+ private Class type;
+
+ public EditorLookupListener(Class type) {
+ this.type = type;
+ }
+
+ public void resultChanged(LookupEvent ev) {
+ //System.err.println("EditorContextDispatcher.resultChanged(), type = "+type);
+ if (type == FileObject.class) {
+ Collection extends FileObject> fos = resFileObject.allInstances();
+ FileObject oldFile;
+ FileObject newFile;
+ synchronized (EditorContextDispatcher.this) {
+ oldFile = currentFile;
+ if (fos.size() == 0) {
+ currentFile = null;
+ } else if (fos.size() == 1) {
+ currentFile = fos.iterator().next();
+ } else {
+ currentFile = findPrimary(fos);
+ }
+ //System.err.println("\nCURRENT FILES = "+fos+"\n");
+ newFile = currentFile;
+ currentURL = null;
+ /*if (newFile != null) { - NO, we need the last file in editor.
+ mostRecentFileRef = new WeakReference(newFile);
+ }*/
+ }
+ if (oldFile != newFile) {
+ refreshProcessor.post(new EventFirer(PROP_FILE, oldFile, newFile));
+ }
+ } else if (type == EditorCookie.class) {
+ Collection extends EditorCookie> ecs = resEditorCookie.allInstances();
+ EditorCookie newEditor;
+ synchronized (EditorContextDispatcher.this) {
+ if (ecs.size() == 0) {
+ currentEditorCookie = null;
+ } else {
+ currentEditorCookie = ecs.iterator().next();
+ }
+ newEditor = currentEditorCookie;
+ if (currentFile != null) {
+ if (newEditor != null) {
+ mostRecentEditorCookieRef = new WeakReference(newEditor);
+ }
+ }
+ }
+ /* Fire the editor event only when JEditorPane is set/unset
+ if (oldEditor != newEditor) {
+ // refreshProcessor.post(new EventFirer(PROP_EDITOR, oldEditor, newEditor, MIMEType));
+ }
+ */
+ }
+ }
+
+ public void propertyChange(PropertyChangeEvent evt) {
+ String propertyName = evt.getPropertyName();
+ //System.err.println("EditorContextDispatcher.propertyChanged("+evt.getPropertyName()+": "+evt.getOldValue()+", "+evt.getNewValue()+"), type = "+type);
+ if (type == TopComponent.class) {
+ if (propertyName.equals(TopComponent.Registry.PROP_ACTIVATED)) {
+ TopComponent newComponnet = (TopComponent) evt.getNewValue();
+ JEditorPane oldEditor;
+ JEditorPane newEditor;
+ String MIMEType = null;
+ synchronized (EditorContextDispatcher.this) {
+ boolean isSetPane = false;
+ oldEditor = currentOpenedPane;
+ if (currentEditorCookie != null && newComponnet != null) {
+ JEditorPane[] openedPanes = currentEditorCookie.getOpenedPanes();
+ if (openedPanes != null && openedPanes.length >= 1) {
+ for (JEditorPane openedPane : openedPanes) {
+ if (newComponnet.isAncestorOf(openedPane)) {
+ //System.err.println("\n"+newComponnet+".isAncestorOf("+openedPane+")\n");
+ currentOpenedPane = openedPane;
+ isSetPane = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!isSetPane) {
+ currentOpenedPane = null;
+ }
+ newEditor = currentOpenedPane;
+ if (currentFile != null) {
+ MIMEType = currentFile.getMIMEType();
+ if (newEditor != null) {
+ mostRecentOpenedPaneRef = new WeakReference(newEditor);
+ mostRecentFileRef = new WeakReference(currentFile);
+ }
+ } else {
+ MIMEType = null;
+ }
+ //System.err.println("\nCurrent Opened Pane = "+currentOpenedPane+", currentFile = "+currentFile+"\n");
+ }
+ if (oldEditor != newEditor) {
+ refreshProcessor.post(new EventFirer(PROP_EDITOR, oldEditor, newEditor, MIMEType));
+ }
+ }
+ }
+ }
+
+ private FileObject findPrimary(Collection extends FileObject> fos) {
+ for (FileObject fo : fos) {
+ try {
+ DataObject dobj = DataObject.find(fo);
+ if (fo.equals(dobj.getPrimaryFile())) {
+ return fo;
+ }
+ } catch (DataObjectNotFoundException ex) {}
+ }
+ // No primary file, return just the first one:
+ return fos.iterator().next();
+ }
+
+ }
+
+ private final class EventFirer implements Runnable {
+
+ private final PropertyChangeEvent evt;
+ private final String MIMEType;
+
+ public EventFirer(String propertyName, Object oldValue, Object newValue) {
+ this(propertyName, oldValue, newValue, null);
+ }
+
+ public EventFirer(String propertyName, Object oldValue, Object newValue, String MIMEType) {
+ this.evt = new PropertyChangeEvent(EditorContextDispatcher.this, propertyName, oldValue, newValue);
+ this.MIMEType = MIMEType;
+ }
+
+ public void run() {
+ firePropertyChange(evt, MIMEType);
+ }
+
+ }
+
+}