The FileSelector
class is the main file browser
class and forms the bulk of the MIDlet. It creates the UI for navigating
the device file system and selecting images to view. It also provides
support for file management operations such as delete, rename, and
directory creation.
The FileSelector
checks whether the fileconn.dir.photos
system property is specified and, if specified, opens the file browser
in that directory. If the system property is not specified, FileSelector
displays a list of available roots instead.
To implement the FileSelector
class:
Create the FileSelector.java
class file.
Import the required packages and classes.
import java.io.*; import java.util.*; import javax.microedition.io.*; import javax.microedition.io.file.*; import javax.microedition.lcdui.*;
Set FileSelector
to extend List
and implement CommandListener
and FileSystemListener
. Create the required folder
icons, Commands
, and other variables.
// Simple file selector class. // It navigates the file system and shows images currently available class FileSelector extends List implements CommandListener, FileSystemListener { private final static Image ROOT_IMAGE = ImageViewerMIDlet.makeImage("/root_1.png"); private final static Image FOLDER_IMAGE = ImageViewerMIDlet.makeImage("/folder1.png"); private final static Image FILE_IMAGE = ImageViewerMIDlet.makeImage("/file1.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.SCREEN, 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; private Ticker ticker = new Ticker("Image Viewer");
Add the Commands
and a CommandListener
, and implement
the commandAction
method.
FileSelector(ImageViewerMIDlet midlet) { super("Image Viewer", List.IMPLICIT); setTicker(ticker); this.midlet = midlet; addCommand(openCommand); addCommand(createDirCommand); addCommand(deleteCommand); addCommand(renameCommand); addCommand(exitCommand); setSelectCommand(openCommand); setCommandListener(this); } // ... 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(); } }
Create a set
of methods for initializing and stopping the FileSystemListener
.
void initialize() { 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; } }
Create methods for listening to changes in the displayed folder and displaying the current root directory.
// Listen for changes in the roots public void rootChanged(int state, String rootName) { queue.enqueueOperation(new ImageViewerOperations(INIT_OP)); } private void displayAllRoots() { ticker.setString("Image Viewer - [Roots]"); deleteAll(); Enumeration roots = rootsList.elements(); while (roots.hasMoreElements()) { String root = (String) roots.nextElement(); root = root.replace('/', FILE_SEPARATOR.charAt(0)); append(root.substring(1), ROOT_IMAGE); } currentRoot = null; } // ... private void loadRoots() { if (!rootsList.isEmpty()) { rootsList.removeAllElements(); } try { Enumeration roots = FileSystemRegistry.listRoots(); while (roots.hasMoreElements()) { rootsList.addElement("/" + (String) roots.nextElement()); } } catch (Throwable e) { midlet.showMsg(e.getMessage()); } }
Create methods for handling the creation of new directories.
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(); } }
Create a method for deleting the currently selected item.
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 { String tmp = selectedFile.replace(FILE_SEPARATOR.charAt(0), '/'); FileConnection fileToDelete = (FileConnection) Connector.open( currentRoot.getURL() + tmp, Connector.READ_WRITE); if (!fileToDelete.exists()) { midlet.showMsg("File " + fileToDelete.getName() + " does not exists"); } else { if (getConfirmation("Do you really want to delete " + tmp + "?")) { fileToDelete.delete(); midlet.showMsg(tmp + " deleted."); } else { midlet.showMsg("Operation cancelled."); } } } catch (IOException e) { midlet.showError(e); } catch (SecurityException e) { midlet.showError(e); } displayCurrentRoot(); } } } }
Create methods for renaming the currently selected item.
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 { String tmp = selectedFile.replace(FILE_SEPARATOR.charAt(0), '/'); FileConnection fileToRename = (FileConnection) Connector.open( currentRoot.getURL() + tmp, Connector.READ_WRITE); if (fileToRename.exists()) { if(fileToRename.isDirectory()) { if(newName.indexOf('/')>-1) newName = newName.substring(0,newName.indexOf('/')); } else { newName = newName.replace(FILE_SEPARATOR.charAt(0), '/'); } fileToRename.rename(newName); } else { midlet.showMsg("File " + fileToRename.getName() + " does not exists"); } } catch (IOException e) { e.printStackTrace(); midlet.showError(e); } catch (SecurityException e) { e.printStackTrace(); midlet.showError(e); } displayCurrentRoot(); } } } }
Create a method
for handling the actions that occur when the currently selected item
is opened. If the item is a folder, it is made the currently visible
folder (defined as currentRoot
). If the item is an
image file, it is opened in the ImageCanvas
.
private void openSelected() { int selectedIndex = getSelectedIndex(); if (selectedIndex >= 0) { String selectedFile = getString(selectedIndex); if (selectedFile.endsWith(FILE_SEPARATOR)) { try { String tmp = selectedFile.replace(FILE_SEPARATOR.charAt(0), '/'); if (currentRoot == null) { currentRoot = (FileConnection) Connector.open( "file:///" + tmp, Connector.READ); } else { currentRoot.setFileConnection(tmp); } 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); } } }
Create a method for drawing the file hierarchy in the currently visible folder.
private void displayCurrentRoot() { try { ticker.setString("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("/")) { String tmp = currentDir.replace('/', FILE_SEPARATOR.charAt(0)); append(tmp, FOLDER_IMAGE); // always display the platform specific seperator to the user } } // 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); } } listOfFiles = currentRoot.list("*.bmp", false); while (listOfFiles.hasMoreElements()) { String currentFile = (String) listOfFiles.nextElement(); if (currentFile.endsWith(FILE_SEPARATOR)) { append(currentFile, FOLDER_IMAGE); } else { append(currentFile, FILE_IMAGE); } } //Making the top item visible. setSelectedIndex(0, true); } catch (IOException e) { midlet.showError(e); } catch (SecurityException e) { midlet.showError(e); } }
Create an inner class for handling the actual user actions in the file manager. When the user selects an action (select, create, rename, or delete), the following class launches the corresponding method using an operations queue.
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(); } } } }
Create a confirmation dialog for sensitive file operations, such as delete.
boolean getConfirmation(String message) { Object lock = new Object(); Confirm prompt = new Confirm(message, lock, this); synchronized (lock) { try { lock.wait(); } catch (InterruptedException ex) { ex.printStackTrace(); } } // set current displayable, when notification arrives Display.getDisplay(midlet).setCurrent(this); return prompt.getResponse(); } // ... private class Confirm extends Alert implements CommandListener { private Command okCommand = new Command("Yes", Command.OK, 0); private Command nokCommand = new Command("No", Command.EXIT, 0); private boolean isOkResponse; private Object waitLock; Confirm(String message, Object lock, Displayable next) { super("Image Viewer", message, midlet.getLogo(), AlertType.CONFIRMATION); addCommand(okCommand); addCommand(nokCommand); setCommandListener(this); waitLock = lock; Display.getDisplay(midlet).setCurrent(this, next); } public void commandAction(Command command, Displayable display) { if (command == okCommand) { isOkResponse = true; } else if (command == nokCommand) { isOkResponse = false; } synchronized (waitLock) { waitLock.notifyAll(); } } boolean getResponse() { return isOkResponse; } } }
Now that you have implemented the file browser functionality, implement the image viewing functionality.