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;
}
}