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

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

Implementation of ProfileManager. Refactor + additional content for how new profiles are created. The refactoring split out the creation of the default profile from user profiles. Refactoring revealed a long term bug that was causing user profiles to generate with incorrect information. The additional content fixed this bug by introducing the ${USER.NAME} variable, so that the default profile frameset can specify resource locations located in the users resource directory.

org.expeditee.auth.AuthenticatorBrowser
org.expeditee.auth.account.Create
org.expeditee.gui.Browser
org.expeditee.gui.management.ProfileManager
org.expeditee.setting.DirectoryListSetting
org.expeditee.setting.ListSetting
org.expeditee.settings.UserSettings

Implementation of ResourceManager as a core location to get resources from the file system. Also the additional variable ${CURRENT_FRAMESET} to represent the current frameset, so that images can be stored in the directory of the current frameset. This increases portability of framesets.

org.expeditee.gui.FrameIO
org.expeditee.gui.management.ResourceManager
org.expeditee.gui.management.ResourceUtil
Audio:

#NB: Audio used to only operate on a single directory. This has been updated to work in a same way as images. That is: when you ask for a specific resouce, it looks to the user settings to find a sequence of directories to look at in order until it manages to find the desired resource.


There is still need however for a single(ish) source of truth for the .banks and .mastermix file. Therefore these files are now always located in resource-<username>\audio.
org.apollo.agents.MelodySearch
org.apollo.audio.structure.AudioStructureModel
org.apollo.audio.util.MultiTrackPlaybackController
org.apollo.audio.util.SoundDesk
org.apollo.gui.FrameLayoutDaemon
org.apollo.io.AudioPathManager
org.apollo.util.AudioPurger
org.apollo.widgets.FramePlayer
org.apollo.widgets.SampledTrack

Images:

org.expeditee.items.ItemUtils

Frames:

org.expeditee.gui.FrameIO

Fixed a error in the FramePlayer class caused by an incorrect use of toArray().

org.apollo.widgets.FramePlayer


Added several short cut keys to allow for the Play/Pause (Ctrl + P), mute (Ctrl + M) and volume up/down (Ctrl + +/-) when hovering over SampledTrack widgets.

org.apollo.widgets.SampledTrack


Changed the way that Authenticate.login parses the new users profile to be more consistance with other similar places in code.

org.expeditee.auth.account.Authenticate


Encapsulated _body, _surrogateItemsBody and _primaryItemsBody in Frame class. Also changed getBody function to take a boolean flag as to if it should respect the current surrogate mode. If it should then it makes sure that labels have not changed since last time getBody was called.

org.expeditee.gui.Frame

