001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.microedition.lcdui.pda;
043:
044: import java.util.Date;
045: import java.util.Enumeration;
046: import java.util.Hashtable;
047: import javax.microedition.lcdui.Alert;
048: import javax.microedition.lcdui.AlertType;
049: import javax.microedition.lcdui.Command;
050: import javax.microedition.lcdui.CommandListener;
051: import javax.microedition.lcdui.DateField;
052: import javax.microedition.lcdui.Display;
053: import javax.microedition.lcdui.Displayable;
054: import javax.microedition.lcdui.Form;
055: import javax.microedition.lcdui.Item;
056: import javax.microedition.lcdui.List;
057: import javax.microedition.lcdui.StringItem;
058: import javax.microedition.pim.Contact;
059: import javax.microedition.pim.Event;
060: import javax.microedition.pim.PIM;
061: import javax.microedition.pim.PIMException;
062: import javax.microedition.pim.PIMItem;
063: import javax.microedition.pim.PIMList;
064: import javax.microedition.pim.ToDo;
065:
066: /**
067: * The <code>PIMBrowser</code> custom component uses PIM API which gives access to the Personal
068: * Information Management (PIM) database including to-do lists, calendars and
069: * contact data. Requires JSR 75.
070: * @author
071: */
072: public class PIMBrowser extends List implements CommandListener {
073:
074: /**
075: * Command fired when <code>PIMItem</code> selected.
076: */
077: public static final Command SELECT_PIM_ITEM = new Command("Select",
078: Command.OK, 1);
079: private int listType = PIM.CONTACT_LIST;
080: private final Command details = new Command("Details",
081: Command.ITEM, 1);
082: private final Command selectList = new Command("Select",
083: Command.OK, 1);
084: private final Command back = new Command("Back", Command.BACK, 1);
085: private Display display;
086: private String selectedList;
087: private PIMItem selectedItem;
088: private CommandListener commandListener;
089:
090: /**
091: * Creates a new instance of <code>PIMBrowser</code> for given <code>Display</code> object
092: * and <code>PIM</code> list type.
093: * @param display non-null <code>Display</code> object.
094: * @param listType type representing the PIM list type to open, either <code>PIM.CONTACT_LIST</code>,
095: * <code>PIM.EVENT_LIST</code>, or <code>PIM.TODO_LIST</code>.
096: */
097: public PIMBrowser(Display display, int listType) {
098: super ("", IMPLICIT);
099: this .display = display;
100: this .listType = listType;
101: super .setCommandListener(this );
102:
103: showLists();
104: }
105:
106: private void showLists() {
107: new Thread(new Runnable() {
108:
109: public void run() {
110: String[] lists = PIM.getInstance().listPIMLists(
111: listType);
112: if (lists.length == 0) {
113: reportError("No lists for requested PIM type");
114: return;
115: }
116:
117: //if only one list open it.
118: if (lists.length == 1) {
119: loadList(lists[0]);
120: return;
121: }
122:
123: //if more then one list show them all and let the user choose
124: setTitle("select list");
125: for (int i = 0; i < lists.length; i++) {
126: append(lists[i], null);
127: }
128: setSelectCommand(selectList);
129: }
130: }).start();
131: }
132:
133: private void reportException(Exception e) {
134: reportError(e.getMessage());
135: }
136:
137: private void reportError(String error) {
138: Alert alert = new Alert(error, error, null, AlertType.ERROR);
139: alert.setTimeout(Alert.FOREVER);
140: display.setCurrent(alert, this );
141: }
142:
143: /**
144: * Returns command listener.
145: * @return non null <code>CommandListener</code> object
146: */
147: protected CommandListener getCommandListener() {
148: return commandListener;
149: }
150:
151: /**
152: * Sets command listener to this component.
153: * @param commandListener <code>CommandListener</code> to be used
154: */
155: public void setCommandListener(CommandListener commandListener) {
156: this .commandListener = commandListener;
157: }
158:
159: private void doDismiss() {
160: CommandListener commandListener = getCommandListener();
161: if (commandListener != null) {
162: commandListener.commandAction(SELECT_PIM_ITEM, this );
163: }
164: }
165:
166: /**
167: * Called by a system to indicated that a command has been invoked on a particular displayable.
168: * @param command the <code>Command</code> that was invoked
169: * @param displayable the <code>Displayable</code> where the command was invoked
170: */
171: public void commandAction(Command command, Displayable displayable) {
172: if (command.equals(back)) {
173: removeCommand(back);
174: removeCommand(details);
175: showLists();
176: } else if (command.equals(selectList)) {
177: new Thread(new Runnable() {
178: public void run() {
179: loadList(getString(getSelectedIndex()));
180: }
181: }).start();
182: addCommand(back);
183: } else if (command.equals(details)) {
184: new Thread(new Runnable() {
185: public void run() {
186: selectedItem = getItem(selectedList,
187: getString(getSelectedIndex()));
188: showItem(selectedItem);
189: }
190: }).start();
191: } else if (command.equals(SELECT_PIM_ITEM)) {
192: new Thread(new Runnable() {
193:
194: public void run() {
195: selectedItem = getItem(selectedList,
196: getString(getSelectedIndex()));
197: doDismiss();
198: }
199: }).start();
200: } else if (commandListener != null) {
201: commandListener.commandAction(command, displayable);
202: }
203: }
204:
205: /**
206: * Returns PIM list type.
207: * @return possible values: <code>PIM.CONTACT_LIST</code> represents contact list,
208: * <code>PIM.EVENT_LIST</code> represents event list, <code>PIM.TODO_LIST</code>
209: * represents to-do list.
210: */
211: public int getListType() {
212: return listType;
213: }
214:
215: /**
216: * Returns selected <code>PIMItem</code> object.
217: * @return selected <code>PIMItem</code> object
218: */
219: public PIMItem getSelectedItem() {
220: return selectedItem;
221: }
222:
223: private void loadList(final String listName) {
224: selectedList = listName;
225: Form form = new Form("Loading PIM list");
226: form.append("Please wait...");
227: display.setCurrent(form);
228: deleteAll();
229: openList(selectedList);
230: }
231:
232: private void openList(String listName) {
233: try {
234: PIMList list = PIM.getInstance().openPIMList(listType,
235: PIM.READ_WRITE, listName);
236: if (getTitle() == null || getTitle().equals("")) {
237: setTitle(list.getName());
238: }
239: int fieldCode = getFieldCode(listType);
240: Enumeration items = list.items();
241: while (items.hasMoreElements()) {
242: append(((PIMItem) items.nextElement()).getString(
243: fieldCode, 0), null);
244: }
245: if (size() == 0) {
246: reportError("List: " + listName + " is Empty");
247: return;
248: }
249: addCommand(details);
250: setSelectCommand(SELECT_PIM_ITEM);
251: display.setCurrent(this );
252: } catch (Exception e) {
253: reportException(e);
254: }
255: }
256:
257: private PIMItem getItem(String listName, String itemName) {
258: try {
259: Enumeration items = PIM.getInstance().openPIMList(listType,
260: PIM.READ_WRITE, listName).items();
261: int fieldCode = getFieldCode(listType);
262:
263: while (items.hasMoreElements()) {
264: PIMItem current = (PIMItem) items.nextElement();
265: String name = current.getString(fieldCode, 0);
266: if (name.equals(itemName)) {
267: return current;
268: }
269: }
270: } catch (Exception e) {
271: reportException(e);
272: }
273: return null;
274: }
275:
276: private int getFieldCode(int listType) {
277: int fieldCode = 0;
278: switch (listType) {
279: case PIM.CONTACT_LIST:
280: fieldCode = Contact.FORMATTED_NAME;
281: break;
282: case PIM.EVENT_LIST:
283: fieldCode = Event.SUMMARY;
284: break;
285: case PIM.TODO_LIST:
286: fieldCode = ToDo.SUMMARY;
287: break;
288: }
289: return fieldCode;
290: }
291:
292: private void showItem(PIMItem selectedItem) {
293: ItemDisplayScreen screen = new ItemDisplayScreen(selectedItem);
294: //screen.
295: display.setCurrent(screen);
296: }
297:
298: class ItemDisplayScreen extends Form implements CommandListener {
299:
300: private final Command backCommand = new Command("Back",
301: Command.BACK, 1);
302: private final PIMItem item;
303: private final Hashtable fieldTable = new Hashtable(); // maps field indices to items
304:
305: public ItemDisplayScreen(PIMItem item) {
306: super ("PIM Item");
307: this .item = item;
308: try {
309: populateForm();
310: } catch (PIMException ex) {
311: ex.printStackTrace();
312: }
313:
314: addCommand(backCommand);
315: setCommandListener(this );
316: }
317:
318: private boolean isClassField(int field) {
319: return item instanceof Contact && field == Contact.CLASS
320: || item instanceof Event && field == Event.CLASS
321: || item instanceof ToDo && field == ToDo.CLASS;
322: }
323:
324: private void populateForm() throws PIMException {
325: deleteAll();
326: fieldTable.clear();
327: int[] fields = item.getPIMList().getSupportedFields();
328: for (int i = 0; i < fields.length; i++) {
329: int field = fields[i];
330: // exclude CLASS field
331: if (isClassField(field)) {
332: continue;
333: }
334:
335: if (item.countValues(field) == 0) {
336: continue;
337: }
338:
339: int dataType = item.getPIMList()
340: .getFieldDataType(field);
341: String label = item.getPIMList().getFieldLabel(field);
342: Item formItem = null;
343: switch (dataType) {
344: case PIMItem.STRING: {
345: String sValue = item.getString(field, 0);
346: if (sValue == null) {
347: sValue = "";
348: }
349: formItem = new StringItem(label, sValue);
350: break;
351: }
352: case PIMItem.BOOLEAN: {
353: formItem = new StringItem(label, item.getBoolean(
354: field, 0) ? "yes" : "no");
355: break;
356: }
357: case PIMItem.STRING_ARRAY: {
358: String[] a = item.getStringArray(field, 0);
359: if (a != null) {
360: formItem = new StringItem(label,
361: joinStringArray(a));
362: }
363: break;
364: }
365: case PIMItem.DATE: {
366: long time = item.getDate(field, 0);
367: int style = DateField.DATE_TIME;
368: // some fields are date only, without a time.
369: // correct for these fields:
370: if (item instanceof Contact) {
371: switch (field) {
372: case Contact.BIRTHDAY:
373: style = DateField.DATE;
374: break;
375: }
376: }
377: formItem = new DateField(label, style);
378: ((DateField) formItem).setDate(new Date(time));
379: break;
380: }
381: case PIMItem.INT: {
382: formItem = new StringItem(label, String
383: .valueOf(item.getInt(field, 0)));
384: break;
385: }
386: case PIMItem.BINARY: {
387: byte[] data = item.getBinary(field, 0);
388: if (data != null) {
389: formItem = new StringItem(label, data.length
390: + " bytes");
391: }
392: break;
393: }
394: }
395: append(formItem);
396: }
397: }
398:
399: /**
400: * Indicates that a command event has occurred on <code>Displayable</code> d.
401: * @param c a <code>Command</code> object identifying the command. This is either
402: * one of the applications have been added to <code>Displayable</code> with addCommand(Command)
403: * or is the implicit <code>SELECT_COMMAND</code> of List.
404: * @param the <code>Displayable</code> on which this event has occurred
405: */
406: public void commandAction(final Command c, Displayable d) {
407: if (c == backCommand) {
408: showLists();
409: display.setCurrent(PIMBrowser.this );
410: }
411: }
412:
413: private String joinStringArray(String[] a) {
414: StringBuffer sb = new StringBuffer();
415: for (int i = 0; i < a.length; i++) {
416: if (a[i] != null && a[i].length() > 0) {
417: if (sb.length() > 0) {
418: sb.append(", ");
419: }
420: sb.append(a[i]);
421: }
422: }
423: return sb.toString();
424: }
425: }
426: }
|