/*
* FileExplorerScreen.java
*
* Copyright � 1998-2011 Research In Motion Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Note: For the sake of simplicity, this sample application may not leverage
* resource bundles and resource strings. However, it is STRONGLY recommended
* that application developers make use of the localization features available
* within the BlackBerry development platform to ensure a seamless application
* experience across a variety of languages and geographies. For more information
* on localizing your application, please refer to the BlackBerry Java Development
* Environment Development Guide associated with this release.
*/
package com.rim.samples.device.attachmentdemo;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import javax.microedition.io.file.FileSystemRegistry;
import net.rim.device.api.command.Command;
import net.rim.device.api.command.CommandHandler;
import net.rim.device.api.command.ReadOnlyCommandMetadata;
import net.rim.device.api.system.Characters;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.DrawStyle;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.Screen;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.XYRect;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.component.table.DataTemplate;
import net.rim.device.api.ui.component.table.TableController;
import net.rim.device.api.ui.component.table.TableModelAdapter;
import net.rim.device.api.ui.component.table.TableView;
import net.rim.device.api.ui.component.table.TemplateColumnProperties;
import net.rim.device.api.ui.component.table.TemplateRowProperties;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.decor.BackgroundFactory;
import net.rim.device.api.util.StringProvider;
/**
* Shows the listing of all directories/files
*/
public class FileExplorerScreen extends MainScreen {
private static final String ROOT = "file:///SDCard/";
private final Vector _elements = new Vector();
private FileExplorerTableModelAdapter _model;
private TableView _view;
private String _parentRoot;
private UiApplication _app;
/**
* Constructs a new FileExplorerScreen object
*
* @param app
* Reference to the UiApplication instance
*/
public FileExplorerScreen(final UiApplication app) {
super(Manager.NO_VERTICAL_SCROLL);
_app = app;
_model = new FileExplorerTableModelAdapter();
_view = new TableView(_model);
final TableController controller = new TableController(_model, _view);
controller.setFocusPolicy(TableController.ROW_FOCUS);
_view.setController(controller);
// Set the highlight style for the view
_view.setDataTemplateFocus(BackgroundFactory
.createLinearGradientBackground(Color.LIGHTBLUE,
Color.LIGHTBLUE, Color.BLUE, Color.BLUE));
// Create a data template that will format the model data as an array of
// LabelFields
final DataTemplate dataTemplate = new DataTemplate(_view, 1, 1) {
public Field[] getDataFields(final int modelRowIndex) {
final FileHolder fileholder =
(FileHolder) _model.getRow(modelRowIndex);
String text;
if (fileholder.isDirectory()) {
int pathIndex = fileholder.getPath().lastIndexOf('/');
pathIndex =
fileholder.getPath().substring(0, pathIndex)
.lastIndexOf('/');
text = fileholder.getPath().substring(pathIndex + 1);
} else {
text = fileholder.getFileName();
}
final Field[] fields =
{ new LabelField(text, DrawStyle.ELLIPSIS
| Field.NON_FOCUSABLE) };
return fields;
}
};
// Define the regions of the data template and column/row size
dataTemplate.createRegion(new XYRect(0, 0, 1, 1));
dataTemplate.setColumnProperties(0, new TemplateColumnProperties(
Display.getWidth()));
dataTemplate.setRowProperties(0, new TemplateRowProperties(24));
_view.setDataTemplate(dataTemplate);
dataTemplate.useFixedHeight(true);
// Add the TableView to the screen
add(_view);
readRoots(ROOT);
_selectItem = new MenuItem(new StringProvider("Select"), 0x230010, 0);
_selectItem.setCommand(new Command(new CommandHandler() {
/**
* @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(final ReadOnlyCommandMetadata metadata,
final Object context) {
selectAction();
}
}));
_backItem = new MenuItem(new StringProvider("Go Back"), 0x230020, 1);
_backItem.setCommand(new Command(new CommandHandler() {
/**
* @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(final ReadOnlyCommandMetadata metadata,
final Object context) {
goBack();
}
}));
}
/**
* @see Screen#keyChar(char, int, int)
*/
public boolean keyChar(final char c, final int status, final int time) {
// Enter key will take action on directory/file. Escape key will go up
// one directory or close screen if at top level.
switch (c) {
case Characters.ESCAPE:
if (goBack()) {
return true;
}
}
return super.keyChar(c, status, time);
}
/**
* @see MainScreen#makeMenu(Menu, int)
*/
public void makeMenu(final Menu menu, final int instance) {
// Only display our menu items if no actions are performed
if (instance == Menu.INSTANCE_DEFAULT) {
menu.add(_selectItem);
if (_parentRoot != null) {
menu.add(_backItem);
}
}
super.makeMenu(menu, instance);
}
/**
* @see Screen#invokeAction(int)
*/
protected boolean invokeAction(final int action) {
if (action == ACTION_INVOKE) {
selectAction();
return true;
}
return super.invokeAction(action);
}
/**
* Reads the given path and enumerates through it
*
* @param root
* Path to be read
*/
private void readRoots(final String root) {
_parentRoot = root;
setTitle(root);
// Reset the table contents
_model.removeAllRows();
Enumeration rootEnum = null;
if (root != null) {
FileConnection fc = null;
// Open the file system and get the list of directories/files
try {
fc = (FileConnection) Connector.open(root);
rootEnum = fc.list();
} catch (final IOException e) {
AttachmentDemo.errorDialog(e.toString());
return;
} finally {
if (fc != null) {
// Everything is read, make sure to close the connection
try {
fc.close();
fc = null;
} catch (final IOException e) {
}
}
}
}
// There was no root to read, so read the system roots
if (rootEnum == null) {
rootEnum = FileSystemRegistry.listRoots();
}
// Read through the list of directories/files
while (rootEnum.hasMoreElements()) {
String file = (String) rootEnum.nextElement();
if (root != null) {
file = root + file;
}
readSubroots(file);
}
}
/**
* Reads all the directories and files from the provided path
*
* @param file
* Upper directory to be read
*/
private void readSubroots(final String file) {
FileConnection fc = null;
try {
fc = (FileConnection) Connector.open(file);
// Create a file holder from the FileConnection so that the
// connection is not left open
final FileHolder fileholder =
new FileHolder(file, fc.isDirectory());
_model.addRow(fileholder);
} catch (final IOException e) {
System.out.println("Connector.open(" + file + ") threw "
+ e.toString());
} finally {
if (fc != null) {
// Everything is read. Close the connection.
try {
fc.close();
fc = null;
} catch (final Exception ioex) {
}
}
}
}
/**
* Performs an action on a selected directory or file
*/
private void selectAction() {
final FileHolder fileholder =
(FileHolder) _model.getRow(_view.getRowNumberWithFocus());
if (fileholder != null) {
// If the FileHolder represents a directory, then show what's
// in the directory. Otherwise prompt user to upload.
if (fileholder.isDirectory()) {
readRoots(fileholder.getPath());
} else {
_app.pushModalScreen(new FileUploadDialog(fileholder, this));
}
}
}
/**
* Goes back one directory in the directory hierarchy, if possible
*
* @return True if we went back a directory, otherwise false
*/
private boolean goBack() {
if (_parentRoot != null) {
if (_parentRoot.equals(ROOT)) {
return false;
}
String backParentRoot =
_parentRoot.substring(0, _parentRoot.lastIndexOf('/'));
backParentRoot =
backParentRoot.substring(0,
backParentRoot.lastIndexOf('/') + 1);
if (backParentRoot.length() > 0) {
readRoots(backParentRoot);
return true;
}
}
return false;
}
/**
* Method to present a message to the user
*
* @param msg
* The text to display
*/
public void displayStatus(final String msg) {
_app.invokeLater(new Runnable() {
public void run() {
Dialog.alert(msg);
}
});
}
/**
* Adapter for displaying file explorer entries in table format
*/
private class FileExplorerTableModelAdapter extends TableModelAdapter {
/**
* @see net.rim.device.api.ui.component.table.TableModelAdapter#getNumberOfRows()
*/
public int getNumberOfRows() {
return _elements.size();
}
/**
* @see net.rim.device.api.ui.component.table.TableModelAdapter#getNumberOfColumns()
*/
public int getNumberOfColumns() {
return 1;
}
/**
* @see net.rim.device.api.ui.component.table.TableModelAdapter#doAddRow(Object)
*/
protected boolean doAddRow(final Object row) {
_elements.addElement(row);
return true;
}
/**
* @see net.rim.device.api.ui.component.table.TableModelAdapter#doRemoveRowAt(int)
*/
protected boolean doRemoveRowAt(final int index) {
_elements.removeElementAt(index);
return true;
}
/**
* @see net.rim.device.api.ui.component.table.TableModelAdapter#doGetRow(int)
*/
protected Object doGetRow(final int index) {
return _elements.elementAt(index);
}
/**
* Removes all rows by repeatedly invoking {@link #removeRowAt}
*/
public void removeAllRows() {
while (getNumberOfRows() > 0) {
removeRowAt(0);
}
}
}
/**
* Menu item for displaying information on a selected file
*/
private MenuItem _selectItem;
/**
* Menu item for going back one directory in the directory hierarchy
*/
private MenuItem _backItem;
}