001: /*
002: * $Header: /cvs/j3dfly/J3dFly/src/org/jdesktop/j3dfly/J3dFly.java,v 1.3 2007/05/02 22:06:32 paulby Exp $
003: *
004: * Sun Public License Notice
005: *
006: * The contents of this file are subject to the Sun Public License Version
007: * 1.0 (the "License"). You may not use this file except in compliance with
008: * the License. A copy of the License is available at http://www.sun.com/
009: *
010: * The Original Code is Java 3D(tm) Fly Through.
011: * The Initial Developer of the Original Code is Paul Byrne.
012: * Portions created by Paul Byrne are Copyright (C) 2002.
013: * All Rights Reserved.
014: *
015: * Contributor(s): Paul Byrne.
016: *
017: **/
018: package org.jdesktop.j3dfly;
019:
020: import javax.swing.JWindow;
021: import javax.swing.JFrame;
022: import javax.swing.JMenuBar;
023: import java.lang.Package;
024: import java.awt.Dimension;
025: import java.awt.Toolkit;
026:
027: import javax.media.j3d.Canvas3D;
028: import javax.media.j3d.BranchGroup;
029: import com.sun.j3d.utils.universe.SimpleUniverse;
030: import com.sun.j3d.utils.universe.ConfiguredUniverse;
031: import org.jdesktop.j3dfly.utils.developmenttools.DevelopmentLocale;
032: import org.jdesktop.j3dfly.utils.developmenttools.DevelopmentLocaleFactory;
033: import org.jdesktop.j3dfly.utils.vpbehaviors.ViewUtils;
034: import org.jdesktop.j3dfly.utils.gui.SplashWindow;
035: import org.jdesktop.j3dfly.utils.gui.ErrorHandler;
036: import org.jdesktop.j3dfly.utils.gui.ErrorManager;
037:
038: import org.jdesktop.j3dfly.event.EventProcessor;
039: import org.jdesktop.j3dfly.event.FileLoadEvent;
040: import org.jdesktop.j3dfly.event.FlyEventListener;
041:
042: /**
043: * @author Paul Byrne
044: * @version $Revision: 1.3 $
045: */
046:
047: public class J3dFly implements java.awt.event.WindowListener {
048:
049: private J3dFlyController controller;
050: private java.awt.Container[] containers;
051:
052: private boolean fullscreen = false;
053: private boolean showall = false;
054: private boolean showControls = true;
055: private boolean addLights = false;
056: private boolean showDocTools = false;
057:
058: private ControlFrame controlFrame = null;
059: private javax.swing.JPanel toolBarPanel = null;
060:
061: private SimpleUniverse universe;
062: private J3dFlyContext context;
063: private Class contextClass = null;
064:
065: private JMenuBar mainMenuBar = null;
066:
067: /**
068: * @param mainMenuBar the menu bar to which the plugins will add
069: * their menus
070: *
071: * @param showControls Determines if the menuBar should be attached to
072: * the J3dFly Frame (or in full screen if the control panel should be shown)
073: */
074: public J3dFly(JMenuBar mainMenuBar, boolean showControls) {
075: this (mainMenuBar, null, showControls, null, null, null);
076: }
077:
078: /**
079: * @param mainMenuBar the menu bar to which the plugins will add
080: * their menus
081: *
082: * @param toolBarPanel the panel in which plugins can place their toolbars
083: *
084: * @param showControls Determines if the menuBar should be attached to
085: * the J3dFly Frame (or in full screen if the control panel should be shown)
086: *
087: * @param systemPrefsFile The File for the system preferences, if this is
088: * null the method will first check the property J3dFly.SystemPlugins and
089: * then try the default file systemPrefs.xml
090: *
091: * @param contextClass the class used to construct the context, if this is
092: * null J3dFlyContext is used
093: *
094: * @param toolBG this is the Branch Graph in which all tools will be placed.
095: * This BranchGraph is not saved.
096: */
097: public J3dFly(JMenuBar mainMenuBar,
098: javax.swing.JPanel toolBarPanel, boolean showControls,
099: java.io.File systemPrefsFile, Class contextClass,
100: BranchGroup toolBG) {
101: this (mainMenuBar, toolBarPanel, showControls, systemPrefsFile,
102: contextClass, toolBG, null);
103: }
104:
105: /**&
106: * Constructor used by J3dEdit
107: */
108: public J3dFly(JMenuBar mainMenuBar,
109: javax.swing.JPanel toolBarPanel, boolean showControls,
110: java.io.File systemPrefsFile, Class contextClass,
111: BranchGroup toolBG, SimpleUniverse userUniverse) {
112: this .mainMenuBar = mainMenuBar;
113: this .showControls = showControls;
114: this .contextClass = contextClass;
115: this .toolBarPanel = toolBarPanel;
116:
117: if (systemPrefsFile == null) {
118: String prop = System.getProperty("J3dFly.SystemPlugins");
119: if (prop == null)
120: systemPrefsFile = new java.io.File("systemPrefs.xml");
121: else
122: systemPrefsFile = new java.io.File(prop);
123: }
124:
125: if (toolBG == null) {
126: toolBG = new BranchGroup();
127: toolBG.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
128: toolBG.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
129: toolBG.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
130: }
131:
132: j3dFlyInit(systemPrefsFile, toolBG, userUniverse);
133: }
134:
135: /** Creates new form j3dfly */
136: public J3dFly(String[] args) {
137: SplashWindow.showSplashscreen("org/jdesktop/j3dfly/splash.jpg");
138:
139: checkProperties(args);
140:
141: BranchGroup toolBG = new BranchGroup();
142: toolBG.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
143: toolBG.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
144: toolBG.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
145:
146: mainMenuBar = new JMenuBar();
147: String prop = System.getProperty("J3dFly.SystemPlugins");
148: if (prop == null)
149: prop = "systemPrefs.xml";
150: j3dFlyInit(new java.io.File(prop), toolBG, null);
151:
152: if (args.length != 0 && !args[args.length - 1].startsWith("-")) {
153: SplashWindow.showMessage("Loading Scene");
154: controller.loadGeometry(new java.io.File(
155: args[args.length - 1]));
156: if (showall) {
157: context.getEventProcessor().addListener(
158: new FileLoadedListener(), FileLoadEvent.class);
159: }
160: }
161:
162: SplashWindow.destroySplashscreen();
163:
164: ((ConfiguredUniverse) universe).setVisible(true);
165:
166: if (controlFrame != null)
167: controlFrame.setVisible(true);
168: }
169:
170: /**
171: * Get the controller class which handles all the features
172: * in J3dFly
173: */
174: public J3dFlyController getController() {
175: return controller;
176: }
177:
178: /**
179: * Get the Context which is currently active in J3dFly.
180: *
181: * In this version only a single Context is supported, in the future
182: * the API may be extended to allow the Context to be changed
183: */
184: public J3dFlyContext getCurrentContext() {
185: return context;
186: }
187:
188: private void j3dFlyInit(java.io.File systemPrefsFile,
189: BranchGroup toolBG, SimpleUniverse userUniverse) {
190: new J3dVersionCheck(this );
191:
192: java.io.File userPrefsFile;
193: String prop = System.getProperty("J3dFly.UserPlugins");
194: if (prop == null)
195: userPrefsFile = new java.io.File("userPrefs.xml");
196: else
197: userPrefsFile = new java.io.File(prop);
198:
199: SplashWindow.showMessage("Getting Graphics Configuration");
200:
201: if (userUniverse == null) {
202: java.net.URL configURL = ConfiguredUniverse
203: .getConfigURL(null);
204: if (configURL == null)
205: SplashWindow
206: .showMessage("Creating Configured Universe ");
207: else
208: SplashWindow
209: .showMessage("Creating Configured Universe : "
210: + configURL.getFile());
211:
212: universe = new ConfiguredUniverse(configURL,
213: new DevelopmentLocaleFactory(), false);
214: } else
215: universe = userUniverse;
216:
217: ((DevelopmentLocale) universe.getLocale())
218: .setHiddenBranchGraph(toolBG);
219:
220: universe.getViewer().getView().setBackClipDistance(100.0);
221: containers = universe.getViewer().getJFrames();
222:
223: SplashWindow.showMessage("Creating Controls");
224:
225: if (contextClass == null)
226: context = new J3dFlyContext((DevelopmentLocale) universe
227: .getLocale(), this );
228: else {
229: try {
230: java.lang.reflect.Constructor con = contextClass
231: .getConstructor(new Class[] {
232: DevelopmentLocale.class, J3dFly.class });
233: context = (J3dFlyContext) con
234: .newInstance(new Object[] {
235: (DevelopmentLocale) universe
236: .getLocale(), this });
237: } catch (Exception e) {
238: ErrorManager.getDefault().notify(
239: e,
240: ErrorHandler.ERROR,
241: "Error trying to instantiate context "
242: + contextClass);
243: System.exit(1);
244: }
245: }
246:
247: if (userUniverse != null)
248: context.setUniverse(userUniverse);
249:
250: controller = new J3dFlyController(context);
251:
252: if (System.getProperty("j3d.configURL") != null
253: || containers.length > 1) {
254: // User specified a ConfiguredUniverse config file
255: // So put controls in a seperate Frame
256: KeyControls keyControls = null;
257: if (showControls) {
258: controlFrame = new ControlFrame(context, controller);
259: controlFrame.setJMenuBar(mainMenuBar);
260: keyControls = new KeyControls(this , controlFrame);
261: toolBarPanel = controlFrame.getToolBarPanel();
262: }
263: if (containers[0] instanceof JWindow)
264: for (int i = 0; i < containers.length; i++) {
265: ((JWindow) containers[i]).addWindowListener(this );
266: }
267: else if (containers[0] instanceof JFrame)
268: for (int i = 0; i < containers.length; i++) {
269: ((JFrame) containers[i]).addWindowListener(this );
270: }
271: Canvas3D[] canvases = universe.getViewer().getCanvas3Ds();
272: for (int i = 0; i < canvases.length; i++)
273: canvases[i].addKeyListener(keyControls);
274: } else {
275: Dimension screenSize = Toolkit.getDefaultToolkit()
276: .getScreenSize();
277: ((JFrame) containers[0]).addWindowListener(this );
278: ((JFrame) containers[0])
279: .setTitle("Sun Java 3D(tm) Fly Through 2.0beta "
280: + Version.version);
281: if (showControls) {
282: ((JFrame) containers[0]).setJMenuBar(mainMenuBar);
283: ((JFrame) containers[0]).invalidate();
284: }
285: ((JFrame) containers[0]).pack();
286: containers[0].setSize(screenSize.width / 2,
287: screenSize.height / 2);
288: }
289:
290: context.getPluginPreferenceControl().installPlugins(
291: systemPrefsFile, userPrefsFile, context);
292:
293: /*
294: if (showDocTools && container instanceof javax.swing.JFrame) {
295: org.jdesktop.j3dfly.doctools.DocViewer docViewer = new org.jdesktop.j3dfly.doctools.DocViewer( (JFrame)container, false, context );
296: Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
297: docViewer.setSize( screenSize.width/2, screenSize.height/2 );
298: docViewer.setLocation( 0, screenSize.height/2 );
299: docViewer.setVisible(true);
300:
301: SplashWindow.showMessage("Starting PDF Viewer");
302: org.jdesktop.j3dfly.pdfdoctools.DocViewer docViewer2 = new org.jdesktop.j3dfly.pdfdoctools.DocViewer( (JFrame)container, false, context );
303: docViewer2.setSize( screenSize.width/2, screenSize.height );
304: docViewer2.setLocation( screenSize.width/2, 0 );
305: docViewer2.setVisible(true);
306: }
307: */
308:
309: }
310:
311: /**
312: * Set the title on the first frame.
313: *
314: * If the system is running full screen windows then no action is taken
315: */
316: void setFrameTitle(String title) {
317: if (containers[0] instanceof JFrame)
318: ((JFrame) containers[0]).setTitle(title);
319: }
320:
321: /**
322: * Returns the menu bar for j3dFly
323: *
324: * The menu created when the main window is created but it has
325: * no submenus be default. Each plugin will call this method and
326: * add itself to the set of menus
327: */
328: JMenuBar getMainMenuBar() {
329: return mainMenuBar;
330: }
331:
332: /**
333: * Returns the Panel in which the Plugins can insert toolbars. May
334: * return null
335: */
336: javax.swing.JPanel getToolBarPanel() {
337: return toolBarPanel;
338: }
339:
340: /**
341: * Check the value of any properties associated with J3dFly
342: */
343: private void checkProperties(String[] args) {
344: if (System.getProperty("j3dfly.fullscreen") != null)
345: fullscreen = true;
346:
347: if (args == null)
348: return;
349:
350: for (int i = 0; i < args.length; i++) {
351: if (args[i].equalsIgnoreCase("-fullscreen"))
352: fullscreen = true;
353: else if (args[i].equalsIgnoreCase("-hidecontrols"))
354: showControls = false;
355: else if (args[i].equalsIgnoreCase("-showall"))
356: showall = true;
357: /* else if (args[i].equalsIgnoreCase("-orbit"))
358: defaultBehavior = "Orbit";
359: else if (args[i].equalsIgnoreCase("-hover"))
360: defaultBehavior = "Hover";
361: else if (args[i].equalsIgnoreCase("-drive"))
362: defaultBehavior = "Drive";
363: else if (args[i].equalsIgnoreCase("-fly"))
364: defaultBehavior = "Fly";
365: else if (args[i].equalsIgnoreCase("-key"))
366: defaultBehavior = "KeyNavigator";
367: */
368: else if (args[i].equalsIgnoreCase("-addlights"))
369: addLights = true;
370: else if (args[i].equalsIgnoreCase("-doctools"))
371: showDocTools = true;
372: else if (args[i].equalsIgnoreCase("-help")) {
373: System.out.println("Usage : fly [options] [filename]");
374: System.out
375: .println("Options : -fullscreen, -hidecontrols, -showall, -orbit, -hover, -drive, -fly, -addlights, -doctools, -hidecontrols");
376: } else {
377: if (args[i].charAt(0) == '-')
378: System.out
379: .println("Unrecognised option " + args[i]);
380: }
381: }
382:
383: }
384:
385: /**
386: * Exit the app
387: */
388: protected void exit() {
389: System.exit(0);
390: }
391:
392: /**
393: * Return the first top level container of J3dFly
394: */
395: public java.awt.Container getContainer() {
396: return containers[0];
397: }
398:
399: /**
400: * Return the top level containers of J3dFly
401: */
402: public java.awt.Container[] getContainers() {
403: return containers;
404: }
405:
406: /**
407: * Returns the frame which should be the parent of all dialogs
408: *
409: * If J3dFly is running in fullscreen this method will return null
410: */
411: public java.awt.Frame getDialogParent() {
412: if (containers[0] instanceof java.awt.Frame)
413: return (java.awt.Frame) containers[0];
414: else
415: return null;
416: }
417:
418: /**
419: * Get the Universe
420: */
421: public SimpleUniverse getUniverse() {
422: return universe;
423: }
424:
425: /**
426: * Used by J3dEdit to allow user to load a scene,
427: * a FileCHooser will be displayed allowing scene selection
428: */
429: public void loadScene() {
430: controller.loadScene();
431: }
432:
433: public void saveScene() {
434: throw new RuntimeException("Not Implemented");
435: }
436:
437: public void saveAsScene() {
438: throw new RuntimeException("Not Implemented");
439: }
440:
441: /**
442: * @param args the command line arguments
443: */
444: public static void main(String args[]) {
445: new J3dFly(args);
446: }
447:
448: public void windowDeactivated(final java.awt.event.WindowEvent p1) {
449: }
450:
451: public void windowClosed(final java.awt.event.WindowEvent p1) {
452: exit();
453: }
454:
455: public void windowDeiconified(final java.awt.event.WindowEvent p1) {
456: }
457:
458: public void windowOpened(final java.awt.event.WindowEvent p1) {
459: }
460:
461: public void windowIconified(final java.awt.event.WindowEvent p1) {
462: }
463:
464: public void windowClosing(final java.awt.event.WindowEvent p1) {
465: if (containers[0] instanceof javax.swing.JWindow) {
466: for (int i = 0; i < containers.length; i++)
467: ((JWindow) containers[i]).dispose();
468: } else if (containers[0] instanceof javax.swing.JFrame) {
469: for (int i = 0; i < containers.length; i++)
470: ((JFrame) containers[i]).dispose();
471: } else
472: throw new RuntimeException("Internal Error");
473: }
474:
475: public void windowActivated(final java.awt.event.WindowEvent p1) {
476: }
477:
478: class FileLoadedListener implements FlyEventListener {
479:
480: public FileLoadedListener() {
481: }
482:
483: /**
484: * Called by EventProcessor when an event occurs for which this
485: * listener has registered interest
486: */
487: public void processFlyEvent(
488: final org.jdesktop.j3dfly.event.FlyEvent evt) {
489: controller.showAll(ViewUtils.POSITIVE_X_AXIS);
490: if (addLights)
491: controller.checkForLights(true);
492: context.getEventProcessor().removeListener(this ,
493: FileLoadEvent.class);
494: }
495: }
496:
497: /**
498: * Check which version of Java3D is installed
499: */
500: class J3dVersionCheck {
501: private boolean patchNext = false;
502:
503: private int getTokenEnd(int start, String str) {
504: int ret = start;
505: boolean finished = false;
506: char c;
507:
508: while (ret < str.length() && !finished) {
509: c = str.charAt(ret);
510: if (c == '.' || c == ' ')
511: finished = true;
512: else if (c == '_') {
513: finished = true;
514: patchNext = true;
515: } else {
516: ret++;
517: }
518: }
519:
520: return ret;
521: }
522:
523: /**
524: * Check which version of Java3D we are using
525: */
526: public J3dVersionCheck(J3dFly fly) {
527: Package p = Package.getPackage("javax.media.j3d");
528: String version = p.getImplementationVersion();
529:
530: if (version == null) {
531: javax.swing.JOptionPane
532: .showMessageDialog(
533: null,
534: "Java 3D can not be found, please reinstall Java3D 1.3.",
535: "Java 3D Not Installed",
536: javax.swing.JOptionPane.ERROR_MESSAGE);
537: fly.exit();
538: }
539:
540: // Syntax of version number is <int>.<int>[.<int[_<int>]][_<int>] [<str>]
541: // 1.2 1.2.1 1.2.1_001, 1.3_001, 1.2 text
542:
543: //version = "1.2";
544: //version = "1.2.1";
545: //version = "1.2.1_001";
546: //version = "1.3_001";
547: //version = "1.3_001 test data";
548: //version = "1.2 test data";
549: //version = "1.2.1 test data";
550: //version = "1.2.1_001 test data";
551:
552: int majorV = 0;
553: int minorV = 0;
554: int subV = 0;
555: int patchV = 0;
556:
557: int tokenStart = 0;
558: int tokenEnd = getTokenEnd(tokenStart, version);
559:
560: try {
561: majorV = Integer.parseInt(version.substring(tokenStart,
562: tokenEnd));
563:
564: tokenStart = tokenEnd + 1;
565: tokenEnd = getTokenEnd(tokenStart, version);
566:
567: minorV = Integer.parseInt(version.substring(tokenStart,
568: tokenEnd));
569:
570: if (patchNext) {
571: tokenStart = tokenEnd + 1;
572: tokenEnd = getTokenEnd(tokenStart, version);
573: if (tokenStart != tokenEnd)
574: patchV = Integer.parseInt(version.substring(
575: tokenStart, tokenEnd));
576: } else {
577: tokenStart = tokenEnd + 1;
578: tokenEnd = getTokenEnd(tokenStart, version);
579:
580: if (tokenStart != tokenEnd) {
581: subV = Integer.parseInt(version.substring(
582: tokenStart, tokenEnd));
583: } else
584: patchV = Integer.parseInt(version.substring(
585: tokenStart, tokenEnd));
586:
587: tokenStart = tokenEnd + 1;
588: tokenEnd = getTokenEnd(tokenStart, version);
589:
590: if (tokenStart != tokenEnd)
591: patchV = Integer.parseInt(version.substring(
592: tokenStart, tokenEnd));
593: }
594: } catch (NumberFormatException e) {
595: }
596:
597: if (minorV < 3) {
598: // Not 1.3 or greater
599: javax.swing.JOptionPane
600: .showMessageDialog(
601: null,
602: "Java3D Fly Through 2.0 is designed for use with Java 3D 1.3 or later.\nPlease upgrade your version of Java 3D.",
603: "Old Java 3D Version",
604: javax.swing.JOptionPane.ERROR_MESSAGE);
605: fly.exit();
606: }
607:
608: //System.out.println("Java3D Version "+majorV+"."+minorV+"_"+subV );
609:
610: // Check VM version
611: try {
612: Class vm = Class.forName("java.nio.channels.Channels");
613: } catch (ClassNotFoundException e) {
614: javax.swing.JOptionPane
615: .showMessageDialog(
616: null,
617: "Java3D Fly Through 2.0 is designed for use with JRE 1.4.\nPlease upgrade your version of Java.",
618: "Old Java VM",
619: javax.swing.JOptionPane.ERROR_MESSAGE);
620: fly.exit();
621: }
622: }
623:
624: }
625:
626: }
|