1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.xmlhammer.gui;
23
24 import java.awt.BorderLayout;
25 import java.awt.FlowLayout;
26 import java.awt.Font;
27 import java.awt.event.ActionEvent;
28 import java.awt.event.ActionListener;
29 import java.io.File;
30 import java.net.URI;
31 import java.util.ArrayList;
32 import java.util.Enumeration;
33 import java.util.List;
34
35 import javax.swing.AbstractButton;
36 import javax.swing.ButtonGroup;
37 import javax.swing.Icon;
38 import javax.swing.ImageIcon;
39 import javax.swing.JButton;
40 import javax.swing.JOptionPane;
41 import javax.swing.JPanel;
42 import javax.swing.JToggleButton;
43 import javax.swing.SwingUtilities;
44 import javax.swing.border.EmptyBorder;
45 import javax.swing.event.AncestorEvent;
46 import javax.swing.event.AncestorListener;
47 import javax.swing.event.ChangeEvent;
48 import javax.swing.event.ChangeListener;
49 import javax.xml.bind.JAXBException;
50 import javax.xml.transform.TransformerException;
51
52 import org.apache.log4j.Level;
53 import org.apache.log4j.Logger;
54 import org.apache.log4j.PatternLayout;
55 import org.apache.log4j.WriterAppender;
56 import org.bounce.CardPanel;
57 import org.bounce.image.ImageLoader;
58 import org.bounce.util.URIUtils;
59 import org.xmlhammer.Module;
60 import org.xmlhammer.ModuleThread;
61 import org.xmlhammer.ModuleThreadListener;
62 import org.xmlhammer.PreferencesHandler;
63 import org.xmlhammer.ResultModel;
64 import org.xmlhammer.gui.actions.OpenAction;
65 import org.xmlhammer.gui.input.InputPage;
66 import org.xmlhammer.gui.output.ConsolePanel;
67 import org.xmlhammer.gui.output.JavaPanel;
68 import org.xmlhammer.gui.output.LogPanel;
69 import org.xmlhammer.gui.output.ResultPanel;
70 import org.xmlhammer.gui.output.SourceBuilder;
71 import org.xmlhammer.gui.overview.OverviewNode;
72 import org.xmlhammer.gui.overview.OverviewNodeRenderer;
73 import org.xmlhammer.gui.overview.OverviewPanel;
74 import org.xmlhammer.gui.parser.ParserPage;
75 import org.xmlhammer.gui.status.StatusBar;
76 import org.xmlhammer.model.jaxp.SchemaFactoryProperty;
77 import org.xmlhammer.model.jaxp.Settings;
78 import org.xmlhammer.model.project.Filter;
79 import org.xmlhammer.model.project.Project;
80
81 /***
82 * The UI representation of a Project.
83 *
84 * @version $Revision: 1.48 $, $Date: 2008/03/05 22:13:43 $
85 * @author Edwin Dankert <edankert@gmail.com>
86 */
87 public abstract class ProjectView extends JPanel implements ModuleThreadListener {
88 private static final long serialVersionUID = 4121138017445755189L;
89
90 private AnimatedThread animatedThread = null;
91
92 private static final ImageIcon ICON = ImageLoader.get().getImage( "/org/xmlhammer/gui/icons/project.gif");
93
94 private long lastModifiedTime = -1;
95 private FieldManager fieldManager = null;
96 private ProjectUndoManager changeManager = null;
97 private boolean selected = false;
98 protected Project project = null;
99 private Logger logger = null;
100
101 private OverviewPanel overview = null;
102
103 private ModuleThread thread = null;
104 private CardPanel<Page> cardPanel = null;
105
106 protected InputPage inputPage = null;
107 protected ParserPage parserPage = null;
108
109 private LogPanel logPanel = null;
110 private ConsolePanel consolePanel = null;
111 private JavaPanel javaPanel = null;
112 private ResultPanel resultPanel = null;
113 protected StatusBar statusBar = null;
114 private URI uri = null;
115 private ProjectsView parent = null;
116 private ButtonGroup pageGroup = null;
117 private JPanel pageButtonsPanel = null;
118
119 /***
120 * @param parent the projects view parent.
121 * @param uri the uri for the project.
122 */
123 public ProjectView(ProjectsView parent, URI uri) {
124 super(new BorderLayout());
125
126 setName(ProjectView.getName( parent, uri));
127
128 this.parent = parent;
129 this.uri = uri;
130
131 if (uri != null) {
132 lastModifiedTime = System.currentTimeMillis();
133 }
134
135 cardPanel = new CardPanel<Page>();
136 pageGroup = new ButtonGroup();
137
138 JPanel main = new JPanel( new BorderLayout( 0, 0));
139 main.setBorder( new EmptyBorder( 0, 0, 0, 0));
140 main.add( cardPanel, BorderLayout.CENTER);
141
142 add( main, BorderLayout.CENTER);
143
144 JPanel buttonPanel = new JPanel( new BorderLayout());
145 buttonPanel.setBorder( new EmptyBorder( 5, 0, 5, 0));
146 pageButtonsPanel = new JPanel( new FlowLayout());
147 pageGroup = new ButtonGroup();
148
149 buttonPanel.add( pageButtonsPanel, BorderLayout.WEST);
150
151 JPanel executeStopPanel = new JPanel( new FlowLayout());
152
153 JButton executeButton = new JButton( getProjectsView().getRoot().getExecuteAction());
154 executeStopPanel.add( executeButton);
155 JButton stopButton = new JButton( getProjectsView().getRoot().getStopAction());
156 executeStopPanel.add( stopButton);
157
158 buttonPanel.add( executeStopPanel, BorderLayout.EAST);
159
160 addAncestorListener(new AncestorListener() {
161 public void ancestorAdded(AncestorEvent event) {
162 Logger.getLogger(getClass()).debug("ancestorAdded("+event+")");
163
164 checkForUpdate();
165 }
166
167 public void ancestorRemoved(AncestorEvent event) {}
168 public void ancestorMoved(AncestorEvent event) {}
169 });
170
171 add( buttonPanel, BorderLayout.SOUTH);
172 }
173
174 /***
175 * Should be called by child constructor.
176 */
177 protected void initPages() {
178 createPages();
179
180 getOverviewPanel().expandAll();
181
182 if (getInputPage() != null) {
183 getOverviewPanel().selectNode( getInputPage());
184 }
185 }
186
187 /***
188 * @return the project URI.
189 */
190 public OverviewPanel getOverviewPanel() {
191 if ( overview == null) {
192 overview = new OverviewPanel( this);
193 }
194
195 return overview;
196 }
197
198 public void update() {
199 if (uri != null) {
200 parent.getRoot().setWait(true);
201 getStatusBar().setStatus("Updating "+uri.toString()+" ...");
202
203
204 Runnable runner = new Runnable() {
205 public void run() {
206 Project project = null;
207
208 try {
209 project = OpenAction.open(uri);
210 } catch ( JAXBException e) {
211 Logger.getLogger(getClass()).error("JAXB Error", e);
212 } catch (TransformerException e) {
213 Logger.getLogger(getClass()).error("Transformer Error", e);
214 } finally {
215 openProject(project);
216 }
217 }
218 };
219
220
221 Thread thread = new Thread( runner);
222 thread.start();
223 }
224 }
225
226 private void openProject(final Project project) {
227 SwingUtilities.invokeLater( new Runnable() {
228 public void run() {
229 try {
230 if (project != null) {
231 setProject( project);
232 }
233 } finally {
234 getStatusBar().setStatus("Done");
235 parent.getRoot().setWait(false);
236 }
237 }
238 });
239 }
240
241 /***
242 * @return the underlying projects view.
243 */
244 public ProjectsView getProjectsView() {
245 return parent;
246 }
247
248 /***
249 * @return the project URI.
250 */
251 public URI getURI() {
252 return uri;
253 }
254
255 /***
256 * @return the last modified time.
257 */
258 public long getLastModifiedTime() {
259 return lastModifiedTime;
260 }
261
262 public boolean hasError() {
263
264 if (overview != null) {
265 return OverviewNodeRenderer.isError(overview.getModel());
266 }
267
268 return false;
269 }
270
271 /***
272 * @param the last modified time.
273 */
274 public void setLastModifiedTime(long time) {
275 lastModifiedTime = time;
276 }
277
278 /***
279 * @param true when the file has been modified on disk.
280 */
281 private boolean isModified() {
282 if (uri != null && lastModifiedTime != -1) {
283 return lastModifiedTime < (new File(uri)).lastModified();
284 }
285
286 return false;
287 }
288
289 public void checkForUpdate() {
290 if (isModified()) {
291 lastModifiedTime = System.currentTimeMillis();
292
293 int result = JOptionPane.showConfirmDialog(parent.getRoot(), "The \""+getName()+"\" Project has been changed by an external process.\nUpdate the Project?", "Please Confirm", JOptionPane.YES_NO_OPTION);
294 if (result == JOptionPane.OK_OPTION) {
295 update();
296 }
297 }
298 }
299
300 /***
301 * @param the view's URI.
302 */
303 public void setURI(URI uri) {
304 this.uri = uri;
305
306 setName( ProjectView.getName( parent, uri));
307 }
308
309 /***
310 * Override when want to add new pages overridden.
311 */
312 protected abstract void createPages();
313
314 protected ParserPage createParserPage() {
315 parserPage = new ParserPage( this, true);
316
317 return parserPage;
318 }
319
320 protected ParserPage getParserPage() {
321 return parserPage;
322 }
323
324 /***
325 * @param page the page to add.
326 */
327 public void addPage( Page page) {
328 cardPanel.add( page);
329 getOverviewPanel().addPage( page);
330 addPageButton( page);
331 }
332
333 private void addPageButton( final Page page) {
334 JToggleButton pageButton = new JToggleButton( page.getShortName());
335 pageButton.setFont( pageButton.getFont().deriveFont(Font.PLAIN));
336 pageButton.addActionListener( new ActionListener() {
337 public void actionPerformed(ActionEvent arg0) {
338 page.getProjectView().getOverviewPanel().selectNode( page);
339 }
340 });
341 pageGroup.add( pageButton);
342 pageButtonsPanel.add( pageButton);
343 }
344
345 protected InputPage createInputPage() {
346 inputPage = new InputPage(this);
347
348 return inputPage;
349 }
350
351 protected InputPage getInputPage() {
352 return inputPage;
353 }
354
355 /***
356 * Returns the status bar.
357 *
358 * @return the status bar.
359 */
360 public StatusBar getStatusBar() {
361 if ( statusBar == null) {
362 statusBar = new StatusBar();
363 }
364
365 return statusBar;
366 }
367
368
369 /***
370 * @return the ResultPanel
371 */
372 public ResultPanel getResultPanel() {
373 if ( resultPanel == null) {
374 resultPanel = new ResultPanel(parent.getRoot());
375 }
376
377 return resultPanel;
378 }
379
380 /***
381 * @return the ResultPanel
382 */
383 public JavaPanel getJavaPanel() {
384 if ( javaPanel == null) {
385 javaPanel = new JavaPanel();
386 javaPanel.addAncestorListener(new AncestorListener() {
387 public void ancestorAdded(AncestorEvent event) {
388 Logger.getLogger(getClass()).debug("ancestorAdded("+event+")");
389 getJavaPanel().setSource(getSource());
390 }
391
392 public void ancestorRemoved(AncestorEvent event) {
393 Logger.getLogger(getClass()).debug("ancestorRemoved("+event+")");
394 }
395
396 public void ancestorMoved(AncestorEvent event) {
397 Logger.getLogger(getClass()).debug("ancestorMoved("+event+")");
398 }
399 });
400 }
401
402 return javaPanel;
403 }
404
405 /***
406 * @return the LogPanel
407 */
408 public LogPanel getLogPanel() {
409 if (logPanel == null) {
410 logPanel = new LogPanel();
411 }
412
413 return logPanel;
414 }
415
416 /***
417 * @return the LogPanel
418 */
419 public ConsolePanel getConsolePanel() {
420 if (consolePanel == null) {
421 consolePanel = new ConsolePanel();
422 }
423
424 return consolePanel;
425 }
426
427 /***
428 * @return the underlying project.
429 */
430 public Project getProject() {
431 if ( project == null) {
432 project = new Project();
433 }
434
435 return project;
436 }
437
438 /***
439 * @return the underlying project, setting input and parser values .
440 */
441 public Project getProject(URI base) {
442 if ( project == null) {
443 project = new Project();
444 }
445
446 if (getParserPage() != null && getInputPage() != null) {
447 project.setInput( getInputPage().getInput(base));
448 project.setParser( getParserPage().getParser(base));
449 }
450
451 return project;
452 }
453
454 /***
455 * @return the project Specific Logger.
456 */
457 public Logger getLogger() {
458 if ( logger == null) {
459 logger = Logger.getLogger( getClass().getName() + "@" + Integer.toHexString(hashCode()));
460 logger.setLevel(Level.INFO);
461 logger.addAppender( new WriterAppender( new PatternLayout("%m%n"), getLogPanel().getOutputStream()));
462 }
463
464 return logger;
465 }
466
467 public void firePreferencesUpdated() {
468 updateSchemaLanguages();
469 }
470
471 protected void updateSchemaLanguages() {
472 Logger.getLogger(getClass()).debug("updateSchemaLanguages()");
473
474 Settings settings = project.getJAXPSettings();
475 ArrayList<String> languages = new ArrayList<String>();
476
477 if ( settings.getJAXPSchemaFactory().getSchemaFactoryProperties() != null) {
478 List<SchemaFactoryProperty> properties = settings.getJAXPSchemaFactory().getSchemaFactoryProperties().getSchemaFactoryProperty();
479 for ( SchemaFactoryProperty property : properties) {
480 languages.add( property.getLanguage());
481 }
482 } else {
483 settings = PreferencesHandler.getInstance().getPreferences().getJAXPSettings();
484
485 List<SchemaFactoryProperty> properties = settings.getJAXPSchemaFactory().getSchemaFactoryProperties().getSchemaFactoryProperty();
486 for ( SchemaFactoryProperty property : properties) {
487 languages.add( property.getLanguage());
488 }
489 }
490
491 getParserPage().setSchemaLanguages(languages);
492 }
493
494 /***
495 * Show the properties dialog.
496 */
497 public abstract void showPropertiesDialog();
498
499 /***
500 * @return the module.
501 */
502 public abstract Module getModule();
503
504 /***
505 * @param thread the currently active thread that runs the project.
506 */
507 public void setModuleThread(ModuleThread thread) {
508 if ( this.thread != null) {
509 this.thread.removeListener( this);
510 }
511
512 this.thread = thread;
513
514 if (thread != null) {
515 thread.addListener(this);
516 } else {
517 animatedThread.setRunning(false);
518 animatedThread = null;
519 thread = null;
520 }
521 }
522
523 public Page getSelectedPage() {
524 return cardPanel.selected();
525 }
526
527 public void threadFinished(ModuleThread thread) {
528 getConsolePanel().stop(thread);
529
530 animatedThread.setRunning(false);
531 animatedThread = null;
532
533 this.thread.removeListener( this);
534 this.thread = null;
535 }
536
537 public void threadStarted( ModuleThread thread) {
538 getConsolePanel().start(thread);
539
540 animatedThread = getProjectsView().createAnimatedThread(this);
541 animatedThread.start();
542 }
543
544 /***
545 * @return the currently active thread running the project.
546 */
547 public ModuleThread getModuleThread() {
548 return thread;
549 }
550
551 /***
552 * @return the result model.
553 */
554 public ResultModel getResult() {
555 URI dir = null;
556
557 if (getInputPage() != null) {
558 Filter filter = getInputPage().getInput(null).getFilter();
559 if ( filter != null) {
560 dir = URIUtils.createURI( filter.getDir());
561 }
562
563 return getResultPanel().createModel( dir);
564 }
565
566 return null;
567 }
568
569 /***
570 * @param changed updated when any of the project content has changed or when the
571 * project has been saved.
572 */
573 public void setChanged( boolean changed) {
574 notifyChange( changed);
575 }
576
577 public abstract SourceBuilder getSource();
578
579 /***
580 * @return true when the project content has changed and needs to be saved.
581 */
582 public boolean isChanged() {
583 if (uri == null) {
584 return true;
585 }
586
587 return getFieldManager().isChanged();
588 }
589
590 /***
591 * @param changed true when the content has changed.
592 */
593 public void notifyChange( boolean changed) {
594 parent.notifyChange( this);
595 }
596
597 /***
598 * @param selected The selected to set.
599 */
600 public void setSelected( boolean selected) {
601 this.selected = selected;
602 }
603
604 /***
605 * @return Returns the selected.
606 */
607 public boolean isSelected() {
608 return selected;
609 }
610
611 /***
612 * @pre the field manager does not have to exist yet.
613 * @post field manager created.
614 *
615 * @return the manager for the fields.
616 */
617 public FieldManager getFieldManager() {
618 if ( fieldManager == null) {
619 fieldManager = new FieldManager( this);
620 }
621
622 return fieldManager;
623 }
624
625 /***
626 * @pre the field manager does not have to exist yet.
627 * @post field manager created.
628 *
629 * @return the manager for the fields.
630 */
631 public ProjectUndoManager getUndoManager() {
632 if ( changeManager == null) {
633 changeManager = new ProjectUndoManager();
634 changeManager.addChangeListener(new ChangeListener() {
635 public void stateChanged(ChangeEvent arg0) {
636 if (getJavaPanel().isDisplayable()) {
637
638 SwingUtilities.invokeLater(new Runnable() {
639 public void run() {
640 getJavaPanel().setSource(getSource());
641 }
642 });
643 }
644 }
645 });
646 }
647
648 return changeManager;
649 }
650
651 /***
652 * Set the project.
653 *
654 * @param project the project.
655 */
656 public void setProject( Project project) {
657 this.project = project;
658
659 updateSchemaLanguages();
660
661 if (getParserPage() != null && getInputPage() != null) {
662 if ( project != null) {
663 getInputPage().setInput(getURI(), project.getInput());
664 getParserPage().setParser(getURI(), project.getParser());
665 } else {
666 getInputPage().setInput(getURI(), null);
667 getParserPage().setParser(getURI(), null);
668 }
669
670 getOverviewPanel().selectNode(getInputPage());
671 getOverviewPanel().expandAll();
672 }
673
674 getFieldManager().setChanged(false);
675 getUndoManager().discardAllEdits();
676 }
677
678 private static String getName( ProjectsView parent, URI uri) {
679 if ( uri != null) {
680 return URIUtils.getName( uri);
681 }
682
683 return parent.getNewProjectName();
684 }
685
686 /***
687 * @param node the panel to show.
688 */
689 public void show( OverviewNode node) {
690 if (node != null) {
691 while (node.getParentNode() != getOverviewPanel().getModel().getRoot()) {
692 node = node.getParentNode();
693 }
694
695 if (!(cardPanel.selected() == node)) {
696 cardPanel.show((Page)node);
697 selectPageButton((Page)node);
698 }
699
700 getProjectsView().getRoot().getHelpPanel().showID(((Page)node).getHelpID());
701 }
702 }
703
704 private void selectPageButton( Page page) {
705 Enumeration<AbstractButton> buttons = pageGroup.getElements();
706
707 while ( buttons.hasMoreElements()) {
708 AbstractButton button = buttons.nextElement();
709 if ( button.getText().equals(page.getShortName())) {
710 button.setSelected( true);
711 }
712 }
713 }
714
715 public Icon getIcon() {
716 return ICON;
717 }
718
719 public abstract void dispose();
720
721 public void showInitializationErrorMessage(Exception exception) {
722 Throwable cause = exception;
723
724 while (cause.getCause() != null) {
725 cause = cause.getCause();
726 }
727
728 showMessage("Fatal Error: \""+cause.getLocalizedMessage()+"\""+
729 "\nSee log for more information.", "Initialization Fatal Error");
730 }
731
732 public void setAnimatedThread(AnimatedThread thread) {
733 animatedThread = thread;
734 }
735
736 public AnimatedThread getAnimatedThread() {
737 return animatedThread;
738 }
739
740 public abstract String getHelpID();
741
742 public void showMessage(final String message, final String title) {
743 if (SwingUtilities.isEventDispatchThread()) {
744 JOptionPane.showMessageDialog(getProjectsView().getRoot(), message, title, JOptionPane.ERROR_MESSAGE);
745 } else {
746 SwingUtilities.invokeLater(new Runnable() {
747 public void run() {
748 JOptionPane.showMessageDialog(getProjectsView().getRoot(), message, title, JOptionPane.ERROR_MESSAGE);
749 }
750 });
751 }
752 }
753 }