/** * SyncDemo.java * * Copyright � 1998-2011 Research In Motion Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Note: For the sake of simplicity, this sample application may not leverage * resource bundles and resource strings. However, it is STRONGLY recommended * that application developers make use of the localization features available * within the BlackBerry development platform to ensure a seamless application * experience across a variety of languages and geographies. For more information * on localizing your application, please refer to the BlackBerry Java Development * Environment Development Guide associated with this release. */ package com.rim.samples.device.syncdemo; import java.io.EOFException; import java.util.Vector; import net.rim.device.api.command.Command; import net.rim.device.api.command.CommandHandler; import net.rim.device.api.command.ReadOnlyCommandMetadata; import net.rim.device.api.i18n.Locale; import net.rim.device.api.synchronization.ConverterUtilities; import net.rim.device.api.synchronization.SyncCollection; import net.rim.device.api.synchronization.SyncConverter; import net.rim.device.api.synchronization.SyncManager; import net.rim.device.api.synchronization.SyncObject; import net.rim.device.api.system.Display; import net.rim.device.api.system.PersistentObject; import net.rim.device.api.system.PersistentStore; import net.rim.device.api.ui.Color; import net.rim.device.api.ui.DrawStyle; import net.rim.device.api.ui.Field; import net.rim.device.api.ui.Manager; import net.rim.device.api.ui.MenuItem; import net.rim.device.api.ui.UiApplication; import net.rim.device.api.ui.XYRect; import net.rim.device.api.ui.component.Dialog; import net.rim.device.api.ui.component.LabelField; import net.rim.device.api.ui.component.Menu; import net.rim.device.api.ui.component.table.DataTemplate; import net.rim.device.api.ui.component.table.TableController; import net.rim.device.api.ui.component.table.TableModelAdapter; import net.rim.device.api.ui.component.table.TableView; import net.rim.device.api.ui.component.table.TemplateColumnProperties; import net.rim.device.api.ui.component.table.TemplateRowProperties; import net.rim.device.api.ui.container.MainScreen; import net.rim.device.api.ui.decor.BackgroundFactory; import net.rim.device.api.util.DataBuffer; import net.rim.device.api.util.StringProvider; /** * This application stores contact information in a PersistantObject which can * be synchronized with BlackBerry Desktop Manager using Backup and Restore. * * Note: This class always retrieves the most recent contact list by loading the * contacts from the persistant store so any instance of the SyncDemo class may * be used for synchronization. */ public final class SyncDemo extends UiApplication implements SyncConverter, SyncCollection { // Members // ------------------------------------------------------------------ private AddContactAction _addContactAction; private ViewContactAction _viewContactAction; private ContactTableModelAdapter _model; private TableView _view; // Statics // ------------------------------------------------------------------ private static final int FIELDTAG_FIRST_NAME = 1; private static final int FIELDTAG_LAST_NAME = 2; private static final int FIELDTAG_EMAIL_ADDRESS = 3; private static final long KEY = -2115940372; // Hash of // com.rim.samples.device.syncdemo private static PersistentObject _persist; private static Vector _contacts; /** * Entry point for application. * * @param args * Command line arguments */ public static void main(final String[] args) { _persist = PersistentStore.getPersistentObject(KEY); _contacts = (Vector) _persist.getContents(); if (args != null && args.length > 0 && args[0].equals("init")) { // Initialize persistent store on startup if (_contacts == null) { _contacts = new Vector(); _persist.setContents(_contacts); _persist.commit(); } // Enable app for synchronization SyncManager.getInstance().enableSynchronization(new SyncDemo()); } else { // Create a new instance of the application and make the currently // running thread the application's event dispatch thread. final SyncDemo app = new SyncDemo(); app.enterEventDispatcher(); } } // Inner classes ----------------------------------------------------------- /** * Adapter for displaying ContactData objects in table format */ private static class ContactTableModelAdapter extends TableModelAdapter { /** * @see net.rim.device.api.ui.component.table.TableModelAdapter#getNumberOfRows() */ public int getNumberOfRows() { return _contacts.size(); } /** * @see net.rim.device.api.ui.component.table.TableModelAdapter#getNumberOfColumns() */ public int getNumberOfColumns() { return 1; } /** * @see net.rim.device.api.ui.component.table.TableModelAdapter#doAddRow(Object) */ protected boolean doAddRow(final Object row) { _contacts.addElement(row); return true; } /** * @see net.rim.device.api.ui.component.table.TableModelAdapter#doGetRow(int) */ protected Object doGetRow(final int index) { return _contacts.elementAt(index); } /** * @see net.rim.device.api.ui.component.table.TableModelAdapter#doRemoveRowAt(int) */ protected boolean doRemoveRowAt(final int index) { _contacts.removeElementAt(index); return true; } /** * @see net.rim.device.api.ui.component.table.TableModelAdapter#doInsertRowAt(int, * Object) */ protected boolean doInsertRowAt(final int index, final Object row) { _contacts.insertElementAt(row, index); return true; } /** * Replaces a row with a new one * * @param index * The index at which to replace the row * @param newRow * The new row to insert */ public void replaceRowAt(final int index, final Object newRow) { removeRowAt(index); if (getNumberOfRows() == 0) { // Can't use insert row when there are no entries addRow(newRow); } else { insertRowAt(index, newRow); } } } /** * Adds a contact to the persistent store */ private class AddContactAction extends MenuItem { /** * Creates a new AddContactAction object */ private AddContactAction() { super(new StringProvider("Add"), 0x230010, 10); this.setCommand(new Command(new CommandHandler() { /** * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata, * Object) */ public void execute(final ReadOnlyCommandMetadata metadata, final Object context) { final ContactScreen screen = new ContactScreen(); UiApplication.getUiApplication().pushModalScreen(screen); final ContactData contact = screen.getContact(); if (contact != null) { _model.addRow(contact); _persist.setContents(_contacts); _persist.commit(); } } })); } } /** * Views the selected contact's information */ private class ViewContactAction extends MenuItem { /** * Create a new ViewContactAction object */ public ViewContactAction() { super(new StringProvider("View"), 0x230020, 10); this.setCommand(new Command(new CommandHandler() { /** * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata, * Object) */ public void execute(final ReadOnlyCommandMetadata metadata, final Object context) { final ContactScreen screen = new ContactScreen((ContactData) _model.getRow(_view .getRowNumberWithFocus()), false); UiApplication.getUiApplication().pushScreen(screen); } })); } } /** * Edits a contact */ private class EditContactAction extends MenuItem { private final int _index; /** * Creates a new EditContactAction object * * @param index * The index of the contact in the contact list to edit */ private EditContactAction(final int index) { super(new StringProvider("Edit"), 0x230030, 6); _index = index; this.setCommand(new Command(new CommandHandler() { /** * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata, * Object) */ public void execute(final ReadOnlyCommandMetadata metadata, final Object context) { final ContactData oldContactData = (ContactData) _contacts.elementAt(_index); final ContactScreen screen = new ContactScreen(oldContactData, true); UiApplication.getUiApplication().pushModalScreen(screen); final ContactData newContactData = screen.getContact(); if (newContactData != null) { if (_contacts.contains(oldContactData)) { _model.replaceRowAt(_index, newContactData); PersistentObject.commit(_contacts); } } } })); } } /** * Deletes a contact */ private class DeleteContactAction extends MenuItem { private final int _deleteIndex; /** * Creates a new DeleteContactAction object * * @param deleteIndex * The index of the contact to delete */ private DeleteContactAction(final int deleteIndex) { super(new StringProvider("Delete"), 0x230040, 7); _deleteIndex = deleteIndex; this.setCommand(new Command(new CommandHandler() { /** * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata, * Object) */ public void execute(final ReadOnlyCommandMetadata metadata, final Object context) { final ContactData contactData = (ContactData) _contacts.elementAt(_deleteIndex); final int result = Dialog.ask(Dialog.DELETE, "Delete " + contactData.getFirst() + " " + contactData.getLast() + "?"); if (result == Dialog.YES) { _model.removeRowAt(_deleteIndex); } } })); } } /** * This screen acts as the main screen which allows the user to add and view * synchronized contacts. */ private final class SyncDemoScreen extends MainScreen { /** * Creates a new SyncDemoScreen object */ private SyncDemoScreen() { super(Manager.NO_VERTICAL_SCROLL); setTitle(new LabelField("Contacts", DrawStyle.ELLIPSIS | Field.USE_ALL_WIDTH)); } /** * @see net.rim.device.api.ui.container.MainScreen#makeMenu(Menu,int) */ protected void makeMenu(final Menu menu, final int instance) { menu.add(_addContactAction); menu.addSeparator(); if (_contacts.size() > 0) { final EditContactAction _editContactAction = new EditContactAction(_view.getRowNumberWithFocus()); menu.add(_editContactAction); final DeleteContactAction _deleteContactAction = new DeleteContactAction(_view.getRowNumberWithFocus()); menu.add(_deleteContactAction); menu.add(_viewContactAction); } menu.addSeparator(); super.makeMenu(menu, instance); } } /** * Creates a new SyncDemo object */ public SyncDemo() { _model = new ContactTableModelAdapter(); // Create the view and the controller _view = new TableView(_model); final TableController controller = new TableController(_model, _view); controller.setFocusPolicy(TableController.ROW_FOCUS); _view.setController(controller); _view.setDataTemplateFocus(BackgroundFactory .createLinearGradientBackground(Color.LIGHTBLUE, Color.LIGHTBLUE, Color.BLUE, Color.BLUE)); final DataTemplate dataTemplate = new DataTemplate(_view, 1, 1) { public Field[] getDataFields(final int modelRowIndex) { final ContactData contact = (ContactData) _model.getRow(modelRowIndex); final Field[] fields = { new LabelField(contact.getFirst() + " " + contact.getLast(), Field.NON_FOCUSABLE) }; return fields; } }; dataTemplate.createRegion(new XYRect(0, 0, 1, 1)); dataTemplate.setColumnProperties(0, new TemplateColumnProperties( Display.getWidth())); dataTemplate.setRowProperties(0, new TemplateRowProperties(32)); _view.setDataTemplate(dataTemplate); dataTemplate.useFixedHeight(true); _addContactAction = new AddContactAction(); _viewContactAction = new ViewContactAction(); // Create a new screen for the application final SyncDemoScreen screen = new SyncDemoScreen(); screen.add(_view); // Push the screen onto the UI stack for rendering pushScreen(screen); } // SyncConverter methods // ---------------------------------------------------- /** * @see net.rim.device.api.synchronization.SyncConverter#convert(SyncObject,DataBuffer,int) */ public boolean convert(final SyncObject object, final DataBuffer buffer, final int version) { if (version == getSyncVersion()) { if (object instanceof ContactData) { final String first = ((ContactData) object).getFirst(); final String last = ((ContactData) object).getLast(); final String email = ((ContactData) object).getEmail(); // Write the contact information to the DataBuffer. ConverterUtilities.writeString(buffer, FIELDTAG_FIRST_NAME, first); ConverterUtilities .writeString(buffer, FIELDTAG_LAST_NAME, last); ConverterUtilities.writeString(buffer, FIELDTAG_EMAIL_ADDRESS, email); return true; } } return false; } /** * @see net.rim.device.api.synchronization.SyncConverter#convert(DataBuffer,int,int) */ public SyncObject convert(final DataBuffer data, final int version, final int UID) { final ContactData contact = new ContactData(UID); try { // Extract the contact information from the DataBuffer while (data.available() > 0) { if (ConverterUtilities.isType(data, FIELDTAG_FIRST_NAME)) { contact.setFirst(new String(ConverterUtilities .readByteArray(data)).trim()); } if (ConverterUtilities.isType(data, FIELDTAG_LAST_NAME)) { contact.setLast(new String(ConverterUtilities .readByteArray(data)).trim()); } if (ConverterUtilities.isType(data, FIELDTAG_EMAIL_ADDRESS)) { contact.setEmail(new String(ConverterUtilities .readByteArray(data)).trim()); } } return contact; } catch (final EOFException e) { System.err.println(e.toString()); } return null; } // SyncCollection methods // ---------------------------------------------------- /** * @see net.rim.device.api.synchronization.SyncCollection#addSyncObject(SyncObject) */ public boolean addSyncObject(final SyncObject object) { _model.addRow(object); return true; } /** * @see net.rim.device.api.synchronization.SyncCollection#updateSyncObject(SyncObject,SyncObject) */ public boolean updateSyncObject(final SyncObject oldObject, final SyncObject newObject) { return false; // NA } /** * @see net.rim.device.api.synchronization.SyncCollection#removeSyncObject(SyncObject) */ public boolean removeSyncObject(final SyncObject object) { return false; // NA } /** * @see net.rim.device.api.synchronization.SyncCollection#removeAllSyncObjects() */ public boolean removeAllSyncObjects() { return false; // NA } /** * @see net.rim.device.api.synchronization.SyncCollection#getSyncObjects() */ public SyncObject[] getSyncObjects() { final SyncObject[] contactArray = new SyncObject[_contacts.size()]; for (int i = _contacts.size() - 1; i >= 0; --i) { contactArray[i] = (SyncObject) _contacts.elementAt(i); } return contactArray; } /** * @see net.rim.device.api.synchronization.SyncCollection#getSyncObject(int) */ public SyncObject getSyncObject(final int uid) { for (int i = _contacts.size() - 1; i >= 0; --i) { final SyncObject so = (SyncObject) _contacts.elementAt(i); if (so.getUID() == uid) { return so; } } return null; } /** * @see net.rim.device.api.synchronization.SyncCollection#isSyncObjectDirty(SyncObject) */ public boolean isSyncObjectDirty(final SyncObject object) { return false; // NA } /** * @see net.rim.device.api.synchronization.SyncCollection#setSyncObjectDirty(SyncObject) */ public void setSyncObjectDirty(final SyncObject object) { // NA } /** * @see net.rim.device.api.synchronization.SyncCollection#clearSyncObjectDirty(SyncObject) */ public void clearSyncObjectDirty(final SyncObject object) { // NA } /** * @see net.rim.device.api.synchronization.SyncCollection#getSyncObjectCount() */ public int getSyncObjectCount() { _persist = PersistentStore.getPersistentObject(KEY); _contacts = (Vector) _persist.getContents(); return _contacts.size(); } /** * @see net.rim.device.api.synchronization.SyncCollection#getSyncVersion() */ public int getSyncVersion() { return 1; } /** * @see net.rim.device.api.synchronization.SyncCollection#getSyncName() */ public String getSyncName() { return "Contacts"; } /** * @see net.rim.device.api.synchronization.SyncCollection#getSyncName(Locale) */ public String getSyncName(final Locale locale) { return null; } /** * @see net.rim.device.api.synchronization.SyncCollection#getSyncConverter() */ public SyncConverter getSyncConverter() { return this; } /** * @see net.rim.device.api.synchronization.SyncCollection#beginTransaction() */ public void beginTransaction() { _persist = PersistentStore.getPersistentObject(KEY); _contacts = (Vector) _persist.getContents(); } /** * @see net.rim.device.api.synchronization.SyncCollection#endTransaction() */ public void endTransaction() { _persist.setContents(_contacts); _persist.commit(); } }