This section provides the source code for the ImageViewer MIDlet. For the complete Eclipse project ZIP file, see Forum Nokia.
The example includes the following classes:
import javax.microedition.lcdui.*; import javax.microedition.midlet.*; // Main class which inits the connection and create the screens public class ImageViewerMIDlet extends MIDlet { private final Image logo; private final ImageCanvas imageCanvas; private FileSelector fileSelector; private final InputScreen inputScreen; private int operationCode = -1; public ImageViewerMIDlet() { // init basic parameters logo = makeImage("/logo.png"); ErrorScreen.init(logo, Display.getDisplay(this)); imageCanvas = new ImageCanvas(this); fileSelector = new FileSelector(this); inputScreen = new InputScreen(this); } public void startApp() { Displayable current = Display.getDisplay(this).getCurrent(); if (current == null) { // Checks whether the API is available boolean isAPIAvailable = System.getProperty( "microedition.io.file.FileConnection.version") != null; // shows splash screen String text = getAppProperty("MIDlet-Name") + "\n" + getAppProperty("MIDlet-Vendor")+ System.getProperty("fileconn.dir.photos"); if (!isAPIAvailable) { text += "\nFile Connection API is not available"; } Alert splashScreen = new Alert(null, text, logo, AlertType.INFO); if (isAPIAvailable) { splashScreen.setTimeout(30); Display.getDisplay(this).setCurrent( splashScreen, fileSelector); } else { Display.getDisplay(this).setCurrent(splashScreen); } } else { Display.getDisplay(this).setCurrent(current); } } public void pauseApp() { } public void destroyApp(boolean unconditional) { // stop the commands queue thread fileSelector.stop(); notifyDestroyed(); } void fileSelectorExit() { destroyApp(false); } void cancelInput() { Display.getDisplay(this).setCurrent(fileSelector); } void input(String input) { fileSelector.inputReceived(input, operationCode); Display.getDisplay(this).setCurrent(fileSelector); } void displayImage(String imageName) { imageCanvas.displayImage(imageName); Display.getDisplay(this).setCurrent(imageCanvas); } void displayFileBrowser() { Display.getDisplay(this).setCurrent(fileSelector); } void showError(Exception e) { ErrorScreen.showError(e.getMessage(), fileSelector); } void showMsg(String text) { Alert infoScreen = new Alert(null, text, logo, AlertType.INFO); infoScreen.setTimeout(3000); Display.getDisplay(this).setCurrent(infoScreen, fileSelector); } void requestInput(String text, String label, int operationCode) { inputScreen.setQuestion(text, label); this.operationCode = operationCode; Display.getDisplay(this).setCurrent(inputScreen); } // loads a given image by name static Image makeImage(String filename) { Image image = null; try { image = Image.createImage(filename); } catch (Exception e) { // use a null image instead } return image; } }
import java.io.*; import java.util.*; import javax.microedition.io.*; import javax.microedition.io.file.*; import javax.microedition.lcdui.*; // Simple file selector class. // It naviagtes the file system and shows images currently available class FileSelector extends List implements CommandListener, FileSystemListener { private final static Image ROOT_IMAGE = ImageViewerMIDlet.makeImage("/root.png"); private final static Image FOLDER_IMAGE = ImageViewerMIDlet.makeImage("/folder.png"); private final static Image FILE_IMAGE = ImageViewerMIDlet.makeImage("/file.png"); private final OperationsQueue queue = new OperationsQueue(); private final static String FILE_SEPARATOR = (System.getProperty("file.separator")!=null)? System.getProperty("file.separator"): "/"; private final static String UPPER_DIR = ".."; private final ImageViewerMIDlet midlet; private final Command openCommand = new Command("Open", Command.ITEM, 1); private final Command createDirCommand = new Command("Create new directory", Command.ITEM, 2); private final Command deleteCommand = new Command("Delete", Command.ITEM, 3); private final Command renameCommand = new Command("Rename", Command.ITEM, 4); private final Command exitCommand = new Command("Exit", Command.EXIT, 1); private final static int RENAME_OP = 0; private final static int MKDIR_OP = 1; private final static int INIT_OP = 2; private final static int OPEN_OP = 3; private final static int DELETE_OP = 4; private Vector rootsList = new Vector(); // Stores the current root, if null we are showing all the roots private FileConnection currentRoot = null; FileSelector(ImageViewerMIDlet midlet) { super("Image Viewer", List.IMPLICIT); this.midlet = midlet; addCommand(openCommand); addCommand(createDirCommand); addCommand(deleteCommand); addCommand(renameCommand); addCommand(exitCommand); setSelectCommand(openCommand); setCommandListener(this); queue.enqueueOperation(new ImageViewerOperations(INIT_OP)); FileSystemRegistry.addFileSystemListener(FileSelector.this); } void stop() { queue.abort(); FileSystemRegistry.removeFileSystemListener(this); } void inputReceived(String input, int code) { switch (code) { case RENAME_OP: queue.enqueueOperation(new ImageViewerOperations( input, RENAME_OP)); break; case MKDIR_OP: queue.enqueueOperation(new ImageViewerOperations( input, MKDIR_OP)); break; } } public void commandAction(Command c, Displayable d) { if (c == openCommand) { queue.enqueueOperation(new ImageViewerOperations(OPEN_OP)); } else if (c == renameCommand) { queue.enqueueOperation(new ImageViewerOperations(RENAME_OP)); } else if (c == deleteCommand) { queue.enqueueOperation(new ImageViewerOperations(DELETE_OP)); } else if (c == createDirCommand) { queue.enqueueOperation(new ImageViewerOperations(MKDIR_OP)); } else if (c == exitCommand) { midlet.fileSelectorExit(); } } // Listen for changes in the roots public void rootChanged(int state, String rootName) { queue.enqueueOperation(new ImageViewerOperations(INIT_OP)); } private void displayAllRoots() { setTitle("Image Viewer - [Roots]"); deleteAll(); Enumeration roots = rootsList.elements(); while (roots.hasMoreElements()) { String root = (String) roots.nextElement(); append(root.substring(1), ROOT_IMAGE); } currentRoot = null; } private void createNewDir() { if (currentRoot == null) { midlet.showMsg("Is not possible to create a new root"); } else { midlet.requestInput("New dir name", "", MKDIR_OP); } } private void createNewDir(String newDirURL) { if (currentRoot != null) { try { FileConnection newDir = (FileConnection) Connector.open( currentRoot.getURL() + newDirURL, Connector.WRITE); newDir.mkdir(); } catch (IOException e) { midlet.showError(e); } displayCurrentRoot(); } } private void loadRoots() { if (!rootsList.isEmpty()) { rootsList.removeAllElements(); } try { Enumeration roots = FileSystemRegistry.listRoots(); while (roots.hasMoreElements()) { rootsList.addElement(FILE_SEPARATOR + (String) roots.nextElement()); } } catch (Throwable e) { midlet.showMsg(e.getMessage()); } } private void deleteCurrent() { if (currentRoot == null) { midlet.showMsg("Is not possible to delete a root"); } else { int selectedIndex = getSelectedIndex(); if (selectedIndex >= 0) { String selectedFile = getString(selectedIndex); if (selectedFile.equals(UPPER_DIR)) { midlet.showMsg("Is not possible to delete an upper dir"); } else { try { FileConnection fileToDelete = (FileConnection) Connector.open( currentRoot.getURL() + selectedFile, Connector.WRITE); if (fileToDelete.exists()) { fileToDelete.delete(); } else { midlet.showMsg("File " + fileToDelete.getName() + " does not exists"); } } catch (IOException e) { midlet.showError(e); } catch (SecurityException e) { midlet.showError(e); } displayCurrentRoot(); } } } } private void renameCurrent() { if (currentRoot == null) { midlet.showMsg("Is not possible to rename a root"); } else { int selectedIndex = getSelectedIndex(); if (selectedIndex >= 0) { String selectedFile = getString(selectedIndex); if (selectedFile.equals(UPPER_DIR)) { midlet.showMsg("Is not possible to rename the upper dir"); } else { midlet.requestInput("New name", selectedFile, RENAME_OP); } } } } private void renameCurrent(String newName) { if (currentRoot == null) { midlet.showMsg("Is not possible to rename a root"); } else { int selectedIndex = getSelectedIndex(); if (selectedIndex >= 0) { String selectedFile = getString(selectedIndex); if (selectedFile.equals(UPPER_DIR)) { midlet.showMsg("Is not possible to rename the upper dir"); } else { try { FileConnection fileToRename = (FileConnection) Connector.open( currentRoot.getURL() + selectedFile, Connector.WRITE); if (fileToRename.exists()) { fileToRename.rename(newName); } else { midlet.showMsg("File " + fileToRename.getName() + " does not exists"); } } catch (IOException e) { midlet.showError(e); } catch (SecurityException e) { midlet.showError(e); } displayCurrentRoot(); } } } } private void openSelected() { int selectedIndex = getSelectedIndex(); if (selectedIndex >= 0) { String selectedFile = getString(selectedIndex); if (selectedFile.endsWith(FILE_SEPARATOR)) { try { if (currentRoot == null) { currentRoot = (FileConnection) Connector.open( "file:///" + selectedFile, Connector.READ); } else { currentRoot.setFileConnection(selectedFile); } displayCurrentRoot(); } catch (IOException e) { midlet.showError(e); } catch (SecurityException e) { midlet.showError(e); } } else if (selectedFile.equals(UPPER_DIR)) { if(rootsList.contains(currentRoot.getPath() +currentRoot.getName())) { displayAllRoots(); } else { try { currentRoot.setFileConnection(UPPER_DIR); displayCurrentRoot(); } catch (IOException e) { midlet.showError(e); } } } else { String url = currentRoot.getURL() + selectedFile; midlet.displayImage(url); } } } private void displayCurrentRoot() { try { setTitle("Image Viewer - [" + currentRoot.getURL() + "]"); // open the root deleteAll(); append(UPPER_DIR, FOLDER_IMAGE); // list all dirs Enumeration listOfDirs = currentRoot.list("*", false); while (listOfDirs.hasMoreElements()) { String currentDir = (String) listOfDirs.nextElement(); if (currentDir.endsWith(FILE_SEPARATOR)) { append(currentDir, FOLDER_IMAGE); } } // list all png files and dont show hidden files Enumeration listOfFiles = currentRoot.list("*.png", false); while (listOfFiles.hasMoreElements()) { String currentFile = (String) listOfFiles.nextElement(); if (currentFile.endsWith(FILE_SEPARATOR)) { append(currentFile, FOLDER_IMAGE); } else { append(currentFile, FILE_IMAGE); } } listOfFiles = currentRoot.list("*.jpg", false); while (listOfFiles.hasMoreElements()) { String currentFile = (String) listOfFiles.nextElement(); if (currentFile.endsWith(FILE_SEPARATOR)) { append(currentFile, FOLDER_IMAGE); } else { append(currentFile, FILE_IMAGE); } } } catch (IOException e) { midlet.showError(e); } catch (SecurityException e) { midlet.showError(e); } } private class ImageViewerOperations implements Operation { private final String parameter; private final int operationCode; ImageViewerOperations(int operationCode) { this.parameter = null; this.operationCode = operationCode; } ImageViewerOperations(String parameter, int operationCode) { this.parameter = parameter; this.operationCode = operationCode; } public void execute() { switch (operationCode) { case INIT_OP: String initDir = System.getProperty("fileconn.dir.photos"); loadRoots(); if (initDir != null) { try { currentRoot = (FileConnection) Connector.open( initDir, Connector.READ); displayCurrentRoot(); } catch (Exception e) { midlet.showError(e); displayAllRoots(); } } else { displayAllRoots(); } break; case OPEN_OP: openSelected(); break; case DELETE_OP: deleteCurrent(); break; case RENAME_OP: if (parameter != null) { renameCurrent(parameter); } else { renameCurrent(); } break; case MKDIR_OP: if (parameter != null) { createNewDir(parameter); } else { createNewDir(); } } } } }
import java.io.*; import javax.microedition.io.*; import javax.microedition.io.file.*; import javax.microedition.lcdui.*; // This class displays a selected image centered in the screen class ImageCanvas extends Canvas { private final ImageViewerMIDlet midlet; private static final int CHUNK_SIZE = 1024; private Image currentImage = null; ImageCanvas(ImageViewerMIDlet midlet) { this.midlet = midlet; } public void displayImage(String imgName) { try { FileConnection fileConn = (FileConnection)Connector.open(imgName, Connector.READ); // load the image data in memory // Read data in CHUNK_SIZE chunks InputStream fis = fileConn.openInputStream(); long overallSize = fileConn.fileSize(); int length = 0; byte[] imageData = new byte[0]; while (length < overallSize) { byte[] data = new byte[CHUNK_SIZE]; int readAmount = fis.read(data, 0, CHUNK_SIZE); byte[] newImageData = new byte[imageData.length + CHUNK_SIZE]; System.arraycopy(imageData, 0, newImageData, 0, length); System.arraycopy(data, 0, newImageData, length, readAmount); imageData = newImageData; length += readAmount; } fis.close(); fileConn.close(); currentImage = Image.createImage(imageData, 0, length); repaint(); } catch (IOException e) { midlet.showError(e); } catch (Exception e) { e.printStackTrace(); midlet.showError(e); } } protected void paint(Graphics g) { int w = getWidth(); int h = getHeight(); // Set background color to black g.setColor(0x00000000); g.fillRect(0, 0, w, h); if (currentImage != null) { g.drawImage(currentImage, w / 2, h / 2, Graphics.HCENTER | Graphics.VCENTER); } else { // If no image is available display a message g.setColor(0x00FFFFFF); g.drawString("No image", w / 2, h / 2, Graphics.HCENTER | Graphics.BASELINE); } } protected void keyReleased(int keyCode) { // Exit with any key midlet.displayFileBrowser(); } }
import javax.microedition.lcdui.*; // This class displays an input field in the screen // and returns the value entered to the MIDlet class InputScreen extends Form implements CommandListener { private final ImageViewerMIDlet midlet; private final TextField inputField = new TextField("Input", "", 32, TextField.ANY); private final Command okCommand = new Command("OK", Command.OK, 1); private final Command cancelCommand = new Command("Cancel", Command.OK, 1); InputScreen(ImageViewerMIDlet midlet) { super("Input"); this.midlet = midlet; append(inputField); addCommand(okCommand); addCommand(cancelCommand); setCommandListener(this); } public void setQuestion(String question, String text) { inputField.setLabel(question); inputField.setString(text); } public String getInputText() { return inputField.getString(); } public void commandAction(Command command, Displayable d) { if (command == okCommand) { midlet.input(inputField.getString()); } else if (command == cancelCommand) { midlet.cancelInput(); } } }
// Defines the interface for a single operation executed by the commands queue interface Operation { // Implement here the operation to be executed void execute(); }
import java.util.*; // Simple Operations Queue // It runs in an independent thread and executes Operations serially class OperationsQueue implements Runnable { private volatile boolean running = true; private final Vector operations = new Vector(); OperationsQueue() { // Notice that all operations will be done in another // thread to avoid deadlocks with GUI thread new Thread(this).start(); } void enqueueOperation(Operation nextOperation) { operations.addElement(nextOperation); synchronized (this) { notify(); } } // stop the thread void abort() { running = false; synchronized (this) { notify(); } } public void run() { while (running) { while (operations.size() > 0) { try { // execute the first operation on the queue ((Operation) operations.firstElement()).execute(); } catch (Exception e) { // Nothing to do. It is expected that each operations handle // their own locally exception but this block is to ensure // that the queue continues to operate } operations.removeElementAt(0); } synchronized (this) { try { wait(); } catch (InterruptedException e) { // it doesn't matter } } } } }
import javax.microedition.lcdui.*; class ErrorScreen extends Alert { private static Image image; private static Display display; private static ErrorScreen instance = null; private ErrorScreen() { super("Error"); setType(AlertType.ERROR); setTimeout(5000); setImage(image); } static void init(Image img, Display disp) { image = img; display = disp; } static void showError(String message, Displayable next) { if (instance == null) { instance = new ErrorScreen(); } instance.setTitle("Error"); instance.setString(message); display.setCurrent(instance, next); } }