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: