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

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

Removed reliance of System.getProperty("user.name") by introducing some functions and a variable to Browser to be used instead. All previous occurrences of System.getProperty("user.name") now use these functions.

At the time, introduced new piping into various functions related to the creation and management of profile frames that distinguished between a profile name and a user name. This allows functions to be more specific about what is being used. For example, when modifying the users profile frames (in the profiles directory) that users profile name can be used instead of naming the variable 'username'. This distinction is important because while username's can end with numbers, profile names cannot and therefore get an 'A' on the end.

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: " + Browser.getExpediteeUserName());
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.