package org.bbssh.terminal.fonts;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import net.rim.device.api.io.FileNotFoundException;
import net.rim.device.api.system.UnsupportedOperationException;
import net.rim.device.api.ui.Font;
import org.bbssh.exceptions.FontNotFoundException;
import org.bbssh.io.ConfigLineReader;
import org.bbssh.model.FontSettings;
import org.bbssh.util.Tools;
import org.bbssh.util.Version;
/**
* Singleton that provides font management services to the client application.
*/
public class BBSSHFontManager {
private static BBSSHFontManager me;
private BitmapFontData[] bitmapFonts;
protected Font[] truetypeFonts;
protected String[] truetypeFontNames;
/**
* Constructor for BBSSHFontManager.
*/
public BBSSHFontManager() {
}
/**
* Load font data from index file.
*
* @throws FileNotFoundException
* @throws FontInitializationFailedException
*/
private void loadFontData() throws FileNotFoundException, FontInitializationFailedException {
InputStream stream = Tools.getResourceInputStream("font.idx");
ConfigLineReader reader = new ConfigLineReader(stream);
int idx = 0, count = 0;
try {
// First valid line
count = Integer.parseInt(reader.readNextLine());
bitmapFonts = new BitmapFontData[count];
// remaining lines each contains a 12-field font definition record
while (idx < count) {
bitmapFonts[idx++] = new BitmapFontData(reader.readNextLine());
}
// Next, truetype list. Even though we don't support truetype in prior to 5.0,
// we can still load the list of font info.
count = Integer.parseInt(reader.readNextLine());
idx = 0;
truetypeFonts = new Font[count];
truetypeFontNames = new String[count];
while (idx < count) {
truetypeFontNames[idx++] = reader.readNextLine();
}
stream.close();
} catch (EOFException eof) {
if (idx < count) {
throw new FontInitializationFailedException("Unexpected end of font definition file.");
}
} catch (IOException ioe) {
throw new FontInitializationFailedException("Unable to read font definition file.");
} catch (NumberFormatException nfe) {
throw new FontInitializationFailedException("Invalid format in font definition file.");
} catch (IllegalArgumentException iae) {
throw new FontInitializationFailedException("Font definition record " + idx
+ " contains incorrect number of fields.");
}
}
/**
* Retrieve instance of the font factory.
*
* @return font factory instance
* @throws UnsupportedOperationException if initialize() hasn't been invoked first.
*/
public static synchronized BBSSHFontManager getInstance() {
if (me == null) {
throw new UnsupportedOperationException();
}
return me;
}
/**
* Separate initailize allows us to more cleanly throw exceptions rather than someone having to worry about those
* exceptions every time they call getInstance. This will initialize our singleton with the correct instance of
* BBSSHFontManager based on current platform version.
*
* @throws FileNotFoundException if index file font.idx doesn't exist
* @throws FontInitializationFailedException if index file can't be read.
*/
public static synchronized void initialize() throws FileNotFoundException, FontInitializationFailedException {
Class cl = BBSSHFontManager.class;
me = (BBSSHFontManager) Version.createOSObjectInstance(cl.getName());
me.loadFontData();
}
/**
* Return the requested font. If unsupported on the current platform or if the requested font doesn't exist, then
* FontNotFoundException is thrown.
*
* @param request
* @return the requested font instance
* @throws FontNotFoundException
*/
public Font getTruetypeFont(FontSettings request) throws FontNotFoundException {
throw new FontNotFoundException();
}
/**
* Get the bitmap font that matches the requested font
*
* @param request
* @return requested bitmap font, if found
* @throws FontNotFoundException
*/
public BitmapFont getBitmapFont(FontSettings request) throws FontNotFoundException {
int id = request.getFontId();
if (id < 0 || id > bitmapFonts.length - 1) {
throw new FontNotFoundException();
}
return bitmapFonts[id].getFont(request.getFontSize());
}
// public Font getNativeFont(FontSettings request) {
// FontFamily.getFontFamilies();
// }
/**
* Get list of available custom truetype fonts
*
* @return array of fonts
*/
public Font[] getTTFonts() {
return truetypeFonts;
}
/**
* Return supported fonts.
*
* @return array of font data about supported bitmap fonts.
*/
public BitmapFontData[] getBitmapFonts() {
return bitmapFonts;
}
/**
* Return an appropriate FontRenderer based on the options provided
*
* @param settings font configuration options.
* @return font renderer instance
* @throws FontNotFoundException if the font could not be loaded
*/
public FontRenderer getRenderer(FontSettings settings) throws FontNotFoundException {
FontRenderer renderer = null;
if (settings.getFontType() == FontSettings.FONT_BITMAP) {
renderer = new BitmapFontRenderer(settings);
}
return renderer;
}
/**
* @return true if this platform version supports truetype fonts.
*/
public boolean areTruetypeFontsSupported() {
return false;
}
/**
* @return truetype font names
*/
public String[] getTTFontNames() {
return this.truetypeFontNames;
}
public BitmapFontData getBitmapFontData(int fontId) throws FontNotFoundException {
if (fontId < 0 || fontId > bitmapFonts.length - 1) {
throw new FontNotFoundException();
}
return bitmapFonts[fontId];
}
// @todo - okay this is a mess - we should be doing :
// FontData
// -> FontRecord
// -> BitmapFont
}