001: /*
002: * Jacareto Copyright (c) 2002-2005
003: * Applied Computer Science Research Group, Darmstadt University of
004: * Technology, Institute of Mathematics & Computer Science,
005: * Ludwigsburg University of Education, and Computer Based
006: * Learning Research Group, Aachen University. All rights reserved.
007: *
008: * Jacareto is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation; either
011: * version 2 of the License, or (at your option) any later version.
012: *
013: * Jacareto is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public
019: * License along with Jacareto; if not, write to the Free
020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
021: *
022: */
023:
024: package jacareto.cleverphl.gui;
025:
026: import jacareto.cleverphl.CleverPHL;
027: import jacareto.cleverphl.session.Session;
028: import jacareto.cleverphl.session.SessionEvent;
029: import jacareto.cleverphl.session.SessionListener;
030: import jacareto.editor.Editor;
031: import jacareto.replay.event.ReplayEvent;
032: import jacareto.replay.event.ReplayListener;
033: import jacareto.struct.StructureElement;
034: import jacareto.struct.StructureTree;
035: import jacareto.system.Customization;
036: import jacareto.system.Language;
037: import jacareto.toolkit.EnhancedHashtable;
038: import jacareto.toolkit.HashtableException;
039: import jacareto.toolkit.PriorityList;
040:
041: import org.apache.log4j.Logger;
042:
043: import java.awt.BorderLayout;
044: import java.awt.Color;
045: import java.awt.FlowLayout;
046: import java.awt.GridBagConstraints;
047: import java.awt.GridBagLayout;
048:
049: import java.lang.reflect.Constructor;
050: import java.lang.reflect.InvocationTargetException;
051:
052: import java.util.Enumeration;
053: import java.util.Iterator;
054:
055: import javax.swing.JPanel;
056: import javax.swing.border.LineBorder;
057: import javax.swing.border.TitledBorder;
058: import javax.swing.event.TreeSelectionEvent;
059: import javax.swing.event.TreeSelectionListener;
060:
061: /**
062: * Instances of this class display the general information of structure elements (name,
063: * description, ...) and their editor. This class loads a list of editors and their priorities
064: * out of the {@link jacareto.system.Customization} instance delivered by the {@link
065: * jacareto.system.Environment} instance. The xml file which contains the list of editors should
066: * have a map element of this form:
067: * <pre>
068: * <map name="StructureElementEditors">
069: * <mapelem key="jacareto.cleverphl.gui.editors.MouseEventRecordableEditor" value="1"/>
070: * <mapelem key="jacareto.cleverphl.gui.editors.AnnotationRecordableEditor" value="1"/>
071: * <mapelem key="jacareto.cleverphl.gui.editors.CalendarRecordableEditor" value="1"/>
072: * </map>
073: * </pre>
074: *
075: * @author <a href="mailto:cspannagel@web.de">Christian Spannagel</a>
076: * @version 1.01
077: */
078: public class StructureElementPanel extends JPanel implements
079: ReplayListener, SessionListener, TreeSelectionListener {
080: /** The CleverPHL instance. */
081: private CleverPHL cleverPHL;
082:
083: /** The language. */
084: private Language language;
085:
086: /** The logger. */
087: private Logger logger;
088:
089: /** The structure element tree. */
090: private StructureTree tree;
091:
092: /** The information display of the structure element. */
093: private InformationDisplay infoDisplay;
094:
095: /** The list of the Structure Element Editors. */
096: private PriorityList editors;
097:
098: /** The panel for the recordable editors. */
099: private JPanel editorsPanel;
100:
101: /** Whether or not cleverphl is replaying. */
102: private boolean isReplaying;
103:
104: /** The actual session. */
105: private Session session;
106:
107: /**
108: * Creates a new structure element panel.
109: *
110: * @param cleverPHL the CleverPHL instance
111: * @param session the session this panel belongs to
112: * @param tree the tree instances of this class listen to
113: */
114: public StructureElementPanel(CleverPHL cleverPHL, Session session,
115: StructureTree tree) {
116: this .cleverPHL = cleverPHL;
117: this .session = session;
118:
119: language = cleverPHL.getLanguage();
120: logger = cleverPHL.getLogger();
121:
122: this .tree = tree;
123: tree.addTreeSelectionListener(this );
124: editors = new PriorityList();
125:
126: loadEditors(session.getSessionClassLoader());
127:
128: infoDisplay = new InformationDisplay(cleverPHL);
129:
130: JPanel infoDisplayWrapper = new JPanel();
131: infoDisplayWrapper.setLayout(new FlowLayout(FlowLayout.LEFT));
132: infoDisplayWrapper.add(infoDisplay);
133:
134: editorsPanel = new JPanel();
135: editorsPanel.setLayout(new BorderLayout());
136: editorsPanel.setBorder(new TitledBorder(new LineBorder(
137: Color.black, 1, true), language
138: .getString("CleverPHL.StructureElementPanel.Editor")));
139:
140: JPanel editorsPanelWrapper = new JPanel();
141: editorsPanelWrapper.setLayout(new FlowLayout(FlowLayout.LEFT));
142: editorsPanelWrapper.add(editorsPanel);
143:
144: setLayout(new GridBagLayout());
145:
146: GridBagConstraints c = new GridBagConstraints();
147:
148: c.gridx = 0;
149: c.gridy = 0;
150: c.fill = GridBagConstraints.HORIZONTAL;
151: c.anchor = GridBagConstraints.WEST;
152: add(infoDisplayWrapper, c);
153:
154: c.gridy = 1;
155: add(editorsPanelWrapper, c);
156: setVisible(true);
157:
158: session.getReplay().addReplayListener(this );
159: session.addSessionListener(this );
160: isReplaying = false;
161:
162: // fast hack to get the right dimensions
163: editorsPanel.setVisible(false);
164: infoDisplay.setVisible(false);
165: }
166:
167: /**
168: * Called when the tree selection has changed. Updates the structure element information
169: * display and the editor.
170: *
171: * @param event the tree selection event
172: */
173: public void valueChanged(TreeSelectionEvent event) {
174: if (!isReplaying) {
175: showActualEditor();
176: }
177: }
178:
179: /**
180: * Shows the editor fot the marked structure element.
181: */
182: public void showActualEditor() {
183: boolean showInfoDisplay = false;
184: boolean showEditorsPanel = false;
185:
186: if (tree.getSelectionCount() == 1) {
187: setVisible(false);
188: editorsPanel.setVisible(false);
189: infoDisplay.setVisible(false);
190: editorsPanel.removeAll();
191:
192: Object selectedComponent = tree
193: .getLastSelectedPathComponent();
194:
195: if (selectedComponent instanceof StructureElement) {
196: StructureElement element = (StructureElement) selectedComponent;
197: infoDisplay.displayElement(element);
198: showInfoDisplay = true;
199:
200: Editor editor = getEditor(element);
201:
202: if (editor != null) {
203: editor.setUpdateOnChange(false);
204: editor.setComponents(session.getComponents());
205: editor.setElement(element);
206: editor.setUpdateOnChange(true);
207: editorsPanel.add(editor.getComponent(),
208: BorderLayout.WEST);
209: infoDisplay.setDescriptionAreaWidth(editorsPanel
210: .getWidth());
211: showEditorsPanel = true;
212: }
213: }
214:
215: setVisible(showInfoDisplay || showEditorsPanel);
216: infoDisplay.setVisible(showInfoDisplay);
217: editorsPanel.setVisible(showEditorsPanel);
218: } else {
219: editorsPanel.removeAll();
220: infoDisplay.setVisible(false);
221: editorsPanel.setVisible(false);
222: }
223:
224: cleverPHL.getMainFrame().repaint();
225: }
226:
227: /**
228: * Returns the {@link StructureTree} of this panel
229: *
230: * @return {@link StructureTree}
231: */
232: public StructureTree getStructureTree() {
233: return this .tree;
234: }
235:
236: /**
237: * Called when replay state has changed. This panel will not show the actual editor during
238: * replay
239: *
240: * @param event DOCUMENT ME!
241: */
242: public void replayStateChanged(ReplayEvent event) {
243: int ID = event.getID();
244:
245: switch (ID) {
246: case ReplayEvent.STARTED:
247: case ReplayEvent.CONTINUED:
248: case ReplayEvent.RESTARTED:
249: isReplaying = true;
250:
251: break;
252:
253: case ReplayEvent.STOPPED:
254: case ReplayEvent.PAUSED:
255: isReplaying = false;
256: showActualEditor();
257:
258: break;
259: }
260: }
261:
262: /**
263: * Invoked when a session event has occured.
264: *
265: * @param event the session event
266: */
267: public void sessionStateChanged(SessionEvent event) {
268: int ID = event.getID();
269:
270: switch (ID) {
271: case SessionEvent.REPLAY_RESET:
272: isReplaying = false;
273: showActualEditor();
274:
275: break;
276: }
277: }
278:
279: /**
280: * Registers an editor to the structure element panel with the specified priority. A greater
281: * value of priority symbolizes a higher priority.
282: *
283: * @param editor the editor to add
284: * @param priority the priority
285: */
286: public void addEditor(Editor editor, int priority) {
287: if (priority >= 0) {
288: editors.add(editor, priority);
289: } else {
290: editors.add(editor);
291: }
292: }
293:
294: /**
295: * Registers an editor with the lowest priority.
296: *
297: * @param editor the editor
298: */
299: public void addEditor(Editor editor) {
300: addEditor(editor, -1);
301: }
302:
303: /**
304: * Returns the first registered editor which is responsible for the given structure element.
305: *
306: * @param element the structure element
307: *
308: * @return the editor responsible for the structure element, or <code>null</code> if there is
309: * no editor which is responsible
310: */
311: private Editor getEditor(StructureElement element) {
312: Iterator i = editors.iterator();
313:
314: while (i.hasNext()) {
315: Editor editor = (Editor) i.next();
316: logger
317: .debug(language
318: .getString("CleverPHL.StructureElementPanel.Msg.Asking")
319: + " " + editor.getClass().getName());
320:
321: if (editor.handlesElement(element)) {
322: return editor;
323: }
324: }
325:
326: return null;
327: }
328:
329: /**
330: * Loads the editors from the {@link jacareto.system.Customization} instance of the {@link
331: * jacareto.system.Environment} object with the default class loader.
332: */
333: private void loadEditors() {
334: loadEditors(null);
335: }
336:
337: /**
338: * Loads the editors from the {@link jacareto.system.Customization} instance of the {@link
339: * jacareto.system.Environment} object with the specified class loader.
340: *
341: * @param classLoader DOCUMENT ME!
342: */
343: private void loadEditors(ClassLoader classLoader) {
344: Logger logger = cleverPHL.getLogger();
345: Language language = cleverPHL.getLanguage();
346: Customization customization = cleverPHL.getCustomization();
347:
348: if (classLoader == null) {
349: classLoader = ClassLoader.getSystemClassLoader();
350: }
351:
352: try {
353: // some reflection instances
354: Class editorClass = Class.forName(customization
355: .getString("Editor.Class"), true, classLoader);
356: Class[] parameterTypes = new Class[1];
357: parameterTypes[0] = Class.forName(
358: "jacareto.system.Environment", true, classLoader);
359:
360: Object[] parameters = new Object[1];
361: parameters[0] = cleverPHL.getEnvironment();
362:
363: // load the map of editors
364: EnhancedHashtable editorsMap = cleverPHL.getCustomization()
365: .getMap("StructureElementEditors",
366: new EnhancedHashtable());
367: Enumeration enumeration = editorsMap.keys();
368:
369: while (enumeration.hasMoreElements()) {
370: String editorClassName = (String) enumeration
371: .nextElement();
372:
373: try {
374: int priority = editorsMap
375: .getInt(editorClassName, 0);
376: Class edClass = Class.forName(editorClassName,
377: true, classLoader);
378: Constructor editorConstructor = edClass
379: .getConstructor(parameterTypes);
380:
381: if (editorClass.isAssignableFrom(edClass)) {
382: try {
383: logger
384: .debug(language
385: .getString("CleverPHL.StructureElementPanel.Msg.Loading")
386: + " "
387: + editorClassName
388: + ", "
389: + language
390: .getString("General.Priority")
391: + " " + priority);
392: addEditor((Editor) editorConstructor
393: .newInstance(parameters), priority);
394: } catch (InstantiationException inst) {
395: logger
396: .debug(
397: language
398: .getString("CleverPHL.StructureElementPanel.Error.Construction"),
399: inst);
400: } catch (IllegalAccessException ill) {
401: logger
402: .debug(
403: language
404: .getString("CleverPHL.StructureElementPanel.Error.Construction"),
405: ill);
406: } catch (IllegalArgumentException ila) {
407: logger
408: .debug(
409: language
410: .getString("CleverPHL.StructureElementPanel.Error.Construction"),
411: ila);
412: } catch (InvocationTargetException inv) {
413: logger
414: .debug(
415: language
416: .getString("CleverPHL.StructureElementPanel.Error.Construction"),
417: inv);
418: }
419: } else {
420: logger
421: .debug(language
422: .getString("CleverPHL.StructureElementPanel.Msg.NotSubclass")
423: + ": " + editorClassName);
424: }
425: } catch (ClassNotFoundException c) {
426: logger
427: .debug(
428: language
429: .getString("CleverPHL.StructureElementPanel.Error.MissingClass")
430: + ": " + editorClassName, c);
431: } catch (NoSuchMethodException n) {
432: logger
433: .debug(
434: language
435: .getString("CleverPHL.StructureElementPanel.Error.MissingConstructor"),
436: n);
437: }
438: }
439: } catch (ClassNotFoundException c) {
440: logger
441: .error(
442: language
443: .getString("CleverPHL.StructureElementPanel.Error.MissingClass"),
444: c);
445: } catch (HashtableException h) {
446: logger.error(h);
447: }
448: }
449: }
|