view src/uk/ac/qmul/eecs/ccmi/activities/FileSelectorActivity.java @ 0:e0ee6ac3a45f

first import
author Fiore Martin <fiore@eecs.qmul.ac.uk>
date Thu, 13 Dec 2012 20:00:21 +0000
parents
children
line wrap: on
line source
/*  
 CCmI Diagram Editor for Android 
  
 Copyright (C) 2012  Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package uk.ac.qmul.eecs.ccmi.activities;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.List;

import uk.ac.qmul.eecs.ccmi.accessibility.AccessibilityService.SoundEvent;
import uk.ac.qmul.eecs.ccmi.accessibility.AccessibilityService;
import uk.ac.qmul.eecs.ccmi.accessibility.AccessibleDialogBuilder;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.TextView;

/**
 * An abstract activity for file selection. 
 * 
 * The file system is shown as follows: the current directory is displayed 
 * on a the header and all the files or folder contained in it are displayed in a list view. Clicking on a list item 
 * will only take effect if the item is a directory. The selected directory will become the current directory.
 * In order to select the parent directory a click on the back button is needed.
 *  
 * Being an {@code AccessibleActivity} the view can be explored though sound and haptics by hovering on it. 
 * in order to scroll the list a double-finger scroll is required or, if the device does not support multitouch, a
 * scroll button will appear on the bottom for scrolling.
 *  
 */
