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

Last change on this file since 1314 was 1314, checked in by bln4, 5 years ago

Feedback is now provided during account creation. In order to achieve this a forced refresh for the message bay area has been added.
Upon login the existing preview area for messages is now cleared.

File size: 17.4 KB
Line 
1/**
2 * MessageBay.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.gui;
20
21import java.util.LinkedList;
22import java.util.List;
23
24import org.expeditee.Util;
25import org.expeditee.actions.Misc;
26import org.expeditee.auth.AuthenticatorBrowser;
27import org.expeditee.core.Clip;
28import org.expeditee.core.Colour;
29import org.expeditee.core.Dimension;
30import org.expeditee.core.Font;
31import org.expeditee.core.Image;
32import org.expeditee.gio.EcosystemManager;
33import org.expeditee.gio.GraphicsManager;
34import org.expeditee.items.Item;
35import org.expeditee.items.Text;
36import org.expeditee.settings.UserSettings;
37
38/**
39 * The bay at the bottom of the expeditee browser which displays messages. TODO:
40 * Make it thread safe!
41 */
42public final class MessageBay {
43
44 /** The distance from the top of the message bay to the Message frame link. */
45 private static final int MESSAGE_LINK_Y_OFFSET = 100;
46
47 /** TODO: Comment. cts16 */
48 private static final int MESSAGE_LINK_X = 50;
49
50 /** TODO: Comment. cts16 */
51 public static final Colour ERROR_COLOR = Colour.RED;
52
53 /** TODO: Comment. cts16 */
54 public static final String MESSAGES_FRAMESET_NAME = "Messages";
55
56 /** The list of messages shown in the message bay. */
57 private static List<Item> _messages = new LinkedList<Item>();
58
59 /**
60 * Messages which were delayed because they couldn't be shown at time of
61 * creation.
62 */
63 private static List<DelayedMessage> _delayedMessages = new LinkedList<DelayedMessage>();
64
65 /** TODO: Comment. cts16 */
66 private static Text _status = null;
67
68 private static Text _authorisedUser = null;
69
70 /** Buffer image of the message window. */
71 private static Image _messageBuffer = null;
72
73 /** Creator for creating the message frames. */
74 private static FrameCreator _creator = null;
75
76 /** The user we are providing messages for **/
77 private static String _forUser = null;
78
79 /** Font used for the messages. */
80 private static Font _messageFont = new Font("Serif-Plain-16");
81
82 /** The number of messages currently shown (used for scrolling up). */
83 private static int _messageCount = 0;
84
85 /** If true, error messages are not shown to the user. */
86 private static boolean _suppressMessages = false;
87
88 /** The link to the message frameset. */
89 private static Item _messageLink = new Text(-2, "@" + MESSAGES_FRAMESET_NAME, Colour.BLACK, Colour.WHITE);
90
91 /** TODO: Comment. cts16 */
92 private static String _lastMessage = null;
93
94 /** TODO: Comment. cts16 */
95 private static boolean isLinkInitialized = false;
96
97 /** Static-only class. */
98 private MessageBay() {
99 }
100
101 /** Whether the message bay is ready to display messages. */
102 public static boolean isReady() {
103 return Browser.isInitComplete();
104 }
105
106 /** Syncs message bay size according to FrameGraphics max size. */
107 private static void updateSize() {
108 for (Item i : _messages) {
109 if (i != null) {
110 i.setOffset(0, -DisplayController.getMessageBayPaintArea().getMinY());
111 }
112 }
113
114 _messageLink.setOffset(0, -DisplayController.getMessageBayPaintArea().getMinY());
115
116 updateLink();
117 }
118
119 /** Whether the given item is an item in the message bay. */
120 public static boolean isMessageItem(Item i) {
121 return _messages.contains(i) || i == _messageLink || i == getStatus();
122 }
123
124 /** TODO: Comment. cts16 */
125 public synchronized static Item getMessageLink() {
126 return _messageLink;
127 }
128
129 /** TODO: Comment. cts16 */
130 public synchronized static List<Item> getMessages() {
131 return _messages;
132 }
133
134 /** Causes the entire message bay area to be invalidated. */
135 public synchronized static void invalidateFullBay() {
136 DisplayController.invalidateArea(DisplayController.getMessageBayPaintArea());
137 }
138
139 /** TODO: Comment. cts16 */
140 private static void updateLink() {
141 if (!isLinkInitialized && DisplayController.getFramePaintArea() != null
142 && DisplayController.getFramePaintAreaWidth() > 0) {
143 // set up 'Messages' link on the right hand side
144 _messageLink.setPosition(DisplayController.getMessageBayPaintArea().getWidth() - MESSAGE_LINK_Y_OFFSET,
145 MESSAGE_LINK_X);
146 _messageLink.setOffset(0, -DisplayController.getMessageBayPaintArea().getMinY());
147 isLinkInitialized = true;
148 } else {
149 _messageLink.setPosition(DisplayController.getMessageBayPaintArea().getWidth() - MESSAGE_LINK_Y_OFFSET,
150 MESSAGE_LINK_X);
151 }
152 }
153
154 /** TODO: Comment. cts16 */
155 public static Image getImage(Clip clip, Dimension size) {
156 // Can't get an image with an invalid size
157 if (size == null || size.width <= 0 || size.height <= 0) {
158 return null;
159 }
160
161 // Update the buffer
162 updateBuffer(Item.DEFAULT_BACKGROUND, clip, size);
163
164 // Return the image buffer
165 return _messageBuffer;
166 }
167
168 public static void clear() {
169 MessageBay._messageCount = 0;
170 MessageBay._messages.clear();
171 }
172
173 /** Updates the image buffer to reflect the current state of the message bay. */
174 private synchronized static void updateBuffer(Colour background, Clip clip, Dimension size) {
175 // If the buffer doesn't exist or is the wrong size, recreate it
176 if (_messageBuffer == null || !_messageBuffer.getSize().equals(size)) {
177 _messageBuffer = Image.createImage(size, true);
178 clip = null; // Need to recreate the entire image;
179 updateSize();
180 }
181
182 GraphicsManager g = EcosystemManager.getGraphicsManager();
183 g.pushDrawingSurface(_messageBuffer);
184
185 if (clip != null) {
186 g.pushClip(clip);
187 }
188 g.setAntialiasing(true);
189
190 g.clear(background);
191
192 g.setFont(_messageFont);
193
194 for (Item message : _messages) {
195 if (message != null) {
196 if (clip == null || clip.isNotClipped() || message.isInDrawingArea(clip.getBounds())) {
197 FrameGraphics.PaintItem(message);
198 }
199 }
200 }
201
202 if (getStatus() != null) {
203 FrameGraphics.PaintItem(getStatus());
204 }
205
206 if (AuthenticatorBrowser.isAuthenticated() && _authorisedUser != null) {
207 FrameGraphics.PaintItem(_authorisedUser);
208 }
209
210 if (clip == null || clip.isNotClipped() || _messageLink.isInDrawingArea(clip.getBounds())) {
211 FrameGraphics.PaintItem(_messageLink);
212 }
213
214 g.popDrawingSurface();
215 }
216
217 /** TODO: Comment. cts16 */
218 private static Text displayMessage(String message, String link, List<String> actions, Colour color) {
219 return displayMessage(message, link, actions, color, true);
220 }
221
222 /** TODO: Comment. cts16 */
223 public synchronized static Text displayMessage(String message, String link, Colour color, boolean displayAlways,
224 String action) {
225 List<String> actions = new LinkedList<String>();
226 if (action != null) {
227 actions.add(action);
228 }
229 return displayMessage(message, link, actions, color, displayAlways);
230 }
231
232 public static void updateFramesetLocation() {
233 if (_forUser != UserSettings.UserName.get()) {
234 if (AuthenticatorBrowser.isAuthenticated()) {
235 _creator = new FrameCreator(MESSAGES_FRAMESET_NAME, FrameIO.MESSAGES_PATH, MESSAGES_FRAMESET_NAME, FrameCreator.ExistingFramesetOptions.OverrideExistingFrames,
236 false, AuthenticatorBrowser.PROFILEENCRYPTIONLABEL);
237 } else {
238 _creator = new FrameCreator(MESSAGES_FRAMESET_NAME, FrameIO.MESSAGES_PATH, MESSAGES_FRAMESET_NAME, FrameCreator.ExistingFramesetOptions.OverrideExistingFrames,
239 false, null);
240 }
241 _forUser = UserSettings.UserName.get();
242 }
243 }
244
245 /** TODO: Comment. cts16 */
246 private static Text newMessage(String message, String link, List<String> actions, Colour color) {
247 Text t = new Text(getMessagePrefix(true) + message);
248 t.setPosition(20, 15 + _messages.size() * 25);
249 t.setOffset(0, -DisplayController.getFramePaintAreaHeight());
250 t.setColor(color);
251 t.setLink(link);
252 t.setActions(actions);
253 t.setFont(_messageFont.clone());
254 _creator.addItem(t.copy(), true);
255 if (link == null) {
256 t.setLink(_creator.getCurrent());
257 }
258 return t;
259 }
260
261 /** TODO: Comment. cts16 */
262 private synchronized static Text displayMessage(String message, String link, List<String> actions, Colour color,
263 boolean displayAlways, boolean redraw) {
264 assert (message != null);
265
266 if (!isReady()) {
267 delayMessage(message, link, actions, color, displayAlways, redraw);
268 return null;
269 }
270
271 System.out.println(message);
272
273 // Invalidate whole area
274 invalidateFullBay();
275
276 if (_suppressMessages) {
277 return null;
278 }
279
280 if (!displayAlways && message.equals(_lastMessage)) {
281 DisplayController.DisableMailMode();
282 Misc.beep();
283 return null;
284 }
285
286 _lastMessage = message;
287
288 if (_creator == null) {
289 if (AuthenticatorBrowser.isAuthenticated()) {
290 _creator = new FrameCreator(MESSAGES_FRAMESET_NAME, FrameIO.MESSAGES_PATH, MESSAGES_FRAMESET_NAME, FrameCreator.ExistingFramesetOptions.OverrideExistingFrames,
291 false, AuthenticatorBrowser.PROFILEENCRYPTIONLABEL);
292 } else {
293 _creator = new FrameCreator(MESSAGES_FRAMESET_NAME, FrameIO.MESSAGES_PATH, MESSAGES_FRAMESET_NAME, FrameCreator.ExistingFramesetOptions.OverrideExistingFrames,
294 false, null);
295 }
296 _forUser = UserSettings.UserName.get();
297 }
298
299 // set up 'Messages' link on the right hand side
300 updateLink();
301
302 if (_messages.size() >= 3) {
303 _messages.remove(0);
304 for (Item i : _messages) {
305 i.setY(i.getY() - 25);
306 }
307 }
308
309 Text t = newMessage(message, link, actions, color);
310
311 _messages.add(t);
312
313 // update the link to the latest message frame
314 _messageLink.setLink(_creator.getCurrent());
315
316 if (redraw) {
317 DisplayController.DisableMailMode();
318 DisplayController.requestRefresh(true);
319 }
320
321 return t;
322 }
323
324 /** TODO: Comment. cts16 */
325 public synchronized static Text displayMessage(String message, String link, List<String> actions, Colour color,
326 boolean displayAlways) {
327 return displayMessage(message, link, actions, color, displayAlways, true);
328 }
329
330 /** TODO: Comment. cts16 */
331 public synchronized static void overwriteMessage(String message) {
332 overwriteMessage(message, null);
333 }
334
335 /** TODO: Comment. cts16 */
336 public synchronized static void overwriteMessage(String message, Colour color) {
337 _messages.remove(_messages.size() - 1);
338 Text t = newMessage(message, null, null, color);
339 _messages.add(t);
340 DisplayController.requestRefresh(true);
341 }
342
343 /** TODO: Comment. cts16 */
344 private static String getMessagePrefix(int counter) {
345 return "@" + counter + ": ";
346 }
347
348 /** TODO: Comment. cts16 */
349 private static String getMessagePrefix(boolean incrementCounter) {
350 if (incrementCounter) {
351 _messageCount++;
352 }
353
354 return getMessagePrefix(_messageCount);
355 }
356
357 /**
358 * Checks if the error message ends with a frame name after the
359 * frameNameSeparator symbol
360 *
361 * @param message
362 * the message to be displayed
363 */
364 public synchronized static Text linkedErrorMessage(String message) {
365 if (_suppressMessages) {
366 return null;
367 }
368 Misc.beep();
369 String[] tokens = message.split(Text.FRAME_NAME_SEPARATOR);
370 String link = null;
371 if (tokens.length > 1) {
372 link = tokens[tokens.length - 1];
373 }
374 return displayMessage(message, link, null, ERROR_COLOR);
375 }
376
377 /** TODO: Comment. cts16 */
378 public synchronized static Text errorMessage(String message) {
379 if (_suppressMessages) {
380 return null;
381 }
382 Misc.beep();
383 return displayMessage(message, null, null, ERROR_COLOR, false);
384 }
385
386 /**
387 * Displays the given message in the message area of the Frame, any previous
388 * message is cleared from the screen.
389 *
390 * @param message
391 * The message to display to the user in the message area
392 */
393 public synchronized static Text displayMessage(String message) {
394 return displayMessageAlways(message);
395 }
396
397 /** TODO: Comment. cts16 */
398 public synchronized static Text displayMessageOnce(String message) {
399 return displayMessage(message, null, null, Colour.BLACK, false);
400 }
401
402 /** TODO: Comment. cts16 */
403 public synchronized static Text displayMessage(String message, Colour textColor) {
404 return displayMessage(message, null, null, textColor);
405 }
406
407 /** TODO: Comment. cts16 */
408 public synchronized static Text displayMessage(Text message) {
409 Text t = null;
410 String link = message.getLink();
411 List<String> action = message.getAction();
412 Colour color = message.getColor();
413 for (String s : message.getTextList()) {
414 t = displayMessage(s, link, action, color);
415 }
416 return t;
417 }
418
419 /** TODO: Comment. cts16 */
420 public synchronized static Text displayMessageAlways(String message) {
421 return displayMessage(message, null, null, Colour.BLACK);
422 // Misc.Beep();
423 }
424
425 /** TODO: Comment. cts16 */
426 public synchronized static Text warningMessage(String message) {
427 return displayMessage(message, null, null, Colour.MAGENTA);
428 }
429
430 /** TODO: Comment. cts16 */
431 public synchronized static List<Text> warningMessages(List<String> messages) {
432 if (messages == null) {
433 return null;
434 }
435 List<Text> ret = new LinkedList<Text>();
436 for (String message : messages) {
437 ret.add(warningMessage(message));
438 }
439 return ret;
440 }
441
442 /** TODO: Comment. cts16 */
443 public synchronized static void suppressMessages(boolean val) {
444 _suppressMessages = val;
445 }
446
447 /** TODO: Comment. cts16 */
448 public synchronized static void setStatus(String status) {
449 if (_status == null) {
450 _status = new Text(status);
451 _status.setPosition(0, 85);
452 _status.setOffset(0, -DisplayController.getMessageBayPaintArea().getMinY());
453 _status.setLink(null); // maybe link to a help frame?
454 _status.setFont(new Font(Text.MONOSPACED_FONT));
455 } else {
456 _status.setText(status);
457 }
458
459 _authorisedUser = new Text("Username: " + UserSettings.UserName.get());
460 _authorisedUser.setFont(new Font(Text.MONOSPACED_FONT));
461 _authorisedUser.setY(95);
462 _authorisedUser.setAnchorRight(1);
463
464 // invalidateFullBay();
465 DisplayController.requestRefresh(true);
466 }
467
468 /** TODO: Comment. cts16 */
469 public static final class Progress {
470 /** The colour progress bars should be displayed in. */
471 private static final Colour BAR_COLOUR = Colour.GREEN.darker();
472
473 /**
474 * The character used to assemble the uncompleted portions of the progress bar.
475 */
476 private static final char UNCOMPLETED_CHARACTER = '\u2591'; // ░
477 /**
478 * The character used to assemble the completed portions of the progress bar.
479 */
480 private static final char COMPLETED_CHARACTER = '\u2592'; // ▒
481
482 /** What the progress bar should look like when at 100% completion. */
483 private static final String COMPLETED_BAR = Util.nCopiesOf(20, COMPLETED_CHARACTER);
484 /** What the progress bar should look like when at 0% completion. */
485 private static final String UNCOMPLETED_BAR = Util.nCopiesOf(20, UNCOMPLETED_CHARACTER);
486
487 private String _message;
488 private Text _text;
489
490 protected Progress(String text) {
491 this._text = displayMessage(text, null, null, BAR_COLOUR, true, false);
492 this._message = this._text.getText();
493 this._text.setText(this._message + " [" + UNCOMPLETED_BAR + "] 0%");
494 DisplayController.requestRefresh(true);
495 }
496
497 public void UpdateMessage(final String text, final int newProgress) throws Exception {
498 this._message = text;
499 set(newProgress);
500 }
501
502 public String GetMessage() {
503 return _message;
504 }
505
506 /**
507 *
508 * @param progress
509 * progress value from 0 to 100
510 * @return true if the progress was updated, false if the progress was off the
511 * screen
512 * @throws Exception
513 * if progress out of bounds
514 */
515 public boolean set(int progress) throws Exception {
516 if (progress < 0 || progress > 100) {
517 throw new Exception("Progress value out of bounds");
518 }
519 int p = progress / 5;
520 if (isMessageItem(this._text)) {
521 this._text.setText(this._message + " [" + COMPLETED_BAR.substring(0, p) + UNCOMPLETED_BAR.substring(p)
522 + "] " + progress + "%");
523 DisplayController.requestRefresh(true);
524 return true;
525 }
526 return false;
527 }
528 }
529
530 /** TODO: Comment. cts16 */
531 public synchronized static Progress displayProgress(String message) {
532 return new Progress(message);
533 }
534
535 /** Remembers the arguments to a displayMessage call for later use. */
536 private static class DelayedMessage {
537
538 private String _message;
539 private String _link;
540 private List<String> _actions;
541 private Colour _colour;
542 private boolean _displayAlways;
543 private boolean _redraw;
544
545 public DelayedMessage(String message, String link, List<String> actions, Colour color, boolean displayAlways,
546 boolean redraw) {
547 _message = message;
548 _link = link;
549 if (actions == null) {
550 _actions = null;
551 } else {
552 _actions = new LinkedList<String>();
553 _actions.addAll(actions);
554 }
555 _colour = color == null ? null : color.clone();
556 _displayAlways = displayAlways;
557 _redraw = redraw;
558 }
559
560 public void display() {
561 displayMessage(_message, _link, _actions, _colour, _displayAlways, _redraw);
562 }
563
564 }
565
566 private static void delayMessage(String message, String link, List<String> actions, Colour color,
567 boolean displayAlways, boolean redraw) {
568 _delayedMessages.add(new DelayedMessage(message, link, actions, color, displayAlways, redraw));
569 }
570
571 public static void showDelayedMessages(final boolean requestRefresh) {
572 if (isReady()) {
573 for (DelayedMessage message : _delayedMessages) {
574 message.display();
575 }
576 _delayedMessages.clear();
577 invalidateFullBay();
578 if(requestRefresh) {
579 DisplayController.requestRefresh(true);
580 }
581 }
582 }
583
584 public static Text getStatus() {
585 return _status;
586 }
587}
Note: See TracBrowser for help on using the repository browser.