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

Last change on this file since 298 was 298, checked in by ra33, 16 years ago

Adding networking stuff for peer to peer sharing of frames

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