Source code: javax/ide/editor/EditorManager.java
1 package javax.ide.editor;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashMap;
6 import java.util.Iterator;
7 import java.util.List;
8 import java.util.Map;
9
10 import javax.ide.Service;
11 import javax.ide.spi.ProviderNotFoundException;
12 import javax.ide.command.Context;
13 import javax.ide.editor.spi.EditorHook;
14 import javax.ide.extension.ExtensionRegistry;
15 import javax.ide.util.MetaClass;
16
17 /**
18 * The <code>EditorManager</code> manages the life cycle of {@link Editor}s.
19 * It is also the registry of information about what editors can be used with
20 * particular documents.<p>
21 *
22 * Clients use this class to open an editor on a {@link javax.ide.model.Document}.
23 * When clients request to open an editor on a specific document, the editor
24 * manager performs the following tasks:<p>
25 *
26 * <ul>
27 * <li>1. Create an instance of the requested editor type. If no type is
28 * specified, create an instance of the preferred editor associated with
29 * the target document.</li><p>
30 * <li>2. Call the {@link Editor#open} method passing the appropriate
31 * context.</li><p>
32 * <li>3. Call the {@link Editor#restore} method to restore any previously
33 * saved editor state.</li><p>
34 * <li>5. Call the {@link javax.ide.view.View#setVisible} method to display
35 * the editor.
36 * <li>4. Fire the {@link EditorListener#opened} event.
37 * </ul>
38 *
39 * Similarly, the editor manager {@link #closeEditor} method should be called
40 * by clients to request closing an editor. When closing an editor the
41 * editor manager performs the following tasks:<p>
42 *
43 * <ul>
44 * <li>3. Call the {@link Editor#save} method to save the editor
45 * current state.</li><p>
46 * <li>1. Call the {@link Editor#close} method.</li><p>
47 * <li>4. Fire the {@link EditorListener#closed} event.
48 * </ul>
49 *
50 * Extensions that need to know when editors are opened, closed, activated,
51 * and/or deactivated can add {@link EditorListener}s to the editor manager.
52 * Listener implementations are declared in the <b>editor-listener</b>
53 * section of the extension manifest.<p>
54 *
55 * IDE service providers must provide a concrete implementation of this class.
56 */
57 public abstract class EditorManager extends Service
58 {
59 /**
60 * Map of String:List. Keys are ids of editor types, values are lists of
61 * EditorListener.
62 */
63 private final Map _listenerMap = new HashMap();
64 private boolean _initializedHookListeners = false;
65
66 /**
67 * Returns the Editor that is currently active.
68 *
69 * @return the currently active editor.
70 */
71 public abstract Editor getActiveEditor();
72
73 /**
74 * Opens a document in the editor identified by the given editor
75 * type identifier. If <code>type</code> is null, the IDE will open the
76 * document with the most appropriate editor.<p>
77 *
78 * If the document is already open using that editor, the editor will be
79 * made active.
80 *
81 * @param context the context to open an editor for.
82 * @param typeID the id of an editor type to open the context document in. If
83 * null, the IDE will open the document with the default editor.
84 * @return the editor that was opened or activated.
85 * @throws UnsupportedOperationException when the document cannot be
86 * opened by any editor.
87 */
88 public abstract Editor openEditor( Context context, String typeID );
89
90 /**
91 * Close the specified {@link Editor}.
92 *
93 * @param editor The editor to be closed.
94 */
95 public abstract void closeEditor( Editor editor );
96
97 /**
98 * Add an {@link EditorListener}.
99 *
100 * @param listener the {@link EditorListener} to add.
101 * @param editorClass Only events for this class of editor will be dispatched
102 * to the specified listener. May be null, indicating that all editor events
103 * will be dispatched.
104 */
105 public final void addEditorListener( EditorListener listener,
106 String editorClass )
107 {
108 if ( editorClass == null )
109 {
110 editorClass = EditorHook.ANY_EDITOR_CLASS;
111 }
112 List listeners = (List) _listenerMap.get( editorClass );
113 if ( listeners == null )
114 {
115 listeners = new ArrayList();
116 _listenerMap.put( editorClass, listeners );
117 }
118 listeners.add( listener );
119 }
120
121 /**
122 * Remove an {@link EditorListener}.
123 *
124 * @param l The {@link EditorListener} to remove.
125 * @param editorClass The class of editors from which listener should be
126 * removed. May be null, indicating that all editor events
127 * will be dispatched.
128 */
129 public final void removeEditorListener( EditorListener l,
130 String editorClass )
131 {
132 if ( editorClass == null )
133 {
134 editorClass = EditorHook.ANY_EDITOR_CLASS;
135 }
136 List listeners = (List) _listenerMap.get( editorClass );
137 if ( listeners != null )
138 {
139 listeners.remove( l );
140 }
141 else
142 {
143 throw new IllegalArgumentException(
144 "No listeners are registered for editor type "+editorClass
145 );
146 }
147 }
148
149 private final Collection getListeners( Editor editor )
150 {
151 initializeHookListeners();
152 List listeners = (List) _listenerMap.get( editor.getClass().getName() );
153 List allListeners = (List) _listenerMap.get( EditorHook.ANY_EDITOR_CLASS );
154 List fullList = new ArrayList();
155 if ( listeners != null )
156 {
157 fullList.addAll( listeners );
158 }
159 if ( allListeners != null )
160 {
161 fullList.addAll( allListeners );
162 }
163
164 return fullList;
165 }
166
167 /**
168 * Notifies all editor listeners that the specified editor was
169 * opened.
170 *
171 * @param editor the editor which was opened.
172 */
173 protected final void fireEditorOpened( Editor editor )
174 {
175 Collection listeners = getListeners( editor );
176
177 if ( !listeners.isEmpty() )
178 {
179 EditorEvent event = new EditorEvent( editor );
180 for ( Iterator i = listeners.iterator(); i.hasNext(); )
181 {
182 ((EditorListener)i.next()).opened( event );
183 }
184 }
185 }
186
187 /**
188 * Notifies all editor listeners that the specified editor was
189 * closed.
190 *
191 * @param editor the editor which was closed.
192 */
193 protected final void fireEditorClosed( Editor editor )
194 {
195 Collection listeners = getListeners( editor );
196
197 if ( !listeners.isEmpty() )
198 {
199 EditorEvent event = new EditorEvent( editor );
200 for ( Iterator i = listeners.iterator(); i.hasNext(); )
201 {
202 ((EditorListener)i.next()).closed( event );
203 }
204 }
205 }
206
207 /**
208 * Notifies all editor listeners that the specified editor was
209 * activated.
210 *
211 * @param editor the editor which was activated.
212 */
213 protected final void fireEditorActivated( Editor editor )
214 {
215 Collection listeners = getListeners( editor );
216
217 if ( !listeners.isEmpty() )
218 {
219 EditorEvent event = new EditorEvent( editor );
220 for ( Iterator i = listeners.iterator(); i.hasNext(); )
221 {
222 ((EditorListener)i.next()).activated( event );
223 }
224 }
225 }
226
227 /**
228 * Notifies all editor listeners that the specified editor was
229 * deactivated.
230 *
231 * @param editor the editor which was deactivated.
232 */
233 protected final void fireEditorDeactivated( Editor editor )
234 {
235 Collection listeners = getListeners( editor );
236
237 if ( !listeners.isEmpty() )
238 {
239 EditorEvent event = new EditorEvent( editor );
240 for ( Iterator i = listeners.iterator(); i.hasNext(); )
241 {
242 ((EditorListener)i.next()).deactivated( event );
243 }
244 }
245 }
246
247 private void initializeHookListeners()
248 {
249 if ( !_initializedHookListeners )
250 {
251 try
252 {
253 EditorHook editorHook =
254 (EditorHook) ExtensionRegistry.getExtensionRegistry().getHook( EditorHook.ELEMENT );
255
256 Map listeners = editorHook.getListeners();
257 for ( Iterator i = listeners.keySet().iterator(); i.hasNext(); )
258 {
259 String key = (String) i.next();
260 Collection listenerClasses = (Collection) listeners.get( key );
261 for ( Iterator j = listenerClasses.iterator(); j.hasNext(); )
262 {
263 MetaClass thisClass = (MetaClass) j.next();
264 try
265 {
266 EditorListener el = (EditorListener) thisClass.newInstance();
267 addEditorListener( el, key );
268 }
269 catch ( Exception e )
270 {
271 e.printStackTrace();
272 }
273 }
274 }
275 }
276 finally
277 {
278 _initializedHookListeners = true;
279 }
280 }
281 }
282
283 /**
284 * Get the editor manager implementation for this IDE.
285 *
286 * @return the editor manager implementation.
287 */
288 public static EditorManager getEditorManager()
289 {
290 try
291 {
292 return (EditorManager) getService( EditorManager.class );
293 }
294 catch ( ProviderNotFoundException nse )
295 {
296 nse.printStackTrace();
297 throw new IllegalStateException( "No editor manager." );
298 }
299 }
300
301
302 }