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
RevLine 
[919]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
[4]19package org.expeditee.gui;
20
[10]21import java.awt.Color;
[4]22import java.awt.Dimension;
23import java.awt.Graphics;
24import java.awt.Graphics2D;
[455]25import java.awt.Image;
[145]26import java.awt.MouseInfo;
27import java.awt.Point;
[4]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;
[348]35import java.io.File;
[535]36import java.net.Authenticator;
[455]37import java.net.URL;
[427]38import java.util.ArrayList;
[80]39import java.util.Collection;
[376]40import java.util.LinkedList;
[4]41
42import javax.swing.JFrame;
[121]43import javax.swing.RepaintManager;
[139]44import javax.swing.SwingUtilities;
[4]45
[10]46import org.expeditee.AbsoluteLayout;
[4]47import org.expeditee.actions.Actions;
[139]48import org.expeditee.actions.Simple;
[238]49import org.expeditee.agents.mail.MailSession;
[253]50import org.expeditee.importer.FrameDNDTransferHandler;
[535]51import org.expeditee.io.ProxyAuth;
[427]52import org.expeditee.items.Item;
[777]53import org.expeditee.items.Text;
[219]54import org.expeditee.items.widgets.WidgetCacheManager;
[298]55import org.expeditee.network.FrameShare;
[570]56import org.expeditee.settings.Settings;
57import org.expeditee.settings.UserSettings;
[419]58import org.expeditee.stats.Logger;
[139]59import org.expeditee.stats.StatsLogger;
60import org.expeditee.taskmanagement.EntitySaveManager;
61import org.expeditee.taskmanagement.SaveStateChangedEvent;
62import org.expeditee.taskmanagement.SaveStateChangedEventListener;
[4]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,
[139]74 WindowListener, WindowStateListener, SaveStateChangedEventListener {
[67]75
[4]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
[139]83 public static Browser _theBrowser = null;
[535]84
85 public static ProxyAuth proxyAuth = new ProxyAuth();
[348]86
[763]87 public static boolean _hasExited = false;
88
[320]89 private MouseEventRouter _mouseEventRouter;
[147]90
[139]91 // A flag which is set once the application is exiting.
92 private boolean _isExiting = false;
[67]93
[467]94 private boolean _minimum_version6 = false;
[311]95
[467]96 public boolean isMinimumVersion6() {
97 return _minimum_version6;
[309]98 }
99
[154]100 private static boolean _initComplete = false;
[667]101
102 private static String _startFrame = null;
[154]103
[4]104 /**
105 * Constructs a new Browser object, then launches it
106 *
107 * @param args
108 */
109 public static void main(String[] args) {
[667]110
111 if(args.length > 0) {
112 _startFrame = args[0];
113 if(! Character.isDigit(_startFrame.charAt(_startFrame.length() - 1)))
114 _startFrame = _startFrame + "1";
115 }
[147]116
[667]117
118
[139]119 // Prepare all expeditee and swing data on the AWT event thread.
120 SwingUtilities.invokeLater(new Runnable() {
121 public void run() {
[147]122 // MessageBay.supressMessages(true);
123
124 // MessageBay.supressMessages(false);
125
[139]126 _theBrowser = new Browser();
[455]127
[427]128 DisplayIO.refreshCursor();
[139]129 _theBrowser.requestFocus();
[147]130 FrameMouseActions.MouseX = MouseInfo.getPointerInfo()
131 .getLocation().x
132 - _theBrowser.getOrigin().x;
133 FrameMouseActions.MouseY = MouseInfo.getPointerInfo()
134 .getLocation().y
135 - _theBrowser.getOrigin().y;
[154]136 _initComplete = true;
[535]137
138 Authenticator.setDefault(proxyAuth);
[139]139 }
140 });
141
[4]142 }
[147]143
[145]144 public Point getOrigin() {
145 return getContentPane().getLocationOnScreen();
146 }
[348]147
[320]148 /**
[760]149 * @return The mouse event router used for this browser. Never null after
[348]150 * browser constructed.
[320]151 */
152 public MouseEventRouter getMouseEventRouter() {
153 return _mouseEventRouter;
154 }
[147]155
[139]156 /**
[147]157 * @return
[139]158 *
[147]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.
[139]162 *
163 * @see Browser#exit()
164 *
165 */
166 public boolean isExisting() {
167 return _isExiting;
168 }
[67]169
[763]170 public static boolean isInitComplete() {
[154]171 return _initComplete;
172 }
173
[4]174 public void setSizes(Dimension size) {
175 setSize(size);
176 setPreferredSize(size);
[80]177 Dimension paneSize = getContentPane().getSize();
178 FrameGraphics.setMaxSize(paneSize);
[4]179 }
180
[139]181 private Browser() {
[67]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;
[655]186 setLocation((int) (xpos - (UserSettings.InitialWidth.get() / 2)),
187 (int) (ypos - (UserSettings.InitialHeight.get() / 2)));
[4]188
[67]189 addWindowListener(this);
190 addWindowStateListener(this);
[233]191
[219]192 DisplayIO.addDisplayIOObserver(WidgetCacheManager.getInstance());
193 DisplayIO.addDisplayIOObserver(PopupManager.getInstance());
[67]194
[455]195
196 // set up the image used for the icon
197 try
198 {
[618]199 URL iconURL = ClassLoader.getSystemResource("org/expeditee/assets/icons/expediteeicon128.png");
[455]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
[699]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
[655]233 // UserSettings.ProfileName.set(FrameIO.ConvertToValidFramesetName(System.getProperty("user.name")));
234 String userName = UserSettings.ProfileName.get();
235 //UserSettings.UserName.set(UserSettings.ProfileName.get());
[781]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();
[147]241
[348]242 Frame profile = loadProfile(userName);
243
[233]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.
[4]247
[348]248 Frame defaultProfile = loadProfile(UserSettings.DEFAULT_PROFILE_NAME);
249
[376]250 Collection<String> warningMessages = new LinkedList<String>();
251 warningMessages.addAll(FrameUtils.ParseProfile(defaultProfile));
[427]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 }
[348]258 warningMessages.addAll(FrameUtils.ParseProfile(profile));
[427]259 if(cursor != null && !FreeItems.hasCursor()){
260 FreeItems.setCursor(cursor);
261 }
[348]262
263 /*
264 * See Java bug ID 4016934. They say that window closed events are
265 * called once the JFrame is disposed.
266 */
[147]267 setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
268
[121]269 // Expeditee handles its own repainting of AWT/Swing components
270 RepaintManager.setCurrentManager(ExpediteeRepaintManager.getInstance());
[147]271
[139]272 // Listen for save status to display during and after runtime
273 EntitySaveManager.getInstance().addSaveStateChangedEventListener(this);
[147]274
[467]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 }
[154]288 }
[467]289 else {
290 System.err.println("Unable to parse Java version number " + full_version + " to determin if Drag and Drop supported");
291
292 }
293
[154]294
[4]295 try {
[233]296 warningMessages.addAll(Actions.Init());
[570]297
298 Settings.Init();
[4]299
[108]300 DisplayIO.Init(this);
[147]301 // Set visible must be just after DisplayIO.Init for the message box
302 // to
[108]303 // be the right size
304 setVisible(true);
[4]305
[108]306 setupGraphics();
[102]307
[108]308 // required to accept TAB key
309 setFocusTraversalKeysEnabled(false);
[147]310
311 // Must be loaded after setupGraphics if images are on the frame
312 // Turn off XRay mode and load the first frame
[282]313 FrameGraphics.setMode(FrameGraphics.MODE_NORMAL, false);
[667]314
315 // Go to the start frame if specified, otherwise go to the profile frame
316 Frame start = null;
[732]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 }
[667]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 }
[115]338 DisplayIO.UpdateTitle();
[147]339
[348]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 */
[108]345 for (String message : warningMessages)
[121]346 MessageBay.warningMessage(message);
[4]347
[667]348 this.getContentPane().addKeyListener(FrameKeyboardActions.getInstance());
[345]349 this.addKeyListener(FrameKeyboardActions.getInstance());
[147]350
[667]351 _mouseEventRouter.addExpediteeMouseListener(FrameMouseActions.getInstance());
352 _mouseEventRouter.addExpediteeMouseMotionListener(FrameMouseActions.getInstance());
353 _mouseEventRouter.addExpediteeMouseWheelListener(FrameMouseActions.getInstance());
[348]354
[513]355 // Dont refresh for the profile frame otherwise error messages are shown twice
356 if (!DisplayIO.getCurrentFrame().equals(profile)) {
[348]357 FrameKeyboardActions.Refresh();
[513]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 }
[147]362 // setVisible(true);
[108]363 } catch (Exception e) {
364 e.printStackTrace();
365 Logger.Log(e);
366 }
367 }
[4]368
[348]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
[121]388 public Graphics2D g;
[80]389
[7]390 private void setupGraphics() {
[71]391 if (g != null)
392 g.dispose();
[7]393 g = (Graphics2D) this.getContentPane().getGraphics();
[67]394 assert (g != null);
[7]395 g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
396 RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
397 g.setFont(g.getFont().deriveFont(40f));
398 FrameGraphics.setDisplayGraphics(g);
[4]399 }
400
[67]401 // private int count = 0;
[4]402 @Override
403 public void paint(Graphics g) {
[67]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
[4]407 super.paint(g);
[121]408 FrameGraphics.ForceRepaint();
[102]409 // System.out.println("Paint " + count++);
[4]410 }
411
412 /**
413 * @inheritDoc
414 */
415 public void componentResized(ComponentEvent e) {
[7]416 setSizes(this.getSize());
417 setupGraphics();
[67]418 FrameIO.RefreshCasheImages();
[121]419 FrameGraphics.ForceRepaint();
[4]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) {
[139]445 exit();
[4]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 }
[139]475
476 public void saveCompleted(SaveStateChangedEvent event) {
[147]477 // if (isExisting()) {
478
479 // } else {
480 MessageBay.displayMessage("Save finished!", Color.BLUE);
481 // }
[139]482 }
483
484 public void saveStarted(SaveStateChangedEvent event) {
[147]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 // }
[139]493 }
[147]494
[139]495 /**
[147]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.
[139]499 */
500 public void exit() {
[147]501
[139]502 // Set exiting flag
503 _isExiting = true;
[147]504
[139]505 MessageBay.displayMessage("System exiting...");
[147]506
[139]507 /**
508 * TODO: Prompt the user etc.
509 */
510
[147]511 // TODO: Should we should a popup with a progress bar for user feedback?
512 // this would be nice and easy to do.
[139]513 // Exit on a dedicated thread so that feedback can be obtained
514 new Exiter().start(); // this will exit the application
515 }
[147]516
[139]517 /**
[147]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
[139]520 * provide user feedback on asynchronous save operations.
521 *
522 * @author Brook Novak
[147]523 *
[139]524 */
525 private class Exiter extends Thread {
526
527 @Override
528 public void run() {
[147]529
[139]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
[238]538 // The final phase must save on the swing thread since dealing with
539 // the expeditee data model
[139]540 SwingUtilities.invokeLater(new Runnable() {
541 public void run() {
542
[147]543 // Stop any agents or simple programs
[139]544 Simple.stop();
545 Actions.stopAgent();
[147]546 // Wait for them to stop
547 try {
548 MessageBay
549 .displayMessage("Stopping Simple programs..."); // TODO:
[298]550 /**
551 * Only stop if need to...
552 */
[147]553 while (Simple.isProgramRunning()) {
[311]554 Thread.sleep(100);
555 /* Brook: What purpose does this serve? */
[139]556 }
[311]557 MessageBay.displayMessage("Stopping Agents...");
558 /* TODO: Only stop if need to... */
[147]559 while (Actions.isAgentRunning()) {
560 Thread.sleep(100); // Brook: What purpose does this
[154]561 // serve?
[139]562 }
[147]563 } catch (Exception e) {
564
[139]565 }
[147]566
567 MessageBay.displayMessage("Saving current frame...");
[139]568 FrameIO.SaveFrame(DisplayIO.getCurrentFrame());
569
[147]570 MessageBay.displayMessage("Saving stats...");
[139]571 StatsLogger.WriteStatsFile();
[242]572
[254]573 if (MailSession.getInstance() != null) {
[290]574 if (MailSession.getInstance().finalise()) {
[298]575 // TODO display this message before the finalising
576 // is done but only if the mail needs closing
577 MessageBay.displayMessage("Closed ExpMail...");
[290]578 }
[254]579 }
[147]580
[298]581 if (FrameShare.getInstance() != null) {
582 MessageBay.displayMessage("Stopping FrameServer...");
583 FrameShare.getInstance().finalise();
584 }
585
[147]586 MessageBay.displayMessage("System exited");
[311]587
[348]588 // Finally remove the messages frameset
589 FrameIO.moveFrameset("messages", FrameIO.MESSAGES_PATH);
[311]590
[348]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
[763]599 Browser._hasExited = true;
600
[139]601 System.exit(0);
602 }
603 });
604 }
605 }
606
[242]607 /**
608 * Used to set up the the browser for use in testing.
609 *
610 * @return
611 */
612 public static Browser initializeForTesting() {
[156]613 if (Browser._theBrowser == null) {
[311]614 FrameShare.disableNetworking = true;
[242]615 MailSession._autoConnect = false;
[311]616
[926]617 Browser.main(new String[]{});
[156]618 try {
619 while (!isInitComplete()) {
620 Thread.sleep(10);
621 }
622 } catch (Exception e) {
623 }
624 }
625 return _theBrowser;
626 }
627
[4]628}
Note: See TracBrowser for help on using the repository browser.