f@0
|
1 /*
|
f@0
|
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
|
f@0
|
3
|
f@0
|
4 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
f@0
|
5
|
f@0
|
6 This program is free software: you can redistribute it and/or modify
|
f@0
|
7 it under the terms of the GNU General Public License as published by
|
f@0
|
8 the Free Software Foundation, either version 3 of the License, or
|
f@0
|
9 (at your option) any later version.
|
f@0
|
10
|
f@0
|
11 This program is distributed in the hope that it will be useful,
|
f@0
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
f@0
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
f@0
|
14 GNU General Public License for more details.
|
f@0
|
15
|
f@0
|
16 You should have received a copy of the GNU General Public License
|
f@0
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
f@0
|
18 */
|
f@0
|
19
|
f@0
|
20 package uk.ac.qmul.eecs.ccmi.main;
|
f@0
|
21
|
f@0
|
22 import java.io.File;
|
f@0
|
23 import java.io.FilenameFilter;
|
f@0
|
24 import java.io.IOException;
|
f@0
|
25 import java.lang.reflect.InvocationTargetException;
|
f@0
|
26 import java.text.MessageFormat;
|
f@0
|
27 import java.util.ResourceBundle;
|
f@0
|
28
|
f@0
|
29 import javax.swing.JOptionPane;
|
f@0
|
30 import javax.swing.SwingUtilities;
|
f@0
|
31 import javax.swing.UIManager;
|
f@0
|
32
|
f@0
|
33 import uk.ac.qmul.eecs.ccmi.gui.Diagram;
|
f@0
|
34 import uk.ac.qmul.eecs.ccmi.gui.EditorFrame;
|
f@0
|
35 import uk.ac.qmul.eecs.ccmi.gui.HapticKindle;
|
f@0
|
36 import uk.ac.qmul.eecs.ccmi.gui.SpeechOptionPane;
|
f@0
|
37 import uk.ac.qmul.eecs.ccmi.gui.TemplateEditor;
|
f@0
|
38 import uk.ac.qmul.eecs.ccmi.haptics.Haptics;
|
f@0
|
39 import uk.ac.qmul.eecs.ccmi.haptics.HapticsFactory;
|
f@0
|
40 import uk.ac.qmul.eecs.ccmi.simpletemplate.SimpleTemplateEditor;
|
f@0
|
41 import uk.ac.qmul.eecs.ccmi.sound.SoundFactory;
|
f@0
|
42 import uk.ac.qmul.eecs.ccmi.speech.NarratorFactory;
|
f@0
|
43 import uk.ac.qmul.eecs.ccmi.utils.CCmIUncaughtExceptionHandler;
|
f@0
|
44 import uk.ac.qmul.eecs.ccmi.utils.InteractionLog;
|
f@0
|
45 import uk.ac.qmul.eecs.ccmi.utils.PreferencesService;
|
f@0
|
46 import uk.ac.qmul.eecs.ccmi.utils.ResourceFileWriter;
|
f@0
|
47
|
f@0
|
48 /**
|
f@0
|
49 *
|
f@0
|
50 * The application class with the main method. The main performs
|
f@0
|
51 * the start up initialization and then displays the graphical user interface.
|
f@0
|
52 *
|
f@0
|
53 */
|
f@0
|
54 public class DiagramEditorApp implements Runnable {
|
f@0
|
55
|
f@0
|
56 /* initialize all the non gui resources */
|
f@0
|
57 private void init() throws IOException {
|
f@0
|
58 Thread.setDefaultUncaughtExceptionHandler(new CCmIUncaughtExceptionHandler());
|
f@0
|
59 final ResourceBundle resources = ResourceBundle.getBundle(DiagramEditorApp.class.getName());
|
f@0
|
60 /* create the home directory if it does not exist and store the path into the preferences */
|
f@0
|
61 PreferencesService preferences = PreferencesService.getInstance();
|
f@0
|
62 String homeDirPath = preferences.get("home", null);
|
f@0
|
63 if(homeDirPath == null){
|
f@0
|
64 homeDirPath = new StringBuilder(System.getProperty("user.home")).append(System.getProperty("file.separator")).append(resources.getString("dir.home")).toString();
|
f@0
|
65 preferences.put("home", homeDirPath);
|
f@0
|
66 }
|
f@0
|
67 File homeDir = new File(homeDirPath);
|
f@0
|
68 mkDir(homeDir, resources);
|
f@0
|
69
|
f@0
|
70 File backupDir = new File(homeDir,resources.getString("dir.backups"));
|
f@0
|
71 mkDir(backupDir, resources);
|
f@0
|
72 backupDirPath = backupDir.getAbsolutePath();
|
f@0
|
73
|
f@0
|
74 /* create the templates directory into the home directory */
|
f@0
|
75 File templateDir = new File(homeDir,resources.getString("dir.templates"));
|
f@0
|
76 mkDir(templateDir,resources);
|
f@0
|
77
|
f@0
|
78 /* create the images directory into the home directory */
|
f@0
|
79 File imagesDir = new File(homeDir,resources.getString("dir.images"));
|
f@0
|
80 mkDir(imagesDir,resources);
|
f@0
|
81 preferences.put("dir.images", imagesDir.getAbsolutePath());
|
f@0
|
82
|
f@0
|
83 /* create the diagrams dir into the home directory */
|
f@0
|
84 File diagramDir = new File(homeDir,resources.getString("dir.diagrams"));
|
f@0
|
85 mkDir(diagramDir,resources);
|
f@0
|
86 preferences.put("dir.diagrams", diagramDir.getAbsolutePath());
|
f@0
|
87
|
f@0
|
88 /* create the libs directory into he home directory */
|
f@0
|
89 File libsDir = new File(homeDir,resources.getString("dir.libs"));
|
f@0
|
90 mkDir(libsDir,resources);
|
f@0
|
91 preferences.put("dir.libs", libsDir.getAbsolutePath());
|
f@0
|
92
|
f@0
|
93 /* write the template files included in the software in the template dir, if they don't exist yet */
|
f@0
|
94 ResourceFileWriter resourceWriter = new ResourceFileWriter(getClass().getResource("UML Diagram.xml"));
|
f@0
|
95 resourceWriter.writeOnDisk(templateDir.getAbsolutePath(),"UML Diagram.xml");
|
f@0
|
96 resourceWriter.setResource(getClass().getResource("Tube.xml"));
|
f@0
|
97 resourceWriter.writeOnDisk(templateDir.getAbsolutePath(),"Tube.xml");
|
f@0
|
98 resourceWriter.setResource(getClass().getResource("Organization Chart.xml"));
|
f@0
|
99 resourceWriter.writeOnDisk(templateDir.getAbsolutePath(),"Organization Chart.xml");
|
f@0
|
100
|
f@0
|
101 /* read the template files into an array to pass to the EditorFrame instance */
|
f@0
|
102 FilenameFilter filter = new FilenameFilter() {
|
f@0
|
103 @Override
|
f@0
|
104 public boolean accept(File f, String name) {
|
f@0
|
105 return (name.endsWith(resources.getString("template.extension")));
|
f@0
|
106 }
|
f@0
|
107 };
|
f@0
|
108 templateFiles = templateDir.listFiles(filter);
|
f@0
|
109 File logDir = new File(homeDir,resources.getString("dir.log"));
|
f@0
|
110 mkDir(logDir,resources);
|
f@0
|
111 preferences.put("dir.log", logDir.getAbsolutePath());
|
f@0
|
112
|
f@0
|
113 String enableLog = preferences.get("enable_log", "false");
|
f@0
|
114 if(Boolean.parseBoolean(enableLog)){
|
f@0
|
115 try{
|
f@0
|
116 InteractionLog.enable(logDir.getAbsolutePath());
|
f@0
|
117 InteractionLog.log("PROGRAM STARTED");
|
f@0
|
118 }catch(IOException ioe){
|
f@0
|
119 /* if logging was enabled, the possibility to log is considered inescapable */
|
f@0
|
120 /* at launch time: do not allow the execution to continue any further */
|
f@0
|
121 throw new RuntimeException(ioe);
|
f@0
|
122 }
|
f@0
|
123 }
|
f@0
|
124
|
f@0
|
125 /* create sound, speech engines */
|
f@0
|
126 NarratorFactory.createInstance();
|
f@0
|
127 SoundFactory.createInstance();
|
f@0
|
128 }
|
f@0
|
129
|
f@0
|
130 /* loads haptic device. If the user is running the software for the first time *
|
f@0
|
131 * they're prompted with a dialog to select the device they want to use */
|
f@0
|
132 private void initHaptics(){
|
f@0
|
133 final PreferencesService preferences = PreferencesService.getInstance();
|
f@0
|
134 if(!Boolean.parseBoolean(preferences.get("haptic_device.initialized", "false"))){
|
f@0
|
135 try {
|
f@0
|
136 SwingUtilities.invokeAndWait(new Runnable(){
|
f@0
|
137 @Override
|
f@0
|
138 public void run() {
|
f@0
|
139 try {
|
f@0
|
140 UIManager.setLookAndFeel(
|
f@0
|
141 UIManager.getSystemLookAndFeelClassName());
|
f@0
|
142 }catch(Exception e){/* nevermind */}
|
f@0
|
143
|
f@0
|
144 String [] hapticDevices = {
|
f@0
|
145 HapticsFactory.PHANTOM_ID,
|
f@0
|
146 HapticsFactory.FALCON_ID,
|
f@0
|
147 HapticsFactory.TABLET_ID};
|
f@0
|
148 String selection = (String)SpeechOptionPane.showSelectionDialog(null,
|
f@0
|
149 ResourceBundle.getBundle(DiagramEditorApp.class.getName()).getString("haptics_init.welcome"),
|
f@0
|
150 hapticDevices,
|
f@0
|
151 hapticDevices[2]);
|
f@0
|
152 if(selection == null)
|
f@0
|
153 System.exit(0);
|
f@0
|
154 preferences.put("haptic_device", selection);
|
f@0
|
155 preferences.put("haptic_device.initialized", "true");
|
f@0
|
156 }
|
f@0
|
157 });
|
f@0
|
158 }catch(InvocationTargetException ite){
|
f@0
|
159 throw new RuntimeException(ite);
|
f@0
|
160 }catch(InterruptedException ie){
|
f@0
|
161 throw new RuntimeException(ie);
|
f@0
|
162 }
|
f@0
|
163 }
|
f@0
|
164
|
f@0
|
165 /* creates the Haptics instance */
|
f@0
|
166 HapticsFactory.createInstance(new HapticKindle());
|
f@0
|
167 haptics = HapticsFactory.getInstance();
|
f@0
|
168 if(haptics.isAlive())
|
f@0
|
169 NarratorFactory.getInstance().speakWholeText("Haptic device successfully initialized");
|
f@0
|
170 }
|
f@0
|
171
|
f@0
|
172 /* return true if the directory was created, false if it existed before */
|
f@0
|
173 private boolean mkDir(File dir,ResourceBundle resources) throws IOException{
|
f@0
|
174 boolean created = dir.mkdir();
|
f@0
|
175 if(!dir.exists())
|
f@0
|
176 throw new IOException(MessageFormat.format(
|
f@0
|
177 resources.getString("dir.error_msg"),
|
f@0
|
178 dir.getAbsolutePath())
|
f@0
|
179 );
|
f@0
|
180 return created;
|
f@0
|
181 }
|
f@0
|
182
|
f@0
|
183 /**
|
f@0
|
184 * build up the GUI and display it
|
f@0
|
185 */
|
f@0
|
186 @Override
|
f@0
|
187 public void run() {
|
f@0
|
188 editorFrame = new EditorFrame(haptics,getTemplateFiles(),backupDirPath,getTemplateEditors(),getDiagrams());
|
f@0
|
189 }
|
f@0
|
190
|
f@0
|
191 /**
|
f@0
|
192 * Provides template editors to create own templates using the diagram editor.
|
f@0
|
193 *
|
f@0
|
194 * Subclasses who don't want any template editor to appear in the diagram
|
f@0
|
195 * can just return an empty array. Returning {@code null} will throw an exception.
|
f@0
|
196 *
|
f@0
|
197 * @return an array of template editors
|
f@0
|
198 */
|
f@0
|
199 protected TemplateEditor[] getTemplateEditors(){
|
f@0
|
200 TemplateEditor[] templateEditors = new TemplateEditor[1];
|
f@0
|
201 templateEditors[0] = new SimpleTemplateEditor();
|
f@0
|
202 return templateEditors;
|
f@0
|
203 }
|
f@0
|
204
|
f@0
|
205 /**
|
f@0
|
206 * Returns the template files detected in the ccmi_editor_data/templates directory.
|
f@0
|
207 *
|
f@0
|
208 * Returning {@code null} will throw an exception.
|
f@0
|
209 *
|
f@0
|
210 * @return an array of (xml) Files containing a template
|
f@0
|
211 */
|
f@0
|
212 protected File[] getTemplateFiles(){
|
f@0
|
213 return templateFiles;
|
f@0
|
214 }
|
f@0
|
215
|
f@0
|
216 /**
|
f@0
|
217 * Returns an empty list. This method can be overwritten by subclasses to
|
f@0
|
218 * provide their own custom diagrams. Such diagrams will appear in the menu.
|
f@0
|
219 *
|
f@0
|
220 * Returning {@code null} will throw an exception.
|
f@0
|
221 *
|
f@0
|
222 * @return an array of diagram templates. The array is empty in this implementation.
|
f@0
|
223 */
|
f@0
|
224 protected Diagram[] getDiagrams(){
|
f@0
|
225 return new Diagram[0];
|
f@0
|
226 }
|
f@0
|
227
|
f@0
|
228 /**
|
f@0
|
229 * The main function
|
f@0
|
230 * @param args this software accepts no args from the command line
|
f@0
|
231 */
|
f@0
|
232 public static void main(String[] args){
|
f@0
|
233 DiagramEditorApp application = new DiagramEditorApp();
|
f@0
|
234 mainImplementation(application);
|
f@0
|
235 }
|
f@0
|
236
|
f@0
|
237
|
f@0
|
238 /**
|
f@0
|
239 * Implementation of the main body. It can be used to run the program
|
f@0
|
240 * using a subclass of {@code DiagramEditorApp}, providing it's own
|
f@0
|
241 * diagram templates
|
f@0
|
242 *
|
f@0
|
243 * @param application the diagram editor application to execute
|
f@0
|
244 */
|
f@0
|
245 public final static void mainImplementation(DiagramEditorApp application) {
|
f@0
|
246 try{
|
f@0
|
247 application.init();
|
f@0
|
248 } catch (IOException e) {
|
f@0
|
249 final String msg = e.getLocalizedMessage();
|
f@0
|
250 try {
|
f@0
|
251 SwingUtilities.invokeAndWait(new Runnable(){
|
f@0
|
252 @Override
|
f@0
|
253 public void run(){
|
f@0
|
254 try {
|
f@0
|
255 UIManager.setLookAndFeel(
|
f@0
|
256 UIManager.getSystemLookAndFeelClassName());
|
f@0
|
257 }catch(Exception e){/* nevermind */}
|
f@0
|
258 JOptionPane.showMessageDialog(null, msg);
|
f@0
|
259 }
|
f@0
|
260 });
|
f@0
|
261 } catch (InterruptedException ex) {
|
f@0
|
262 throw new RuntimeException(ex);
|
f@0
|
263 } catch (InvocationTargetException ex) {
|
f@0
|
264 throw new RuntimeException(ex);
|
f@0
|
265 }
|
f@0
|
266 System.exit(-1);
|
f@0
|
267 }
|
f@0
|
268
|
f@0
|
269 application.initHaptics();
|
f@0
|
270
|
f@0
|
271 /* start the application */
|
f@0
|
272 try {
|
f@0
|
273 SwingUtilities.invokeAndWait(application);
|
f@0
|
274 } catch (InvocationTargetException ex) {
|
f@0
|
275 throw new RuntimeException(ex);
|
f@0
|
276 } catch (InterruptedException ex) {
|
f@0
|
277 throw new RuntimeException(ex);
|
f@0
|
278 }
|
f@0
|
279 }
|
f@0
|
280
|
f@0
|
281 /**
|
f@0
|
282 * Returns the reference to the unique {@code EditorFrame} instance of the program.
|
f@0
|
283 * The main GUI class.
|
f@0
|
284 *
|
f@0
|
285 * @return an reference to {@code EditorFrame}
|
f@0
|
286 */
|
f@0
|
287 public static EditorFrame getFrame(){
|
f@0
|
288 return editorFrame;
|
f@0
|
289 }
|
f@0
|
290
|
f@0
|
291 private static EditorFrame editorFrame;
|
f@0
|
292 Haptics haptics;
|
f@0
|
293 File[] templateFiles;
|
f@0
|
294 TemplateEditor[] templateCreators;
|
f@0
|
295 String backupDirPath;
|
f@0
|
296 }
|
f@0
|
297
|