root/trunk/LogicMail/src/org/logicprobe/LogicMail/ui/MailboxScreen.java

Revision 702, 27.2 KB (checked in by octorian, 35 hours ago)

Moved screen update batch logic into AbstractScreenProvider

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*-
2 * Copyright (c) 2008, Derek Konigsberg
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the project nor the names of its
15 *    contributors may be used to endorse or promote products derived
16 *    from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.logicprobe.LogicMail.ui;
33
34import java.util.Calendar;
35import java.util.Date;
36import java.util.Hashtable;
37import java.util.Vector;
38
39import net.rim.device.api.i18n.DateFormat;
40import net.rim.device.api.system.Bitmap;
41import net.rim.device.api.ui.Field;
42import net.rim.device.api.ui.Keypad;
43import net.rim.device.api.ui.Manager;
44import net.rim.device.api.ui.MenuItem;
45import net.rim.device.api.ui.Screen;
46import net.rim.device.api.ui.component.Dialog;
47import net.rim.device.api.ui.component.Menu;
48import net.rim.device.api.ui.container.VerticalFieldManager;
49import net.rim.device.api.util.Comparator;
50import net.rim.device.api.util.DateTimeUtilities;
51
52import org.logicprobe.LogicMail.LogicMailResource;
53import org.logicprobe.LogicMail.conf.GlobalConfig;
54import org.logicprobe.LogicMail.conf.MailSettings;
55import org.logicprobe.LogicMail.conf.MailSettingsEvent;
56import org.logicprobe.LogicMail.conf.MailSettingsListener;
57import org.logicprobe.LogicMail.model.MailboxNode;
58import org.logicprobe.LogicMail.model.MailboxNodeEvent;
59import org.logicprobe.LogicMail.model.MailboxNodeListener;
60import org.logicprobe.LogicMail.model.MessageNode;
61import org.logicprobe.LogicMail.model.MessageNodeEvent;
62import org.logicprobe.LogicMail.model.MessageNodeListener;
63import org.logicprobe.LogicMail.model.NetworkAccountNode;
64import org.logicprobe.LogicMail.util.EventObjectRunnable;
65
66/**
67 * Display the active mailbox listing.
68 * If the supplied folder matches the configured sent folder
69 * for the provided account, then the display fields will be
70 * adjusted accordingly.
71 */
72public class MailboxScreen extends AbstractScreenProvider {
73        private static final int SHORTCUT_COMPOSE = 0;
74        private static final int SHORTCUT_UP = 3;
75        private static final int SHORTCUT_DOWN = 4;
76       
77        private MailboxNode mailboxNode;
78    private Vector knownMessages;
79    private Hashtable messageFieldMap;
80    private boolean firstDisplay = true;
81    private MailSettings mailSettings;
82    private GlobalConfig globalConfig;
83    private VerticalFieldManager messageFieldManager;
84    private boolean navigationMoved;
85    private boolean displayOrder;
86    private boolean hideDeleted;
87    private MessageActions messageActions;
88    private boolean composeEnabled;
89
90        private MenuItem compositionItem;
91   
92    /**
93     * Initializes a new MailboxScreen to view the provided mailbox.
94     *
95     * @param mailboxNode Mailbox node to view.
96     */
97    public MailboxScreen(MailboxNode mailboxNode) {
98        this.mailboxNode = mailboxNode;
99        this.knownMessages = new Vector();
100        this.messageFieldMap = new Hashtable();
101        this.mailSettings = MailSettings.getInstance();
102        this.globalConfig = this.mailSettings.getGlobalConfig();
103    }
104
105    public String getTitle() {
106        return mailboxNode.toString();
107    }
108   
109    /**
110     * Gets the mailbox node being displayed by this screen.
111     *
112     * @return The mailbox node
113     */
114    public MailboxNode getMailboxNode() {
115        return mailboxNode;
116    }
117   
118    private MailSettingsListener mailSettingsListener = new MailSettingsListener() {
119        public void mailSettingsSaved(MailSettingsEvent e) {
120            if((e.getGlobalChange() & GlobalConfig.CHANGE_TYPE_OTHER) != 0) {
121                if(globalConfig.getDispOrder() != displayOrder) {
122                    invokeLater(new EventObjectRunnable(e) {
123                        public void run() {
124                            displayOrder = !displayOrder;
125                            displayableChanged();
126                        }
127                    });
128                }
129                if(globalConfig.getHideDeletedMsg() != hideDeleted) {
130                    invokeLater(new EventObjectRunnable(e) {
131                        public void run() {
132                            hideDeleted = !hideDeleted;
133                            displayableChanged();
134                        }
135                    });
136                }
137            }
138        }
139    };
140   
141    /** The mailbox node listener. */
142    private MailboxNodeListener mailboxNodeListener = new MailboxNodeListener() {
143                public void mailboxStatusChanged(MailboxNodeEvent e) {
144                        invokeLater(new EventObjectRunnable(e) {
145                                public void run() {
146                                        mailboxNode_MailboxStatusChanged((MailboxNodeEvent)getEvent());
147                                }
148                        });
149                }
150    };
151   
152    /** The message node listener. */
153    private MessageNodeListener messageNodeListener = new MessageNodeListener() {
154                public void messageStatusChanged(MessageNodeEvent e) {
155                        invokeLater(new EventObjectRunnable(e) {
156                                public void run() {
157                                        messageNode_MessageStatusChanged((MessageNodeEvent)getEvent());
158                                }
159                        });
160                }
161    };
162
163    /* (non-Javadoc)
164     * @see org.logicprobe.LogicMail.ui.BaseScreen#onDisplay()
165     */
166    public void onDisplay() {
167        if(this.hideDeleted != globalConfig.getHideDeletedMsg()) {
168            this.hideDeleted = !this.hideDeleted;
169            displayableChanged();
170        }
171       
172        if(this.displayOrder != globalConfig.getDispOrder()) {
173            this.displayOrder = !this.displayOrder;
174            displayableChanged();
175        }
176        this.mailSettings.addMailSettingsListener(mailSettingsListener);
177        this.mailboxNode.addMailboxNodeListener(mailboxNodeListener);
178       
179        if(firstDisplay) {
180            MessageNode[] initialMessages = this.mailboxNode.getMessages();
181            for(int i=0; i<initialMessages.length; i++) {
182                knownMessages.addElement(initialMessages[i]);
183                if(isMessageDisplayable(initialMessages[i])) {
184                        insertDisplayableMessage(initialMessages[i]);
185                }
186            }
187           
188                this.mailboxNode.refreshMessages();
189                firstDisplay = false;
190        }
191        int size = knownMessages.size();
192        for(int i=0; i<size; i++) {
193                ((MessageNode)knownMessages.elementAt(i)).addMessageNodeListener(messageNodeListener);
194        }
195       
196        composeEnabled = (mailboxNode.getParentAccount() instanceof NetworkAccountNode)
197            && ((NetworkAccountNode)mailboxNode.getParentAccount()).hasMailSender();
198        ((StandardScreen)screen).setShortcutEnabled(SHORTCUT_COMPOSE, composeEnabled);
199       
200        // TODO: Support message list changes between display pushing
201        // TODO: Support updating when messages are deleted
202    }
203   
204        /* (non-Javadoc)
205         * @see org.logicprobe.LogicMail.ui.BaseScreen#onUndisplay()
206         */
207        public void onUndisplay() {
208        this.mailSettings.removeMailSettingsListener(mailSettingsListener);
209        this.mailboxNode.removeMailboxNodeListener(mailboxNodeListener);
210        int size = knownMessages.size();
211        for(int i=0; i<size; i++) {
212                ((MessageNode)knownMessages.elementAt(i)).removeMessageNodeListener(messageNodeListener);
213        }
214    }
215   
216        /* (non-Javadoc)
217         * @see org.logicprobe.LogicMail.ui.AbstractScreenProvider#hasShortcuts()
218         */
219        public boolean hasShortcuts() {
220                return true;
221        }
222       
223        /* (non-Javadoc)
224         * @see org.logicprobe.LogicMail.ui.AbstractScreenProvider#getShortcuts()
225         */
226        public ShortcutItem[] getShortcuts() {
227                // Note: This method is only called once, during initialization of the screen,
228                // and only on devices that have touchscreen support.  The strings for the
229                // shortcuts are contained within the main application library's resources.
230                // However, the icons are contained within the platform support library
231                // containing actual touchscreen API support.
232                return new ShortcutItem[] {
233                        new ShortcutItem(
234                                        SHORTCUT_COMPOSE,
235                                        resources.getString(LogicMailResource.MENUITEM_COMPOSE_EMAIL),
236                                        "shortcut-compose.png", "shortcut-compose-d.png"),
237                        null,
238                        null,
239                        new ShortcutItem(
240                                        SHORTCUT_UP,
241                                        resources.getString(LogicMailResource.MENUITEM_SCROLL_UP),
242                                        "shortcut-up.png", "shortcut-up-d.png"),
243                        new ShortcutItem(
244                                        SHORTCUT_DOWN,
245                                        resources.getString(LogicMailResource.MENUITEM_SCROLL_DOWN),
246                                        "shortcut-down.png", "shortcut-down-d.png")
247                };
248        }
249       
250        /**
251         * Initializes the fields.
252         */
253        public void initFields(Screen screen) {
254        super.initFields(screen);
255
256                messageFieldManager = new VerticalFieldManager(Manager.VERTICAL_SCROLL | Manager.VERTICAL_SCROLLBAR) {
257                    protected boolean navigationMovement(int dx, int dy, int status, int time) {
258                        navigationMoved = true;
259                        return super.navigationMovement(dx, dy, status, time);
260                    }
261                };
262        screen.add(messageFieldManager);
263        this.messageActions = navigationController.getMessageActions();
264        initMenuItems();
265        }   
266       
267        private void initMenuItems() {
268            compositionItem = new MenuItem(resources, LogicMailResource.MENUITEM_COMPOSE_EMAIL, 400100, 2000) {
269                public void run() {
270                        navigationController.displayComposition((NetworkAccountNode)mailboxNode.getParentAccount());
271                }
272            };
273        }
274
275    /* (non-Javadoc)
276     * @see org.logicprobe.LogicMail.ui.BaseScreen#makeMenu(net.rim.device.api.ui.component.Menu, int)
277     */
278    public void makeMenu(Menu menu, int instance) {
279        Field fieldWithFocus = messageFieldManager.getFieldWithFocus();
280        if(fieldWithFocus instanceof MailboxMessageField) {
281            MessageNode messageNode = ((MailboxMessageField)fieldWithFocus).getMessageNode();
282            messageActions.makeMenu(menu, instance, messageNode, false);
283        }
284        if(composeEnabled) {
285            menu.add(compositionItem);
286        }
287    }
288   
289    public boolean onClose() {
290        // Check for deleted messages in the mailbox
291        if(mailboxNode.getParentAccount().hasExpunge()
292                && mailboxNode.hasDeletedMessages()) {
293            MailSettings mailSettings = MailSettings.getInstance();
294            int expungeMode = globalConfig.getExpungeMode();
295            if(expungeMode == GlobalConfig.EXPUNGE_PROMPT) {
296                Dialog dialog = new Dialog(
297                        Dialog.D_YES_NO,
298                        resources.getString(LogicMailResource.MAILBOX_EXPUNGE_PROMPT),
299                        Dialog.NO,
300                        Bitmap.getPredefinedBitmap(Bitmap.QUESTION), 0, true);
301                int choice = dialog.doModal();
302
303                // Request expunge if desired
304                if(choice == Dialog.YES) {
305                    mailboxNode.expungeDeletedMessages();
306                }
307
308                if(dialog.getDontAskAgainValue()) {
309                    if(choice == Dialog.YES) {
310                        globalConfig.setExpungeMode(GlobalConfig.EXPUNGE_ALWAYS);
311                        mailSettings.saveSettings();
312                    }
313                    else if(choice == Dialog.NO) {
314                        globalConfig.setExpungeMode(GlobalConfig.EXPUNGE_NEVER);
315                        mailSettings.saveSettings();
316                    }
317                }
318            }
319            else if(expungeMode == GlobalConfig.EXPUNGE_ALWAYS) {
320                mailboxNode.expungeDeletedMessages();
321            }
322        }
323
324        // Close the screen
325        screen.close();
326        return true;
327    }
328   
329    /**
330     * Handles mailbox status change events.
331     *
332     * @param e Event data.
333     */
334    private void mailboxNode_MailboxStatusChanged(MailboxNodeEvent e) {
335        int type = e.getType();
336        if(type == MailboxNodeEvent.TYPE_NEW_MESSAGES) {
337                MessageNode[] messageNodes = e.getAffectedMessages();
338                for(int i=0; i<messageNodes.length; i++) {
339                        knownMessages.addElement(messageNodes[i]);
340                       
341                        if(isMessageDisplayable(messageNodes[i])) {
342                                // Insert the message
343                                insertDisplayableMessage(messageNodes[i]);
344                        }
345                       
346                        if(screen != null && screen.isDisplayed()) {
347                                messageNodes[i].addMessageNodeListener(messageNodeListener);
348                        }
349                }
350        }
351        else if(type == MailboxNodeEvent.TYPE_DELETED_MESSAGES) {
352            MessageNode[] messageNodes = e.getAffectedMessages();
353            for(int i=0; i<messageNodes.length; i++) {
354                if(screen != null && screen.isDisplayed()) {
355                    messageNodes[i].removeMessageNodeListener(messageNodeListener);
356                }
357                removeDisplayableMessage(messageNodes[i]);
358                knownMessages.removeElement(messageNodes[i]);
359            }
360        }
361        }
362   
363    /**
364     * Determines whether a message should be displayed,
365     * per the configuration.
366     *
367     * @param messageNode Message to check.
368     *
369     * @return True if it should be displayed, false otherwise.
370     */
371    private boolean isMessageDisplayable(MessageNode messageNode) {
372        if((messageNode.getFlags() & MessageNode.Flag.DELETED) != 0
373                && hideDeleted) {
374            return false;
375        }
376        else {
377            return true;
378        }
379    }
380   
381    /**
382     * A configuration item affecting the displayable state of messages has
383     * changed.  Since this is infrequent, this operation will take the simple
384     * approach of emptying and repopulating the screen.
385     */
386    private void displayableChanged() {
387        int size = knownMessages.size();
388        if(size == 0) { return; }
389       
390        // Clear out all the existing content from the field manager and map
391        messageFieldMap.clear();
392        messageFieldManager.deleteAll();
393       
394        // Reset the flag that controls field focus behavior
395        navigationMoved = false;
396       
397        // Get the known messages display them if appropriate
398        for(int i=0; i<size; i++) {
399            MessageNode messageNode = (MessageNode)knownMessages.elementAt(i);
400            if(isMessageDisplayable(messageNode)) {
401                insertDisplayableMessage(messageNode);
402            }
403        }
404    }
405   
406    /**
407     * Insert a message into the list and associated data structures.
408     * This will insert into the correct order, per the configuration.
409     *
410     * @param messageNode Message to insert.
411     */
412    private void insertDisplayableMessage(MessageNode messageNode) {
413        Field selectedField = messageFieldManager.getFieldWithFocus();
414       
415                if(messageFieldManager.getFieldCount() > 0) {
416                        Comparator comparator = MessageNode.getComparator();
417                        int index = messageFieldManager.getFieldCount();
418                       
419                        if(displayOrder) {
420                                // Ascending order
421                                MessageNode lastMessage = getLastDisplayedMessage(index - 1);
422                                while(lastMessage != null && index > 0 && comparator.compare(lastMessage, messageNode) >= 0) {
423                                        index--;
424                                        if(index > 0) { lastMessage = getLastDisplayedMessage(index - 1); }
425                                }
426                        }
427                        else {
428                                // Descending order
429                                MessageNode lastMessage = getLastDisplayedMessage(index - 1);
430                                while(lastMessage != null && index > 0 && comparator.compare(lastMessage, messageNode) <= 0) {
431                                        index--;
432                                        if(index > 0) { lastMessage = getLastDisplayedMessage(index - 1); }
433                                }
434                        }
435                        MailboxMessageField mailboxMessageField =
436                                new MailboxMessageField(mailboxNode, messageNode, Field.USE_ALL_WIDTH | Field.FOCUSABLE);
437                        messageFieldMap.put(messageNode, mailboxMessageField);
438            insertMessageField(mailboxMessageField, index);
439                }
440                else {
441                        MailboxMessageField mailboxMessageField =
442                                new MailboxMessageField(mailboxNode, messageNode, Field.USE_ALL_WIDTH | Field.FOCUSABLE);
443                        messageFieldMap.put(messageNode, mailboxMessageField);
444                        insertMessageField(mailboxMessageField, 0);
445                }
446               
447                if(!navigationMoved) {
448                    // Select newest message
449            int count = messageFieldManager.getFieldCount();
450            if(count > 0) {
451                if(displayOrder) {
452                    messageFieldManager.getField(count - 1).setFocus();
453                }
454                else {
455                    messageFieldManager.getField(0).setFocus();
456                }
457            }
458                }
459                else {
460                    // Keep previous selection
461            if(selectedField != null) { selectedField.setFocus(); }
462                }
463    }
464
465    /**
466     * Remove a message from the list and associated data structures,
467     * if that message exists in the list.
468     *
469     * @param messageNode Message to insert.
470     */
471    private void removeDisplayableMessage(MessageNode messageNode) {
472        MailboxMessageField mailboxMessageField = (MailboxMessageField)messageFieldMap.remove(messageNode);
473        if(mailboxMessageField == null) { return; }
474
475        deleteMessageField(mailboxMessageField);
476    }
477   
478    private void insertMessageField(MailboxMessageField messageField, int index) {
479        // It is assumed that the index will only be 0 for the first message.
480       
481        Date messageDate = messageField.getMessageNode().getDate();
482       
483        if(displayOrder) {
484            // Ascending order
485            if(messageFieldManager.getFieldCount() == 0) {
486                messageFieldManager.add(messageField);
487                messageFieldManager.add(new MessageSeparatorField(messageDate));
488            }
489            else {
490                if(index > 0 && messageFieldManager.getField(index - 1) instanceof MessageSeparatorField) {
491                    Date sepDate = ((MessageSeparatorField)messageFieldManager.getField(index - 1)).getDate();
492                    if(DateTimeUtilities.isSameDate(messageDate.getTime(), sepDate.getTime())) {
493                        index--;
494                    }
495                }
496               
497                Field nextField;
498                if(index < messageFieldManager.getFieldCount()) {
499                    nextField = messageFieldManager.getField(index);
500                }
501                else {
502                    nextField = null;
503                }
504               
505                if(nextField instanceof MessageSeparatorField) {
506                    Date sepDate = ((MessageSeparatorField)nextField).getDate();
507                    if(DateTimeUtilities.isSameDate(messageDate.getTime(), sepDate.getTime())) {
508                        messageFieldManager.insert(messageField, index);
509                    }
510                    else {
511                        messageFieldManager.insert(new MessageSeparatorField(messageDate), index + 1);
512                        messageFieldManager.insert(messageField, index + 1);
513                    }
514                }
515                else if(nextField instanceof MailboxMessageField) {
516                    Date nextDate = ((MailboxMessageField)nextField).getMessageNode().getDate();
517                    if(DateTimeUtilities.isSameDate(messageDate.getTime(), nextDate.getTime())) {
518                        messageFieldManager.insert(messageField, index);
519                    }
520                    else {
521                        messageFieldManager.insert(new MessageSeparatorField(messageDate), index);
522                        messageFieldManager.insert(messageField, index);
523                    }
524                }
525                else {
526                    messageFieldManager.insert(new MessageSeparatorField(messageDate), index);
527                    messageFieldManager.insert(messageField, index);
528                }
529            }
530        }
531        else {
532            // Descending order
533            if(messageFieldManager.getFieldCount() == 0) {
534                messageFieldManager.add(new MessageSeparatorField(messageDate));
535                messageFieldManager.add(messageField);
536            }
537            else  {
538                Field prevField = messageFieldManager.getField(index - 1);
539
540                if(prevField instanceof MessageSeparatorField) {
541                    Date sepDate = ((MessageSeparatorField)prevField).getDate();
542                    if(!DateTimeUtilities.isSameDate(messageDate.getTime(), sepDate.getTime())
543                            && index > 1
544                            && messageFieldManager.getField(index - 2) instanceof MailboxMessageField) {
545                        index--;
546                        prevField = messageFieldManager.getField(index - 1);
547                    }
548                }
549               
550                if(prevField instanceof MessageSeparatorField) {
551                    Date sepDate = ((MessageSeparatorField)prevField).getDate();
552                    if(DateTimeUtilities.isSameDate(messageDate.getTime(), sepDate.getTime())) {
553                        messageFieldManager.insert(messageField, index);
554                    }
555                    else {
556                        messageFieldManager.insert(new MessageSeparatorField(messageDate), index - 1);
557                        messageFieldManager.insert(messageField, index);
558                    }
559                }
560                else {
561                    Date prevDate = ((MailboxMessageField)prevField).getMessageNode().getDate();
562                    if(DateTimeUtilities.isSameDate(messageDate.getTime(), prevDate.getTime())) {
563                        messageFieldManager.insert(messageField, index);
564                    }
565                    else {
566                        messageFieldManager.insert(new MessageSeparatorField(messageDate), index);
567                        messageFieldManager.insert(messageField, index + 1);
568                    }
569                }
570            }
571        }
572    }
573   
574    private void deleteMessageField(MailboxMessageField messageField) {
575        int fieldCount = messageFieldManager.getFieldCount();
576        int index = messageField.getIndex();
577       
578        if(displayOrder) {
579            // Ascending order
580            if(messageFieldManager.getField(index + 1) instanceof MessageSeparatorField
581                    && (index == 0 || messageFieldManager.getField(index - 1) instanceof MessageSeparatorField)) {
582                messageFieldManager.deleteRange(index, 2);
583            }
584            else {
585                messageFieldManager.delete(messageField);
586            }
587        }
588        else {
589            // Descending order
590            if(messageFieldManager.getField(index - 1) instanceof MessageSeparatorField
591                    && (index == fieldCount - 1 || messageFieldManager.getField(index + 1) instanceof MessageSeparatorField)) {
592                messageFieldManager.deleteRange(index - 1, 2);
593            }
594            else {
595                messageFieldManager.delete(messageField);
596            }
597        }
598    }
599   
600    /**
601     * Gets the last displayed message.
602     *
603     * @param index the index
604     *
605     * @return the last displayed message
606     */
607    private MessageNode getLastDisplayedMessage(int index) {
608        while(index >= 0) {
609                if(messageFieldManager.getField(index) instanceof MailboxMessageField) {
610                        return ((MailboxMessageField)messageFieldManager.getField(index)).getMessageNode();
611                }
612                index--;
613        }
614        return null;
615    }
616   
617    /**
618     * Handles message status change events.
619     *
620     * @param e Event data.
621     */
622        private void messageNode_MessageStatusChanged(MessageNodeEvent e) {
623                if(e.getType() == MessageNodeEvent.TYPE_FLAGS) {
624                        MessageNode messageNode = (MessageNode)e.getSource();
625                        boolean currentlyDisplayed = messageFieldMap.containsKey(messageNode);
626                        boolean displayable = isMessageDisplayable(messageNode);
627                       
628                        if(currentlyDisplayed && !displayable) {
629                                // Remove from display
630                            removeDisplayableMessage(messageNode);
631                        }
632                        else if(!currentlyDisplayed && displayable) {
633                                // Add to display
634                                insertDisplayableMessage(messageNode);
635                        }
636                        else if(currentlyDisplayed) {
637                                // Just a visual flag update, so find and invalidate the item
638                                MailboxMessageField mailboxMessageField = (MailboxMessageField)messageFieldMap.get(messageNode);
639                                mailboxMessageField.invalidate();
640                        }
641                }
642        }
643
644    /**
645     * Gets the selected message.
646     *
647     * @return the selected message
648     */
649    private MessageNode getSelectedMessage() {
650        Field fieldWithFocus = messageFieldManager.getFieldWithFocus();
651        if(fieldWithFocus instanceof MailboxMessageField) {
652                return ((MailboxMessageField)fieldWithFocus).getMessageNode();
653        }
654        else {
655                return null;
656        }
657    }
658   
659    /* (non-Javadoc)
660     * @see net.rim.device.api.ui.Screen#navigationClick(int, int)
661     */
662    public boolean navigationClick(int status, int time) {
663        MessageNode messageNode = getSelectedMessage();
664        if(messageNode != null) {
665                messageActions.openMessage(messageNode);
666                return true;
667        }
668        else {
669                return false;
670        }
671    }
672   
673    /* (non-Javadoc)
674     * @see net.rim.device.api.ui.Screen#keyChar(char, int, int)
675     */
676    public boolean keyChar(char key, int status, int time) {
677        boolean retval = false;
678        MessageNode messageNode;
679        switch(key) {
680            case Keypad.KEY_ENTER:
681                messageNode = getSelectedMessage();
682                if(messageNode != null) {
683                        messageActions.openMessage(messageNode);
684                        retval = true;
685                }
686                break;
687            case Keypad.KEY_BACKSPACE:
688                messageNode = getSelectedMessage();
689                if(messageNode != null) {
690                        messageActions.deleteMessage(messageNode);
691                        retval = true;
692                }
693                break;
694        }
695        return retval;
696    }
697   
698    /* (non-Javadoc)
699     * @see org.logicprobe.LogicMail.ui.AbstractScreenProvider#shortcutAction(org.logicprobe.LogicMail.ui.ScreenProvider.ShortcutItem)
700     */
701    public void shortcutAction(ShortcutItem item) {
702        switch(item.getId()) {
703        case SHORTCUT_COMPOSE:
704                compositionItem.run();
705                break;
706        case SHORTCUT_UP:
707                screen.scroll(Manager.UPWARD);
708                break;
709        case SHORTCUT_DOWN:
710                screen.scroll(Manager.DOWNWARD);
711                break;
712        }
713    }
714   
715    private static class MessageSeparatorField extends LabeledSeparatorField {
716        private final Date date;
717       
718        public MessageSeparatorField(Date date) {
719            super(Field.FOCUSABLE | LabeledSeparatorField.BOTTOM_BORDER);
720   
721            Calendar cal = Calendar.getInstance();
722            cal.setTime(date);
723            cal.set(Calendar.HOUR_OF_DAY, 0);
724            cal.set(Calendar.MINUTE, 0);
725            cal.set(Calendar.SECOND, 0);
726            cal.set(Calendar.MILLISECOND, 0);
727           
728            StringBuffer buffer = new StringBuffer();
729            DateFormat.getInstance(DateFormat.DATE_LONG).format(cal, buffer, null);
730            setText(buffer.toString());
731           
732            this.date = cal.getTime();
733        }
734       
735        public Date getDate() {
736            return date;
737        }
738    }
739}
Note: See TracBrowser for help on using the browser.