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

Last change on this file since 649 was 649, checked in by davidb, 10 years ago

Code added so command-line version of FrameShare starts the thread for the server(s)

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