File size: 18.0 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 Item lastMessage = _messages.get(_messages.size() - 1);
282 String text = lastMessage.getText();
283 if (text.endsWith("}")) {
284 int startOfRepeat = text.lastIndexOf("{");
285 String repeatString = text.substring(startOfRepeat);
286 repeatString = repeatString.substring(1, repeatString.length() - 1);
287 try {
288 int repeatCount = Integer.parseInt(repeatString) + 1;
289 text = text.substring(0, startOfRepeat).trim() + " {" + repeatCount + "}";
290 } catch (NumberFormatException e) {
291 e.printStackTrace();
292 }
293 } else {
294 text = text.trim() + " {2}";
295 }
296 lastMessage.setText(text);
297 DisplayController.DisableMailMode();
298 return null;
299 }
300
301 _lastMessage = message;
302
303 if (_creator == null) {
304 if (AuthenticatorBrowser.isAuthenticated()) {
305 _creator = new FrameCreator(MESSAGES_FRAMESET_NAME, FrameIO.MESSAGES_PATH, MESSAGES_FRAMESET_NAME, FrameCreator.ExistingFramesetOptions.OverrideExistingFrames,
306 false, AuthenticatorBrowser.PROFILEENCRYPTIONLABEL);
307 } else {
308 _creator = new FrameCreator(MESSAGES_FRAMESET_NAME, FrameIO.MESSAGES_PATH, MESSAGES_FRAMESET_NAME, FrameCreator.ExistingFramesetOptions.OverrideExistingFrames,
309 false, null);
310 }
311 _forUser = UserSettings.UserName.get();
312 }
313
314 // set up 'Messages' link on the right hand side
315 updateLink();
316
317 if (_messages.size() >= 3) {
318 _messages.remove(0);
319 for (Item i : _messages) {
320 i.setY(i.getY() - 25);
321 }
322 }
323
324 Text t = newMessage(message, link, actions, color);
325
326 _messages.add(t);
327
328 // update the link to the latest message frame
329 _messageLink.setLink(_creator.getCurrent());
330
331 if (redraw) {
332 DisplayController.DisableMailMode();
333 DisplayController.requestRefresh(true);
334 }
335
336 return t;
337 }
338
339 /** TODO: Comment. cts16 */
340 public synchronized static Text displayMessage(String message, String link, List<String> actions, Colour color,
341 boolean displayAlways) {
342 return displayMessage(message, link, actions, color, displayAlways, true);
343 }
344
345 /** TODO: Comment. cts16 */
346 public synchronized static void overwriteMessage(String message) {
347 overwriteMessage(message, null);
348 }
349
350 /** TODO: Comment. cts16 */
351 public synchronized static void overwriteMessage(String message, Colour color) {
352 _messages.remove(_messages.size() - 1);
353 Text t = newMessage(message, null, null, color);
354 _messages.add(t);
355 DisplayController.requestRefresh(true);
356 }
357
358 /** TODO: Comment. cts16 */
359 private static String getMessagePrefix(int counter) {
360 return "@" + counter + ": ";
361 }
362
363 /** TODO: Comment. cts16 */
364 private static String getMessagePrefix(boolean incrementCounter) {
365 if (incrementCounter) {
366 _messageCount++;
367 }
368
369 return getMessagePrefix(_messageCount);
370 }
371
372 /**
373 * Checks if the error message ends with a frame name after the
374 * frameNameSeparator symbol
375 *
376 * @param message
377 * the message to be displayed
378 */
379 public synchronized static Text linkedErrorMessage(String message) {
380 if (_suppressMessages) {
381 return null;
382 }
383 Misc.beep();
384 String[] tokens = message.split(Text.FRAME_NAME_SEPARATOR);
385 String link = null;
386 if (tokens.length > 1) {
387 link = tokens[tokens.length - 1];
388 }
389 return displayMessage(message, link, null, ERROR_COLOR);
390 }
391
392 /** TODO: Comment. cts16 */
393 public synchronized static Text errorMessage(String message) {
394 if (_suppressMessages) {
395 return null;
396 }
397 Misc.beep();
398 return displayMessage(message, null, null, ERROR_COLOR, false);
399 }
400
401 /**
402 * Displays the given message in the message area of the Frame, any previous
403 * message is cleared from the screen.
404 *
405 * @param message
406 * The message to display to the user in the message area
407 */
408 public synchronized static Text displayMessage(String message) {
409 return displayMessageAlways(message);
410 }
411
412 /** TODO: Comment. cts16 */
413 public synchronized static Text displayMessageOnce(String message) {
414 return displayMessage(message, null, null, Colour.BLACK, false);
415 }
416
417 /** TODO: Comment. cts16 */
418 public synchronized static Text displayMessage(String message, Colour textColor) {
419 return displayMessage(message, null, null, textColor);
420 }
421
422 /** TODO: Comment. cts16 */
423 public synchronized static Text displayMessage(Text message) {
424 Text t = null;
425 String link = message.getLink();
426 List<String> action = message.getAction();
427 Colour color = message.getColor();
428 for (String s : message.getTextList()) {
429 t = displayMessage(s, link, action, color);
430 }
431 return t;
432 }
433
434 /** TODO: Comment. cts16 */
435 public synchronized static Text displayMessageAlways(String message) {
436 return displayMessage(message, null, null, Colour.BLACK);
437 // Misc.Beep();
438 }
439
440 /** TODO: Comment. cts16 */
441 public synchronized static Text warningMessage(String message) {
442 return displayMessage(message, null, null, Colour.MAGENTA);
443 }
444
445 /** TODO: Comment. cts16 */
446 public synchronized static List<Text> warningMessages(List<String> messages) {
447 if (messages == null) {
448 return null;
449 }
450 List<Text> ret = new LinkedList<Text>();
451 for (String message : messages) {
452 ret.add(warningMessage(message));
453 }
454 return ret;
455 }
456
457 /** TODO: Comment. cts16 */
458 public synchronized static void suppressMessages(boolean val) {
459 _suppressMessages = val;
460 }
461
462 /** TODO: Comment. cts16 */
463 public synchronized static void setStatus(String status) {
464 if (_status == null) {
465 _status = new Text(status);
466 _status.setPosition(0, 85);
467 _status.setOffset(0, -DisplayController.getMessageBayPaintArea().getMinY());
468 _status.setLink(null); // maybe link to a help frame?
469 _status.setFont(new Font(Text.MONOSPACED_FONT));
470 } else {
471 _status.setText(status);
472 }
473
474 _authorisedUser = new Text("Username: " + UserSettings.UserName.get());
475 _authorisedUser.setFont(new Font(Text.MONOSPACED_FONT));
476 _authorisedUser.setY(95);
477 _authorisedUser.setAnchorRight(1);
478
479 // invalidateFullBay();
480 DisplayController.requestRefresh(true);
481 }
482
483 /** TODO: Comment. cts16 */
484 public static final class Progress {
485 /** The colour progress bars should be displayed in. */
486 private static final Colour BAR_COLOUR = Colour.GREEN.darker();
487
488 /**
489 * The character used to assemble the uncompleted portions of the progress bar.
490 */
491 private static final char UNCOMPLETED_CHARACTER = '\u2591'; // ░
492 /**
493 * The character used to assemble the completed portions of the progress bar.
494 */
495 private static final char COMPLETED_CHARACTER = '\u2592'; // ▒
496
497 /** What the progress bar should look like when at 100% completion. */
498 private static final String COMPLETED_BAR = Util.nCopiesOf(20, COMPLETED_CHARACTER);
499 /** What the progress bar should look like when at 0% completion. */
500 private static final String UNCOMPLETED_BAR = Util.nCopiesOf(20, UNCOMPLETED_CHARACTER);
501
502 private String _message;
503 private Text _text;
504
505 protected Progress(String text) {
506 this._text = displayMessage(text, null, null, BAR_COLOUR, true, false);
507 this._message = this._text.getText();
508 this._text.setText(this._message + " [" + UNCOMPLETED_BAR + "] 0%");
509 DisplayController.requestRefresh(true);
510 }
511
512 public void UpdateMessage(final String text, final int newProgress) throws Exception {
513 this._message = text;
514 set(newProgress);
515 }
516
517 public String GetMessage() {
518 return _message;
519 }
520
521 /**
522 *
523 * @param progress
524 * progress value from 0 to 100
525 * @return true if the progress was updated, false if the progress was off the
526 * screen
527 * @throws Exception
528 * if progress out of bounds
529 */
530 public boolean set(int progress) throws Exception {
531 if (progress < 0 || progress > 100) {
532 throw new Exception("Progress value out of bounds");
533 }
534 int p = progress / 5;
535 if (isMessageItem(this._text)) {
536 this._text.setText(this._message + " [" + COMPLETED_BAR.substring(0, p) + UNCOMPLETED_BAR.substring(p)
537 + "] " + progress + "%");
538 DisplayController.requestRefresh(true);
539 return true;
540 }
541 return false;
542 }
543 }
544
545 /** TODO: Comment. cts16 */
546 public synchronized static Progress displayProgress(String message) {
547 return new Progress(message);
548 }
549
550 /** Remembers the arguments to a displayMessage call for later use. */
551 private static class DelayedMessage {
552
553 private String _message;
554 private String _link;
555 private List<String> _actions;
556 private Colour _colour;
557 private boolean _displayAlways;
558 private boolean _redraw;
559
560 public DelayedMessage(String message, String link, List<String> actions, Colour color, boolean displayAlways,
561 boolean redraw) {
562 _message = message;
563 _link = link;
564 if (actions == null) {
565 _actions = null;
566 } else {
567 _actions = new LinkedList<String>();
568 _actions.addAll(actions);
569 }
570 _colour = color == null ? null : color.clone();
571 _displayAlways = displayAlways;
572 _redraw = redraw;
573 }
574
575 public void display() {
576 displayMessage(_message, _link, _actions, _colour, _displayAlways, _redraw);
577 }
578
579 }
580
581 private static void delayMessage(String message, String link, List<String> actions, Colour color,
582 boolean displayAlways, boolean redraw) {
583 _delayedMessages.add(new DelayedMessage(message, link, actions, color, displayAlways, redraw));
584 }
585
586 public static void showDelayedMessages(final boolean requestRefresh) {
587 if (isReady()) {
588 for (DelayedMessage message : _delayedMessages) {
589 message.display();
590 }
591 _delayedMessages.clear();
592 invalidateFullBay();
593 if(requestRefresh) {
594 DisplayController.requestRefresh(true);
595 }
596 }
597 }
598
599 public static Text getStatus() {
600 return _status;
601 }
602}
Note: See TracBrowser for help on using the repository browser.