PageRenderTime 113ms CodeModel.GetById 92ms app.highlight 16ms RepoModel.GetById 2ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/gui/DockableWindowFactory.java

#
Java | 570 lines | 401 code | 69 blank | 100 comment | 35 complexity | 177f43ef630ac1ef01aa64bf36d8cf98 MD5 | raw file
  1/*
  2 * DockableWindowFactory.java - loads dockables.xml, etc
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 2005 Slava Pestov
  7 *
  8 * This program is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU General Public License
 10 * as published by the Free Software Foundation; either version 2
 11 * of the License, or any later version.
 12 *
 13 * This program is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16 * GNU General Public License for more details.
 17 *
 18 * You should have received a copy of the GNU General Public License
 19 * along with this program; if not, write to the Free Software
 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 21 */
 22
 23package org.gjt.sp.jedit.gui;
 24
 25//{{{ Imports
 26import java.io.IOException;
 27import java.net.URL;
 28import java.util.HashMap;
 29import java.util.Iterator;
 30import java.util.LinkedList;
 31import java.util.Map;
 32import java.util.Stack;
 33
 34import javax.swing.JComponent;
 35
 36import org.gjt.sp.jedit.ActionSet;
 37import org.gjt.sp.jedit.BeanShell;
 38import org.gjt.sp.jedit.EditAction;
 39import org.gjt.sp.jedit.MiscUtilities;
 40import org.gjt.sp.jedit.PluginJAR;
 41import org.gjt.sp.jedit.View;
 42import org.gjt.sp.jedit.jEdit;
 43import org.gjt.sp.util.Log;
 44import org.gjt.sp.util.XMLUtilities;
 45import org.xml.sax.Attributes;
 46import org.xml.sax.InputSource;
 47import org.xml.sax.helpers.DefaultHandler;
 48
 49import org.gjt.sp.jedit.bsh.NameSpace;
 50import org.gjt.sp.jedit.bsh.UtilEvalError;
 51//}}}
 52
 53/**
 54 * Loads <code>dockable.xml</code> files and manages creation
 55 * of new dockable windows.
 56 *
 57 * @see DockableWindowManager
 58 *
 59 * @since jEdit 4.3pre2
 60 */
 61public class DockableWindowFactory
 62{
 63	//{{{ getInstance() method
 64	public static synchronized DockableWindowFactory getInstance()
 65	{
 66		if(instance == null)
 67			instance = new DockableWindowFactory();
 68		return instance;
 69	} //}}}
 70
 71	//{{{ DockableWindowFactory constructor
 72	public DockableWindowFactory()
 73	{
 74		dockableWindowFactories = new HashMap<String, Window>();
 75	} //}}}
 76
 77	//{{{ loadDockableWindows() method
 78	/**
 79	 * Plugins shouldn't need to call this method.
 80	 * @since jEdit 4.2pre1
 81	 */
 82	public void loadDockableWindows(PluginJAR plugin, URL uri,
 83		PluginJAR.PluginCacheEntry cache)
 84	{
 85		try
 86		{
 87			Log.log(Log.DEBUG,DockableWindowManager.class,
 88				"Loading dockables from " + uri);
 89			DockableListHandler dh = new DockableListHandler(plugin,uri);
 90			boolean failure = XMLUtilities.parseXML(uri.openStream(), dh);
 91
 92			if (!failure && cache != null)
 93			{
 94				cache.cachedDockableNames = dh.getCachedDockableNames();
 95				cache.cachedDockableActionFlags = dh.getCachedDockableActionFlags();
 96				cache.cachedDockableMovableFlags = dh.getCachedDockableMovableFlags();
 97			}
 98		}
 99		catch(IOException e)
100		{
101			Log.log(Log.ERROR,DockableWindowManager.class,e);
102		}
103	} //}}}
104
105	//{{{ unloadDockableWindows() method
106	/**
107	 * Plugins shouldn't need to call this method.
108	 * @since jEdit 4.2pre1
109	 */
110	public void unloadDockableWindows(PluginJAR plugin)
111	{
112		Iterator entries = dockableWindowFactories.entrySet().iterator();
113		while(entries.hasNext())
114		{
115			Map.Entry entry = (Map.Entry)entries.next();
116			Window factory = (Window)entry.getValue();
117			if(factory.plugin == plugin)
118				entries.remove();
119		}
120	} //}}}
121
122	//{{{ cacheDockableWindows() method
123	/**
124	 * @since jEdit 4.2pre1
125	 */
126	public void cacheDockableWindows(PluginJAR plugin,
127		String[] name, boolean[] actions, boolean[] movable)
128	{
129		for(int i = 0; i < name.length; i++)
130		{
131			Window factory = new Window(plugin,
132				name[i],null,actions[i],movable[i]);
133			dockableWindowFactories.put(name[i],factory);
134		}
135	} //}}}
136
137	//{{{ registerDockableWindow() method
138	public void registerDockableWindow(PluginJAR plugin,
139		String name, String code, boolean actions, boolean movable)
140	{
141		Window factory = dockableWindowFactories.get(name);
142		if(factory != null)
143		{
144			factory.code = code;
145			factory.loaded = true;
146		}
147		else
148		{
149			factory = new Window(plugin,name,code,actions, movable);
150			dockableWindowFactories.put(name,factory);
151		}
152	} //}}}
153
154	//{{{ getRegisteredDockableWindows() method
155	public String[] getRegisteredDockableWindows()
156	{
157		String[] retVal = new String[dockableWindowFactories.size()];
158		Iterator<Window> entries = dockableWindowFactories.values().iterator();
159		int i = 0;
160		while(entries.hasNext())
161		{
162			Window factory = entries.next();
163			retVal[i++] = factory.name;
164		}
165
166		return retVal;
167	} //}}}
168
169	public Window getDockableWindowFactory(String name)
170	{
171		return dockableWindowFactories.get(name);
172	}
173	
174	public String getDockableWindowPluginClass(String name)
175	{
176		Window w = getDockableWindowFactory(name);
177		if (w == null || w.plugin == null || w.plugin.getPlugin() == null)
178			return null;
179		return w.plugin.getPlugin().getClassName();
180	}
181	
182	//{{{ getDockableWindowIterator() method
183	Iterator<Window> getDockableWindowIterator()
184	{
185		return dockableWindowFactories.values().iterator();
186	} //}}}
187
188	//{{{ DockableListHandler class
189	class DockableListHandler extends DefaultHandler
190	{
191		//{{{ DockableListHandler constructor
192		/**
193		 * @param plugin - the pluginJAR for which we are loading the dockables.xml
194		 * @param uri - the uri of the dockables.xml file?
195		 */
196		DockableListHandler(PluginJAR plugin, URL uri)
197		{
198			this.plugin = plugin;
199			this.uri = uri;
200			stateStack = new Stack<String>();
201			actions = true;
202			movable = MOVABLE_DEFAULT;
203
204			code = new StringBuilder();
205			cachedDockableNames = new LinkedList<String>();
206			cachedDockableActionFlags = new LinkedList<Boolean>();
207			cachedDockableMovableFlags = new LinkedList<Boolean>();
208		} //}}}
209
210		//{{{ resolveEntity() method
211		@Override
212		public InputSource resolveEntity(String publicId, String systemId)
213		{
214			return XMLUtilities.findEntity(systemId, "dockables.dtd", MiscUtilities.class);
215		} //}}}
216
217		//{{{ characters() method
218		@Override
219		public void characters(char[] c, int off, int len)
220		{
221			String tag = peekElement();
222			if (tag.equals("DOCKABLE"))
223				code.append(c, off, len);
224		} //}}}
225
226		//{{{ startElement() method
227		@Override
228		public void startElement(String uri, String localName,
229					 String qName, Attributes attrs)
230		{
231			String tag = pushElement(qName);
232			if (tag.equals("DOCKABLE"))
233			{
234				dockableName = attrs.getValue("NAME");
235				actions = "FALSE".equals(attrs.getValue("NO_ACTIONS"));
236				String movableAttr = attrs.getValue("MOVABLE");
237				if (movableAttr != null)
238					movable = movableAttr.equalsIgnoreCase("TRUE");
239			}
240		} //}}}
241
242		//{{{ endElement() method
243		@Override
244		public void endElement(String uri, String localName, String name)
245		{
246			if(name == null)
247				return;
248
249			String tag = peekElement();
250
251			if(name.equals(tag))
252			{
253				if(tag.equals("DOCKABLE"))
254				{
255					registerDockableWindow(plugin,
256						dockableName,code.toString(),actions, movable);
257					cachedDockableNames.add(dockableName);
258					cachedDockableActionFlags.add(
259						Boolean.valueOf(actions));
260					cachedDockableMovableFlags.add(
261							Boolean.valueOf(movable));
262					// make default be true for the next
263					// action
264					actions = true;
265					movable = MOVABLE_DEFAULT;
266					code.setLength(0);
267				}
268
269				popElement();
270			}
271			else
272			{
273				// can't happen
274				throw new InternalError();
275			}
276		} //}}}
277
278		//{{{ startDocument() method
279		@Override
280		public void startDocument()
281		{
282			try
283			{
284				pushElement(null);
285			}
286			catch (Exception e)
287			{
288				Log.log(Log.ERROR, this, e);
289			}
290		} //}}}
291
292		//{{{ getCachedDockableNames() method
293		public String[] getCachedDockableNames()
294		{
295			return cachedDockableNames.toArray(new String[cachedDockableNames.size()]);
296		} //}}}
297
298		//{{{ getCachedDockableActionFlags() method
299		public boolean[] getCachedDockableActionFlags()
300		{
301			return booleanListToArray(cachedDockableActionFlags);
302		} //}}}
303
304		//{{{ getCachedDockableMovableFlags() method
305		public boolean[] getCachedDockableMovableFlags()
306		{
307			return booleanListToArray(cachedDockableMovableFlags);
308		} //}}}
309		
310		//{{{ booleanListToArray() method
311		/**
312		 * This method transforms a List<Boolean> into the corresponding
313		 * boolean[] array
314		 * @param list the List<Boolean> you want to convert
315		 * @return a boolean[] array
316		 */
317		private boolean[] booleanListToArray(java.util.List<Boolean> list)
318		{
319			boolean[] returnValue = new boolean[list.size()];
320			int i = 0;
321			for (Boolean value : list)
322			{
323				returnValue[i++] = value.booleanValue();
324			}
325
326			return returnValue;
327		} //}}}
328
329		//{{{ Private members
330
331		//{{{ Instance variables
332		private PluginJAR plugin;
333		// What is the purpose of this?
334		private URL uri;
335
336		private java.util.List<String> cachedDockableNames;
337		private java.util.List<Boolean> cachedDockableActionFlags;
338		private java.util.List<Boolean> cachedDockableMovableFlags;
339		
340		private String dockableName;
341		private StringBuilder code;
342		private boolean actions;
343		private boolean movable;
344		static final boolean MOVABLE_DEFAULT = false;
345		
346		private Stack<String> stateStack;
347		//}}}
348
349		//{{{ pushElement() method
350		private String pushElement(String name)
351		{
352			name = (name == null) ? null : name.intern();
353
354			stateStack.push(name);
355
356			return name;
357		} //}}}
358
359		//{{{ peekElement() method
360		private String peekElement()
361		{
362			return stateStack.peek();
363		} //}}}
364
365		//{{{ popElement() method
366		private String popElement()
367		{
368			return stateStack.pop();
369		} //}}}
370
371		//}}}
372	} //}}}
373
374	//{{{ Window class
375	class Window
376	{
377		PluginJAR plugin;
378		String name;
379		String code;
380		boolean loaded;
381		boolean movable;
382		boolean isBeingCreated = false;
383
384		//{{{ Window constructor
385		Window(PluginJAR plugin, String name, String code,
386			boolean actions, boolean movable)
387		{
388			this.plugin = plugin;
389			this.name = name;
390			this.code = code;
391			this.movable = movable;
392
393			if(code != null)
394				loaded = true;
395
396			if(actions)
397			{
398				ActionSet actionSet = (plugin == null
399					? jEdit.getBuiltInActionSet()
400					: plugin.getActionSet());
401				actionSet.addAction(new OpenAction(name));
402				actionSet.addAction(new ToggleAction(name));
403				actionSet.addAction(new FloatAction(name));
404
405				String label = jEdit.getProperty(name
406					+ ".label");
407				if(label == null)
408					label = "NO LABEL PROPERTY: " + name;
409
410				String[] args = { label };
411				jEdit.setTemporaryProperty(name + ".label",
412					label);
413				jEdit.setTemporaryProperty(name
414					+ "-toggle.label",
415					jEdit.getProperty(
416					"view.docking.toggle.label",args));
417				jEdit.setTemporaryProperty(name
418					+ "-toggle.toggle","true");
419				jEdit.setTemporaryProperty(name
420					+ "-float.label",
421					jEdit.getProperty(
422					"view.docking.float.label",args));
423			}
424		} //}}}
425
426		//{{{ load() method
427		void load()
428		{
429			if(loaded)
430				return;
431
432			loadDockableWindows(plugin,plugin.getDockablesURI(),null);
433		} //}}}
434
435		//{{{ createDockableWindow() method
436		JComponent createDockableWindow(View view, String position)
437		{
438			// Avoid infinite recursion
439			synchronized(this)
440			{
441				if (isBeingCreated)
442					return null;
443				isBeingCreated = true;
444			}
445
446			load();
447
448			if(!loaded)
449			{
450				Log.log(Log.WARNING,this,"Outdated cache");
451				return null;
452			}
453
454			NameSpace nameSpace = new NameSpace(
455				BeanShell.getNameSpace(),
456				"DockableWindowManager.Factory"
457				+ ".createDockableWindow()");
458			try
459			{
460				nameSpace.setVariable(
461					"position",position);
462			}
463			catch(UtilEvalError e)
464			{
465				Log.log(Log.ERROR,this,e);
466			}
467			JComponent win = (JComponent)BeanShell.eval(view,
468				nameSpace,code);
469			synchronized(this)
470			{
471				isBeingCreated = false;
472			}
473			return win;
474		} //}}}
475
476		//{{{ OpenAction class
477		class OpenAction extends EditAction
478		{
479			private String dockable;
480
481			//{{{ OpenAction constructor
482			OpenAction(String name)
483			{
484				super(name);
485				this.dockable = name;
486			} //}}}
487
488			//{{{ invoke() method
489			public void invoke(View view)
490			{
491				view.getDockableWindowManager()
492					.showDockableWindow(dockable);
493			} //}}}
494
495			//{{{ getCode() method
496			@Override
497			public String getCode()
498			{
499				return "view.getDockableWindowManager()"
500					+ ".showDockableWindow(\"" + dockable + "\");";
501			} //}}}
502		} //}}}
503
504		//{{{ ToggleAction class
505		class ToggleAction extends EditAction
506		{
507			private String dockable;
508
509			//{{{ ToggleAction constructor
510			ToggleAction(String name)
511			{
512				super(name + "-toggle");
513				this.dockable = name;
514			} //}}}
515
516			//{{{ invoke() method
517			public void invoke(View view)
518			{
519				view.getDockableWindowManager()
520					.toggleDockableWindow(dockable);
521			} //}}}
522
523			//{{{ isSelected() method
524			public boolean isSelected(View view)
525			{
526				return view.getDockableWindowManager()
527					.isDockableWindowVisible(dockable);
528			} //}}}
529
530			//{{{ getCode() method
531			@Override
532			public String getCode()
533			{
534				return "view.getDockableWindowManager()"
535					+ ".toggleDockableWindow(\"" + dockable + "\");";
536			} //}}}
537		} //}}}
538
539		//{{{ FloatAction class
540		class FloatAction extends EditAction
541		{
542			private String dockable;
543
544			//{{{ FloatAction constructor
545			FloatAction(String name)
546			{
547				super(name + "-float");
548				this.dockable = name;
549			} //}}}
550
551			//{{{ invoke() method
552			public void invoke(View view)
553			{
554				view.getDockableWindowManager()
555					.floatDockableWindow(dockable);
556			} //}}}
557
558			//{{{ getCode() method
559			@Override
560			public String getCode()
561			{
562				return "view.getDockableWindowManager()"
563					+ ".floatDockableWindow(\"" + dockable + "\");";
564			} //}}}
565		} //}}}
566	} //}}}
567
568	private static DockableWindowFactory instance;
569	private final Map<String, Window> dockableWindowFactories;
570}