fiore@0: /*
fiore@0: CCmI Diagram Editor for Android
fiore@0:
fiore@0: Copyright (C) 2012 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
fiore@0:
fiore@0: This program is free software: you can redistribute it and/or modify
fiore@0: it under the terms of the GNU General Public License as published by
fiore@0: the Free Software Foundation, either version 3 of the License, or
fiore@0: (at your option) any later version.
fiore@0:
fiore@0: This program is distributed in the hope that it will be useful,
fiore@0: but WITHOUT ANY WARRANTY; without even the implied warranty of
fiore@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
fiore@0: GNU General Public License for more details.
fiore@0:
fiore@0: You should have received a copy of the GNU General Public License
fiore@0: along with this program. If not, see .
fiore@0: */
fiore@0: package uk.ac.qmul.eecs.ccmi.activities;
fiore@0:
fiore@0: import java.io.File;
fiore@0: import java.io.FileInputStream;
fiore@0: import java.io.FileOutputStream;
fiore@0: import java.io.InputStream;
fiore@0: import java.io.OutputStream;
fiore@0:
fiore@0: import org.simpleframework.xml.Serializer;
fiore@0: import org.simpleframework.xml.core.Persister;
fiore@0:
fiore@0: import uk.ac.qmul.eecs.ccmi.accessibility.AccessibilityService;
fiore@0: import uk.ac.qmul.eecs.ccmi.accessibility.AccessibilityService.SoundEvent;
fiore@0: import uk.ac.qmul.eecs.ccmi.accessibility.AccessibleDialogBuilder;
fiore@1: import uk.ac.qmul.eecs.ccmi.utilities.ILogger;
fiore@0: import uk.ac.qmul.eecs.ccmi.xmlparser.Diagram;
fiore@0: import android.content.Intent;
fiore@0: import android.content.res.AssetManager;
fiore@0: import android.os.Bundle;
fiore@0: import android.support.v4.app.DialogFragment;
fiore@0: import android.view.View;
fiore@0: import android.widget.AdapterView;
fiore@0: import android.widget.AdapterView.OnItemClickListener;
fiore@0: import android.widget.AdapterView.OnItemLongClickListener;
fiore@0: import android.widget.ArrayAdapter;
fiore@1: import android.widget.TextView;
fiore@0:
fiore@0: /**
fiore@0: *
fiore@0: * The main activity. It displays the diagram through the hierarchical view
fiore@0: * of the CCmI Diagram Editor
fiore@0: *
fiore@0: */
fiore@0: public class CcmiEditorAppActivity extends AccessibleActivity implements
fiore@0: OnItemClickListener, OnItemLongClickListener, TreeNavigation.Updateable {
fiore@0: private final static int OPEN_REQUEST = 1;
fiore@0: private final static int SAVE_REQUEST = 2;
fiore@0: private final static String CCMI_EXTENSION = ".ccmi";
fiore@0:
fiore@0: private Diagram diagram;
fiore@0: private TreeNavigation navigation;
fiore@0:
fiore@0: private String file;
fiore@0: private InputStream in;
fiore@0:
fiore@0: public String getName(){
fiore@0: return "";
fiore@0: }
fiore@0:
fiore@0: /** Called when the activity is first created. */
fiore@0: @Override
fiore@0: public void onCreate(Bundle savedInstanceState) {
fiore@0: super.onCreate(savedInstanceState);
fiore@0:
fiore@0: list.setOnItemClickListener(this);
fiore@0: list.setOnItemLongClickListener(this);
fiore@0:
fiore@1:
fiore@1: ILogger.log("--- APPLICATION STARTED ---");
fiore@1:
fiore@1:
fiore@0: /* init assets */
fiore@0: AssetManager assetManager = getAssets();
fiore@0: try {
fiore@0: file = assetManager.list("diagrams")[0];
fiore@0: in = assetManager.open("diagrams/"+file);
fiore@0: readXML(in);
fiore@0: } catch (Exception e) {
fiore@0: e.printStackTrace();
fiore@0: throw new RuntimeException(e);
fiore@0: }
fiore@0: }
fiore@0:
fiore@0: /* create a new list and display it */
fiore@0: @Override
fiore@0: public void update(){
fiore@0: /* header */
fiore@0: setHeaderText(navigation.getCurrentItemName());
fiore@0: /* list */
fiore@0: ArrayAdapter adapter = new ArrayAdapter(this,R.layout.list_item_1,navigation.getCurrentChildList());
fiore@0: list.setAdapter(adapter);
fiore@0: }
fiore@0:
fiore@0: /*----- listeners to implement the navigation ----*/
fiore@0: @Override
fiore@0: public void onItemClick(AdapterView> av, View v, int pos, long id) {
fiore@1: ILogger.logTap(((TextView)v).getText());
fiore@0: if(!navigation.goNext(pos)){
fiore@0: accessibilityService.playSound(AccessibilityService.SoundEvent.V_ERROR);
fiore@1: ILogger.logError("end of tree");
fiore@0: return;
fiore@0: }
fiore@0: accessibilityService.playSound(AccessibilityService.SoundEvent.V_EXPAND);
fiore@1: accessibilityService.speak("displaying " + getHeaderText());
fiore@1: ILogger.logActivity(getHeaderText());
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * The activity listens to long clicks performed on the list view.
fiore@0: *
fiore@0: * When a user long clicks an item, a dialog is displayed accordingly. For example if the types of nodes and
fiore@0: * edges are listed when the user long clicks, then a dialog for insertion of a new node or edge is displayed.
fiore@0: */
fiore@0: @Override
fiore@0: public boolean onItemLongClick(AdapterView> parent, View view, int position, long id) {
fiore@1: ILogger.logLongTap(((TextView)view).getText());
fiore@0: boolean doneSomething = navigation.getController().performEditAction(parent, view, position, id, this);
fiore@1: if(!doneSomething){
fiore@0: accessibilityService.playSound(AccessibilityService.SoundEvent.V_ERROR);
fiore@1: ILogger.logError("no action available on this item");
fiore@1: }
fiore@0: return doneSomething;
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * When the back button is pressed the activity will cursor back in the tree
fiore@0: * view, which means the parent of the currently displayed items will be displayed
fiore@0: * together with its siblings.
fiore@0: */
fiore@0: @Override
fiore@0: public void onBackPressed() {
fiore@1: ILogger.logTap("back");
fiore@0: if(navigation.goPrevious()){
fiore@0: accessibilityService.playSound(SoundEvent.V_COLLAPSE);
fiore@0: accessibilityService.speak("Displaying "+getHeaderText());
fiore@1: ILogger.logActivity(getHeaderText());
fiore@0: update();
fiore@0: }else{
fiore@0: accessibilityService.playSound(SoundEvent.V_EDITING_MODE, true);
fiore@0: dialogBuilder.displayDialog(R.layout.alert_dialog_confirm_exit,"Exit Dialog",new AccessibleDialogBuilder.ButtonClickListener() {
fiore@0: @Override
fiore@0: public void onClick(View v, DialogFragment dialogFragment, String tag) {
fiore@0: if("EXIT".equals(v.getTag())){
fiore@1: ILogger.logButton("exit");
fiore@0: accessibilityService.speak(getResources().getString(R.string.exitMessage));
fiore@1: ILogger.log("--- EXIT ---");
fiore@1: ILogger.dispose();
fiore@0: finish();
fiore@0: }else if("CANCEL".equals(v.getTag())){
fiore@1: ILogger.logButton("cancel");
fiore@1: accessibilityService.playSound(SoundEvent.V_CANCEL);
fiore@0: accessibilityService.speak("Cancel");
fiore@0: accessibilityService.stopSound();
fiore@0: dialogFragment.dismiss();
fiore@0: }else if("OPEN".equals(v.getTag())){
fiore@1: ILogger.logButton("open");
fiore@0: /* start the activity to open a file */
fiore@0: Intent intent = new Intent(CcmiEditorAppActivity.this, FileSelectorActivity.Open.class);
fiore@0: intent.putExtra("extension", CCMI_EXTENSION);
fiore@0: startActivityForResult(intent,OPEN_REQUEST);
fiore@0: dialogFragment.dismiss();
fiore@0: }else if("SAVE".equals(v.getTag())){
fiore@1: ILogger.logButton("save");
fiore@0: Intent intent = new Intent(CcmiEditorAppActivity.this, FileSelectorActivity.Save.class);
fiore@0: intent.putExtra("extension", CCMI_EXTENSION);
fiore@0: startActivityForResult(intent,SAVE_REQUEST);
fiore@0: dialogFragment.dismiss();
fiore@0: }
fiore@0: }
fiore@0: });
fiore@0: }
fiore@0: }
fiore@0:
fiore@0: @Override
fiore@0: protected void onActivityResult(int requestCode, int resultCode, Intent data) {
fiore@0: if(resultCode == RESULT_OK){
fiore@0: if(requestCode == OPEN_REQUEST){
fiore@0: try {
fiore@0: InputStream in = new FileInputStream(new File(data.getData().getPath()));
fiore@0: readXML(in);
fiore@1: ILogger.logActivity(navigation.getCurrentPath());
fiore@0: } catch (Exception e) {
fiore@0: accessibilityService.playSound(SoundEvent.V_ERROR);
fiore@0: accessibilityService.speak("File could not be open");
fiore@0: }
fiore@0: }else if(requestCode == SAVE_REQUEST){
fiore@0: try {
fiore@0: String filePath = data.getData().getPath();
fiore@0: String diagramName = data.getData().getLastPathSegment();
fiore@0: /* make sure the extension is .ccmi */
fiore@0: if(!filePath.endsWith(CCMI_EXTENSION)||(CCMI_EXTENSION.equals(diagramName)))
fiore@0: filePath += CCMI_EXTENSION;
fiore@0:
fiore@0: /* make sure diagram name doesn't have trailing .ccmi, unless the name is just ".ccmi" */
fiore@0: if(diagramName.endsWith(CCMI_EXTENSION) && !(CCMI_EXTENSION.equals(diagramName))){
fiore@0: diagramName = diagramName.substring(0, diagramName.length()-CCMI_EXTENSION.length());
fiore@0: }
fiore@0:
fiore@0: diagram.setName(diagramName);
fiore@0: OutputStream out = new FileOutputStream(new File(filePath));
fiore@0: saveXML(out);
fiore@0: } catch (Exception e) {
fiore@0: accessibilityService.playSound(SoundEvent.V_ERROR);
fiore@0: accessibilityService.speak("File could not be saved");
fiore@0: }
fiore@0: }
fiore@0: }
fiore@0: }
fiore@0:
fiore@0: private void saveXML(OutputStream out) throws Exception {
fiore@0: Serializer serializer = new Persister();
fiore@0: serializer.write(diagram, out);
fiore@0: out.close();
fiore@0: navigation = new TreeNavigation(diagram,dialogBuilder,this);
fiore@0: update();
fiore@0: accessibilityService.playSound(SoundEvent.V_OK);
fiore@0: accessibilityService.speak("Filed saved");
fiore@0: }
fiore@0:
fiore@0: private void readXML(InputStream in) throws Exception {
fiore@0: Serializer serializer = new Persister();
fiore@0: diagram = serializer.read(Diagram.class, in);
fiore@0: in.close();
fiore@0: navigation = new TreeNavigation(diagram,dialogBuilder,this);
fiore@0: update();
fiore@0: }
fiore@0: }
fiore@0: