LandmarkEditorUI 繼承 Form,實作 CommandListener,提供地標的新增、修改、刪除與列表選擇功能。支援兩種模式:MODE_UPDATE(編輯既有)與 MODE_ADDNEW(新增)。
class LandmarkEditorUI extends Form implements CommandListener {
// 必填欄位標示 (*)
private TextField nameField = new TextField("Name (*):", "", 20, TextField.ANY);
private TextField descField = new TextField("Description (*):", "", 40, TextField.ANY);
private TextField countryField = new TextField("Country:", "", 20, TextField.ANY);
private TextField stateField = new TextField("State:", "", 20, TextField.ANY);
private TextField cityField = new TextField("City:", "", 20, TextField.ANY);
private TextField streetField = new TextField("Street:", "", 20, TextField.ANY);
private TextField buildingNameField = new TextField("Building name (*):", "", 20, TextField.ANY);
// 座標顯示 (唯讀)
private StringItem lat = new StringItem("Lat:", "");
private StringItem lon = new StringItem("Lon:", "");
private StringItem alt = new StringItem("Alt:", "");
// 地標選擇清單
private List list = new List("Landmarks:", List.EXCLUSIVE);
// 命令
private Command saveNewCmd = new Command("Save", Command.OK, 1);
private Command saveUpdatedCmd = new Command("Save", Command.OK, 1);
private Command updateCmd = new Command("Update", Command.OK, 1);
private Command removeCmd = new Command("Remove", Command.OK, 1);
private Command listCmd = new Command("List", Command.OK, 1);
private Command routeCmd = new Command("Route", Command.BACK, 1);
public static final int MODE_UPDATE = 0;
public static final int MODE_ADDNEW = 1;
private QualifiedCoordinates coord = null;
private Displayable route = null;
private TouristData data = null;
// ...
public LandmarkEditorUI(Displayable route, TouristData data) {
super("Landmark Editor");
this.route = route;
this.data = data;
addCommand(routeCmd);
addCommand(listCmd);
setCommandListener(this);
list.addCommand(routeCmd);
list.setCommandListener(this);
}
依模式初始化欄位、切換可用命令:
public void showEditor(QualifiedCoordinates newCoord, int mode) {
this.coord = newCoord;
lat.setText(Utils.formatDouble(newCoord.getLatitude(), 3));
lon.setText(Utils.formatDouble(newCoord.getLongitude(), 3));
alt.setText(Utils.formatDouble(newCoord.getAltitude(), 1));
// 清空可編輯欄位
nameField.setString(""); descField.setString("");
countryField.setString(""); stateField.setString("");
cityField.setString(""); streetField.setString("");
buildingNameField.setString("");
deleteAll();
append(nameField); append(descField);
append(countryField); append(stateField);
append(cityField); append(streetField);
append(buildingNameField);
append(lat); append(lon); append(alt);
if (mode == MODE_UPDATE) {
// 載入既有地標資料
Landmark lm = ControlPoints.getInstance().findNearestLandMark(newCoord);
if (lm != null) {
nameField.setString(lm.getName());
descField.setString(lm.getDescription());
AddressInfo info = lm.getAddressInfo();
if (info != null) {
countryField.setString(info.getField(AddressInfo.COUNTRY));
stateField.setString(info.getField(AddressInfo.STATE));
cityField.setString(info.getField(AddressInfo.CITY));
streetField.setString(info.getField(AddressInfo.STREET));
buildingNameField.setString(info.getField(AddressInfo.BUILDING_NAME));
}
}
removeCommand(updateCmd); removeCommand(saveNewCmd);
addCommand(saveUpdatedCmd); addCommand(listCmd);
} else if (mode == MODE_ADDNEW) {
removeCommand(updateCmd); removeCommand(saveUpdatedCmd);
addCommand(saveNewCmd); addCommand(listCmd);
}
TouristMIDlet.getDisplay().setCurrent(this);
}
public void showList() {
list.deleteAll();
Enumeration landmarks = ControlPoints.getInstance().getLandMarks();
if (landmarks != null) {
while (landmarks.hasMoreElements()) {
Landmark lm = (Landmark) landmarks.nextElement();
list.append(lm.getName(), null);
}
list.addCommand(updateCmd); list.addCommand(removeCmd);
} else {
list.removeCommand(updateCmd); list.removeCommand(removeCmd);
}
TouristMIDlet.getDisplay().setCurrent(list);
}
private String checkRequiredFields() {
if (nameField.getString().equals("")) return "Name";
else if (descField.getString().equals("")) return "Description";
else if (buildingNameField.getString().equals("")) return "Building name";
return null;
}
private Landmark generateLandmark() {
String field = checkRequiredFields();
if (field != null) {
Alert alert = new Alert("Error", "Value for required field " + field + " is missing.", null, AlertType.ERROR);
alert.setTimeout(3000);
TouristMIDlet.getDisplay().setCurrent(alert, this);
return null;
}
AddressInfo info = new AddressInfo();
info.setField(AddressInfo.COUNTRY, countryField.getString());
info.setField(AddressInfo.STATE, stateField.getString());
info.setField(AddressInfo.CITY, cityField.getString());
info.setField(AddressInfo.STREET, streetField.getString());
info.setField(AddressInfo.BUILDING_NAME, buildingNameField.getString());
return new Landmark(nameField.getString(), descField.getString(), coord, info);
}
public void commandAction(Command command, Displayable displayable) {
Landmark landmark = null;
if (command == saveNewCmd) { // 新增
landmark = generateLandmark();
if (landmark != null) {
try {
ControlPoints.getInstance().addLandmark(landmark);
data.createProximityListener(coord);
} catch (IOException e) { showError("I/O Error during add Operation"); }
showList();
}
} else if (command == saveUpdatedCmd) { // 更新
landmark = generateLandmark();
if (landmark != null) {
try {
ControlPoints.getInstance().updateLandmark(landmark);
data.createProximityListener(coord);
} catch (IOException e) { showError("I/O Error during update Operation"); }
catch (LandmarkException e) { showError("Can not find landmark from store"); }
showList();
}
} else if (command == routeCmd) { // 返回
TouristMIDlet.getDisplay().setCurrent(route);
} else if (command == updateCmd) { // 編輯選取項
int index = list.getSelectedIndex();
landmark = ControlPoints.getInstance().findLandmark(index);
showEditor(landmark.getQualifiedCoordinates(), MODE_UPDATE);
} else if (command == removeCmd) { // 刪除
try {
int index = list.getSelectedIndex();
landmark = ControlPoints.getInstance().findLandmark(index);
ControlPoints.getInstance().removeLandmark(landmark);
showInfo("Landmark removed successfully.");
} catch (IOException e) { showError("I/O Error during Operation"); }
catch (LandmarkException le) { showError("Landmark not found in store"); }
showList();
} else if (command == listCmd) { // 顯示列表
showList();
}
}
private void showError(String msg) {
Alert alert = new Alert("Error", msg, null, AlertType.ERROR);
alert.setTimeout(3000);
TouristMIDlet.getDisplay().setCurrent(alert);
}
private void showInfo(String msg) {
Alert alert = new Alert("Information", msg, null, AlertType.INFO);
alert.setTimeout(3000);
TouristMIDlet.getDisplay().setCurrent(alert);
}
}
架構優勢: 將地標 CRUD 操作集中於 ControlPoints,UI 僅負責呈現與使用者互動,新增地標後同步呼叫 TouristData.createProximityListener() 註冊鄰近偵測,確保資料與偵測邏輯一致。