fiore@0
|
1 /*
|
fiore@0
|
2 CCmI Diagram Editor for Android
|
fiore@0
|
3
|
fiore@0
|
4 Copyright (C) 2012 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
fiore@0
|
5
|
fiore@0
|
6 This program is free software: you can redistribute it and/or modify
|
fiore@0
|
7 it under the terms of the GNU General Public License as published by
|
fiore@0
|
8 the Free Software Foundation, either version 3 of the License, or
|
fiore@0
|
9 (at your option) any later version.
|
fiore@0
|
10
|
fiore@0
|
11 This program is distributed in the hope that it will be useful,
|
fiore@0
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
fiore@0
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
fiore@0
|
14 GNU General Public License for more details.
|
fiore@0
|
15
|
fiore@0
|
16 You should have received a copy of the GNU General Public License
|
fiore@0
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
fiore@0
|
18 */
|
fiore@0
|
19 package uk.ac.qmul.eecs.ccmi.activities;
|
fiore@0
|
20
|
fiore@0
|
21 import java.io.File;
|
fiore@0
|
22 import java.io.FileInputStream;
|
fiore@0
|
23 import java.io.FileOutputStream;
|
fiore@0
|
24 import java.io.InputStream;
|
fiore@0
|
25 import java.io.OutputStream;
|
fiore@0
|
26
|
fiore@0
|
27 import org.simpleframework.xml.Serializer;
|
fiore@0
|
28 import org.simpleframework.xml.core.Persister;
|
fiore@0
|
29
|
fiore@0
|
30 import uk.ac.qmul.eecs.ccmi.accessibility.AccessibilityService;
|
fiore@0
|
31 import uk.ac.qmul.eecs.ccmi.accessibility.AccessibilityService.SoundEvent;
|
fiore@0
|
32 import uk.ac.qmul.eecs.ccmi.accessibility.AccessibleDialogBuilder;
|
fiore@1
|
33 import uk.ac.qmul.eecs.ccmi.utilities.ILogger;
|
fiore@0
|
34 import uk.ac.qmul.eecs.ccmi.xmlparser.Diagram;
|
fiore@0
|
35 import android.content.Intent;
|
fiore@0
|
36 import android.content.res.AssetManager;
|
fiore@0
|
37 import android.os.Bundle;
|
fiore@0
|
38 import android.support.v4.app.DialogFragment;
|
fiore@0
|
39 import android.view.View;
|
fiore@0
|
40 import android.widget.AdapterView;
|
fiore@0
|
41 import android.widget.AdapterView.OnItemClickListener;
|
fiore@0
|
42 import android.widget.AdapterView.OnItemLongClickListener;
|
fiore@0
|
43 import android.widget.ArrayAdapter;
|
fiore@1
|
44 import android.widget.TextView;
|
fiore@0
|
45
|
fiore@0
|
46 /**
|
fiore@0
|
47 *
|
fiore@0
|
48 * The main activity. It displays the diagram through the hierarchical view
|
fiore@0
|
49 * of the <a href="http://ccmi.eecs.qmul.ac.uk"> CCmI Diagram Editor </a>
|
fiore@0
|
50 *
|
fiore@0
|
51 */
|
fiore@0
|
52 public class CcmiEditorAppActivity extends AccessibleActivity implements
|
fiore@0
|
53 OnItemClickListener, OnItemLongClickListener, TreeNavigation.Updateable {
|
fiore@0
|
54 private final static int OPEN_REQUEST = 1;
|
fiore@0
|
55 private final static int SAVE_REQUEST = 2;
|
fiore@0
|
56 private final static String CCMI_EXTENSION = ".ccmi";
|
fiore@0
|
57
|
fiore@0
|
58 private Diagram diagram;
|
fiore@0
|
59 private TreeNavigation navigation;
|
fiore@0
|
60
|
fiore@0
|
61 private String file;
|
fiore@0
|
62 private InputStream in;
|
fiore@0
|
63
|
fiore@0
|
64 public String getName(){
|
fiore@0
|
65 return "";
|
fiore@0
|
66 }
|
fiore@0
|
67
|
fiore@0
|
68 /** Called when the activity is first created. */
|
fiore@0
|
69 @Override
|
fiore@0
|
70 public void onCreate(Bundle savedInstanceState) {
|
fiore@0
|
71 super.onCreate(savedInstanceState);
|
fiore@0
|
72
|
fiore@0
|
73 list.setOnItemClickListener(this);
|
fiore@0
|
74 list.setOnItemLongClickListener(this);
|
fiore@0
|
75
|
fiore@1
|
76
|
fiore@1
|
77 ILogger.log("--- APPLICATION STARTED ---");
|
fiore@1
|
78
|
fiore@1
|
79
|
fiore@0
|
80 /* init assets */
|
fiore@0
|
81 AssetManager assetManager = getAssets();
|
fiore@0
|
82 try {
|
fiore@0
|
83 file = assetManager.list("diagrams")[0];
|
fiore@0
|
84 in = assetManager.open("diagrams/"+file);
|
fiore@0
|
85 readXML(in);
|
fiore@0
|
86 } catch (Exception e) {
|
fiore@0
|
87 e.printStackTrace();
|
fiore@0
|
88 throw new RuntimeException(e);
|
fiore@0
|
89 }
|
fiore@0
|
90 }
|
fiore@0
|
91
|
fiore@0
|
92 /* create a new list and display it */
|
fiore@0
|
93 @Override
|
fiore@0
|
94 public void update(){
|
fiore@0
|
95 /* header */
|
fiore@0
|
96 setHeaderText(navigation.getCurrentItemName());
|
fiore@0
|
97 /* list */
|
fiore@0
|
98 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.list_item_1,navigation.getCurrentChildList());
|
fiore@0
|
99 list.setAdapter(adapter);
|
fiore@0
|
100 }
|
fiore@0
|
101
|
fiore@0
|
102 /*----- listeners to implement the navigation ----*/
|
fiore@0
|
103 @Override
|
fiore@0
|
104 public void onItemClick(AdapterView<?> av, View v, int pos, long id) {
|
fiore@1
|
105 ILogger.logTap(((TextView)v).getText());
|
fiore@0
|
106 if(!navigation.goNext(pos)){
|
fiore@0
|
107 accessibilityService.playSound(AccessibilityService.SoundEvent.V_ERROR);
|
fiore@1
|
108 ILogger.logError("end of tree");
|
fiore@0
|
109 return;
|
fiore@0
|
110 }
|
fiore@0
|
111 accessibilityService.playSound(AccessibilityService.SoundEvent.V_EXPAND);
|
fiore@1
|
112 accessibilityService.speak("displaying " + getHeaderText());
|
fiore@1
|
113 ILogger.logActivity(getHeaderText());
|
fiore@0
|
114 }
|
fiore@0
|
115
|
fiore@0
|
116 /**
|
fiore@0
|
117 * The activity listens to long clicks performed on the list view.
|
fiore@0
|
118 *
|
fiore@0
|
119 * When a user long clicks an item, a dialog is displayed accordingly. For example if the types of nodes and
|
fiore@0
|
120 * edges are listed when the user long clicks, then a dialog for insertion of a new node or edge is displayed.
|
fiore@0
|
121 */
|
fiore@0
|
122 @Override
|
fiore@0
|
123 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
|
fiore@1
|
124 ILogger.logLongTap(((TextView)view).getText());
|
fiore@0
|
125 boolean doneSomething = navigation.getController().performEditAction(parent, view, position, id, this);
|
fiore@1
|
126 if(!doneSomething){
|
fiore@0
|
127 accessibilityService.playSound(AccessibilityService.SoundEvent.V_ERROR);
|
fiore@1
|
128 ILogger.logError("no action available on this item");
|
fiore@1
|
129 }
|
fiore@0
|
130 return doneSomething;
|
fiore@0
|
131 }
|
fiore@0
|
132
|
fiore@0
|
133 /**
|
fiore@0
|
134 * When the back button is pressed the activity will cursor back in the tree
|
fiore@0
|
135 * view, which means the parent of the currently displayed items will be displayed
|
fiore@0
|
136 * together with its siblings.
|
fiore@0
|
137 */
|
fiore@0
|
138 @Override
|
fiore@0
|
139 public void onBackPressed() {
|
fiore@1
|
140 ILogger.logTap("back");
|
fiore@0
|
141 if(navigation.goPrevious()){
|
fiore@0
|
142 accessibilityService.playSound(SoundEvent.V_COLLAPSE);
|
fiore@0
|
143 accessibilityService.speak("Displaying "+getHeaderText());
|
fiore@1
|
144 ILogger.logActivity(getHeaderText());
|
fiore@0
|
145 update();
|
fiore@0
|
146 }else{
|
fiore@0
|
147 accessibilityService.playSound(SoundEvent.V_EDITING_MODE, true);
|
fiore@0
|
148 dialogBuilder.displayDialog(R.layout.alert_dialog_confirm_exit,"Exit Dialog",new AccessibleDialogBuilder.ButtonClickListener() {
|
fiore@0
|
149 @Override
|
fiore@0
|
150 public void onClick(View v, DialogFragment dialogFragment, String tag) {
|
fiore@0
|
151 if("EXIT".equals(v.getTag())){
|
fiore@1
|
152 ILogger.logButton("exit");
|
fiore@0
|
153 accessibilityService.speak(getResources().getString(R.string.exitMessage));
|
fiore@1
|
154 ILogger.log("--- EXIT ---");
|
fiore@1
|
155 ILogger.dispose();
|
fiore@0
|
156 finish();
|
fiore@0
|
157 }else if("CANCEL".equals(v.getTag())){
|
fiore@1
|
158 ILogger.logButton("cancel");
|
fiore@1
|
159 accessibilityService.playSound(SoundEvent.V_CANCEL);
|
fiore@0
|
160 accessibilityService.speak("Cancel");
|
fiore@0
|
161 accessibilityService.stopSound();
|
fiore@0
|
162 dialogFragment.dismiss();
|
fiore@0
|
163 }else if("OPEN".equals(v.getTag())){
|
fiore@1
|
164 ILogger.logButton("open");
|
fiore@0
|
165 /* start the activity to open a file */
|
fiore@0
|
166 Intent intent = new Intent(CcmiEditorAppActivity.this, FileSelectorActivity.Open.class);
|
fiore@0
|
167 intent.putExtra("extension", CCMI_EXTENSION);
|
fiore@0
|
168 startActivityForResult(intent,OPEN_REQUEST);
|
fiore@0
|
169 dialogFragment.dismiss();
|
fiore@0
|
170 }else if("SAVE".equals(v.getTag())){
|
fiore@1
|
171 ILogger.logButton("save");
|
fiore@0
|
172 Intent intent = new Intent(CcmiEditorAppActivity.this, FileSelectorActivity.Save.class);
|
fiore@0
|
173 intent.putExtra("extension", CCMI_EXTENSION);
|
fiore@0
|
174 startActivityForResult(intent,SAVE_REQUEST);
|
fiore@0
|
175 dialogFragment.dismiss();
|
fiore@0
|
176 }
|
fiore@0
|
177 }
|
fiore@0
|
178 });
|
fiore@0
|
179 }
|
fiore@0
|
180 }
|
fiore@0
|
181
|
fiore@0
|
182 @Override
|
fiore@0
|
183 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
fiore@0
|
184 if(resultCode == RESULT_OK){
|
fiore@0
|
185 if(requestCode == OPEN_REQUEST){
|
fiore@0
|
186 try {
|
fiore@0
|
187 InputStream in = new FileInputStream(new File(data.getData().getPath()));
|
fiore@0
|
188 readXML(in);
|
fiore@1
|
189 ILogger.logActivity(navigation.getCurrentPath());
|
fiore@0
|
190 } catch (Exception e) {
|
fiore@0
|
191 accessibilityService.playSound(SoundEvent.V_ERROR);
|
fiore@0
|
192 accessibilityService.speak("File could not be open");
|
fiore@0
|
193 }
|
fiore@0
|
194 }else if(requestCode == SAVE_REQUEST){
|
fiore@0
|
195 try {
|
fiore@0
|
196 String filePath = data.getData().getPath();
|
fiore@0
|
197 String diagramName = data.getData().getLastPathSegment();
|
fiore@0
|
198 /* make sure the extension is .ccmi */
|
fiore@0
|
199 if(!filePath.endsWith(CCMI_EXTENSION)||(CCMI_EXTENSION.equals(diagramName)))
|
fiore@0
|
200 filePath += CCMI_EXTENSION;
|
fiore@0
|
201
|
fiore@0
|
202 /* make sure diagram name doesn't have trailing .ccmi, unless the name is just ".ccmi" */
|
fiore@0
|
203 if(diagramName.endsWith(CCMI_EXTENSION) && !(CCMI_EXTENSION.equals(diagramName))){
|
fiore@0
|
204 diagramName = diagramName.substring(0, diagramName.length()-CCMI_EXTENSION.length());
|
fiore@0
|
205 }
|
fiore@0
|
206
|
fiore@0
|
207 diagram.setName(diagramName);
|
fiore@0
|
208 OutputStream out = new FileOutputStream(new File(filePath));
|
fiore@0
|
209 saveXML(out);
|
fiore@0
|
210 } catch (Exception e) {
|
fiore@0
|
211 accessibilityService.playSound(SoundEvent.V_ERROR);
|
fiore@0
|
212 accessibilityService.speak("File could not be saved");
|
fiore@0
|
213 }
|
fiore@0
|
214 }
|
fiore@0
|
215 }
|
fiore@0
|
216 }
|
fiore@0
|
217
|
fiore@0
|
218 private void saveXML(OutputStream out) throws Exception {
|
fiore@0
|
219 Serializer serializer = new Persister();
|
fiore@0
|
220 serializer.write(diagram, out);
|
fiore@0
|
221 out.close();
|
fiore@0
|
222 navigation = new TreeNavigation(diagram,dialogBuilder,this);
|
fiore@0
|
223 update();
|
fiore@0
|
224 accessibilityService.playSound(SoundEvent.V_OK);
|
fiore@0
|
225 accessibilityService.speak("Filed saved");
|
fiore@0
|
226 }
|
fiore@0
|
227
|
fiore@0
|
228 private void readXML(InputStream in) throws Exception {
|
fiore@0
|
229 Serializer serializer = new Persister();
|
fiore@0
|
230 diagram = serializer.read(Diagram.class, in);
|
fiore@0
|
231 in.close();
|
fiore@0
|
232 navigation = new TreeNavigation(diagram,dialogBuilder,this);
|
fiore@0
|
233 update();
|
fiore@0
|
234 }
|
fiore@0
|
235 }
|
fiore@0
|
236
|