001: /*
002: *
003: * Copyright (c) 2007, Sun Microsystems, Inc.
004: *
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * * Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * * Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * * Neither the name of Sun Microsystems nor the names of its contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032: package example.fc;
033:
034: import java.io.*;
035:
036: import java.util.*;
037:
038: import javax.microedition.io.*;
039: import javax.microedition.io.file.*;
040: import javax.microedition.lcdui.*;
041: import javax.microedition.midlet.*;
042:
043: /**
044: * Demonstration MIDlet for File Connection API. This MIDlet implements simple
045: * file browser for the filesystem available to the J2ME applications.
046: *
047: */
048: public class FileBrowser extends MIDlet implements CommandListener {
049: private static final String[] attrList = { "Read", "Write",
050: "Hidden" };
051: private static final String[] typeList = { "Regular File",
052: "Directory" };
053: private static final String[] monthList = { "Jan", "Feb", "Mar",
054: "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov",
055: "Dec" };
056:
057: /* special string denotes upper directory */
058: private static final String UP_DIRECTORY = "..";
059:
060: /* special string that denotes upper directory accessible by this browser.
061: * this virtual directory contains all roots.
062: */
063: private static final String MEGA_ROOT = "/";
064:
065: /* separator string as defined by FC specification */
066: private static final String SEP_STR = "/";
067:
068: /* separator character as defined by FC specification */
069: private static final char SEP = '/';
070: private String currDirName;
071: private Command view = new Command("View", Command.ITEM, 1);
072: private Command creat = new Command("New", Command.ITEM, 2);
073:
074: //add delete file functionality
075: private Command delete = new Command("Delete", Command.ITEM, 3);
076: private Command creatOK = new Command("OK", Command.OK, 1);
077: private Command prop = new Command("Properties", Command.ITEM, 2);
078: private Command back = new Command("Back", Command.BACK, 2);
079: private Command exit = new Command("Exit", Command.EXIT, 3);
080: private TextField nameInput; // Input field for new file name
081: private ChoiceGroup typeInput; // Input field for file type (regular/dir)
082: private Image dirIcon;
083: private Image fileIcon;
084: private Image[] iconList;
085:
086: public FileBrowser() {
087: currDirName = MEGA_ROOT;
088:
089: try {
090: dirIcon = Image.createImage("/icons/dir.png");
091: } catch (IOException e) {
092: dirIcon = null;
093: }
094:
095: try {
096: fileIcon = Image.createImage("/icons/file.png");
097: } catch (IOException e) {
098: fileIcon = null;
099: }
100:
101: iconList = new Image[] { fileIcon, dirIcon };
102: }
103:
104: public void startApp() {
105: try {
106: showCurrDir();
107: } catch (SecurityException e) {
108: Alert alert = new Alert(
109: "Error",
110: "You are not authorized to access the restricted API",
111: null, AlertType.ERROR);
112: alert.setTimeout(Alert.FOREVER);
113:
114: Form form = new Form("Cannot access FileConnection");
115: form
116: .append(new StringItem(
117: null,
118: "You cannot run this MIDlet with the current permissions. "
119: + "Sign the MIDlet suite, or run it in a different security domain"));
120: form.addCommand(exit);
121: form.setCommandListener(this );
122: Display.getDisplay(this ).setCurrent(alert, form);
123: } catch (Exception e) {
124: e.printStackTrace();
125: }
126: }
127:
128: public void pauseApp() {
129: }
130:
131: public void destroyApp(boolean cond) {
132: notifyDestroyed();
133: }
134:
135: public void commandAction(Command c, Displayable d) {
136: if (c == view) {
137: List curr = (List) d;
138: final String currFile = curr.getString(curr
139: .getSelectedIndex());
140: new Thread(new Runnable() {
141: public void run() {
142: if (currFile.endsWith(SEP_STR)
143: || currFile.equals(UP_DIRECTORY)) {
144: traverseDirectory(currFile);
145: } else {
146: // Show file contents
147: showFile(currFile);
148: }
149: }
150: }).start();
151: } else if (c == prop) {
152: List curr = (List) d;
153: String currFile = curr.getString(curr.getSelectedIndex());
154:
155: showProperties(currFile);
156: } else if (c == creat) {
157: createFile();
158: } else if (c == creatOK) {
159: String newName = nameInput.getString();
160:
161: if ((newName == null) || newName.equals("")) {
162: Alert alert = new Alert("Error!",
163: "File Name is empty. Please provide file name",
164: null, AlertType.ERROR);
165: alert.setTimeout(Alert.FOREVER);
166: Display.getDisplay(this ).setCurrent(alert);
167: } else {
168: // Create file in a separate thread and disable all commands
169: // except for "exit"
170: executeCreateFile(newName,
171: typeInput.getSelectedIndex() != 0);
172: Display.getDisplay(this ).getCurrent().removeCommand(
173: creatOK);
174: Display.getDisplay(this ).getCurrent().removeCommand(
175: back);
176: }
177: } else if (c == back) {
178: showCurrDir();
179: } else if (c == exit) {
180: destroyApp(false);
181: } else if (c == delete) {
182: List curr = (List) d;
183: String currFile = curr.getString(curr.getSelectedIndex());
184: executeDelete(currFile);
185: }
186: }
187:
188: void delete(String currFile) {
189: if (!currFile.equals(UP_DIRECTORY)) {
190: if (currFile.endsWith(SEP_STR)) {
191: checkDeleteFolder(currFile);
192: } else {
193: deleteFile(currFile);
194: showCurrDir();
195: }
196: } else {
197: Alert cantDeleteFolder = new Alert("Error!",
198: "Can not delete The up-directory (..) "
199: + "symbol! not a real folder", null,
200: AlertType.ERROR);
201: cantDeleteFolder.setTimeout(Alert.FOREVER);
202: Display.getDisplay(this ).setCurrent(cantDeleteFolder);
203: }
204: }
205:
206: private void executeDelete(String currFile) {
207: final String file = currFile;
208: new Thread(new Runnable() {
209: public void run() {
210: delete(file);
211: }
212: }).start();
213: }
214:
215: private void checkDeleteFolder(String folderName) {
216: try {
217: FileConnection fcdir = (FileConnection) Connector
218: .open("file://localhost/" + currDirName
219: + folderName);
220: Enumeration content = fcdir.list("*", true);
221:
222: //only empty directory can be deleted
223: if (!content.hasMoreElements()) {
224: fcdir.delete();
225: showCurrDir();
226: } else {
227: Alert cantDeleteFolder = new Alert("Error!",
228: "Can not delete The non-empty folder: "
229: + folderName, null, AlertType.ERROR);
230: cantDeleteFolder.setTimeout(Alert.FOREVER);
231: Display.getDisplay(this ).setCurrent(cantDeleteFolder);
232: }
233: } catch (IOException ioe) {
234: System.out.println(currDirName + folderName);
235:
236: ioe.printStackTrace();
237: }
238: }
239:
240: //Starts creatFile with another Thread
241: private void executeCreateFile(final String name, final boolean val) {
242: new Thread(new Runnable() {
243: public void run() {
244: createFile(name, val);
245: }
246: }).start();
247: }
248:
249: /**
250: * Show file list in the current directory .
251: */
252: void showCurrDir() {
253: Enumeration e;
254: FileConnection currDir = null;
255: List browser;
256:
257: try {
258: if (MEGA_ROOT.equals(currDirName)) {
259: e = FileSystemRegistry.listRoots();
260: browser = new List(currDirName, List.IMPLICIT);
261: } else {
262: currDir = (FileConnection) Connector
263: .open("file://localhost/" + currDirName);
264: e = currDir.list();
265: browser = new List(currDirName, List.IMPLICIT);
266: // not root - draw UP_DIRECTORY
267: browser.append(UP_DIRECTORY, dirIcon);
268: }
269:
270: while (e.hasMoreElements()) {
271: String fileName = (String) e.nextElement();
272:
273: if (fileName.charAt(fileName.length() - 1) == SEP) {
274: // This is directory
275: browser.append(fileName, dirIcon);
276: } else {
277: // this is regular file
278: browser.append(fileName, fileIcon);
279: }
280: }
281:
282: browser.setSelectCommand(view);
283:
284: //Do not allow creating files/directories beside root
285: if (!MEGA_ROOT.equals(currDirName)) {
286: browser.addCommand(prop);
287: browser.addCommand(creat);
288: browser.addCommand(delete);
289: }
290:
291: browser.addCommand(exit);
292:
293: browser.setCommandListener(this );
294:
295: if (currDir != null) {
296: currDir.close();
297: }
298:
299: Display.getDisplay(this ).setCurrent(browser);
300: } catch (IOException ioe) {
301: ioe.printStackTrace();
302: }
303: }
304:
305: void traverseDirectory(String fileName) {
306: /* In case of directory just change the current directory
307: * and show it
308: */
309: if (currDirName.equals(MEGA_ROOT)) {
310: if (fileName.equals(UP_DIRECTORY)) {
311: // can not go up from MEGA_ROOT
312: return;
313: }
314:
315: currDirName = fileName;
316: } else if (fileName.equals(UP_DIRECTORY)) {
317: // Go up one directory
318: int i = currDirName.lastIndexOf(SEP,
319: currDirName.length() - 2);
320:
321: if (i != -1) {
322: currDirName = currDirName.substring(0, i + 1);
323: } else {
324: currDirName = MEGA_ROOT;
325: }
326: } else {
327: currDirName = currDirName + fileName;
328: }
329:
330: showCurrDir();
331: }
332:
333: void showFile(String fileName) {
334: try {
335: FileConnection fc = (FileConnection) Connector
336: .open("file://localhost/" + currDirName + fileName);
337:
338: if (!fc.exists()) {
339: throw new IOException("File does not exists");
340: }
341:
342: InputStream fis = fc.openInputStream();
343: byte[] b = new byte[1024];
344:
345: int length = fis.read(b, 0, 1024);
346:
347: fis.close();
348: fc.close();
349:
350: TextBox viewer = new TextBox("View File: " + fileName,
351: null, 1024, TextField.ANY | TextField.UNEDITABLE);
352:
353: viewer.addCommand(back);
354: viewer.addCommand(exit);
355: viewer.setCommandListener(this );
356:
357: if (length > 0) {
358: viewer.setString(new String(b, 0, length));
359: }
360:
361: Display.getDisplay(this ).setCurrent(viewer);
362: } catch (Exception e) {
363: Alert alert = new Alert("Error!", "Can not access file "
364: + fileName + " in directory " + currDirName
365: + "\nException: " + e.getMessage(), null,
366: AlertType.ERROR);
367: alert.setTimeout(Alert.FOREVER);
368: Display.getDisplay(this ).setCurrent(alert);
369: }
370: }
371:
372: void deleteFile(String fileName) {
373: try {
374: FileConnection fc = (FileConnection) Connector
375: .open("file:///" + currDirName + fileName);
376: fc.delete();
377: } catch (Exception e) {
378: Alert alert = new Alert("Error!",
379: "Can not access/delete file " + fileName
380: + " in directory " + currDirName
381: + "\nException: " + e.getMessage(), null,
382: AlertType.ERROR);
383: alert.setTimeout(Alert.FOREVER);
384: Display.getDisplay(this ).setCurrent(alert);
385: }
386: }
387:
388: void showProperties(String fileName) {
389: try {
390: if (fileName.equals(UP_DIRECTORY)) {
391: return;
392: }
393:
394: FileConnection fc = (FileConnection) Connector
395: .open("file://localhost/" + currDirName + fileName);
396:
397: if (!fc.exists()) {
398: throw new IOException("File does not exists");
399: }
400:
401: Form props = new Form("Properties: " + fileName);
402: ChoiceGroup attrs = new ChoiceGroup("Attributes:",
403: Choice.MULTIPLE, attrList, null);
404:
405: attrs.setSelectedFlags(new boolean[] { fc.canRead(),
406: fc.canWrite(), fc.isHidden() });
407:
408: props.append(new StringItem("Location:", currDirName));
409: props.append(new StringItem("Type: ",
410: fc.isDirectory() ? "Directory" : "Regular File"));
411: props.append(new StringItem("Modified:", myDate(fc
412: .lastModified())));
413: props.append(attrs);
414:
415: props.addCommand(back);
416: props.addCommand(exit);
417: props.setCommandListener(this );
418:
419: fc.close();
420:
421: Display.getDisplay(this ).setCurrent(props);
422: } catch (Exception e) {
423: Alert alert = new Alert("Error!", "Can not access file "
424: + fileName + " in directory " + currDirName
425: + "\nException: " + e.getMessage(), null,
426: AlertType.ERROR);
427: alert.setTimeout(Alert.FOREVER);
428: Display.getDisplay(this ).setCurrent(alert);
429: }
430: }
431:
432: void createFile() {
433: Form creator = new Form("New File");
434: nameInput = new TextField("Enter Name", null, 256,
435: TextField.ANY);
436: typeInput = new ChoiceGroup("Enter File Type",
437: Choice.EXCLUSIVE, typeList, iconList);
438: creator.append(nameInput);
439: creator.append(typeInput);
440: creator.addCommand(creatOK);
441: creator.addCommand(back);
442: creator.addCommand(exit);
443: creator.setCommandListener(this );
444: Display.getDisplay(this ).setCurrent(creator);
445: }
446:
447: void createFile(String newName, boolean isDirectory) {
448: try {
449: FileConnection fc = (FileConnection) Connector
450: .open("file:///" + currDirName + newName);
451:
452: if (isDirectory) {
453: fc.mkdir();
454: } else {
455: fc.create();
456: }
457:
458: showCurrDir();
459: } catch (Exception e) {
460: String s = "Can not create file '" + newName + "'";
461:
462: if ((e.getMessage() != null)
463: && (e.getMessage().length() > 0)) {
464: s += ("\n" + e);
465: }
466:
467: Alert alert = new Alert("Error!", s, null, AlertType.ERROR);
468: alert.setTimeout(Alert.FOREVER);
469: Display.getDisplay(this ).setCurrent(alert);
470: // Restore the commands that were removed in commandAction()
471: Display.getDisplay(this ).getCurrent().addCommand(creatOK);
472: Display.getDisplay(this ).getCurrent().addCommand(back);
473: }
474: }
475:
476: private String myDate(long time) {
477: Calendar cal = Calendar.getInstance();
478:
479: cal.setTime(new Date(time));
480:
481: StringBuffer sb = new StringBuffer();
482:
483: sb.append(cal.get(Calendar.HOUR_OF_DAY));
484: sb.append(':');
485: sb.append(cal.get(Calendar.MINUTE));
486: sb.append(':');
487: sb.append(cal.get(Calendar.SECOND));
488: sb.append(',');
489: sb.append(' ');
490: sb.append(cal.get(Calendar.DAY_OF_MONTH));
491: sb.append(' ');
492: sb.append(monthList[cal.get(Calendar.MONTH)]);
493: sb.append(' ');
494: sb.append(cal.get(Calendar.YEAR));
495:
496: return sb.toString();
497: }
498: }
|