source: trunk/src/org/expeditee/gui/Browser.java@ 947

Last change on this file since 947 was 947, checked in by bln4, 9 years ago

Removed usused imports

File size: 17.7 KB
Line 
1/**
2 * Browser.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.gui;
20
21import java.awt.Color;
22import java.awt.Dimension;
23import java.awt.Graphics;
24import java.awt.Graphics2D;
25import java.awt.Image;
26import java.awt.MouseInfo;
27import java.awt.Point;
28import java.awt.RenderingHints;
29import java.awt.Toolkit;
30import java.awt.event.ComponentEvent;
31import java.awt.event.ComponentListener;
32import java.awt.event.WindowEvent;
33import java.awt.event.WindowListener;
34import java.awt.event.WindowStateListener;
35import java.io.File;
36import java.net.Authenticator;
37import java.net.URL;
38import java.util.ArrayList;
39import java.util.Collection;
40import java.util.LinkedList;
41
42import javax.swing.JFrame;
43import javax.swing.RepaintManager;
44import javax.swing.SwingUtilities;
45
46import org.expeditee.AbsoluteLayout;
47import org.expeditee.actions.Actions;
48import org.expeditee.actions.Simple;
49import org.expeditee.agents.mail.MailSession;
50import org.expeditee.importer.FrameDNDTransferHandler;
51import org.expeditee.io.ProxyAuth;
52import org.expeditee.items.Item;
53import org.expeditee.items.Text;
54import org.expeditee.items.widgets.WidgetCacheManager;
55import org.expeditee.network.FrameShare;
56import org.expeditee.settings.Settings;
57import org.expeditee.settings.UserSettings;
58import org.expeditee.stats.Logger;
59import org.expeditee.stats.StatsLogger;
60import org.expeditee.taskmanagement.EntitySaveManager;
61import org.expeditee.taskmanagement.SaveStateChangedEvent;
62import org.expeditee.taskmanagement.SaveStateChangedEventListener;
63
64/**
65 * The Main GUI class, comprises what people will see on the screen.<br>
66 * Note: Each Object (Item) is responsible for drawing itself on the screen.<br>
67 * Note2: The Frame is registered as a MouseListener and KeyListener, and
68 * processes any Events.
69 *
70 * @author jdm18
71 *
72 */
73public class Browser extends JFrame implements ComponentListener,
74 WindowListener, WindowStateListener, SaveStateChangedEventListener {
75
76 /**
77 * Default version - just to stop eclipse from complaining about it.
78 */
79 private static final long serialVersionUID = 1L;
80
81 // private static final JScrollPane scrollPane = new JScrollPane();
82
83 public static Browser _theBrowser = null;
84
85 public static ProxyAuth proxyAuth = new ProxyAuth();
86
87 public static boolean _hasExited = false;
88
89 private MouseEventRouter _mouseEventRouter;
90
91 // A flag which is set once the application is exiting.
92 private boolean _isExiting = false;
93
94 private boolean _minimum_version6 = false;
95
96 public boolean isMinimumVersion6() {
97 return _minimum_version6;
98 }
99
100 private static boolean _initComplete = false;
101
102 private static String _startFrame = null;
103
104 /**
105 * Constructs a new Browser object, then launches it
106 *
107 * @param args
108 */
109 public static void main(String[] args) {
110
111 if(args.length > 0) {
112 _startFrame = args[0];
113 if(! Character.isDigit(_startFrame.charAt(_startFrame.length() - 1)))
114 _startFrame = _startFrame + "1";
115 }
116
117
118
119 // Prepare all expeditee and swing data on the AWT event thread.
120 SwingUtilities.invokeLater(new Runnable() {
121 public void run() {
122 // MessageBay.supressMessages(true);
123
124 // MessageBay.supressMessages(false);
125
126 _theBrowser = new Browser();
127
128 DisplayIO.refreshCursor();
129 _theBrowser.requestFocus();
130 FrameMouseActions.MouseX = MouseInfo.getPointerInfo()
131 .getLocation().x
132 - _theBrowser.getOrigin().x;
133 FrameMouseActions.MouseY = MouseInfo.getPointerInfo()
134 .getLocation().y
135 - _theBrowser.getOrigin().y;
136 _initComplete = true;
137
138 Authenticator.setDefault(proxyAuth);
139 }
140 });
141
142 }
143
144 public Point getOrigin() {
145 return getContentPane().getLocationOnScreen();
146 }
147
148 /**
149 * @return The mouse event router used for this browser. Never null after
150 * browser constructed.
151 */
152 public MouseEventRouter getMouseEventRouter() {
153 return _mouseEventRouter;
154 }
155
156 /**
157 * @return
158 *
159 * True if the application is about to exit. False if not. Not that this is
160 * only set once the window is in its closed state (not closing) or if the
161 * application has explicity being requested to exit.
162 *
163 * @see Browser#exit()
164 *
165 */
166 public boolean isExisting() {
167 return _isExiting;
168 }
169
170 public static boolean isInitComplete() {
171 return _initComplete;
172 }
173
174 public void setSizes(Dimension size) {
175 setSize(size);
176 setPreferredSize(size);
177 Dimension paneSize = getContentPane().getSize();
178 FrameGraphics.setMaxSize(paneSize);
179 }
180
181 private Browser() {
182 // center the frame on the screen
183 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
184 double xpos = screen.getWidth() / 2;
185 double ypos = screen.getHeight() / 2;
186 setLocation((int) (xpos - (UserSettings.InitialWidth.get() / 2)),
187 (int) (ypos - (UserSettings.InitialHeight.get() / 2)));
188
189 addWindowListener(this);
190 addWindowStateListener(this);
191
192 DisplayIO.addDisplayIOObserver(WidgetCacheManager.getInstance());
193 DisplayIO.addDisplayIOObserver(PopupManager.getInstance());
194
195
196 // set up the image used for the icon
197 try
198 {
199 URL iconURL = ClassLoader.getSystemResource("org/expeditee/assets/icons/expediteeicon128.png");
200 if (iconURL != null)
201 {
202 Image localImage = Toolkit.getDefaultToolkit().getImage(iconURL);
203 this.setIconImage(localImage);
204 }
205 }
206 catch (Exception e)
207 {
208 e.printStackTrace();
209 }
210
211 setSizes(new Dimension(UserSettings.InitialWidth.get(), UserSettings.InitialHeight.get()));
212
213 // set the layout to absolute layout for widgets
214 this.getContentPane().setLayout(new AbsoluteLayout());
215
216 _mouseEventRouter = new MouseEventRouter(getJMenuBar(),
217 getContentPane());
218
219 // enable the glasspane-for capturing all mouse events
220 this.setGlassPane(_mouseEventRouter);
221
222 this.getGlassPane().setVisible(true);
223 this.getContentPane().setBackground(Color.white);
224 this.getContentPane().setFocusTraversalKeysEnabled(false);
225
226 addComponentListener(this);
227 pack();
228
229 // Reset windows to user specified size
230 // Must be done after initialising the content pane above!
231 setSizes(new Dimension(UserSettings.InitialWidth.get(), UserSettings.InitialHeight.get()));
232
233 // UserSettings.ProfileName.set(FrameIO.ConvertToValidFramesetName(System.getProperty("user.name")));
234 String userName = UserSettings.ProfileName.get();
235 //UserSettings.UserName.set(UserSettings.ProfileName.get());
236
237 // Load documentation and start pages
238 FrameUtils.extractResources(false);
239 // Load fonts before loading any frames so the items on the frames will be able to access their fonts
240 Text.InitFonts();
241
242 Frame profile = loadProfile(userName);
243
244 // Need to display errors once things have been init otherwise
245 // exceptions occur if there are more than four messages neededing to be
246 // displayed.
247
248 Frame defaultProfile = loadProfile(UserSettings.DEFAULT_PROFILE_NAME);
249
250 Collection<String> warningMessages = new LinkedList<String>();
251 warningMessages.addAll(FrameUtils.ParseProfile(defaultProfile));
252 //Save the cursor if the defaultProfile had a custom cursor
253 Collection<Item> cursor = null;
254 if(FreeItems.hasCursor()){
255 cursor = new ArrayList<Item>();
256 cursor.addAll(FreeItems.getCursor());
257 }
258 warningMessages.addAll(FrameUtils.ParseProfile(profile));
259 if(cursor != null && !FreeItems.hasCursor()){
260 FreeItems.setCursor(cursor);
261 }
262
263 /*
264 * See Java bug ID 4016934. They say that window closed events are
265 * called once the JFrame is disposed.
266 */
267 setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
268
269 // Expeditee handles its own repainting of AWT/Swing components
270 RepaintManager.setCurrentManager(ExpediteeRepaintManager.getInstance());
271
272 // Listen for save status to display during and after runtime
273 EntitySaveManager.getInstance().addSaveStateChangedEventListener(this);
274
275 String full_version = System.getProperty("java.version");
276 String[] version_parts = full_version.split("\\.");
277 if (version_parts.length>=2) {
278 String version_str = version_parts[0] + "." + version_parts[1];
279 double version = Double.parseDouble(version_str);
280
281 if (version >= 1.6) {
282 // Set the drag and drop handler
283 _minimum_version6 = true;
284 setTransferHandler(FrameDNDTransferHandler.getInstance());
285 } else {
286 System.err.println("Upgrade to a (minimum) of Java 1.6 to enable drag and drop support in Expeditee");
287 }
288 }
289 else {
290 System.err.println("Unable to parse Java version number " + full_version + " to determin if Drag and Drop supported");
291
292 }
293
294
295 try {
296 warningMessages.addAll(Actions.Init());
297
298 Settings.Init();
299
300 DisplayIO.Init(this);
301 // Set visible must be just after DisplayIO.Init for the message box
302 // to
303 // be the right size
304 setVisible(true);
305
306 setupGraphics();
307
308 // required to accept TAB key
309 setFocusTraversalKeysEnabled(false);
310
311 // Must be loaded after setupGraphics if images are on the frame
312 // Turn off XRay mode and load the first frame
313 FrameGraphics.setMode(FrameGraphics.MODE_NORMAL, false);
314
315 // Go to the start frame if specified, otherwise go to the profile frame
316 Frame start = null;
317 if(_startFrame == null) {
318 _startFrame = UserSettings.StartFrame.get();
319 if(_startFrame != null && !Character.isDigit(_startFrame.charAt(_startFrame.length() - 1)))
320 _startFrame = _startFrame + "1";
321 }
322 if((start = FrameIO.LoadFrame(_startFrame)) != null) {
323 // Make sure HomeFrame gets set
324 if (UserSettings.HomeFrame.get() == null)
325 UserSettings.HomeFrame.set(profile.getName());
326 // Make sure the user can get back to the profile frame easily
327 DisplayIO.addToBack(profile);
328 // Go to the start frame
329 DisplayIO.setCurrentFrame(start, true);
330 } else {
331 // If an invalid start frame was specified, show a warning
332 if(_startFrame != null) {
333 warningMessages.add("Unknown frame: " + _startFrame);
334 }
335 // Go to the profile frame
336 FrameUtils.loadFirstFrame(profile);
337 }
338 DisplayIO.UpdateTitle();
339
340 /*
341 * I think this can be moved back up to the top of the Go method
342 * now... It used to crash the program trying to print error
343 * messages up the top
344 */
345 for (String message : warningMessages)
346 MessageBay.warningMessage(message);
347
348 this.getContentPane().addKeyListener(FrameKeyboardActions.getInstance());
349 this.addKeyListener(FrameKeyboardActions.getInstance());
350
351 _mouseEventRouter.addExpediteeMouseListener(FrameMouseActions.getInstance());
352 _mouseEventRouter.addExpediteeMouseMotionListener(FrameMouseActions.getInstance());
353 _mouseEventRouter.addExpediteeMouseWheelListener(FrameMouseActions.getInstance());
354
355 // Dont refresh for the profile frame otherwise error messages are shown twice
356 if (!DisplayIO.getCurrentFrame().equals(profile)) {
357 FrameKeyboardActions.Refresh();
358 // If it's the profile frame just reparse it in order to display images/circles/widgets correctly
359 } else {
360 FrameUtils.Parse(profile);
361 }
362 // setVisible(true);
363 } catch (Exception e) {
364 e.printStackTrace();
365 Logger.Log(e);
366 }
367 }
368
369 /**
370 * @param userName
371 * @return
372 */
373 private Frame loadProfile(String userName) {
374 Frame profile = FrameIO.LoadProfile(userName);
375 if (profile == null) {
376 try {
377 profile = FrameIO.CreateNewProfile(userName);
378 } catch (Exception e) {
379 // TODO tell the user that there was a problem creating the
380 // profile frame and close nicely
381 e.printStackTrace();
382 assert (false);
383 }
384 }
385 return profile;
386 }
387
388 public Graphics2D g;
389
390 private void setupGraphics() {
391 if (g != null)
392 g.dispose();
393 g = (Graphics2D) this.getContentPane().getGraphics();
394 assert (g != null);
395 g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
396 RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
397 g.setFont(g.getFont().deriveFont(40f));
398 FrameGraphics.setDisplayGraphics(g);
399 }
400
401 // private int count = 0;
402 @Override
403 public void paint(Graphics g) {
404 // All this does is make sure the screen is repainted when the browser
405 // is moved so that some of the window is off the edge of the display
406 // then moved back into view
407 super.paint(g);
408 FrameGraphics.ForceRepaint();
409 // System.out.println("Paint " + count++);
410 }
411
412 /**
413 * @inheritDoc
414 */
415 public void componentResized(ComponentEvent e) {
416 setSizes(this.getSize());
417 setupGraphics();
418 FrameIO.RefreshCasheImages();
419 FrameGraphics.ForceRepaint();
420 }
421
422 /**
423 * @inheritDoc
424 */
425 public void componentMoved(ComponentEvent e) {
426 // FrameGraphics.setMaxSize(this.getSize());
427 }
428
429 /**
430 * @inheritDoc
431 */
432 public void componentShown(ComponentEvent e) {
433 }
434
435 /**
436 * @inheritDoc
437 */
438 public void componentHidden(ComponentEvent e) {
439 }
440
441 public void windowClosing(WindowEvent e) {
442 }
443
444 public void windowClosed(WindowEvent e) {
445 exit();
446 }
447
448 public void windowOpened(WindowEvent e) {
449 }
450
451 public void windowIconified(WindowEvent e) {
452 }
453
454 public void windowDeiconified(WindowEvent e) {
455 }
456
457 public void windowActivated(WindowEvent e) {
458 }
459
460 public void windowDeactivated(WindowEvent e) {
461 }
462
463 public void windowStateChanged(WindowEvent e) {
464 }
465
466 public int getDrawingAreaX() {
467 // return scrollPane.getLocationOnScreen().x;
468 return this.getLocationOnScreen().x;
469 }
470
471 public int getDrawingAreaY() {
472 // return scrollPane.getLocationOnScreen().y;
473 return this.getLocationOnScreen().y;
474 }
475
476 public void saveCompleted(SaveStateChangedEvent event) {
477 // if (isExisting()) {
478
479 // } else {
480 MessageBay.displayMessage("Save finished!", Color.BLUE);
481 // }
482 }
483
484 public void saveStarted(SaveStateChangedEvent event) {
485 // if (isExisting()) {
486
487 // } else {
488 String name = event.getEntity().getSaveName();
489 if (name == null)
490 name = "data";
491 MessageBay.displayMessage("Saving " + name + "...", Color.BLUE);
492 // }
493 }
494
495 /**
496 * Closes the browser and ends the application. Performs saving operations -
497 * halting until saves have completed. Feedback is given to the user while
498 * the application is exiting. Must call on the swing thread.
499 */
500 public void exit() {
501
502 // Set exiting flag
503 _isExiting = true;
504
505 MessageBay.displayMessage("System exiting...");
506
507 /**
508 * TODO: Prompt the user etc.
509 */
510
511 // TODO: Should we should a popup with a progress bar for user feedback?
512 // this would be nice and easy to do.
513 // Exit on a dedicated thread so that feedback can be obtained
514 new Exiter().start(); // this will exit the application
515 }
516
517 /**
518 * The system must exit on a different thread other than the swing thread so
519 * that the save threads can fire save-feedback to the swing thread and thus
520 * provide user feedback on asynchronous save operations.
521 *
522 * @author Brook Novak
523 *
524 */
525 private class Exiter extends Thread {
526
527 @Override
528 public void run() {
529
530 // The final save point for saveable entities
531 EntitySaveManager.getInstance().saveAll();
532 try {
533 EntitySaveManager.getInstance().waitUntilAllSavingFinished();
534 } catch (InterruptedException e) {
535 e.printStackTrace();
536 }
537
538 // The final phase must save on the swing thread since dealing with
539 // the expeditee data model
540 SwingUtilities.invokeLater(new Runnable() {
541 public void run() {
542
543 // Stop any agents or simple programs
544 Simple.stop();
545 Actions.stopAgent();
546 // Wait for them to stop
547 try {
548 MessageBay
549 .displayMessage("Stopping Simple programs..."); // TODO:
550 /**
551 * Only stop if need to...
552 */
553 while (Simple.isProgramRunning()) {
554 Thread.sleep(100);
555 /* Brook: What purpose does this serve? */
556 }
557 MessageBay.displayMessage("Stopping Agents...");
558 /* TODO: Only stop if need to... */
559 while (Actions.isAgentRunning()) {
560 Thread.sleep(100); // Brook: What purpose does this
561 // serve?
562 }
563 } catch (Exception e) {
564
565 }
566
567 MessageBay.displayMessage("Saving current frame...");
568 FrameIO.SaveFrame(DisplayIO.getCurrentFrame());
569
570 MessageBay.displayMessage("Saving stats...");
571 StatsLogger.WriteStatsFile();
572
573 if (MailSession.getInstance() != null) {
574 if (MailSession.getInstance().finalise()) {
575 // TODO display this message before the finalising
576 // is done but only if the mail needs closing
577 MessageBay.displayMessage("Closed ExpMail...");
578 }
579 }
580
581 if (FrameShare.getInstance() != null) {
582 MessageBay.displayMessage("Stopping FrameServer...");
583 FrameShare.getInstance().finalise();
584 }
585
586 MessageBay.displayMessage("System exited");
587
588 // Finally remove the messages frameset
589 FrameIO.moveFrameset("messages", FrameIO.MESSAGES_PATH);
590
591 /*
592 * Create a new messages folder so that it doesn't throw
593 * Exceptions when two Expeditee's open at once and the
594 * second tries to save its messages
595 */
596 File file = new File(FrameIO.MESSAGES_PATH + "messages");
597 file.mkdirs();
598
599 Browser._hasExited = true;
600
601 System.exit(0);
602 }
603 });
604 }
605 }
606
607 /**
608 * Used to set up the the browser for use in testing.
609 *
610 * @return
611 */
612 public static Browser initializeForTesting() {
613 if (Browser._theBrowser == null) {
614 FrameShare.disableNetworking = true;
615 MailSession._autoConnect = false;
616
617 Browser.main(new String[]{});
618 try {
619 while (!isInitComplete()) {
620 Thread.sleep(10);
621 }
622 } catch (Exception e) {
623 }
624 }
625 return _theBrowser;
626 }
627
628}
Note: See TracBrowser for help on using the repository browser.