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

Last change on this file since 1510 was 1510, checked in by bnemhaus, 4 years ago

Updates to the look of some of the more prominant expeditee pages. More to come.
Also first draft of Encryption Cockpit.

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