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

Last change on this file since 125 was 125, checked in by bjn8, 16 years ago

Fixed some drawing issues with the message bay

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