Create the user interface for the SUP101Sample application.
If you are viewing this guide as a PDF, you can locate the referenced document at http://infocenter.sybase.com/. Go to Sybase Unwired Platform 1.5.2 > Tutorial: BlackBerry Application Development using Custom Development to launch this PDF.
import java.util.Vector; import net.rim.device.api.system.Characters; import net.rim.device.api.ui.Graphics; import net.rim.device.api.ui.UiApplication; import net.rim.device.api.ui.XYRect; import net.rim.device.api.ui.component.BasicEditField; import net.rim.device.api.ui.component.KeywordFilterField; import SUP101.Customer; import SUP101.SUP101DB; import com.sybase.collections.ObjectList; /** * @author bdeng * * Customer sample main application. * * 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. */ public final class CustomerSample extends UiApplication { private KeywordFilterField _keywordFilterField; private CustomerList _customerList; private Vector _customers; // sync lock for synchronization private static Object _syncLock = new Object(); /** * Entry point for application. * * @param args * Command line arguments (not used). */ public static void main(String[] args) { // login to sync SUP101DB.loginToSync("supAdmin", "s3pAdmin"); // Create a new instance of the application CustomerSample app = new CustomerSample(); // Make the currently running thread the application's event // dispatch thread and begin processing events. app.enterEventDispatcher(); } /** * Constructor */ public CustomerSample() { // Create an instance of KeywordFilterField class. _keywordFilterField = new KeywordFilterField(); // Refresh the data refreshData(); // Add our list to a KeywordFilterField object. _keywordFilterField.setSourceList(_customerList, _customerList); // We're providing a customized edit field for // the KeywordFilterField. CustomKeywordField customSearchField = new CustomKeywordField(); _keywordFilterField.setKeywordField(customSearchField); // Create main screen. CustomerSampleScreen screen = new CustomerSampleScreen(this); // We need to explicitly add the search/title field via // MainScreen.setTitle(). screen.setTitle(_keywordFilterField.getKeywordField()); // Add our KeywordFilterField to the screen and push the screen // onto the stack. screen.add(_keywordFilterField); pushScreen(screen); } /** * Refreshes the data. */ public void refreshData() { // Populate vector with data. if ( _customers != null ) { _customers.removeAllElements(); _customers = null; } _customers = loadData(); // Create an instance of our SortedReadableList class. if ( _customerList == null ) { _customerList = new CustomerList(); } _customerList.loadFrom(_customers.elements()); } /** * Method to access the KeywordFilterField object. * * @return This applications KeywordFilterField. */ KeywordFilterField getKeywordFilterField() { return _keywordFilterField; } /** * Method populates and returns a vector of Customer objects containing data * read from data source. * * @return A vector containing Customer objects. */ private Vector loadData() { ObjectList customers = Customer.findAll(); Vector customerVec = new Vector(customers.size()); int size = customers.count(); for (int i = 0; i < size; i++) { customerVec.addElement(customers.elementAt(i)); } return customerVec; } /** * Returns the sync lock object * * @return Object */ public Object getSyncLock() { return _syncLock; } /** * Inner Class: A custom keyword input field for the KeywordFilterField. We * want to prevent a save dialog from being presented to the user when * exiting the application as the ability to persist data is not relevent to * this application. We are also using the paint() method to customize the * appearance of the cursor in the input field. */ final static class CustomKeywordField extends BasicEditField { // Contructor CustomKeywordField() { // Custom style. super(USE_ALL_WIDTH | NON_FOCUSABLE | NO_LEARNING | NO_NEWLINE); setLabel("Search: "); } /** * Intercepts ESCAPE key. * * @see net.rim.device.api.ui.component.TextField#keyChar(char,int,int) */ protected boolean keyChar(char ch, int status, int time) { switch (ch) { case Characters.ESCAPE: // Clear keyword. if ( super.getTextLength() > 0 ) { setText(""); return true; } } return super.keyChar(ch, status, time); } /** * Overriding super to add custom painting to our class. * * @see net.rim.device.api.ui.Field#paint(Graphics) */ protected void paint(Graphics graphics) { super.paint(graphics); // Draw caret. getFocusRect(new XYRect()); drawFocus(graphics, true); } } }
import net.rim.device.api.collection.util.SortedReadableList; import net.rim.device.api.ui.component.KeywordProvider; import net.rim.device.api.util.Comparator; import net.rim.device.api.util.StringUtilities; import SUP101.Customer; public class CustomerList extends SortedReadableList implements KeywordProvider { /** * Creates a customer list based on a Vector of customers. */ public CustomerList() { super(new CustomerListComparator()); } /** * @see net.rim.device.api.ui.component.KeywordProvider#getKeywords(Object * element) */ public String[] getKeywords(Object element) { if ( element instanceof Customer ) { Customer customer = (Customer) element; return StringUtilities.stringToWords(customer.getFname() + " " + customer.getLname()); } return null; } /** * A Comparator class used for sorting our Customer objects by name. */ final static class CustomerListComparator implements Comparator { /** * Compares two customers by comparing their names' in alphabetical * order. * * @see net.rim.device.api.util.Comparator#compare(Object, Object) */ public int compare(Object o1, Object o2) { if ( o1 == null || o2 == null ) throw new IllegalArgumentException("Cannot compare null customers"); return o1.toString().compareTo(o2.toString()); } } }
import net.rim.device.api.system.Characters; import net.rim.device.api.ui.Field; import net.rim.device.api.ui.Font; import net.rim.device.api.ui.Graphics; import net.rim.device.api.ui.MenuItem; import net.rim.device.api.ui.UiApplication; import net.rim.device.api.ui.component.BasicEditField; import net.rim.device.api.ui.component.ButtonField; import net.rim.device.api.ui.component.GaugeField; import net.rim.device.api.ui.component.KeywordFilterField; import net.rim.device.api.ui.container.HorizontalFieldManager; import net.rim.device.api.ui.container.MainScreen; import SUP101.Customer; import SUP101.SUP101DB; import com.sybase.persistence.ObjectSyncStatusData; import com.sybase.persistence.SyncStatusListener; import com.sybase.persistence.SyncStatusState; /** * @author bdeng * * This class represents the main screen for the Customer Sample application. * * 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. */ public final class CustomerSampleScreen extends MainScreen implements SyncStatusListener { private CustomerSample _app; private KeywordFilterField _keywordFilterField; // last sync status private int _lastSyncState = -1; // synchronization indicator private GaugeField _syncProgressField; // if a synchronization is happening so that we display an indicator private boolean _isSynchronizing; // whether there are pending changes private boolean _changed; /** * Creates a new CustomerSampleScreen. * * @param app * The UiApplication creating an instance of this class. */ public CustomerSampleScreen(CustomerSample app) { // A reference to the UiApplication instance for use in this class. _app = app; // We need a reference to the UiApplication's KeywordFilterField. _keywordFilterField = _app.getKeywordFilterField(); // Add menu item to the screen's menu. addMenuItem(syncItem); if ( !SUP101DB.isSynchronized("default") ) { synchronize(); } } /** * Intercepts the ENTER key and displays info screen. * * @see net.rim.device.api.ui.Screen#keyChar(char,int,int) */ protected boolean keyChar(char key, int status, int time) { if ( key == Characters.ENTER ) { displayInfoScreen(); return true; // We've consumed the event. } return super.keyChar(key, status, time); } /** * Handles a trackball click. * * @see net.rim.device.api.ui.Screen#invokeAction(int) */ public boolean invokeAction(int action) { switch (action) { case ACTION_INVOKE: // Trackball click. displayInfoScreen(); return true; // We've consumed the event. } return super.invokeAction(action); } /** * Creates an InfoScreen instance and pushes it onto the stack for * rendering. */ private void displayInfoScreen() { // Retrieve the selected Customer and use it to invoke a new InfoScreen. Customer customer = (Customer) _keywordFilterField.getSelectedElement(); if ( customer != null ) { InfoScreen infoScreen = new InfoScreen(this, customer); _app.pushScreen(infoScreen); } } /** * Prevent the save dialog from being displayed. * * @see net.rim.device.api.ui.container.MainScreen#onSavePrompt() */ public boolean onSavePrompt() { return true; } // Inner classes------------------------------------------------------------ /** * Synchronizes the mbos */ private final MenuItem syncItem = new MenuItem("Synchronize", 0, 0) { public void run() { synchronize(); } }; /** * A MainScreen class to display/update secondary information for a selected * customer. */ private final static class InfoScreen extends MainScreen { private CustomerSampleScreen _sampleScreen; private Customer _customer; private BasicEditField _fnameField; private BasicEditField _lnameField; private BasicEditField _companyField; private BasicEditField _addressField; private BasicEditField _stateField; private BasicEditField _cityField; private BasicEditField _phoneField; private BasicEditField _zipField; /** * Constructs a screen to display * * @param customer * The customer to display secondary information about */ InfoScreen(CustomerSampleScreen sampleScreen, Customer customer) { _sampleScreen = sampleScreen; _customer = customer; // Set up and display UI elements. setTitle("Update Customer"); _fnameField = new BasicEditField("First name: ", customer.getFname(), BasicEditField.DEFAULT_MAXCHARS, Field.FOCUSABLE); _lnameField = new BasicEditField("Last name: ", customer.getLname(), BasicEditField.DEFAULT_MAXCHARS, Field.FOCUSABLE); _companyField = new BasicEditField("Company: ", customer.getCompany_name(), BasicEditField.DEFAULT_MAXCHARS, Field.FOCUSABLE); _addressField = new BasicEditField("Address: ", customer.getAddress(), BasicEditField.DEFAULT_MAXCHARS, Field.FOCUSABLE); _stateField = new BasicEditField("State: ", customer.getState(), BasicEditField.DEFAULT_MAXCHARS, Field.FOCUSABLE); _cityField = new BasicEditField("City: ", customer.getCity(), BasicEditField.DEFAULT_MAXCHARS, Field.FOCUSABLE); _phoneField = new BasicEditField("Phone: ", customer.getPhone(), BasicEditField.DEFAULT_MAXCHARS, Field.FOCUSABLE); _zipField = new BasicEditField("Zip: ", customer.getZip(), BasicEditField.DEFAULT_MAXCHARS, Field.FOCUSABLE); add(_fnameField); add(_lnameField); add(_companyField); add(_addressField); add(_stateField); add(_cityField); add(_phoneField); add(_zipField); HorizontalFieldManager hfm = new HorizontalFieldManager(Field.FIELD_HCENTER); ButtonField submitButton = new ButtonField("submit", Field.FIELD_RIGHT) { protected boolean navigationClick(int status, int time) { submit(); return true; } }; ButtonField cancelButton = new ButtonField("cancel", Field.FIELD_LEFT) { protected boolean navigationClick(int status, int time) { close(); return true; } }; hfm.add(submitButton); hfm.add(cancelButton); add(hfm); } protected void submit() { _customer.setFname(_fnameField.getText().trim()); _customer.setLname(_lnameField.getText().trim()); _customer.setCompany_name(_companyField.getText().trim()); _customer.setAddress(_addressField.getText().trim()); _customer.setState(_stateField.getText().trim()); _customer.setCity(_cityField.getText().trim()); _customer.setPhone(_phoneField.getText().trim()); _customer.setZip(_zipField.getText().trim()); _customer.save(); _sampleScreen._changed = true; _sampleScreen._keywordFilterField.updateList(); close(); } } // synchronizes the mbo private void synchronize() { Runnable runnable = new Runnable() { public void run() { synchronized (_app.getSyncLock()) { setSynchronizing(true); try { if ( _changed ) { _changed = false; SUP101DB.submitPendingOperations(); } SUP101DB.synchronize(CustomerSampleScreen.this); } catch (Exception e) { } finally { setSynchronizing(false); } } } }; new Thread(runnable).start(); } /** * Sets sync indicator and updates the sync status message. * * @param isSynchronizing whether synchronization is happending */ public void setSynchronizing(boolean isSynchronizing) { this._isSynchronizing = isSynchronizing; if ( this._isSynchronizing ) { _syncProgressField = new GaugeField("", SyncStatusState.SYNC_STARTING, SyncStatusState.SYNC_DONE, 0, GaugeField.NO_TEXT | GaugeField.LABEL_AS_PROGRESS) { protected void paint(Graphics g) { super.paint(g); int indicatorHeigth = 20; int fontSize = 12; int y = getHeight() - indicatorHeigth; // setting up font style Font f = Font.getDefault().derive(Font.PLAIN, fontSize); g.setFont(f); g.setColor(0x00000000); g.setDrawingStyle(Graphics.DRAWSTYLE_AALINES, true); // paint the synchronizing indicator as it can't be // displayed in the progress bar using // LABEL_AS_PROGRESS style g.drawText(getLabel(), 1, y + (indicatorHeigth - fontSize) / 2); g.setColor(0x00BEBEBE); g.drawRect(0, 0, getWidth(), getHeight()); } }; _app.invokeLater(new Runnable() { public void run() { setStatus(_syncProgressField); } }); } else { _app.invokeLater(new Runnable() { public void run() { _syncProgressField = null; setStatus(null); } }); _app.refreshData(); } } /** * Called when there is information to report about the status of a * synchronization that is taking place. * * @param data * A {@link ObjectSyncStatusData} object that contains * information about the status of the running synchronization. * @return Return true to cancel the synchronization or false to continue. */ public boolean objectSyncStatus(ObjectSyncStatusData data) { if ( !_isSynchronizing ) { return false; } final int syncState = data.getSyncStatusState(); if ( _lastSyncState != syncState ) { _lastSyncState = syncState; String syncMsg = null; if ( syncState == SyncStatusState.SYNC_STARTING ) { syncMsg = "Connecting..."; } else if ( syncState == SyncStatusState.APPLICATION_DATA_UPLOADING ) { syncMsg = "Metadata Uploading..."; } else if ( syncState == SyncStatusState.APPLICATION_DATA_DOWNLOADING ) { syncMsg = "Metadata Downloading..."; } else if ( syncState == SyncStatusState.SYNC_DONE ) { syncMsg = "Completed!"; } if ( syncMsg != null ) { final StringBuffer strLabel = new StringBuffer(256); strLabel.append("Retrieving synchronization group:").append("default").append(" - ").append(syncMsg); UiApplication.getUiApplication().invokeLater(new Runnable() { public void run() { _syncProgressField.setValue(syncState); _syncProgressField.setLabel(strLabel.toString()); } }); } } return false; } }