public abstract class FileSelectorActivity extends AccessibleActivity implements  
	OnItemClickListener, OnItemLongClickListener  {
	
    private File[] currentFileList;
    private File currentFile;
    private FileFilter fileFilter;
    
    @Override
	public void onCreate(Bundle savedInstanceState) {
	    super.onCreate(savedInstanceState);

	    list.setOnItemClickListener(this);
		list.setOnItemLongClickListener(this);

		final CharSequence extension = getIntent().getCharSequenceExtra("extension");
	    fileFilter = new FileFilter() {
	    	/* only accepts directories and .ccmi files */
	        public boolean accept(File file) {
	            if (file.isDirectory()) {
	                return true;
	            }
	            
	            if(extension == null)
	            	return true;
	            else
	            	return file.getName().endsWith(extension.toString());
	        }
	    };

	    update(new File(Environment.getExternalStorageDirectory().getPath()));
	}

    /* false if new list is empty, true otherwise */
	private boolean update(File file) {

        currentFile = file;
        currentFileList = currentFile.listFiles(fileFilter);

        setHeaderText(currentFile.getName());
        List<String> names = new ArrayList<String>(currentFileList.length);
        
    	for (int i = 0; i < currentFileList.length; i ++) {
    		String fileName = currentFileList[i].getName();
    		if (currentFileList[i].isDirectory()) {
    			fileName = "/" + fileName;
    		}
       		names.add(fileName);
       	}

        list.setAdapter(new ArrayAdapter<String>(this,
        		R.layout.list_item_1, names));
        
        return !names.isEmpty();
    }

    @Override
    public void onItemClick(AdapterView<?> av, View v, int position, long id) {
        // the first thing in list is parent directory, so we must offset it
        File selectedFile = currentFileList[position];
        if (selectedFile.isDirectory()) {
        	if(selectedFile.listFiles(fileFilter).length == 0){
        		accessibilityService.playSound(SoundEvent.V_ERROR);
        		accessibilityService.speak("Directory empty");
        	}
            boolean anyItems = update(selectedFile);
            accessibilityService.playSound(AccessibilityService.SoundEvent.V_EXPAND);
            if(anyItems)
            	accessibilityService.speak("Displaying " + getHeaderText());
            else
    			accessibilityService.speak("Displaying " + getHeaderText()+". Empty");
        }else{
        	accessibilityService.playSound(SoundEvent.V_ERROR);
        }
    }
    
    /**
     * To be implemented by subclasses. The long click represent the trigger of an operation on the selected file.
     */
    @Override
	public abstract boolean onItemLongClick(AdapterView<?> av, View v, int position, long id);
	
    /**
     * On pressing the back button, the parent of the current directory will be displayed.   
     */
	@Override
	public void onBackPressed() {
		if(currentFile.getAbsolutePath().equals(Environment.getExternalStorageDirectory().getPath())){
			setResult(RESULT_CANCELED);
			super.onBackPressed(); // finish the activity
			return;
		}
		
		File parent = currentFile.getParentFile();
        update(parent);
        accessibilityService.playSound(SoundEvent.V_COLLAPSE);
		accessibilityService.speak("Displaying "+getHeaderText());
	}
	
	/**
	 * A {@code FileSelectorActivity} for opening a file. A long click on an item will open a confirmation dialog
	 * to open the file. If the user confirms, the activity will finish and set a result intent with the Uri
	 * of the opened file.   
	 */
	public static class Open extends FileSelectorActivity {
		/**
		 * Displays a confirmation dialog to open the file
		 */
		@Override
		public boolean onItemLongClick(AdapterView<?> av, View v, int position, long id) {
			final File selectedFile = super.currentFileList[position];
			if(selectedFile.isDirectory()){
				accessibilityService.playSound(SoundEvent.V_ERROR);
				return true;
			}
			
			dialogBuilder.displayDialog(R.layout.alert_dialog_confirmation, "Do you want to Open File "+(((TextView)v).getText())+" ?", new AccessibleDialogBuilder.ButtonClickListener(){
				@Override
				public void onClick(View v, DialogFragment dialogFragment, String dialogTag){
					if("YES".equals(v.getTag())){ // YES
						dialogFragment.dismiss();
						Intent resultIntent = new Intent();
						resultIntent.setData(Uri.fromFile(selectedFile));
						setResult(RESULT_OK, resultIntent);
						finish();			
					}else{ // NO 
						dialogFragment.dismiss();
						accessibilityService.playSound(SoundEvent.V_CANCEL);
						accessibilityService.speak(getHeaderText().toString());
					}
				}
			});
			return true;
		}
		
		@Override
		public String getName(){
			return "Select File to Open";
		}
	}
	
	/**
	 * A {@code FileSelectorActivity} for saving a file. A long click on an item will open a text dialog
	 * to enter the name of the file to save. If the user clicks on a file list item, the text field will 
	 * be filled with the name thereof.   
	 */
	public static class Save extends FileSelectorActivity {

		/**
		 * When the user long-clicks on an item a text dialog for the user to enter the file name appears. 
		 */
		@Override
		public boolean onItemLongClick(AdapterView<?> av, View v, int position, long id) {
			final File selectedFile = super.currentFileList[position];
			
			final String text = selectedFile.isDirectory() ? "" : selectedFile.getName(); 
			dialogBuilder.displayTextDialog("Enter File name ", text, new AccessibleDialogBuilder.ButtonClickListener(){
				@Override
				public void onClick(View v, DialogFragment dialogFragment, String dialogTag) {
					Object buttonTag = v.getTag();
					if("OK".equals(buttonTag)){
						EditText editText = (EditText)dialogFragment.getDialog().findViewById(R.id.text_edit);
						String text = editText.getText().toString().trim();
						
						if(text.length() == 0){
							accessibilityService.playSound(SoundEvent.V_ERROR);
							accessibilityService.speak("File name cannot be empty");
							return;
						}
						
						/* if the selected file was a directory, then concat it with the text entered by the user           * 
						 * if it was a file, then concat the directory where the file was with the text entered by the user * 
						 * In the latter the user can overwrite a file just by clicking OK without entering any text        */
						Uri dir = selectedFile.isDirectory() ? Uri.fromFile(selectedFile) : Uri.fromFile(selectedFile.getParentFile());
						
						Intent resultIntent = new Intent();
						resultIntent.setData(Uri.withAppendedPath(dir, text));
						setResult(RESULT_OK, resultIntent);
						finish();			
					}else{
						dialogFragment.dismiss();
						accessibilityService.playSound(SoundEvent.V_CANCEL);
						accessibilityService.speak(getHeaderText().toString());
					}
				}
				
			});
			
			return false;
		}
		
		public String getName(){
			return "Select File to Save";
		}
		
	}
	
}