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

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

Restored multicolumn searchresults

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