package org.bbssh.ui.components;
import java.io.IOException;
import net.rim.device.api.i18n.ResourceBundle;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.component.BasicEditField;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.component.ObjectChoiceField;
import net.rim.device.api.ui.container.PopupScreen;
import net.rim.device.api.ui.container.VerticalFieldManager;
import org.bbssh.exceptions.FontNotFoundException;
import org.bbssh.i18n.BBSSHResource;
import org.bbssh.model.FontSettings;
import org.bbssh.terminal.fonts.BBSSHFontManager;
import org.bbssh.terminal.fonts.BitmapFontData;
import org.bbssh.terminal.fonts.FontRenderer;
import org.bbssh.ui.screens.TerminalScreen;
import org.bbssh.util.Logger;
public class FontPicker extends PopupScreen implements BBSSHResource, FieldChangeListener {
ResourceBundle res = ResourceBundle.getBundle(BUNDLE_ID, BUNDLE_NAME);
private BitmapFontData[] bitmapFontChoices;
private String[] truetypeFontChoices;
private ObjectChoiceField fontFaceList;
private BasicEditField fontSizeField;
private ObjectChoiceField fontSizeList;
private ObjectChoiceField fontTypeList;
private FontDisplayField fontDisplay;
FontSettings originalFS;
/** Index of the font size field which we will potentially replace */
private int fontSizeFieldPosition;
private boolean closedThroughButtons;
OKCancelControl okCancel = new OKCancelControl();
FontSettings fs;
TerminalScreen screen;
private ButtonField updatePreview;
public FontPicker(FontSettings fs) {
super(new VerticalFieldManager(VERTICAL_SCROLL | VERTICAL_SCROLLBAR), DEFAULT_CLOSE);
this.fs = fs;
bitmapFontChoices = BBSSHFontManager.getInstance().getBitmapFonts();
okCancel.setChangeListener(this);
updatePreview = new ClickableButtonField(res.getString(SESSION_DTL_LBL_FONT_REFRESH));
updatePreview.setChangeListener(this);
this.fs = new FontSettings(fs);
this.originalFS = fs;
setupFontFields();
addFontFields();
add(okCancel);
if (fontTypeList.getSelectedIndex() == FontSettings.FONT_TT) {
insert(updatePreview, okCancel.getIndex() - 1);
}
this.fs = new FontSettings(fs);
// Now that everything is in place- set using the original values , b/c
// the member may have been updated as a result of changelistener activity during our setup.
setFontFaceSelection(originalFS.getFontId());
setFontSize(originalFS.getFontSize());
if (fontDisplay != null) {
add(fontDisplay);
}
}
private void addFontFields() {
add(fontTypeList);
add(fontFaceList);
if (fs.getFontType() == FontSettings.FONT_BITMAP) {
add(fontSizeList);
fontSizeFieldPosition = fontSizeList.getIndex();
} else {
add(fontSizeField);
fontSizeFieldPosition = fontSizeField.getIndex();
}
handleFontTypeChange();
}
/**
* When font type selection is changed, we need to reset font face name lists, and provide appropriate default
* values for font face selection and font size based on the font type.
*
* This method will also swap in the correct font size field: pick list for bitmap, or numeric freeform text for
* TTF.
*/
private void handleFontTypeChange() {
// If font type changes, reset values to default for the new type.
Field insField = null;
Field removeField = null;
int type = fontTypeList.getSelectedIndex();
if (type == FontSettings.FONT_BITMAP) {
fontFaceList.setChoices(bitmapFontChoices);
insField = fontSizeList;
removeField = fontSizeField;
} else {
fontFaceList.setChoices(truetypeFontChoices);
insField = fontSizeField;
removeField = fontSizeList;
}
fontFaceList.setSelectedIndex(0);
if (removeField.getManager() != null) {
delete(removeField);
}
if (insField.getManager() == null) {
insert(insField, fontSizeFieldPosition);
}
if (type == FontSettings.FONT_BITMAP) {
if (updatePreview.getManager() != null) {
delete(updatePreview);
}
} else {
if (okCancel.getManager() != null) {
insert(updatePreview, okCancel.getIndex() - 1);
}
}
}
private void setupFontFields() {
String[] typeChoices;
if (BBSSHFontManager.getInstance().areTruetypeFontsSupported()) {
typeChoices = res.getStringArray(SESSION_DTL_LIST_FONT_TYPE_CHOICES);
} else {
typeChoices = new String[] { res.getString(SESSION_DTL_VALUE_FONT_BITMAP) };
// if we ever restore settings to a platform that doesn't support TT
// then set up some defaults to prevent errors.
if (fs.getFontType() == FontSettings.FONT_TT) {
fs.setFontType(FontSettings.FONT_BITMAP);
fs.setFontId((byte) 0);
fs.setFontSize(FontSettings.DEFAULT_BITMAP_FONT_SIZE);
}
}
bitmapFontChoices = BBSSHFontManager.getInstance().getBitmapFonts();
truetypeFontChoices = BBSSHFontManager.getInstance().getTTFontNames();
fontTypeList = new ObjectChoiceField(res.getString(SESSION_DTL_LBL_FONT_TYPE), typeChoices, fs
.getFontType());
fontFaceList = new ObjectChoiceField(res.getString(SESSION_DTL_LBL_FONT_NAME), bitmapFontChoices, 0);
fontSizeList = new ObjectChoiceField(res.getString(SESSION_DTL_LBL_FONT_SIZE), null, 0);
fontSizeField = new BasicEditField(res.getString(SESSION_DTL_LBL_FONT_SIZE), "16", 2,
BasicEditField.FILTER_INTEGER | EditField.NO_NEWLINE);
// Not sure how or why, but for some reason the listener is defaulting to this class... as unlikely as that
// sounds.
if (fs.getFontType() == FontSettings.FONT_BITMAP) {
populateFontSizeList(fs.getFontId(), false);
// fontSizeList.setSelectedIndex(fs.getFontSize());
}
try {
fontDisplay = new FontDisplayField(BBSSHFontManager.getInstance().getRenderer(fs));
} catch (FontNotFoundException e) {
Logger.error("FontNotFoundException in FontPicker.setupFontFields [ " + e.getMessage() + " ] ");
}
fontTypeList.setChangeListener(this);
fontFaceList.setChangeListener(this);
}
private void populateFontSizeList(int fontId, boolean setListener) {
try {
fontSizeList.setChangeListener(null);
fontSizeList.setChoices(BBSSHFontManager.getInstance().getBitmapFontData(fontId).getFontRecords());
if (setListener)
fontSizeList.setChangeListener(this);
} catch (FontNotFoundException e) {
// This should not occur - we'll just log it for now; and if instances occur in the wild we'll look further.
Logger.error("FontNotFoundException in FontPicker.populateFontSizeList [ " + e.getMessage() + " ] ");
}
}
private void updateFontSettings() {
fs.setFontType((byte) fontTypeList.getSelectedIndex());
fs.setFontId((byte) fontFaceList.getSelectedIndex());
if (fs.getFontType() == FontSettings.FONT_BITMAP) {
fs.setFontSize((byte) fontSizeList.getSelectedIndex());
} else {
fs.setFontSize((byte) Integer.parseInt(fontSizeField.getText()));
}
}
public void save() throws IOException {
updateFontSettings();
super.save();
}
public void fieldChanged(Field field, int context) {
if (field == okCancel) {
closedThroughButtons = true;
if (context == OKCancelControl.CONTEXT_CANCEL_PRESS) {
fs = null;
} else {
if (isDataValid()) {
try {
save();
} catch (IOException e) {
}
} else {
return;
}
}
close();
} else if (field == fontTypeList) {
handleFontTypeChange();
setFontFaceSelection((byte) 0);
setFontSize(-1);
refreshPreview();
} else if (field == fontFaceList) {
populateFontSizeList(fontFaceList.getSelectedIndex(), true);
refreshPreview();
} else if (field == fontSizeList) {
refreshPreview();
} else if (field == updatePreview) {
refreshPreview();
}
}
private void refreshPreview() {
updateFontSettings();
try {
FontRenderer fr = BBSSHFontManager.getInstance().getRenderer(fs);
if (fontDisplay == null) {
fontDisplay = new FontDisplayField(fr);
insert(fontDisplay, fontSizeFieldPosition + 1);
} else {
fontDisplay.setRenderer(fr);
}
} catch (FontNotFoundException e) {
Logger.error("FontNotFoundException in FontPicker.refreshPreview [ " + e.getMessage() + " ] ");
return;
}
}
/**
* Sets currently displayed font size field to the specified value. If the value is out of range, it will substitute
* with an appropriate default.
*
* @param size font size to change the field value to.
*/
private void setFontSize(int size) {
if (fontSizeField.getManager() == null) {
try {
if (!BBSSHFontManager.getInstance().getBitmapFontData(fontFaceList.getSelectedIndex()).isFontSizeValid(
(byte) size)) {
size = FontSettings.DEFAULT_BITMAP_FONT_SIZE;
}
} catch (FontNotFoundException e) {
// @todo Again, this shouldn't occur here. we'll need to clean this up.
Logger.error("FontNotFoundException in FontPicker.setFontSize [ " + e.getMessage() + " ] ");
}
try {
fontSizeList.setSelectedIndex(size);
} catch (IllegalArgumentException e) {
Logger.error("Unexpected error - font size idx " + size + " not in list!");
fontSizeList.setSelectedIndex(FontSettings.DEFAULT_BITMAP_FONT_SIZE);
}
} else {
if (size < 3 || size > 99) {
size = FontSettings.DEFAULT_TRUETYPE_FONT_SIZE;
}
fontSizeField.setText(Integer.toString(size));
}
}
public boolean isDataValid() {
if (fontTypeList.getSelectedIndex() == FontSettings.FONT_TT) {
// Should not be possible, as we're now not presenting the option;
// still if someone preserves settings across a device change,
// odd things can happen...
if (!BBSSHFontManager.getInstance().areTruetypeFontsSupported()) {
Dialog.alert(res.getString(SESSION_DTL_MSG_NO_TRUETYPE));
fontTypeList.setFocus();
return false;
}
}
return true;
}
private void setFontFaceSelection(byte fontId) {
if (fontTypeList.getSelectedIndex() == FontSettings.FONT_BITMAP) {
if (fontId < 0 || fontId >= bitmapFontChoices.length) {
fontId = 0;
}
} else {
if (fontId < 0 || fontId >= truetypeFontChoices.length) {
fontId = 0;
}
}
fontFaceList.setSelectedIndex(fontId);
}
public FontSettings getUpdatedFontSettings() {
if (originalFS.equals(fs)) {
return null;
}
return fs;
}
public void close() {
if (!closedThroughButtons)
fs = null;
super.close();
}
}