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

Last change on this file since 535 was 535, checked in by jts21, 11 years ago

Get proxy config working

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