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

Revision 701, 12.4 KB (checked in by octorian, 36 hours ago)

Refactoring to separate AccountNode into Local and Network subclasses

Line 
1/*-
2 * Copyright (c) 2009, 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 */
31package org.logicprobe.LogicMail.ui;
32
33import org.logicprobe.LogicMail.LogicMailResource;
34import org.logicprobe.LogicMail.model.AccountNode;
35import org.logicprobe.LogicMail.model.MailManager;
36import org.logicprobe.LogicMail.model.NetworkAccountNode;
37
38import net.rim.device.api.i18n.ResourceBundle;
39import net.rim.device.api.ui.Field;
40import net.rim.device.api.ui.MenuItem;
41import net.rim.device.api.ui.UiApplication;
42import net.rim.device.api.ui.component.Dialog;
43import net.rim.device.api.ui.component.Menu;
44import net.rim.device.api.ui.container.MainScreen;
45
46/**
47 * Standard UI screen implementation.
48 * This implementation is designed to separate RIM API inheritance
49 * relationships from concrete UI screens through composition.
50 * The concrete UI is implemented through a <tt>ScreenProvider</tt>
51 * implementation.
52 */
53public class StandardScreen extends MainScreen {
54    protected static ResourceBundle resources = ResourceBundle.getBundle(LogicMailResource.BUNDLE_ID, LogicMailResource.BUNDLE_NAME);
55    protected static StatusBarField statusBarField = new StatusBarField();
56    private NavigationController navigationController;
57    private Field titleField;
58    private Field originalStatusField;
59    private Field currentStatusField;
60
61    private MenuItem configItem;
62    private MenuItem aboutItem;
63    private MenuItem closeItem;
64    private MenuItem exitItem;
65
66    protected ScreenProvider screenProvider;
67
68    /**
69     * Instantiates a new standard screen.
70     *
71     * @param navigationController the navigation controller
72     * @param screenProvider the screen provider
73     */
74    public StandardScreen(NavigationController navigationController, ScreenProvider screenProvider) {
75        super(screenProvider.getStyle());
76        if(navigationController == null || screenProvider == null) {
77            throw new IllegalArgumentException();
78        }
79
80        this.navigationController = navigationController;
81        this.screenProvider = screenProvider;
82        initialize();
83    }
84
85    /**
86     * Initialize the screen elements.
87     */
88    private void initialize() {
89        // Create screen elements
90        if(screenProvider.getTitle() != null) {
91            this.titleField = createTitleField();
92            setTitle(titleField);
93        }
94
95        initMenuItems();
96        screenProvider.setNavigationController(navigationController);
97        screenProvider.initFields(this);
98    }
99   
100    protected Field createTitleField() {
101        return new HeaderField(
102                resources.getString(LogicMailResource.APPNAME)
103                + " - "
104                + screenProvider.getTitle());
105    }
106
107    /* (non-Javadoc)
108     * @see net.rim.device.api.ui.container.MainScreen#setStatus(net.rim.device.api.ui.Field)
109     */
110    public void setStatus(Field status) {
111        originalStatusField = status;
112        superSetStatusImpl(status);
113    }
114
115    /**
116     * Wrapper for internal calls to {@link MainScreen#setStatus(Field)}
117     * that makes sure <code>IllegalStateException</code>s do not appear
118     * if the field had previously been added, and that the field does
119     * not get added if it is already the active status field.
120     *
121     * @param status the new status field
122     */
123    private void superSetStatusImpl(Field status) {
124        if(currentStatusField != status) {
125            currentStatusField = status;
126            if(status != null && status.getManager() != null) {
127                status.getManager().delete(status);
128            }
129            super.setStatus(status);
130        }
131    }
132
133    /**
134     * Update status text, showing or hiding the status bar as necessary.
135     *
136     * @param statusText the status text
137     */
138    public void updateStatus(String statusText) {
139        statusBarField.setStatusText(statusText);
140        if(statusBarField.hasStatus()) {
141            superSetStatusImpl(statusBarField);
142        }
143        else {
144            superSetStatusImpl(originalStatusField);
145        }
146    }
147
148    /* (non-Javadoc)
149     * @see net.rim.device.api.ui.Screen#onDisplay()
150     */
151    protected void onDisplay() {
152        super.onDisplay();
153        updateStatus(navigationController.getCurrentStatus());
154        NotificationHandler.getInstance().cancelNotification();
155        screenProvider.onDisplay();
156    }
157
158    /* (non-Javadoc)
159     * @see net.rim.device.api.ui.Screen#onUndisplay()
160     */
161    protected void onUndisplay() {
162        screenProvider.onUndisplay();
163        superSetStatusImpl(originalStatusField);
164        statusBarField.setStatusText(null);
165        NotificationHandler.getInstance().cancelNotification();
166        super.onUndisplay();
167    }
168
169    /* (non-Javadoc)
170     * @see net.rim.device.api.ui.Screen#onExposed()
171     */
172    protected void onExposed() {
173        super.onExposed();
174        updateStatus(navigationController.getCurrentStatus());
175    }
176
177    /* (non-Javadoc)
178     * @see net.rim.device.api.ui.Screen#onObscured()
179     */
180    protected void onObscured() {
181        super.onObscured();
182        superSetStatusImpl(originalStatusField);
183        statusBarField.setStatusText(null);
184    }
185
186    /* (non-Javadoc)
187     * @see net.rim.device.api.ui.Screen#onClose()
188     */
189    public boolean onClose() {
190        boolean result = screenProvider.onClose();
191        if(result) {
192            if(this.isDisplayed()) {
193                close();
194            }
195        }
196        return result;
197    }
198
199    /* (non-Javadoc)
200     * @see net.rim.device.api.ui.Field#onVisibilityChange(boolean)
201     */
202    protected void onVisibilityChange(boolean visible) {
203        screenProvider.onVisibilityChange(visible);
204    }
205
206    private void initMenuItems() {
207        configItem = new MenuItem(resources, LogicMailResource.MENUITEM_CONFIGURATION, 800000, 9000) {
208            public void run() {
209                showConfigScreen();
210            }
211        };
212        aboutItem = new MenuItem(resources, LogicMailResource.MENUITEM_ABOUT, 800100, 9000) {
213            public void run() {
214                // Show the about dialog
215                AboutDialog dialog = new AboutDialog();
216                dialog.doModal();
217            }
218        };
219        closeItem = new MenuItem(resources, LogicMailResource.MENUITEM_CLOSE, 60000000, 9000) {
220            public void run() {
221                // TODO: Deal with closing/hiding while still running
222
223                StandardScreen.super.onClose();
224            }
225        };
226        exitItem = new MenuItem(resources, LogicMailResource.MENUITEM_EXIT, 60000100, 9000) {
227            public void run() {
228                tryShutdownApplication();
229            }
230        };
231    }
232
233    public void tryShutdownApplication() {
234        // Get all accounts
235        NetworkAccountNode[] accounts = MailManager.getInstance().getMailRootNode().getNetworkAccounts();
236
237        // Find out of we still have an open connection
238        boolean openConnection = false;
239        for(int i=0; i<accounts.length; i++) {
240            if(accounts[i].getStatus() == AccountNode.STATUS_ONLINE) {
241                openConnection = true;
242                break;
243            }
244        }
245
246        if(openConnection) {
247            if(Dialog.ask(Dialog.D_YES_NO, resources.getString(LogicMailResource.BASE_CLOSEANDEXIT)) == Dialog.YES) {
248                for(int i=0; i<accounts.length; i++) {
249                    if(accounts[i].getStatus() == AccountNode.STATUS_ONLINE) {
250                        accounts[i].requestDisconnect(true);
251                    }
252                }
253                cleanupTitleField(titleField);
254                NotificationHandler.getInstance().shutdown();
255                System.exit(0);
256            }
257        }
258        else {
259            cleanupTitleField(titleField);
260            NotificationHandler.getInstance().shutdown();
261            System.exit(0);
262        }
263    }
264
265    protected void cleanupTitleField(Field titleField) {
266        ((HeaderField)titleField).removeListeners();
267    }
268   
269    /**
270     * Shows the configuration screen.
271     * Subclasses should override this method if they need to
272     * refresh their view of the configuration after the screen
273     * is closed.
274     */
275    protected void showConfigScreen() {
276        UiApplication.getUiApplication().pushModalScreen(new ConfigScreen());
277    }
278
279    /* (non-Javadoc)
280     * @see net.rim.device.api.ui.container.MainScreen#makeMenu(net.rim.device.api.ui.component.Menu, int)
281     */
282    protected void makeMenu(Menu menu, int instance) {
283        screenProvider.makeMenu(menu, instance);
284        menu.add(configItem);
285        menu.add(aboutItem);
286        menu.add(closeItem);
287        menu.add(exitItem);
288    }
289
290    /* (non-Javadoc)
291     * @see net.rim.device.api.ui.container.MainScreen#onSavePrompt()
292     */
293    protected boolean onSavePrompt() {
294        return screenProvider.onSavePrompt();
295    }
296
297    /* (non-Javadoc)
298     * @see net.rim.device.api.ui.Screen#navigationClick(int, int)
299     */
300    protected boolean navigationClick(int status, int time) {
301        return screenProvider.navigationClick(status, time);
302    }
303
304    /**
305     * Provides a way for <code>ScreenProvider</code> implementations to call
306     * {@link net.rim.device.api.ui.Screen#navigationClick(int, int)} if they
307     * do not want to override its behavior.
308     *
309     * @see net.rim.device.api.ui.Screen#navigationClick(int, int)
310     */
311    boolean navigationClickDefault(int status, int time) {
312        return super.navigationClick(status, time);
313    }
314   
315    /* (non-Javadoc)
316     * @see net.rim.device.api.ui.Screen#keyChar(char, int, int)
317     */
318    protected boolean keyChar(char c, int status, int time) {
319        return screenProvider.keyChar(c, status, time);
320    }
321
322    /**
323     * Provides a way for <code>ScreenProvider</code> implementations to call
324     * {@link net.rim.device.api.ui.Screen#keyChar(char, int, int)} if they
325     * do not want to override its behavior.
326     *
327     * @see net.rim.device.api.ui.Screen#keyChar(char, int, int)
328     */
329    boolean keyCharDefault(char c, int status, int time) {
330        return super.keyChar(c, status, time);
331    }
332   
333    /**
334     * Gets the enabled state of a shortcut button.
335     * Provided for subclasses that support shortcut buttons.
336     *
337     * @param id the ID of the button
338     * @return the enabled state
339     */
340    public boolean isShortcutEnabled(int id) {
341        // Shortcuts not supported by the base screen class
342        return false;
343    }
344
345    /**
346     * Sets the enabled state of a shortcut button.
347     * Provided for subclasses that support shortcut buttons.
348     *
349     * @param id the ID of the button
350     * @param enabled the enabled state
351     */
352    public void setShortcutEnabled(int id, boolean enabled) {
353        // Shortcuts not supported by the base screen class
354    }
355}
Note: See TracBrowser for help on using the browser.