source: trunk/src/org/expeditee/gui/MessageBay.java@ 674

Last change on this file since 674 was 674, checked in by jts21, 10 years ago

Add multi-mouse-button commands to status bar, change how status text is set

File size: 12.4 KB
RevLine 
[122]1package org.expeditee.gui;
2
3import java.awt.Color;
4import java.awt.Font;
5import java.awt.Graphics;
6import java.awt.Graphics2D;
7import java.awt.GraphicsEnvironment;
8import java.awt.Rectangle;
9import java.awt.RenderingHints;
10import java.awt.geom.Area;
11import java.awt.image.VolatileImage;
12import java.util.LinkedList;
13import java.util.List;
14
15import org.expeditee.actions.Misc;
16import org.expeditee.items.Item;
17import org.expeditee.items.Text;
18
19/**
[336]20 * The bay at the bottom of the expeditee browser which displays messages. TODO
21 * make it thread safe!
[130]22 *
[122]23 */
24public final class MessageBay {
[130]25
[409]26
[122]27 public static final int MESSAGE_BUFFER_HEIGHT = 100;
28
29 private static final int MESSAGE_LINK_Y_OFFSET = 100;
30
31 private static final int MESSAGE_LINK_X = 50;
[130]32
[122]33 public static final Color ERROR_COLOR = Color.red;
[130]34
[122]35 public static final String MESSAGES_FRAMESET_NAME = "Messages";
36
37 // messages shown in the message window
[673]38 private static Text[] _messages = new Text[3];
39 private static Text _status = null;
[122]40
41 // buffer of the message window
42 private static VolatileImage _messageBuffer = null;
[130]43
[122]44 // creator for creating the message frames
45 private static FrameCreator _creator = null;
46
47 // font used for the messages
48 private static Font _messageFont = Font.decode("Serif-Plain-16");
49
50 // the number of messages currently shown (used for scrolling up)
51 private static int _messageCount = 0;
[130]52
[122]53 // if true, error messages are not shown to the user
54 private static boolean _supressMessages = false;
55
56 // The link to the message frameset
[130]57 private static Item _messageLink = new Text(-2, "@"
58 + MESSAGES_FRAMESET_NAME, Color.black, Color.white);
[122]59
60 private static List<Rectangle> _dirtyAreas = new LinkedList<Rectangle>();
[130]61
[122]62 private static String _lastMessage = null;
63
[130]64 private MessageBay() {
65 }
66
[122]67 /**
68 * Syncs messsage bay size according to FrameGraphics max size.
[130]69 *
[122]70 */
71 static void updateSize() {
72
73 _messageBuffer = null;
74
75 for (int i = 0; i < _messages.length; i++) {
76 if (_messages[i] != null) {
[130]77 _messages[i].setOffset(0,
78 -FrameGraphics.getMaxFrameSize().height);
[336]79 // _messages[i].setMaxWidth(FrameGraphics.getMaxFrameSize().width);
[122]80 }
81 }
82
83 _messageLink.setOffset(0, -FrameGraphics.getMaxFrameSize().height);
[336]84 // _messageLink.setMaxWidth(FrameGraphics.getMaxFrameSize().width);
[130]85 // _messageLink.setPosition(FrameGraphics.getMaxFrameSize().width
86 // - MESSAGE_LINK_Y_OFFSET, MESSAGE_LINK_X);
[125]87 updateLink();
88 initBuffer();
[122]89 }
[130]90
[122]91 /**
92 * @param i
93 * @return True if i is an item in the message bay
94 */
95 public static boolean isMessageItem(Item i) {
96 if (_messages != null) {
97 for (Text txt : _messages) {
[130]98 if (txt == i)
99 return true;
[122]100 }
101 }
[130]102
[122]103 return i == _messageLink;
104 }
[130]105
[409]106 public synchronized static void addDirtyArea(Rectangle r) {
[122]107 _dirtyAreas.add(r);
108 }
[130]109
[409]110 static synchronized int getMessageBufferHeight() {
[130]111 if (_messageBuffer != null)
112 return _messageBuffer.getHeight();
[122]113 return 0;
114 }
[130]115
[409]116 public synchronized static Item getMessageLink() {
[122]117 return _messageLink;
118 }
[130]119
[409]120 public synchronized static Text[] getMessages() {
[122]121 return _messages;
122 }
[130]123
[409]124 public synchronized static boolean isDirty() {
[125]125 return !_dirtyAreas.isEmpty();
126 }
[130]127
[409]128 public synchronized static void invalidateFullBay() {
[138]129 if (_messageBuffer != null) {
130 _dirtyAreas.clear();
[336]131 addDirtyArea(new Rectangle(0,
132 FrameGraphics.getMaxFrameSize().height, _messageBuffer
133 .getWidth(), _messageBuffer.getHeight()));
[138]134 }
[125]135 }
[130]136
[409]137 private synchronized static boolean initBuffer() {
[125]138 if (_messageBuffer == null) {
[336]139 if (FrameGraphics.isAudienceMode()
140 || FrameGraphics.getMaxSize().width <= 0)
141 return false;
142
[125]143 GraphicsEnvironment ge = GraphicsEnvironment
144 .getLocalGraphicsEnvironment();
145 _messageBuffer = ge.getDefaultScreenDevice()
146 .getDefaultConfiguration().createCompatibleVolatileImage(
[147]147 FrameGraphics.getMaxSize().width,
[138]148 MESSAGE_BUFFER_HEIGHT);
[125]149 }
[138]150 return true;
[125]151 }
[130]152
[125]153 private static boolean isLinkInitialized = false;
[130]154
[125]155 private static void updateLink() {
[130]156
[147]157 if (!isLinkInitialized && FrameGraphics.getMaxSize().width > 0) {
[125]158 // set up 'Messages' link on the right hand side
[147]159 _messageLink.setPosition(FrameGraphics.getMaxSize().width
[130]160 - MESSAGE_LINK_Y_OFFSET, MESSAGE_LINK_X);
[125]161 _messageLink.setOffset(0, -FrameGraphics.getMaxFrameSize().height);
162 isLinkInitialized = true;
[130]163
[125]164 } else {
[147]165 _messageLink.setPosition(FrameGraphics.getMaxSize().width
[130]166 - MESSAGE_LINK_Y_OFFSET, MESSAGE_LINK_X);
[125]167 }
168 }
169
[122]170 /**
[130]171 * Repaints the message bay. Updates the message bay buffer and draws to
[122]172 * given graphics.
173 *
[130]174 * @param useInvalidation
175 * Set to true of repinting dirty areas only. Otherwise false for
176 * full-repaint.
177 *
[122]178 * @param g
179 *
180 * @param background
[130]181 * The color of the message background
[122]182 */
[336]183 public static synchronized void refresh(boolean useInvalidation,
184 Graphics g, Color background) {
[130]185
[147]186 if (FrameGraphics.getMaxSize().width <= 0)
[130]187 return;
188
[122]189 Area clip = null;
[130]190
[122]191 if (useInvalidation) { // build clip
192
193 if (!_dirtyAreas.isEmpty()) {
[130]194
[122]195 for (Rectangle r : _dirtyAreas) {
[125]196 r.y = (r.y < 0) ? 0 : r.y;
197 r.x = (r.x < 0) ? 0 : r.x;
[130]198 if (clip == null)
199 clip = new Area(r);
200 else
201 clip.add(new Area(r));
[122]202 }
[130]203 } else
204 return; // nothing to render
[122]205 }
206
207 _dirtyAreas.clear();
208
209 // Update the buffer
210 updateBuffer(background, clip);
[130]211
[122]212 // Now repaint to screen
213 if (!FrameGraphics.isAudienceMode()) {
[130]214
[125]215 // Translate clip to messagebox coords
[130]216 // clip.transform(t) // TODO
217 // g.setClip(clip);
218
219 g.drawImage(_messageBuffer, 0,
220 FrameGraphics.getMaxFrameSize().height, null);
[122]221 }
222
223 }
[130]224
[122]225 private static void updateBuffer(Color background, Area clip) {
[336]226 if (!initBuffer())
227 return;
[125]228
229 Graphics2D g = _messageBuffer.createGraphics();
[122]230
231 g.setClip(clip);
[125]232
[122]233 g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
234 RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
235 g.setColor(background);
[147]236 g.fillRect(0, 0, FrameGraphics.getMaxSize().width,
[130]237 MESSAGE_BUFFER_HEIGHT);
[122]238 g.setFont(_messageFont);
239 g.setColor(Color.BLACK);
[147]240 g.drawLine(0, 0, FrameGraphics.getMaxSize().width, 0);
[130]241
[122]242 for (Item t : _messages) {
[130]243 if (t == null)
244 continue;
[122]245 if (clip == null || t.isInDrawingArea(clip))
246 FrameGraphics.PaintItem(g, t);
247 }
[673]248 if(_status != null)
249 FrameGraphics.PaintItem(g, _status);
[130]250
251 if (// _messageLink.getLink() != null
252 // &&
253 (clip == null || _messageLink.isInDrawingArea(clip))) {
[122]254 FrameGraphics.PaintItem(g, _messageLink);
[125]255 }
[122]256 g.dispose();
[130]257
[122]258 }
[130]259
[284]260 private static Text displayMessage(String message, String link,
[122]261 List<String> actions, Color color) {
[284]262 return displayMessage(message, link, actions, color, true);
[122]263 }
[336]264
[409]265 public synchronized static Text displayMessage(String message, String link, Color color,
[336]266 boolean displayAlways, String action) {
[284]267 List<String> actions = new LinkedList<String>();
[376]268 if (action != null)
269 actions.add(action);
[284]270 return displayMessage(message, link, actions, color, displayAlways);
271 }
[130]272
[409]273 public synchronized static Text displayMessage(String message, String link,
[122]274 List<String> actions, Color color, boolean displayAlways) {
275
276 System.out.println(message);
277 assert (message != null);
[130]278
[125]279 // Invalidate whole area
280 invalidateFullBay();
[130]281
[122]282 if (_supressMessages)
[284]283 return null;
[122]284
285 if (!displayAlways && message.equals(_lastMessage)) {
[181]286 Misc.beep();
[284]287 return null;
[122]288 }
289 _lastMessage = message;
290
291 if (_creator == null) {
[130]292 _creator = new FrameCreator(MESSAGES_FRAMESET_NAME,
[298]293 FrameIO.MESSAGES_PATH, MESSAGES_FRAMESET_NAME, true, false);
[122]294 }
[130]295
[125]296 // set up 'Messages' link on the right hand side
297 updateLink();
[122]298
299 // if the message slots have not all been used yet
300 if (_messageCount <= _messages.length) {
301 int pos = 15;
302 // find the next empty slot, and create the new message
303 for (int i = 0; i < _messages.length; i++) {
304 if (_messages[i] == null) {
305 _messages[i] = new Text(getMessagePrefix(true) + message);
306 _messages[i].setPosition(20, pos);
[130]307 _messages[i].setOffset(0,
308 -FrameGraphics.getMaxFrameSize().height);
[336]309 // _messages[i].setMaxWidth(FrameGraphics.getMaxFrameSize().width);
[122]310 _messages[i].setColor(color);
311 _messages[i].setLink(link);
[247]312 _messages[i].setActions(actions);
[673]313 _messages[i].setFont(_messageFont);
[130]314 _creator.addItem(_messages[i].copy(), true);
[122]315 _messageLink.setLink(_creator.getCurrent());
[130]316
317 Graphics g = FrameGraphics.createGraphics();
[649]318 if (g != null) {
[130]319 refresh(false, g, Item.DEFAULT_BACKGROUND);
[649]320 }
[284]321 return _messages[i];
[122]322 }
323
324 pos += 25;
325 }
326 }
327
328 // if we have not returned then all message slots are used
329 for (int i = 0; i < _messages.length - 1; i++) {
330 _messages[i].setText(_messages[i + 1].getFirstLine());
331 _messages[i].setColor(_messages[i + 1].getColor());
332 _messages[i].setLink(_messages[i + 1].getLink());
[247]333 _messages[i].setActions(_messages[i + 1].getAction());
[122]334 }
335
336 // show the new message
337 Text last = _messages[_messages.length - 1];
338 last.setColor(color);
[130]339 // Set the text for the new message
[122]340 last.setText(getMessagePrefix(true) + message);
341 last.setLink(link);
342 last.setActions(actions);
343
[130]344 _creator.addItem(last.copy(), true);
[122]345 // update the link to the latest message frame
346 _messageLink.setLink(_creator.getCurrent());
[130]347
[649]348 Graphics g = FrameGraphics.createGraphics();
349 if (g != null) {
350 refresh(false, g, Item.DEFAULT_BACKGROUND);
351 }
[336]352
[284]353 return last;
[122]354 }
[130]355
[409]356 public synchronized static void overwriteMessage(String message) {
[247]357 overwriteMessage(message, null);
358 }
[336]359
[409]360 public synchronized static void overwriteMessage(String message, Color color) {
[122]361 for (int ind = _messages.length - 1; ind >= 0; ind--) {
362 if (_messages[ind] != null) {
[247]363 _messages[ind].setColor(color);
[122]364 _messages[ind].setText(getMessagePrefix(false) + message);
[130]365 refresh(false, FrameGraphics.createGraphics(),
366 Item.DEFAULT_BACKGROUND);
[122]367 return;
368 }
369 }
370
371 // if we have not returned, then there are no messages yet
372 displayMessage(message, Color.darkGray);
373 }
374
375 private static String getMessagePrefix(boolean incrementCounter) {
376 if (incrementCounter)
377 _messageCount++;
378 return "@" + _messageCount + ": ";
379 }
380
381 /**
382 * Checks if the error message ends with a frame name after the
383 * frameNameSeparator symbol
384 *
385 * @param message
386 * the message to be displayed
387 */
[409]388 public synchronized static Text linkedErrorMessage(String message) {
[122]389 if (_supressMessages)
[284]390 return null;
[181]391 Misc.beep();
[122]392 String[] tokens = message.split(Text.FRAME_NAME_SEPARATOR);
393 String link = null;
394 if (tokens.length > 1)
395 link = tokens[tokens.length - 1];
[284]396 return displayMessage(message, link, null, ERROR_COLOR);
[122]397 }
398
[409]399 public synchronized static Text errorMessage(String message) {
[122]400 if (_supressMessages)
[284]401 return null;
[181]402 Misc.beep();
[284]403 return displayMessage(message, null, null, ERROR_COLOR, false);
[122]404 }
405
406 /**
407 * Displays the given message in the message area of the Frame, any previous
408 * message is cleared from the screen.
409 *
410 * @param message
411 * The message to display to the user in the message area
412 */
[409]413 public synchronized static Text displayMessage(String message) {
[284]414 return displayMessageAlways(message);
[122]415 }
416
[409]417 public synchronized static Text displayMessageOnce(String message) {
[284]418 return displayMessage(message, null, null, Color.BLACK, false);
[122]419 }
420
[409]421 public synchronized static Text displayMessage(String message, Color textColor) {
[284]422 return displayMessage(message, null, null, textColor);
[122]423 // Misc.Beep();
424 }
425
[409]426 public synchronized static Text displayMessage(Text message) {
[336]427 Text t = null;
428 String link = message.getLink();
429 List<String> action = message.getAction();
430 Color color = message.getColor();
431 for (String s : message.getTextList()) {
432 t = displayMessage(s, link, action, color);
433 }
434 return t;
[122]435 // Misc.Beep();
436 }
437
[409]438 public synchronized static Text displayMessageAlways(String message) {
[284]439 return displayMessage(message, null, null, Color.BLACK);
[122]440 // Misc.Beep();
441 }
442
[409]443 public synchronized static Text warningMessage(String message) {
[284]444 return displayMessage(message, null, null, Color.MAGENTA);
[122]445 // Misc.Beep();
446 }
[130]447
[409]448 public synchronized static void supressMessages(boolean val) {
[122]449 _supressMessages = val;
450 }
[673]451
452 public synchronized static void setStatus(String status) {
453 if (_status == null) {
454 _status = new Text(status);
[674]455 _status.setPosition(0, 90);
[673]456 _status.setOffset(0, FrameGraphics.getMaxFrameSize().height);
457 _status.setLink(null); // maybe link to a help frame?
458 _status.setFont(Font.decode(Text.MONOSPACED_FONT));
459 } else {
460 _status.setText(status);
461 }
462 Graphics g = FrameGraphics.createGraphics();
463 if (g != null) {
464 refresh(false, g, Item.DEFAULT_BACKGROUND);
465 }
466 }
[130]467
[122]468}
Note: See TracBrowser for help on using the repository browser.