f@0
|
1 /*
|
f@0
|
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
|
f@0
|
3
|
f@0
|
4 Copyright (C) 2002 Cay S. Horstmann (http://horstmann.com)
|
f@0
|
5 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
f@0
|
6
|
f@0
|
7 This program is free software: you can redistribute it and/or modify
|
f@0
|
8 it under the terms of the GNU General Public License as published by
|
f@0
|
9 the Free Software Foundation, either version 3 of the License, or
|
f@0
|
10 (at your option) any later version.
|
f@0
|
11
|
f@0
|
12 This program is distributed in the hope that it will be useful,
|
f@0
|
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
f@0
|
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
f@0
|
15 GNU General Public License for more details.
|
f@0
|
16
|
f@0
|
17 You should have received a copy of the GNU General Public License
|
f@0
|
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
f@0
|
19 */
|
f@0
|
20
|
f@0
|
21 package uk.ac.qmul.eecs.ccmi.gui;
|
f@0
|
22
|
f@0
|
23 import java.awt.Color;
|
f@0
|
24 import java.awt.Dimension;
|
f@0
|
25 import java.awt.Graphics2D;
|
f@0
|
26 import java.awt.KeyboardFocusManager;
|
f@0
|
27 import java.awt.Toolkit;
|
f@0
|
28 import java.awt.event.ActionEvent;
|
f@0
|
29 import java.awt.event.ActionListener;
|
f@0
|
30 import java.awt.event.WindowAdapter;
|
f@0
|
31 import java.awt.event.WindowEvent;
|
f@0
|
32 import java.awt.event.WindowFocusListener;
|
f@0
|
33 import java.awt.geom.Rectangle2D;
|
f@0
|
34 import java.awt.image.BufferedImage;
|
f@0
|
35 import java.io.BufferedInputStream;
|
f@0
|
36 import java.io.BufferedOutputStream;
|
f@0
|
37 import java.io.BufferedReader;
|
f@0
|
38 import java.io.ByteArrayInputStream;
|
f@0
|
39 import java.io.File;
|
f@0
|
40 import java.io.FileOutputStream;
|
f@0
|
41 import java.io.IOException;
|
f@0
|
42 import java.io.InputStream;
|
f@0
|
43 import java.io.InputStreamReader;
|
f@0
|
44 import java.io.OutputStream;
|
f@0
|
45 import java.net.InetSocketAddress;
|
f@0
|
46 import java.net.URL;
|
f@0
|
47 import java.nio.channels.SocketChannel;
|
f@0
|
48 import java.text.MessageFormat;
|
f@0
|
49 import java.text.SimpleDateFormat;
|
f@0
|
50 import java.util.ArrayList;
|
f@0
|
51 import java.util.Arrays;
|
f@0
|
52 import java.util.Date;
|
f@0
|
53 import java.util.ResourceBundle;
|
f@0
|
54 import java.util.Set;
|
f@0
|
55 import java.util.concurrent.ExecutionException;
|
f@0
|
56 import java.util.regex.Matcher;
|
f@0
|
57 import java.util.regex.Pattern;
|
f@0
|
58
|
f@0
|
59 import javax.imageio.ImageIO;
|
f@0
|
60 import javax.swing.ImageIcon;
|
f@0
|
61 import javax.swing.JCheckBoxMenuItem;
|
f@0
|
62 import javax.swing.JFrame;
|
f@0
|
63 import javax.swing.JMenu;
|
f@0
|
64 import javax.swing.JMenuBar;
|
f@0
|
65 import javax.swing.JMenuItem;
|
f@0
|
66 import javax.swing.JTree;
|
f@0
|
67 import javax.swing.SwingUtilities;
|
f@0
|
68 import javax.swing.UIManager;
|
f@0
|
69 import javax.swing.UnsupportedLookAndFeelException;
|
f@0
|
70 import javax.swing.event.ChangeEvent;
|
f@0
|
71 import javax.swing.event.ChangeListener;
|
f@0
|
72 import javax.swing.event.MenuEvent;
|
f@0
|
73 import javax.swing.event.MenuListener;
|
f@0
|
74 import javax.swing.event.TreeSelectionEvent;
|
f@0
|
75 import javax.swing.event.TreeSelectionListener;
|
f@0
|
76 import javax.swing.tree.TreePath;
|
f@0
|
77
|
f@0
|
78 import uk.ac.qmul.eecs.ccmi.diagrammodel.ConnectNodesException;
|
f@0
|
79 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramElement;
|
f@0
|
80 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramTreeNode;
|
f@0
|
81 import uk.ac.qmul.eecs.ccmi.diagrammodel.EdgeReferenceMutableTreeNode;
|
f@0
|
82 import uk.ac.qmul.eecs.ccmi.diagrammodel.NodeProperties.Modifiers;
|
f@0
|
83 import uk.ac.qmul.eecs.ccmi.diagrammodel.NodeReferenceMutableTreeNode;
|
f@0
|
84 import uk.ac.qmul.eecs.ccmi.diagrammodel.PropertyMutableTreeNode;
|
f@0
|
85 import uk.ac.qmul.eecs.ccmi.diagrammodel.PropertyTypeMutableTreeNode;
|
f@0
|
86 import uk.ac.qmul.eecs.ccmi.diagrammodel.TypeMutableTreeNode;
|
f@0
|
87 import uk.ac.qmul.eecs.ccmi.gui.awareness.BroadcastFilter;
|
f@0
|
88 import uk.ac.qmul.eecs.ccmi.gui.awareness.DisplayFilter;
|
f@0
|
89 import uk.ac.qmul.eecs.ccmi.gui.persistence.PersistenceManager;
|
f@0
|
90 import uk.ac.qmul.eecs.ccmi.haptics.Haptics;
|
f@0
|
91 import uk.ac.qmul.eecs.ccmi.haptics.HapticsFactory;
|
f@0
|
92 import uk.ac.qmul.eecs.ccmi.network.AwarenessMessage;
|
f@0
|
93 import uk.ac.qmul.eecs.ccmi.network.ClientConnectionManager;
|
f@0
|
94 import uk.ac.qmul.eecs.ccmi.network.ClientConnectionManager.RmDiagramRequest;
|
f@0
|
95 import uk.ac.qmul.eecs.ccmi.network.ClientConnectionManager.SendAwarenessRequest;
|
f@0
|
96 import uk.ac.qmul.eecs.ccmi.network.Command;
|
f@0
|
97 import uk.ac.qmul.eecs.ccmi.network.DiagramDownloader;
|
f@0
|
98 import uk.ac.qmul.eecs.ccmi.network.DiagramEventActionSource;
|
f@0
|
99 import uk.ac.qmul.eecs.ccmi.network.DiagramShareException;
|
f@0
|
100 import uk.ac.qmul.eecs.ccmi.network.NetDiagram;
|
f@0
|
101 import uk.ac.qmul.eecs.ccmi.network.ProtocolFactory;
|
f@0
|
102 import uk.ac.qmul.eecs.ccmi.network.Server;
|
f@0
|
103 import uk.ac.qmul.eecs.ccmi.pdsupport.PdDiagram;
|
f@0
|
104 import uk.ac.qmul.eecs.ccmi.pdsupport.PdPersistenceManager;
|
f@0
|
105 import uk.ac.qmul.eecs.ccmi.sound.PlayerListener;
|
f@0
|
106 import uk.ac.qmul.eecs.ccmi.sound.SoundEvent;
|
f@0
|
107 import uk.ac.qmul.eecs.ccmi.sound.SoundFactory;
|
f@0
|
108 import uk.ac.qmul.eecs.ccmi.speech.Narrator;
|
f@0
|
109 import uk.ac.qmul.eecs.ccmi.speech.NarratorFactory;
|
f@0
|
110 import uk.ac.qmul.eecs.ccmi.utils.ExceptionHandler;
|
f@0
|
111 import uk.ac.qmul.eecs.ccmi.utils.InteractionLog;
|
f@0
|
112 import uk.ac.qmul.eecs.ccmi.utils.PreferencesService;
|
f@0
|
113
|
f@0
|
114 /**
|
f@0
|
115 * The main frame of the editor which contains diagram panes that show graphs and
|
f@0
|
116 * tree representations of diagrams.
|
f@0
|
117 */
|
f@0
|
118 @SuppressWarnings("serial")
|
f@0
|
119 public class EditorFrame extends JFrame {
|
f@0
|
120 /**
|
f@0
|
121 * Creates a new {@code EditorFrame}
|
f@0
|
122 *
|
f@0
|
123 * @param haptics an instance of {@code Haptics} handling the haptic device during this
|
f@0
|
124 * @param templateFiles an array of template files. New diagrams can be created from template files by clonation
|
f@0
|
125 * @param backupDirPath the path of a folder where all the currently open diagrams will be saved if
|
f@0
|
126 * the haptic device crashes
|
f@0
|
127 * @param templateEditors the template editors for this instance of the program
|
f@0
|
128 * @param additionalTemplate additional diagram templates. An entry will be created in {@code File->New Diagram}
|
f@0
|
129 * for each template
|
f@0
|
130 */
|
f@0
|
131 public EditorFrame(Haptics haptics, File[] templateFiles, String backupDirPath, TemplateEditor[] templateEditors, Diagram[] additionalTemplate){
|
f@0
|
132 this.backupDirPath = backupDirPath;
|
f@0
|
133 /* load resources */
|
f@0
|
134 resources = ResourceBundle.getBundle(this.getClass().getName());
|
f@0
|
135
|
f@0
|
136 /* haptics */
|
f@0
|
137 this.haptics = haptics;
|
f@0
|
138 hapticTrigger = new HapticTrigger();
|
f@0
|
139
|
f@0
|
140 /* read editor related preferences */
|
f@0
|
141 preferences = PreferencesService.getInstance();
|
f@0
|
142
|
f@0
|
143 URL url = getClass().getResource("ccmi_favicon.gif");
|
f@0
|
144 setIconImage(new ImageIcon(url).getImage());
|
f@0
|
145 changeLookAndFeel(preferences.get("laf", null));
|
f@0
|
146
|
f@0
|
147 recentFiles = new ArrayList<String>();
|
f@0
|
148 File lastDir = new File(".");
|
f@0
|
149 String recent = preferences.get("recent", "").trim();
|
f@0
|
150 if (recent.length() > 0){
|
f@0
|
151 recentFiles.addAll(Arrays.asList(recent.split("[|]")));
|
f@0
|
152 lastDir = new File(recentFiles.get(0)).getParentFile();
|
f@0
|
153 }
|
f@0
|
154 fileService = new FileService.ChooserService(lastDir);
|
f@0
|
155
|
f@0
|
156 /* set up extensions */
|
f@0
|
157 defaultExtension = resources.getString("files.extension");
|
f@0
|
158 extensionFilter = new ExtensionFilter(
|
f@0
|
159 resources.getString("files.name"),
|
f@0
|
160 new String[] { defaultExtension });
|
f@0
|
161 exportFilter = new ExtensionFilter(
|
f@0
|
162 resources.getString("files.image.name"),
|
f@0
|
163 resources.getString("files.image.extension"));
|
f@0
|
164
|
f@0
|
165 /* start building the GUI */
|
f@0
|
166 editorTabbedPane = new EditorTabbedPane(this);
|
f@0
|
167 setContentPane(editorTabbedPane);
|
f@0
|
168
|
f@0
|
169
|
f@0
|
170 setTitle(resources.getString("app.name"));
|
f@0
|
171 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
|
f@0
|
172
|
f@0
|
173 int screenWidth = (int)screenSize.getWidth();
|
f@0
|
174 int screenHeight = (int)screenSize.getHeight();
|
f@0
|
175
|
f@0
|
176 setLocation(screenWidth / 16, screenHeight / 16);
|
f@0
|
177 editorTabbedPane.setPreferredSize(new Dimension(
|
f@0
|
178 screenWidth * 5 / 8, screenHeight * 5 / 8));
|
f@0
|
179
|
f@0
|
180 /* install the player listener (a narrator speech) for CANCEL, EMPTY and MESSAGE ok event. They are *
|
f@0
|
181 * not depending on what the user is doing and the speech is therefore always the same. We only need *
|
f@0
|
182 * to set the listener once and it will do the job each time the sound is triggered */
|
f@0
|
183 SoundFactory.getInstance().setDefaultPlayerListener(new PlayerListener(){
|
f@0
|
184 @Override
|
f@0
|
185 public void playEnded() {
|
f@0
|
186 DiagramPanel dPanel = getActiveTab();
|
f@0
|
187 if(dPanel != null){// we can cancel a dialog even when no diagram is open (e.g. for tcp connections)
|
f@0
|
188 speakFocusedComponent("");
|
f@0
|
189 }else{
|
f@0
|
190 NarratorFactory.getInstance().speak(MessageFormat.format(resources.getString("speech.cancelled"),""));
|
f@0
|
191 }
|
f@0
|
192 }
|
f@0
|
193 }, SoundEvent.CANCEL);
|
f@0
|
194 SoundFactory.getInstance().setDefaultPlayerListener(new PlayerListener(){
|
f@0
|
195 @Override
|
f@0
|
196 public void playEnded() {
|
f@0
|
197 DiagramPanel dPanel = getActiveTab();
|
f@0
|
198 DiagramTree tree = dPanel.getTree();
|
f@0
|
199 NarratorFactory.getInstance().speak(MessageFormat.format(resources.getString("speech.empty_property"),tree.currentPathSpeech()));
|
f@0
|
200 }
|
f@0
|
201 }, SoundEvent.EMPTY);
|
f@0
|
202 SoundFactory.getInstance().setDefaultPlayerListener(new PlayerListener(){
|
f@0
|
203 @Override
|
f@0
|
204 public void playEnded() {
|
f@0
|
205 DiagramPanel dPanel = getActiveTab();
|
f@0
|
206 if(dPanel != null){
|
f@0
|
207 DiagramTree tree = dPanel.getTree();
|
f@0
|
208 NarratorFactory.getInstance().speak(tree.currentPathSpeech());
|
f@0
|
209 }
|
f@0
|
210 }
|
f@0
|
211 }, SoundEvent.MESSAGE_OK);
|
f@0
|
212
|
f@0
|
213 /* setup listeners */
|
f@0
|
214 initListeners();
|
f@0
|
215 /* set up menus */
|
f@0
|
216 existingTemplateNames = new ArrayList<String>(10);
|
f@0
|
217 existingTemplates = new ArrayList<Diagram>(10);
|
f@0
|
218 int extensionLength = resources.getString("template.extension").length();
|
f@0
|
219 for(File file : templateFiles){
|
f@0
|
220 existingTemplateNames.add(file.getName().substring(0, file.getName().length()-extensionLength));
|
f@0
|
221 }
|
f@0
|
222 initMenu(templateEditors);
|
f@0
|
223 /* read template files. this call must be placed after menu creation as it adds menu items to file->new-> */
|
f@0
|
224 boolean someTemplateFilesNotRead = readTemplateFiles(templateFiles);
|
f@0
|
225
|
f@0
|
226 for(Diagram additionalDiagram : additionalTemplate){
|
f@0
|
227 addDiagramType(additionalDiagram);
|
f@0
|
228 }
|
f@0
|
229
|
f@0
|
230 /* become visible */
|
f@0
|
231 pack();
|
f@0
|
232 setVisible(true);
|
f@0
|
233 /* if some templates were not read successfully, warn the user with a message */
|
f@0
|
234 if(someTemplateFilesNotRead){
|
f@0
|
235 SpeechOptionPane.showMessageDialog(this, resources.getString("dialog.error.filesnotread"), SpeechOptionPane.WARNING_MESSAGE);
|
f@0
|
236 }
|
f@0
|
237 }
|
f@0
|
238
|
f@0
|
239 private void initListeners(){
|
f@0
|
240 /* window closing */
|
f@0
|
241 setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
f@0
|
242 addWindowListener(new WindowAdapter(){
|
f@0
|
243 @Override
|
f@0
|
244 public void windowClosing(WindowEvent event){
|
f@0
|
245 exit();
|
f@0
|
246 }
|
f@0
|
247 @Override
|
f@0
|
248 public void windowOpened(WindowEvent e) {
|
f@0
|
249 // bring the window to front, else the openGL window would have higher priority
|
f@0
|
250 e.getWindow().toFront();
|
f@0
|
251 }
|
f@0
|
252 });
|
f@0
|
253
|
f@0
|
254 addWindowFocusListener(new WindowFocusListener(){
|
f@0
|
255 @Override
|
f@0
|
256 public void windowGainedFocus(WindowEvent evt) {
|
f@0
|
257 if(evt.getOppositeWindow() == null)
|
f@0
|
258 NarratorFactory.getInstance().speak(resources.getString("window.focus"));
|
f@0
|
259 }
|
f@0
|
260
|
f@0
|
261 @Override
|
f@0
|
262 public void windowLostFocus(WindowEvent evt) {
|
f@0
|
263 if(evt.getOppositeWindow() == null)
|
f@0
|
264 NarratorFactory.getInstance().speak(resources.getString("window.unfocus"));
|
f@0
|
265 }
|
f@0
|
266 });
|
f@0
|
267
|
f@0
|
268 /* set up listeners reacting to change of selection in the tree and tab */
|
f@0
|
269 tabChangeListener = new ChangeListener(){
|
f@0
|
270 @Override
|
f@0
|
271 public void stateChanged(ChangeEvent evt) {
|
f@0
|
272 DiagramPanel diagramPanel = getActiveTab();
|
f@0
|
273 if (diagramPanel != null){
|
f@0
|
274 /* give the focus to the Content Pane, otherwise it's grabbed by the rootPane */
|
f@0
|
275 getContentPane().requestFocusInWindow();
|
f@0
|
276 TreePath path = diagramPanel.getTree().getSelectionPath();
|
f@0
|
277 treeEnabledMenuUpdate(path);
|
f@0
|
278 NarratorFactory.getInstance().speak(MessageFormat.format(resources.getString("window.tab"),editorTabbedPane.getTitleAt(editorTabbedPane.getSelectedIndex())));
|
f@0
|
279
|
f@0
|
280 // updated the haptics
|
f@0
|
281 HapticsFactory.getInstance().switchDiagram(diagramPanel.getDiagram().getName());
|
f@0
|
282 iLog("diagram tab changed to "+editorTabbedPane.getTitleAt(editorTabbedPane.getSelectedIndex()));
|
f@0
|
283 }else{
|
f@0
|
284 treeEnabledMenuUpdate(null);
|
f@0
|
285 }
|
f@0
|
286 /* if we change tab, the haptic highlight must be set again */
|
f@0
|
287 selectHapticHighligh(null);
|
f@0
|
288 /* so do the menu depending on the panel */
|
f@0
|
289 diagramPanelEnabledMenuUpdate(diagramPanel);
|
f@0
|
290 }
|
f@0
|
291 };
|
f@0
|
292 editorTabbedPane.addChangeListener(tabChangeListener);
|
f@0
|
293
|
f@0
|
294 treeSelectionListener = new TreeSelectionListener(){
|
f@0
|
295 @Override
|
f@0
|
296 public void valueChanged(TreeSelectionEvent evt) {
|
f@0
|
297 treeEnabledMenuUpdate(evt.getPath());
|
f@0
|
298 }
|
f@0
|
299 };
|
f@0
|
300
|
f@0
|
301 netLocalDiagramExceptionHandler = new ExceptionHandler(){
|
f@0
|
302 @Override
|
f@0
|
303 public void handleException(Exception e) {
|
f@0
|
304 SwingUtilities.invokeLater(new Runnable(){
|
f@0
|
305 @Override
|
f@0
|
306 public void run() {
|
f@0
|
307 SpeechOptionPane.showMessageDialog(EditorFrame.this, resources.getString("dialog.error.local_server"));
|
f@0
|
308 }
|
f@0
|
309 });
|
f@0
|
310 }
|
f@0
|
311 };
|
f@0
|
312 }
|
f@0
|
313
|
f@0
|
314 private void initMenu(TemplateEditor[] templateEditors){
|
f@0
|
315 ResourceFactory factory = new ResourceFactory(resources);
|
f@0
|
316
|
f@0
|
317 JMenuBar menuBar = SpeechMenuFactory.getMenuBar();
|
f@0
|
318 setJMenuBar(menuBar);
|
f@0
|
319
|
f@0
|
320 /* --- FILE MENU --- */
|
f@0
|
321 JMenu fileMenu = factory.createMenu("file");
|
f@0
|
322 menuBar.add(fileMenu);
|
f@0
|
323
|
f@0
|
324 /* menu items and listener added by addDiagramType function */
|
f@0
|
325 newMenu = factory.createMenu("file.new");
|
f@0
|
326 fileMenu.add(newMenu);
|
f@0
|
327
|
f@0
|
328 JMenuItem fileOpenItem = factory.createMenuItem(
|
f@0
|
329 "file.open", this, "openFile");
|
f@0
|
330 fileMenu.add(fileOpenItem);
|
f@0
|
331
|
f@0
|
332 recentFilesMenu = factory.createMenu("file.recent");
|
f@0
|
333 buildRecentFilesMenu();
|
f@0
|
334 fileMenu.add(recentFilesMenu);
|
f@0
|
335
|
f@0
|
336 fileSaveItem = factory.createMenuItem("file.save", this, "saveFile");
|
f@0
|
337 fileMenu.add(fileSaveItem);
|
f@0
|
338
|
f@0
|
339 fileSaveAsItem = factory.createMenuItem("file.save_as", this, "saveFileAs");
|
f@0
|
340 fileMenu.add(fileSaveAsItem);
|
f@0
|
341
|
f@0
|
342 fileSaveCopyItem = factory.createMenuItem("file.save_copy", this, "saveCopy");
|
f@0
|
343 fileMenu.add(fileSaveCopyItem);
|
f@0
|
344
|
f@0
|
345 fileCloseItem = factory.createMenuItem("file.close",this,"closeFile");
|
f@0
|
346 fileMenu.add(fileCloseItem);
|
f@0
|
347
|
f@0
|
348 graphExportItem = factory.createMenuItem("file.export_image", this, "exportImage");
|
f@0
|
349 fileMenu.add(graphExportItem);
|
f@0
|
350
|
f@0
|
351 JMenuItem fileExitItem = factory.createMenuItem(
|
f@0
|
352 "file.exit", this, "exit");
|
f@0
|
353 fileMenu.add(fileExitItem);
|
f@0
|
354
|
f@0
|
355 /* --- EDIT MENU --- */
|
f@0
|
356 JMenu editMenu = factory.createMenu("edit");
|
f@0
|
357 menuBar.add(editMenu);
|
f@0
|
358
|
f@0
|
359 locateMenuItem = factory.createMenuItem("edit.locate", this,"locate");
|
f@0
|
360 editMenu.add(locateMenuItem);
|
f@0
|
361
|
f@0
|
362 highlightMenuItem = factory.createMenuItem("edit.highlight", this, "hHighlight");
|
f@0
|
363 highlightMenuItem.setEnabled(false);
|
f@0
|
364 editMenu.add(highlightMenuItem);
|
f@0
|
365
|
f@0
|
366 jumpMenuItem = factory.createMenuItem("edit.jump",this,"jump");
|
f@0
|
367 editMenu.add(jumpMenuItem);
|
f@0
|
368
|
f@0
|
369 insertMenuItem = factory.createMenuItem("edit.insert", this, "insert");
|
f@0
|
370 editMenu.add(insertMenuItem);
|
f@0
|
371
|
f@0
|
372 deleteMenuItem = factory.createMenuItem("edit.delete",this,"delete");
|
f@0
|
373 editMenu.add(deleteMenuItem);
|
f@0
|
374
|
f@0
|
375 renameMenuItem = factory.createMenuItem("edit.rename",this,"rename");
|
f@0
|
376 editMenu.add(renameMenuItem);
|
f@0
|
377
|
f@0
|
378 selectMenuItem = factory.createMenuItem("edit.select", this, "selectNode");
|
f@0
|
379 editMenu.add(selectMenuItem);
|
f@0
|
380
|
f@0
|
381 bookmarkMenuItem = factory.createMenuItem("edit.bookmark",this,"editBookmarks");
|
f@0
|
382 editMenu.add(bookmarkMenuItem);
|
f@0
|
383
|
f@0
|
384 editNotesMenuItem = factory.createMenuItem("edit.edit_note",this,"editNotes");
|
f@0
|
385 editMenu.add(editNotesMenuItem);
|
f@0
|
386
|
f@0
|
387 /* --- VIEW MENU --- */
|
f@0
|
388 JMenu viewMenu = factory.createMenu("view");
|
f@0
|
389 menuBar.add(viewMenu);
|
f@0
|
390
|
f@0
|
391 viewMenu.add(factory.createMenuItem(
|
f@0
|
392 "view.zoom_out", new
|
f@0
|
393 ActionListener(){
|
f@0
|
394 public void actionPerformed(ActionEvent event){
|
f@0
|
395 DiagramPanel dPanel = getActiveTab();
|
f@0
|
396 if (dPanel == null)
|
f@0
|
397 return;
|
f@0
|
398 dPanel.getGraphPanel().changeZoom(-1);
|
f@0
|
399 }
|
f@0
|
400 }));
|
f@0
|
401
|
f@0
|
402 viewMenu.add(factory.createMenuItem(
|
f@0
|
403 "view.zoom_in", new
|
f@0
|
404 ActionListener(){
|
f@0
|
405 public void actionPerformed(ActionEvent event){
|
f@0
|
406 DiagramPanel dPanel = getActiveTab();
|
f@0
|
407 if (dPanel == null)
|
f@0
|
408 return;
|
f@0
|
409 dPanel.getGraphPanel().changeZoom(1);
|
f@0
|
410 }
|
f@0
|
411 }));
|
f@0
|
412
|
f@0
|
413 viewMenu.add(factory.createMenuItem(
|
f@0
|
414 "view.grow_drawing_area", new
|
f@0
|
415 ActionListener(){
|
f@0
|
416 public void actionPerformed(ActionEvent event){
|
f@0
|
417 DiagramPanel dPanel = getActiveTab();
|
f@0
|
418 if (dPanel == null)
|
f@0
|
419 return;
|
f@0
|
420 GraphPanel gPanel = dPanel.getGraphPanel();
|
f@0
|
421 Rectangle2D bounds = gPanel.getGraphBounds();
|
f@0
|
422 bounds.add(gPanel.getBounds());
|
f@0
|
423 gPanel.setMinBounds(new Rectangle2D.Double(0, 0,
|
f@0
|
424 GROW_SCALE_FACTOR * bounds.getWidth(),
|
f@0
|
425 GROW_SCALE_FACTOR * bounds.getHeight()));
|
f@0
|
426 gPanel.revalidate();
|
f@0
|
427 gPanel.repaint();
|
f@0
|
428 }
|
f@0
|
429 }));
|
f@0
|
430
|
f@0
|
431 viewMenu.add(factory.createMenuItem(
|
f@0
|
432 "view.clip_drawing_area", new
|
f@0
|
433 ActionListener(){
|
f@0
|
434 public void actionPerformed(ActionEvent event){
|
f@0
|
435 DiagramPanel dPanel = getActiveTab();
|
f@0
|
436 if (dPanel == null)
|
f@0
|
437 return;
|
f@0
|
438 GraphPanel gPanel = dPanel.getGraphPanel();
|
f@0
|
439 gPanel.setMinBounds(null);
|
f@0
|
440 gPanel.revalidate();
|
f@0
|
441 gPanel.repaint();
|
f@0
|
442 }
|
f@0
|
443 }));
|
f@0
|
444
|
f@0
|
445 viewMenu.add(factory.createMenuItem(
|
f@0
|
446 "view.smaller_grid", new
|
f@0
|
447 ActionListener()
|
f@0
|
448 {
|
f@0
|
449 public void actionPerformed(ActionEvent event)
|
f@0
|
450 {
|
f@0
|
451 DiagramPanel dPanel = getActiveTab();
|
f@0
|
452 if (dPanel == null)
|
f@0
|
453 return;
|
f@0
|
454 dPanel.getGraphPanel().changeGridSize(-1);
|
f@0
|
455 }
|
f@0
|
456 }));
|
f@0
|
457
|
f@0
|
458 viewMenu.add(factory.createMenuItem(
|
f@0
|
459 "view.larger_grid", new
|
f@0
|
460 ActionListener(){
|
f@0
|
461 public void actionPerformed(ActionEvent event){
|
f@0
|
462 DiagramPanel dPanel = getActiveTab();
|
f@0
|
463 if (dPanel == null)
|
f@0
|
464 return;
|
f@0
|
465 dPanel.getGraphPanel().changeGridSize(1);
|
f@0
|
466 }
|
f@0
|
467 }));
|
f@0
|
468
|
f@0
|
469 final JCheckBoxMenuItem hideGridItem;
|
f@0
|
470 viewMenu.add(hideGridItem = (JCheckBoxMenuItem) factory.createCheckBoxMenuItem(
|
f@0
|
471 "view.hide_grid", new
|
f@0
|
472 ActionListener()
|
f@0
|
473 {
|
f@0
|
474 public void actionPerformed(ActionEvent event)
|
f@0
|
475 {
|
f@0
|
476 DiagramPanel dPanel = getActiveTab();
|
f@0
|
477 if (dPanel == null)
|
f@0
|
478 return;
|
f@0
|
479 JCheckBoxMenuItem menuItem = (JCheckBoxMenuItem) event.getSource();
|
f@0
|
480 dPanel.getGraphPanel().setHideGrid(menuItem.isSelected());
|
f@0
|
481 }
|
f@0
|
482 }));
|
f@0
|
483
|
f@0
|
484 viewMenu.addMenuListener(new
|
f@0
|
485 MenuListener(){
|
f@0
|
486 /* changes the checkbox according to the diagram selected */
|
f@0
|
487 public void menuSelected(MenuEvent event){
|
f@0
|
488 DiagramPanel dPanel = getActiveTab();
|
f@0
|
489 if (dPanel == null)
|
f@0
|
490 return;
|
f@0
|
491 hideGridItem.setSelected(dPanel.getGraphPanel().getHideGrid());
|
f@0
|
492 }
|
f@0
|
493 public void menuDeselected(MenuEvent event){}
|
f@0
|
494 public void menuCanceled(MenuEvent event){}
|
f@0
|
495 });
|
f@0
|
496
|
f@0
|
497 JMenu lafMenu = factory.createMenu("view.change_laf");
|
f@0
|
498 viewMenu.add(lafMenu);
|
f@0
|
499
|
f@0
|
500 UIManager.LookAndFeelInfo[] infos =
|
f@0
|
501 UIManager.getInstalledLookAndFeels();
|
f@0
|
502 for (int i = 0; i < infos.length; i++){
|
f@0
|
503 final UIManager.LookAndFeelInfo info = infos[i];
|
f@0
|
504 JMenuItem item = SpeechMenuFactory.getMenuItem(info.getName());
|
f@0
|
505 lafMenu.add(item);
|
f@0
|
506 item.addActionListener(new
|
f@0
|
507 ActionListener(){
|
f@0
|
508 public void actionPerformed(ActionEvent event){
|
f@0
|
509 String laf = info.getClassName();
|
f@0
|
510 changeLookAndFeel(laf);
|
f@0
|
511 preferences.put("laf", laf);
|
f@0
|
512 }
|
f@0
|
513 });
|
f@0
|
514 }
|
f@0
|
515
|
f@0
|
516 /* --- TEMPLATE --- */
|
f@0
|
517 if(templateEditors.length > 0){
|
f@0
|
518 JMenu templateMenu = factory.createMenu("template");
|
f@0
|
519 menuBar.add(templateMenu);
|
f@0
|
520
|
f@0
|
521 for(final TemplateEditor templateEditor : templateEditors){
|
f@0
|
522 JMenuItem newDiagramItem = SpeechMenuFactory.getMenuItem(templateEditor.getLabelForNew());
|
f@0
|
523 newDiagramItem.addActionListener(new ActionListener(){
|
f@0
|
524 @Override
|
f@0
|
525 public void actionPerformed(ActionEvent evt) {
|
f@0
|
526 Diagram diagram = templateEditor.createNew(EditorFrame.this, existingTemplateNames);
|
f@0
|
527 if(diagram == null)
|
f@0
|
528 return;
|
f@0
|
529 try{
|
f@0
|
530 saveDiagramTemplate(diagram);
|
f@0
|
531 }catch(IOException ioe){
|
f@0
|
532 SpeechOptionPane.showMessageDialog(
|
f@0
|
533 EditorFrame.this,
|
f@0
|
534 resources.getString("dialog.error.save_template"));
|
f@0
|
535 return;
|
f@0
|
536 }
|
f@0
|
537 addDiagramType(diagram);
|
f@0
|
538 SpeechOptionPane.showMessageDialog(
|
f@0
|
539 EditorFrame.this,
|
f@0
|
540 MessageFormat.format(resources.getString("dialog.template_created"), diagram.getName()),
|
f@0
|
541 SpeechOptionPane.INFORMATION_MESSAGE);
|
f@0
|
542 SoundFactory.getInstance().play(SoundEvent.OK,null);
|
f@0
|
543 }
|
f@0
|
544 });
|
f@0
|
545 templateMenu.add(newDiagramItem);
|
f@0
|
546
|
f@0
|
547 JMenuItem editDiagramItem = SpeechMenuFactory.getMenuItem(templateEditor.getLabelForEdit());
|
f@0
|
548 editDiagramItem.addActionListener(new ActionListener(){
|
f@0
|
549 @Override
|
f@0
|
550 public void actionPerformed(ActionEvent evt){
|
f@0
|
551 if(existingTemplates.isEmpty()){
|
f@0
|
552 NarratorFactory.getInstance().speak(resources.getString("dialog.error.no_template_to_edit"));
|
f@0
|
553 return;
|
f@0
|
554 }
|
f@0
|
555 Diagram[] diagrams = new Diagram[existingTemplates.size()];
|
f@0
|
556 diagrams = existingTemplates.toArray(diagrams);
|
f@0
|
557 Diagram selectedDiagram = (Diagram)SpeechOptionPane.showSelectionDialog(
|
f@0
|
558 EditorFrame.this,
|
f@0
|
559 resources.getString("dialog.input.edit_diagram_template"),
|
f@0
|
560 diagrams,
|
f@0
|
561 diagrams[0]);
|
f@0
|
562
|
f@0
|
563 if(selectedDiagram == null){
|
f@0
|
564 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
565 return;
|
f@0
|
566 }
|
f@0
|
567
|
f@0
|
568 Diagram diagram = templateEditor.edit(EditorFrame.this, existingTemplateNames,selectedDiagram);
|
f@0
|
569 if(diagram == null)
|
f@0
|
570 return;
|
f@0
|
571 try{
|
f@0
|
572 saveDiagramTemplate(diagram);
|
f@0
|
573 }catch(IOException ioe){
|
f@0
|
574 SpeechOptionPane.showMessageDialog(
|
f@0
|
575 EditorFrame.this,
|
f@0
|
576 resources.getString("dialog.error.save_template"));
|
f@0
|
577 return;
|
f@0
|
578 }
|
f@0
|
579 addDiagramType(diagram);
|
f@0
|
580 SpeechOptionPane.showMessageDialog(
|
f@0
|
581 EditorFrame.this,
|
f@0
|
582 MessageFormat.format(resources.getString("dialog.template_created"), diagram.getName()),
|
f@0
|
583 SpeechOptionPane.INFORMATION_MESSAGE);
|
f@0
|
584 SoundFactory.getInstance().play(SoundEvent.OK,null);
|
f@0
|
585 }
|
f@0
|
586 }
|
f@0
|
587 );
|
f@0
|
588 templateMenu.add(editDiagramItem);
|
f@0
|
589 }
|
f@0
|
590 }
|
f@0
|
591
|
f@0
|
592 /* --- COLLABORATION ---- */
|
f@0
|
593 JMenu collabMenu = factory.createMenu("collab");
|
f@0
|
594 menuBar.add(collabMenu);
|
f@0
|
595
|
f@0
|
596 startServerMenuItem = factory.createMenuItem("collab.start_server", this, "startServer");
|
f@0
|
597 collabMenu.add(startServerMenuItem);
|
f@0
|
598
|
f@0
|
599 stopServerMenuItem = factory.createMenuItem("collab.stop_server", this, "stopServer");
|
f@0
|
600 collabMenu.add(stopServerMenuItem);
|
f@0
|
601 stopServerMenuItem.setEnabled(false);
|
f@0
|
602
|
f@0
|
603 shareDiagramMenuItem = factory.createMenuItem("collab.share_diagram", this, "shareDiagram");
|
f@0
|
604 collabMenu.add(shareDiagramMenuItem);
|
f@0
|
605
|
f@0
|
606 collabMenu.add(factory.createMenuItem("collab.open_shared_diagram", this, "openSharedDiagram"));
|
f@0
|
607
|
f@0
|
608 showAwarenessPanelMenuItem = factory.createMenuItem("collab.show_awareness_panel", this, "showAwarenessPanel");
|
f@0
|
609 collabMenu.add(showAwarenessPanelMenuItem);
|
f@0
|
610
|
f@0
|
611 hideAwarenessPanelMenuItem = factory.createMenuItem("collab.hide_awareness_panel", this, "hideAwarenessPanel");
|
f@0
|
612 collabMenu.add(hideAwarenessPanelMenuItem);
|
f@0
|
613
|
f@0
|
614 awarenessPanelListener = new AwarenessPanelEnablingListener(){
|
f@0
|
615 @Override
|
f@0
|
616 public void awarenessPanelEnabled(boolean enabled) {
|
f@0
|
617 if(enabled){
|
f@0
|
618 showAwarenessPanelMenuItem.setEnabled(true);
|
f@0
|
619 hideAwarenessPanelMenuItem.setEnabled(false);
|
f@0
|
620 }else{
|
f@0
|
621 showAwarenessPanelMenuItem.setEnabled(false);
|
f@0
|
622 hideAwarenessPanelMenuItem.setEnabled(false);
|
f@0
|
623 }
|
f@0
|
624 }
|
f@0
|
625
|
f@0
|
626 @Override
|
f@0
|
627 public void awarenessPanelVisible(boolean visible) {
|
f@0
|
628 if(visible){
|
f@0
|
629 showAwarenessPanelMenuItem.setEnabled(false);
|
f@0
|
630 hideAwarenessPanelMenuItem.setEnabled(true);
|
f@0
|
631 }else{
|
f@0
|
632 showAwarenessPanelMenuItem.setEnabled(true);
|
f@0
|
633 hideAwarenessPanelMenuItem.setEnabled(false);
|
f@0
|
634 }
|
f@0
|
635 }
|
f@0
|
636 };
|
f@0
|
637
|
f@0
|
638 /* --- PREFERENCES --- */
|
f@0
|
639 JMenu preferencesMenu = factory.createMenu("preferences");
|
f@0
|
640 menuBar.add(preferencesMenu);
|
f@0
|
641
|
f@0
|
642 /* show haptic window menu item only unless it's a actual haptic device thread *
|
f@0
|
643 * that has its own window run by a native dll */
|
f@0
|
644 if(!HapticsFactory.getInstance().isAlive()){
|
f@0
|
645 preferencesMenu.add(factory.createCheckBoxMenuItem("preferences.show_haptics", new ActionListener(){
|
f@0
|
646 @Override
|
f@0
|
647 public void actionPerformed(ActionEvent evt){
|
f@0
|
648 JCheckBoxMenuItem menuItem = (JCheckBoxMenuItem) evt.getSource();
|
f@0
|
649 haptics.setVisible(menuItem.isSelected());
|
f@0
|
650 NarratorFactory.getInstance().speakWholeText(resources.getString(
|
f@0
|
651 menuItem.isSelected() ? "speech.haptic_window_open" : "speech.haptic_window_close"));
|
f@0
|
652 }
|
f@0
|
653 }));
|
f@0
|
654 }
|
f@0
|
655
|
f@0
|
656 preferencesMenu.add(factory.createMenuItem("preferences.change_haptics", new ActionListener(){
|
f@0
|
657 @Override
|
f@0
|
658 public void actionPerformed(ActionEvent evt){
|
f@0
|
659 String [] hapticDevices = {
|
f@0
|
660 HapticsFactory.PHANTOM_ID,
|
f@0
|
661 HapticsFactory.FALCON_ID,
|
f@0
|
662 HapticsFactory.TABLET_ID};
|
f@0
|
663 String selection = (String)SpeechOptionPane.showSelectionDialog(
|
f@0
|
664 EditorFrame.this,
|
f@0
|
665 resources.getString("dialog.input.haptics.select"),
|
f@0
|
666 hapticDevices,
|
f@0
|
667 hapticDevices[0]);
|
f@0
|
668 if(selection == null)
|
f@0
|
669 return;
|
f@0
|
670 preferences.put("haptic_device", selection);
|
f@0
|
671 SpeechOptionPane.showMessageDialog(EditorFrame.this,
|
f@0
|
672 MessageFormat.format(resources.getString("dialog.feedback.haptic_init"),selection),
|
f@0
|
673 SpeechOptionPane.WARNING_MESSAGE);
|
f@0
|
674 }
|
f@0
|
675 }));
|
f@0
|
676
|
f@0
|
677 // awareness menu
|
f@0
|
678 JMenu awarenessMenu = factory.createMenu("preferences.awareness");
|
f@0
|
679 preferencesMenu.add(awarenessMenu);
|
f@0
|
680
|
f@0
|
681 awarenessMenu.add(factory.createMenuItem("preferences.awareness.username", this, "showAwarnessUsernameDialog"));
|
f@0
|
682 awarenessMenu.add(factory.createMenuItem("preferences.awareness.broadcast", this, "showAwarenessBroadcastDialog"));
|
f@0
|
683 awarenessMenu.add(factory.createMenuItem("preferences.awareness.display", this, "showAwarenessDisplayDialog"));
|
f@0
|
684
|
f@0
|
685 JMenuItem enableAwarenessVoiceMenuItem = factory.createCheckBoxMenuItem("preferences.awareness.enable_voice",
|
f@0
|
686 new ActionListener(){
|
f@0
|
687 @Override
|
f@0
|
688 public void actionPerformed(ActionEvent evt) {
|
f@0
|
689 JCheckBoxMenuItem menuItem = (JCheckBoxMenuItem) evt.getSource();
|
f@0
|
690 NarratorFactory.getInstance().setMuted(!menuItem.isSelected(),Narrator.SECOND_VOICE);
|
f@0
|
691 PreferencesService.getInstance().put("second_voice_enabled", Boolean.toString(menuItem.isSelected()));
|
f@0
|
692 }
|
f@0
|
693 });
|
f@0
|
694 NarratorFactory.getInstance().setMuted(true,Narrator.FIRST_VOICE);
|
f@0
|
695 enableAwarenessVoiceMenuItem.setSelected(Boolean.parseBoolean(
|
f@0
|
696 PreferencesService.getInstance().get("second_voice_enabled", Boolean.toString(true))));
|
f@0
|
697 awarenessMenu.add(enableAwarenessVoiceMenuItem);
|
f@0
|
698 NarratorFactory.getInstance().setMuted(false,Narrator.FIRST_VOICE);
|
f@0
|
699
|
f@0
|
700 // sound
|
f@0
|
701 JMenu soundMenu = factory.createMenu("preferences.sound");
|
f@0
|
702 preferencesMenu.add(soundMenu);
|
f@0
|
703
|
f@0
|
704 JMenuItem muteMenuItem = factory.createCheckBoxMenuItem("preferences.sound.mute", new ActionListener(){
|
f@0
|
705 @Override
|
f@0
|
706 public void actionPerformed(ActionEvent evt) {
|
f@0
|
707 JCheckBoxMenuItem menuItem = (JCheckBoxMenuItem) evt.getSource();
|
f@0
|
708 NarratorFactory.getInstance().setMuted(menuItem.isSelected(),Narrator.FIRST_VOICE);
|
f@0
|
709 SoundFactory.getInstance().setMuted(menuItem.isSelected());
|
f@0
|
710 }
|
f@0
|
711 });
|
f@0
|
712 soundMenu.add(muteMenuItem);
|
f@0
|
713
|
f@0
|
714 JMenuItem rateMenuItem = factory.createMenuItem("preferences.sound.rate", new ActionListener(){
|
f@0
|
715 @Override
|
f@0
|
716 public void actionPerformed(ActionEvent evt) {
|
f@0
|
717 Integer newRate = SpeechOptionPane.showNarratorRateDialog(
|
f@0
|
718 EditorFrame.this,
|
f@0
|
719 resources.getString("dialog.input.sound_rate"),
|
f@0
|
720 NarratorFactory.getInstance().getRate(),
|
f@0
|
721 Narrator.MIN_RATE,
|
f@0
|
722 Narrator.MAX_RATE);
|
f@0
|
723 if(newRate != null){
|
f@0
|
724 NarratorFactory.getInstance().setRate(newRate);
|
f@0
|
725 NarratorFactory.getInstance().speak(
|
f@0
|
726 MessageFormat.format(
|
f@0
|
727 resources.getString("dialog.feedback.speech_rate"),
|
f@0
|
728 newRate));
|
f@0
|
729 }else{
|
f@0
|
730 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
731 }
|
f@0
|
732 }
|
f@0
|
733 });
|
f@0
|
734 soundMenu.add(rateMenuItem);
|
f@0
|
735
|
f@0
|
736 //server ports
|
f@0
|
737 JMenu networkingMenu = factory.createMenu("preferences.server");
|
f@0
|
738 preferencesMenu.add(networkingMenu);
|
f@0
|
739
|
f@0
|
740 JMenuItem localPortMenuItem = factory.createMenuItem("preferences.local_server.port", this, "showLocalServerPortDialog");
|
f@0
|
741 networkingMenu.add(localPortMenuItem);
|
f@0
|
742
|
f@0
|
743 JMenuItem remotePortMenuItem = factory.createMenuItem("preferences.remote_server.port", this, "showRemoteServerPortDialog");
|
f@0
|
744 networkingMenu.add(remotePortMenuItem);
|
f@0
|
745
|
f@0
|
746 // accessible file chooser
|
f@0
|
747 JMenuItem fileChooserMenuItem = factory.createCheckBoxMenuItem("preferences.file_chooser", new ActionListener(){
|
f@0
|
748 @Override
|
f@0
|
749 public void actionPerformed(ActionEvent evt) {
|
f@0
|
750 JCheckBoxMenuItem menuItem = (JCheckBoxMenuItem) evt.getSource();
|
f@0
|
751 PreferencesService.getInstance().put("use_accessible_filechooser", Boolean.toString(menuItem.isSelected()));
|
f@0
|
752 }
|
f@0
|
753 });
|
f@0
|
754
|
f@0
|
755 JMenuItem enableLogMenuItem = factory.createCheckBoxMenuItem("preferences.enable_log", new ActionListener(){
|
f@0
|
756 @Override
|
f@0
|
757 public void actionPerformed(ActionEvent evt) {
|
f@0
|
758 JCheckBoxMenuItem menuItem = (JCheckBoxMenuItem) evt.getSource();
|
f@0
|
759 PreferencesService preferences = PreferencesService.getInstance();
|
f@0
|
760 preferences.put("enable_log", Boolean.toString(menuItem.isSelected()));
|
f@0
|
761 if(menuItem.isSelected()){
|
f@0
|
762 try{
|
f@0
|
763 InteractionLog.enable(preferences.get("dir.log", ""));
|
f@0
|
764 }catch(IOException ioe){
|
f@0
|
765 SpeechOptionPane.showMessageDialog(EditorFrame.this, resources.getString("dialog.error.log_enable"));
|
f@0
|
766 }
|
f@0
|
767 }else{
|
f@0
|
768 InteractionLog.disable();
|
f@0
|
769 }
|
f@0
|
770 }
|
f@0
|
771 });
|
f@0
|
772
|
f@0
|
773 /* temporarily mute the narrator to select the menus without triggering a speech */
|
f@0
|
774 NarratorFactory.getInstance().setMuted(true,Narrator.FIRST_VOICE);
|
f@0
|
775 fileChooserMenuItem.setSelected(Boolean.parseBoolean(PreferencesService.getInstance().get("use_accessible_filechooser", "true")));
|
f@0
|
776 enableLogMenuItem.setSelected(Boolean.parseBoolean(PreferencesService.getInstance().get("enable_log", "false")));
|
f@0
|
777 NarratorFactory.getInstance().setMuted(false,Narrator.FIRST_VOICE);
|
f@0
|
778 preferencesMenu.add(fileChooserMenuItem);
|
f@0
|
779 preferencesMenu.add(enableLogMenuItem);
|
f@0
|
780
|
f@0
|
781
|
f@0
|
782 /* --- HELP --- */
|
f@0
|
783 JMenu helpMenu = factory.createMenu("help");
|
f@0
|
784 menuBar.add(helpMenu);
|
f@0
|
785
|
f@0
|
786 helpMenu.add(factory.createMenuItem(
|
f@0
|
787 "help.about", this, "showAboutDialog"));
|
f@0
|
788
|
f@0
|
789 helpMenu.add(factory.createMenuItem(
|
f@0
|
790 "help.license", this, "showLicense"));
|
f@0
|
791
|
f@0
|
792 treeEnabledMenuUpdate(null);
|
f@0
|
793 diagramPanelEnabledMenuUpdate(null);
|
f@0
|
794 }
|
f@0
|
795
|
f@0
|
796 private void changeLookAndFeel(String lafName){
|
f@0
|
797 if(lafName == null)
|
f@0
|
798 lafName = UIManager.getSystemLookAndFeelClassName();
|
f@0
|
799 try{
|
f@0
|
800 UIManager.setLookAndFeel(lafName);
|
f@0
|
801 SwingUtilities.updateComponentTreeUI(EditorFrame.this);
|
f@0
|
802 }
|
f@0
|
803 catch (ClassNotFoundException ex) {}
|
f@0
|
804 catch (InstantiationException ex) {}
|
f@0
|
805 catch (IllegalAccessException ex) {}
|
f@0
|
806 catch (UnsupportedLookAndFeelException ex) {}
|
f@0
|
807 }
|
f@0
|
808
|
f@0
|
809 /**
|
f@0
|
810 * Adds a file name to the "recent files" list and rebuilds the "recent files" menu.
|
f@0
|
811 * @param newFile the file name to add
|
f@0
|
812 */
|
f@0
|
813 private void addRecentFile(final String newFile){
|
f@0
|
814 recentFiles.remove(newFile);
|
f@0
|
815 if (newFile == null || newFile.equals("")) return;
|
f@0
|
816 recentFiles.add(0, newFile);
|
f@0
|
817 buildRecentFilesMenu();
|
f@0
|
818 }
|
f@0
|
819
|
f@0
|
820 /* speaks out the selected tree node if the tree is focused or the tab label if the tab is focused */
|
f@0
|
821 private void speakFocusedComponent(String message){
|
f@0
|
822 message = (message == null) ? "" : message+"; ";//add a dot to pause the TTS
|
f@0
|
823 DiagramPanel dPanel = getActiveTab();
|
f@0
|
824 if(dPanel != null){
|
f@0
|
825 String focusedComponent = null;
|
f@0
|
826 if(KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() instanceof JTree)
|
f@0
|
827 focusedComponent = dPanel.getTree().currentPathSpeech();
|
f@0
|
828 else
|
f@0
|
829 focusedComponent = MessageFormat.format(resources.getString("window.tab"),editorTabbedPane.getComponentTabTitle(dPanel));
|
f@0
|
830 NarratorFactory.getInstance().speak(message+focusedComponent);
|
f@0
|
831 }
|
f@0
|
832 }
|
f@0
|
833 /**
|
f@0
|
834 * Rebuilds the "recent files" menu.
|
f@0
|
835 */
|
f@0
|
836 private void buildRecentFilesMenu(){
|
f@0
|
837 recentFilesMenu.removeAll();
|
f@0
|
838 for (int i = 0; i < recentFiles.size(); i++){
|
f@0
|
839 final String file = recentFiles.get(i);
|
f@0
|
840 String name = new File(file).getName();
|
f@0
|
841 JMenuItem item = SpeechMenuFactory.getMenuItem(name);
|
f@0
|
842 item.setToolTipText(file);
|
f@0
|
843 recentFilesMenu.add(item);
|
f@0
|
844 item.addActionListener(new
|
f@0
|
845 ActionListener(){
|
f@0
|
846 public void actionPerformed(ActionEvent event){
|
f@0
|
847 try {
|
f@0
|
848 FileService.Open open = new FileService.DirectService().open(new File(((JMenuItem)event.getSource()).getToolTipText()));
|
f@0
|
849 InputStream in = open.getInputStream();
|
f@0
|
850 String path = open.getPath();
|
f@0
|
851 for(int i=0; i<editorTabbedPane.getTabCount();i++){
|
f@0
|
852 if(path.equals(editorTabbedPane.getToolTipTextAt(i))){
|
f@0
|
853 editorTabbedPane.setSelectedIndex(i);
|
f@0
|
854 return;
|
f@0
|
855 }
|
f@0
|
856 }
|
f@0
|
857 Diagram diagram = path.endsWith(PdPersistenceManager.PD_EXTENSION) ?
|
f@0
|
858 PdPersistenceManager.getInstance().decodeDiagramInstance(in) :
|
f@0
|
859 PersistenceManager.decodeDiagramInstance(in);
|
f@0
|
860 addTab(open.getPath(), diagram);
|
f@0
|
861 } catch (IOException exception) {
|
f@0
|
862 SpeechOptionPane.showMessageDialog(
|
f@0
|
863 editorTabbedPane,
|
f@0
|
864 exception.getLocalizedMessage());
|
f@0
|
865 }
|
f@0
|
866 }
|
f@0
|
867 });
|
f@0
|
868 }
|
f@0
|
869 }
|
f@0
|
870
|
f@0
|
871 /**
|
f@0
|
872 Asks the user to open a graph file.
|
f@0
|
873 */
|
f@0
|
874 public void openFile(){
|
f@0
|
875 InputStream in = null;
|
f@0
|
876 try{
|
f@0
|
877 FileService.Open open = fileService.open(null,null, extensionFilter,this);
|
f@0
|
878 in = open.getInputStream();
|
f@0
|
879 if(in != null){ // open.getInputStream() == null -> user clicked on cancel
|
f@0
|
880 String path = open.getPath();
|
f@0
|
881 int index = editorTabbedPane.getPathTabIndex(path);
|
f@0
|
882 if(index != -1){ //diagram is already open
|
f@0
|
883 editorTabbedPane.setSelectedIndex(index);
|
f@0
|
884 speakFocusedComponent("");
|
f@0
|
885 return;
|
f@0
|
886 }
|
f@0
|
887 /* every opened diagram must have a unique name */
|
f@0
|
888 if(editorTabbedPane.getDiagramNameTabIndex(open.getName()) != -1)
|
f@0
|
889 throw new IOException(resources.getString("dialog.error.same_file_name"));
|
f@0
|
890 iLog("START READ LOCAL DIAGRAM "+open.getName());
|
f@0
|
891 Diagram diagram = path.endsWith(PdPersistenceManager.PD_EXTENSION) ?
|
f@0
|
892 PdPersistenceManager.getInstance().decodeDiagramInstance(in) :
|
f@0
|
893 PersistenceManager.decodeDiagramInstance(in);
|
f@0
|
894 iLog("END READ LOCAL DIAGRAM "+open.getName());
|
f@0
|
895 /* force the name of the diagram to be the same as the file name *
|
f@0
|
896 * it should never be useful, unless the .ccmi file is edited manually */
|
f@0
|
897 diagram.setName(open.getName());
|
f@0
|
898 addTab(open.getPath(), diagram);
|
f@0
|
899 addRecentFile(open.getPath());
|
f@0
|
900 }
|
f@0
|
901 }
|
f@0
|
902 catch (IOException exception) {
|
f@0
|
903 SpeechOptionPane.showMessageDialog(
|
f@0
|
904 editorTabbedPane,
|
f@0
|
905 exception.getLocalizedMessage());
|
f@0
|
906 }finally{
|
f@0
|
907 if(in != null)
|
f@0
|
908 try{in.close();}catch(IOException ioe){ioe.printStackTrace();}
|
f@0
|
909 }
|
f@0
|
910 }
|
f@0
|
911
|
f@0
|
912 /**
|
f@0
|
913 * Close a diagram tab. If the diagram has not been saved the user will be
|
f@0
|
914 * asked if they want to save the diagram.
|
f@0
|
915 */
|
f@0
|
916 public void closeFile(){
|
f@0
|
917 DiagramPanel dPanel = getActiveTab();
|
f@0
|
918 if(dPanel.isModified()||dPanel.getFilePath() == null){
|
f@0
|
919 int answer = SpeechOptionPane.showConfirmDialog(
|
f@0
|
920 EditorFrame.this,
|
f@0
|
921 resources.getString("dialog.confirm.close"),
|
f@0
|
922 SpeechOptionPane.YES_NO_OPTION);
|
f@0
|
923
|
f@0
|
924 if(answer == SpeechOptionPane.YES_OPTION) // save file only if the user decides to
|
f@0
|
925 if(!saveFile())
|
f@0
|
926 return; /* if the user closes the save dialog do nothing */
|
f@0
|
927 }
|
f@0
|
928 iLog("diagram closed :"+dPanel.getDiagram().getName());
|
f@0
|
929 NarratorFactory.getInstance().speak(MessageFormat.format(resources.getString("speech.diagram_closed"),dPanel.getDiagram().getName()));
|
f@0
|
930 if(dPanel.getDiagram() instanceof NetDiagram){
|
f@0
|
931 if(clientConnectionManager != null && clientConnectionManager.isAlive())
|
f@0
|
932 clientConnectionManager.addRequest(new RmDiagramRequest(dPanel.getDiagram().getName()));
|
f@0
|
933 }
|
f@0
|
934 editorTabbedPane.remove(dPanel);
|
f@0
|
935 //getActiveTab, after removing, returns the new selected panel after the remotion, if any
|
f@0
|
936 String newFocusedTabName = null;
|
f@0
|
937 if(getActiveTab() != null){
|
f@0
|
938 newFocusedTabName = getActiveTab().getDiagram().getName();
|
f@0
|
939 }
|
f@0
|
940 haptics.removeDiagram(dPanel.getDiagram().getName(), newFocusedTabName);
|
f@0
|
941 }
|
f@0
|
942
|
f@0
|
943 /**
|
f@0
|
944 * Saves the currently open tab diagram into a file. If the diagram has no file path associated
|
f@0
|
945 * (it has never been saved before), {@link #saveFileAs()} is called.
|
f@0
|
946 *
|
f@0
|
947 * @return {@code true} if the file is successfully saved, or {@code false} otherwise.
|
f@0
|
948 */
|
f@0
|
949 public boolean saveFile(){
|
f@0
|
950 DiagramPanel diagramPanel = getActiveTab();
|
f@0
|
951 if (diagramPanel == null) // no tabs open
|
f@0
|
952 return false;
|
f@0
|
953 String filePath = diagramPanel.getFilePath();
|
f@0
|
954 if (filePath == null) {
|
f@0
|
955 return saveFileAs();
|
f@0
|
956 }
|
f@0
|
957
|
f@0
|
958 OutputStream out = null;
|
f@0
|
959 try{
|
f@0
|
960 File file = new File(filePath);
|
f@0
|
961 out = new BufferedOutputStream(new FileOutputStream(file));
|
f@0
|
962 Diagram d = diagramPanel.getDiagram();
|
f@0
|
963 if(d instanceof PdDiagram){
|
f@0
|
964 PdPersistenceManager.getInstance().encodeDiagramInstance(d, out);
|
f@0
|
965 }else {
|
f@0
|
966 PersistenceManager.encodeDiagramInstance(d, out);
|
f@0
|
967 }
|
f@0
|
968 /* we saved the diagram, therefore there are no more pending changes */
|
f@0
|
969 diagramPanel.setModified(false);
|
f@0
|
970 speakFocusedComponent(resources.getString("dialog.file_saved"));
|
f@0
|
971 return true;
|
f@0
|
972 }catch(IOException ioe){
|
f@0
|
973 SpeechOptionPane.showMessageDialog(editorTabbedPane,ioe.getLocalizedMessage());
|
f@0
|
974 return false;
|
f@0
|
975 }finally{
|
f@0
|
976 try {
|
f@0
|
977 out.close();
|
f@0
|
978 }catch(IOException ioe){ /*can't do anything */ }
|
f@0
|
979 }
|
f@0
|
980 }
|
f@0
|
981
|
f@0
|
982 /**
|
f@0
|
983 * Prompts the user with a dialog for saving a diagram on disk. The current diagram is not affected
|
f@0
|
984 * by this call and it keeps to be displayed in the editor.
|
f@0
|
985 *
|
f@0
|
986 * @return {@code true} if the file is successfully saved, or {@code false} otherwise.
|
f@0
|
987 */
|
f@0
|
988 public boolean saveCopy(){
|
f@0
|
989 DiagramPanel diagramPanel = getActiveTab();
|
f@0
|
990 if (diagramPanel == null) // no tabs open
|
f@0
|
991 return false;
|
f@0
|
992 OutputStream out = null;
|
f@0
|
993 FileService.Save save;
|
f@0
|
994 try {
|
f@0
|
995 save = fileService.save(
|
f@0
|
996 PreferencesService.getInstance().get("dir.diagrams", "."),
|
f@0
|
997 diagramPanel.getFilePath(), //default file to save to
|
f@0
|
998 extensionFilter,
|
f@0
|
999 null,
|
f@0
|
1000 defaultExtension,
|
f@0
|
1001 null);
|
f@0
|
1002 out = save.getOutputStream();
|
f@0
|
1003 if (out == null) /* user didn't select any file for saving */
|
f@0
|
1004 return false;
|
f@0
|
1005 if(diagramPanel.getDiagram() instanceof PdDiagram){
|
f@0
|
1006 PdPersistenceManager.getInstance().encodeDiagramInstance(diagramPanel.getDiagram(),save.getName(), out);
|
f@0
|
1007 }else{
|
f@0
|
1008 PersistenceManager.encodeDiagramInstance(diagramPanel.getDiagram(),save.getName(), out);
|
f@0
|
1009 }
|
f@0
|
1010 speakFocusedComponent(resources.getString("dialog.file_saved"));
|
f@0
|
1011 return true;
|
f@0
|
1012 } catch (IOException ioe) {
|
f@0
|
1013 SpeechOptionPane.showMessageDialog(editorTabbedPane,ioe.getLocalizedMessage());
|
f@0
|
1014 return false;
|
f@0
|
1015 } finally {
|
f@0
|
1016 if(out != null)
|
f@0
|
1017 try{out.close();}catch(IOException ioe){ioe.printStackTrace();}
|
f@0
|
1018 }
|
f@0
|
1019 }
|
f@0
|
1020
|
f@0
|
1021 /**
|
f@0
|
1022 * Saves the current diagram as a new file. The user is prompter with a {@code FileChooser}
|
f@0
|
1023 * to chose a file to save the diagram to.
|
f@0
|
1024 *
|
f@0
|
1025 * @return {@code true} if the file is successfully saved, or {@code false} otherwise.
|
f@0
|
1026 */
|
f@0
|
1027 public boolean saveFileAs() {
|
f@0
|
1028 DiagramPanel diagramPanel = getActiveTab();
|
f@0
|
1029 if (diagramPanel == null) // no tabs open
|
f@0
|
1030 return false;
|
f@0
|
1031 String oldName = diagramPanel.getDiagram().getName();
|
f@0
|
1032 OutputStream out = null;
|
f@0
|
1033 try {
|
f@0
|
1034 String[] currentTabs = new String[editorTabbedPane.getTabCount()];
|
f@0
|
1035 for(int i=0; i<editorTabbedPane.getTabCount();i++){
|
f@0
|
1036 currentTabs[i] = editorTabbedPane.getTitleAt(i);
|
f@0
|
1037 }
|
f@0
|
1038 FileService.Save save = fileService.save(
|
f@0
|
1039 PreferencesService.getInstance().get("dir.diagrams", "."),
|
f@0
|
1040 diagramPanel.getFilePath(),
|
f@0
|
1041 extensionFilter,
|
f@0
|
1042 null,
|
f@0
|
1043 defaultExtension,
|
f@0
|
1044 currentTabs);
|
f@0
|
1045 out = save.getOutputStream();
|
f@0
|
1046 if (out == null) /* user didn't select any file for saving */
|
f@0
|
1047 return false;
|
f@0
|
1048
|
f@0
|
1049 if(diagramPanel.getDiagram() instanceof PdDiagram){
|
f@0
|
1050 PdPersistenceManager.getInstance().encodeDiagramInstance(diagramPanel.getDiagram(),save.getName(), out);
|
f@0
|
1051 }else{
|
f@0
|
1052 PersistenceManager.encodeDiagramInstance(diagramPanel.getDiagram(),save.getName(), out);
|
f@0
|
1053 }
|
f@0
|
1054
|
f@0
|
1055 /* update the diagram and the diageam panel, after the saving */
|
f@0
|
1056 diagramPanel.getDiagram().setName(save.getName());
|
f@0
|
1057 diagramPanel.setFilePath(save.getPath());
|
f@0
|
1058 diagramPanel.setModified(false);
|
f@0
|
1059 speakFocusedComponent(resources.getString("dialog.file_saved"));
|
f@0
|
1060 /* update the haptics, remove first the diagram that is going o be renamed *
|
f@0
|
1061 * and then re-add the diagram under the new name (avoids haptics *
|
f@0
|
1062 * IllegalArgumentException when switching tab) */
|
f@0
|
1063 haptics.removeDiagram(oldName, null);
|
f@0
|
1064 haptics.addNewDiagram(diagramPanel.getDiagram().getName());
|
f@0
|
1065 for(Node n : diagramPanel.getDiagram().getCollectionModel().getNodes())
|
f@0
|
1066 haptics.addNode(n.getBounds().getCenterX(), n.getBounds().getCenterY(), System.identityHashCode(n),null);
|
f@0
|
1067 for(Edge e : diagramPanel.getDiagram().getCollectionModel().getEdges()){
|
f@0
|
1068 Edge.PointRepresentation pr = e.getPointRepresentation();
|
f@0
|
1069 haptics.addEdge(System.identityHashCode(e),pr.xs,pr.ys,pr.adjMatrix,pr.nodeStart,e.getStipplePattern(),e.getNameLine(),null);
|
f@0
|
1070 }
|
f@0
|
1071 return true;
|
f@0
|
1072 }catch(IOException ioe){
|
f@0
|
1073 SpeechOptionPane.showMessageDialog(editorTabbedPane,ioe.getLocalizedMessage());
|
f@0
|
1074 return false;
|
f@0
|
1075 }finally{
|
f@0
|
1076 if(out != null)
|
f@0
|
1077 try{out.close();}catch(IOException ioe){ioe.printStackTrace();}
|
f@0
|
1078 }
|
f@0
|
1079 }
|
f@0
|
1080
|
f@0
|
1081 /**
|
f@0
|
1082 Exits the program if no graphs have been modified
|
f@0
|
1083 or if the user agrees to abandon modified graphs.
|
f@0
|
1084 */
|
f@0
|
1085 public void exit(){
|
f@0
|
1086 /* check first whether there are modified diagrams */
|
f@0
|
1087 int diagramsToSave = 0;
|
f@0
|
1088 for(int i=0; i<editorTabbedPane.getTabCount();i++){
|
f@0
|
1089 DiagramPanel dPanel = editorTabbedPane.getComponentAt(i);
|
f@0
|
1090 if(dPanel.isModified()||dPanel.getFilePath() == null){
|
f@0
|
1091 diagramsToSave++;
|
f@0
|
1092 }
|
f@0
|
1093 }
|
f@0
|
1094
|
f@0
|
1095 if(diagramsToSave > 0){
|
f@0
|
1096 int answer = SpeechOptionPane.showConfirmDialog(
|
f@0
|
1097 EditorFrame.this,
|
f@0
|
1098 MessageFormat.format(resources.getString("dialog.confirm.exit"), diagramsToSave),
|
f@0
|
1099 SpeechOptionPane.YES_NO_OPTION);
|
f@0
|
1100 // if the doesn't want to save changes, veto the close
|
f@0
|
1101 if(answer != SpeechOptionPane.NO_OPTION){
|
f@0
|
1102 if(answer == SpeechOptionPane.YES_OPTION){ // user clicked on yes button we just get them back to the editor
|
f@0
|
1103 speakFocusedComponent("");
|
f@0
|
1104 }else{// user pressed the ESC button
|
f@0
|
1105 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1106 }
|
f@0
|
1107 return;
|
f@0
|
1108 }
|
f@0
|
1109 }
|
f@0
|
1110
|
f@0
|
1111 NarratorFactory.getInstance().dispose();
|
f@0
|
1112 SoundFactory.getInstance().dispose();
|
f@0
|
1113 haptics.dispose();
|
f@0
|
1114 if(server != null)
|
f@0
|
1115 server.shutdown();
|
f@0
|
1116 if(clientConnectionManager != null)
|
f@0
|
1117 clientConnectionManager.shutdown();
|
f@0
|
1118 BroadcastFilter broadcastFilter = BroadcastFilter.getInstance();
|
f@0
|
1119 if(broadcastFilter != null)
|
f@0
|
1120 broadcastFilter.saveProperties(this);
|
f@0
|
1121 DisplayFilter displayFilter = DisplayFilter.getInstance();
|
f@0
|
1122 if(displayFilter != null)
|
f@0
|
1123 displayFilter.saveProperties(this);
|
f@0
|
1124
|
f@0
|
1125 while(haptics.isAlive()){/* wait */}
|
f@0
|
1126 /* closes the logger's handlers */
|
f@0
|
1127 iLog("PROGRAM EXIT");
|
f@0
|
1128 InteractionLog.dispose();
|
f@0
|
1129
|
f@0
|
1130 savePreferences();
|
f@0
|
1131 System.exit(0);
|
f@0
|
1132 }
|
f@0
|
1133
|
f@0
|
1134 /**
|
f@0
|
1135 * Changes the selection path of the diagram tree to a specific destination.
|
f@0
|
1136 * The user with a selection dialog to choose the destination from the following
|
f@0
|
1137 * choices : the root of the diagram, one of the element types, a bookmarked
|
f@0
|
1138 * node or a node/edge reference.
|
f@0
|
1139 */
|
f@0
|
1140 public void jump(){
|
f@0
|
1141 String[] options = new String[canJumpRef ? 4 : 3];
|
f@0
|
1142 options[0] = resources.getString("options.jump.type");
|
f@0
|
1143 options[1] = resources.getString("options.jump.diagram");
|
f@0
|
1144 options[2] = resources.getString("options.jump.bookmark");
|
f@0
|
1145 if(canJumpRef){
|
f@0
|
1146 options[3] = resources.getString("options.jump.reference");
|
f@0
|
1147 }
|
f@0
|
1148 iLog("open jump to dialog","");
|
f@0
|
1149 String result = (String)SpeechOptionPane.showSelectionDialog(
|
f@0
|
1150 EditorFrame.this,
|
f@0
|
1151 resources.getString("dialog.input.jump.select"),
|
f@0
|
1152 options,
|
f@0
|
1153 options[0]);
|
f@0
|
1154 DiagramPanel dPanel = getActiveTab();
|
f@0
|
1155 DiagramTree tree = dPanel.getTree();
|
f@0
|
1156 if(result != null){
|
f@0
|
1157 if(result.equals(options[0])){ // jump type
|
f@0
|
1158 tree.jump(DiagramTree.JumpTo.SELECTED_TYPE);
|
f@0
|
1159 }else if(result.equals(options[1])){// diagram
|
f@0
|
1160 tree.jump(DiagramTree.JumpTo.ROOT);
|
f@0
|
1161 }else if(result.equals(options[2])){// bookmark
|
f@0
|
1162 tree.jump(DiagramTree.JumpTo.BOOKMARK);
|
f@0
|
1163 }else if(result.equals(options[3])){
|
f@0
|
1164 tree.jump(DiagramTree.JumpTo.REFERENCE);
|
f@0
|
1165 }
|
f@0
|
1166 }else{
|
f@0
|
1167 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1168 iLog("cancel jump to dialog","");
|
f@0
|
1169 }
|
f@0
|
1170 }
|
f@0
|
1171
|
f@0
|
1172 /**
|
f@0
|
1173 * Locates on the haptic device the node or edge currently selected on the diagram tree. A command
|
f@0
|
1174 * is sent to the haptic device which in turns drag the user to the node/edge location.
|
f@0
|
1175 */
|
f@0
|
1176 public void locate(){
|
f@0
|
1177 DiagramPanel dPanel = getActiveTab();
|
f@0
|
1178 DiagramTree tree = dPanel.getTree();
|
f@0
|
1179 DiagramElement de = (DiagramElement)tree.getSelectionPath().getLastPathComponent();
|
f@0
|
1180 HapticsFactory.getInstance().attractTo(System.identityHashCode(de));
|
f@0
|
1181 iLog("locate " +((de instanceof Node)? "node" : "edge"),DiagramElement.toLogString(de));
|
f@0
|
1182 }
|
f@0
|
1183
|
f@0
|
1184 /**
|
f@0
|
1185 * Selects on the diagram tree the node or edge that's currently being touched by the haptic
|
f@0
|
1186 * device.
|
f@0
|
1187 */
|
f@0
|
1188 public void hHighlight() {
|
f@0
|
1189 getActiveTab().getTree().jumpTo(hapticHighlightDiagramElement);
|
f@0
|
1190 iLog("highlight " +((hapticHighlightDiagramElement instanceof Node)? "node" : "edge"),DiagramElement.toLogString(hapticHighlightDiagramElement));
|
f@0
|
1191 }
|
f@0
|
1192
|
f@0
|
1193 /**
|
f@0
|
1194 * Sends a command to the haptic device to pick up an element (node or edge) for
|
f@0
|
1195 * moving it.
|
f@0
|
1196 *
|
f@0
|
1197 * @param de the diagram element to be picked up
|
f@0
|
1198 */
|
f@0
|
1199 public void hPickUp(DiagramElement de) {
|
f@0
|
1200 HapticsFactory.getInstance().pickUp(System.identityHashCode(de));
|
f@0
|
1201 }
|
f@0
|
1202
|
f@0
|
1203 /**
|
f@0
|
1204 * Prompts the user for an object insertion. The object can be a node, an edge, a property,
|
f@0
|
1205 * a modifier, an edge label, an edge arrow head. Which object is to be inserted depends on
|
f@0
|
1206 * the currently selected tree node on the tree.
|
f@0
|
1207 */
|
f@0
|
1208 public void insert(){
|
f@0
|
1209 DiagramPanel dPanel = getActiveTab();
|
f@0
|
1210 final DiagramTree tree = dPanel.getTree();
|
f@0
|
1211 DiagramTreeNode treeNode = (DiagramTreeNode)tree.getSelectionPath().getLastPathComponent();
|
f@0
|
1212 DiagramModelUpdater modelUpdater = dPanel.getDiagram().getModelUpdater();
|
f@0
|
1213 if(treeNode instanceof TypeMutableTreeNode){ //adding a diagram Element
|
f@0
|
1214 TypeMutableTreeNode typeNode = (TypeMutableTreeNode)treeNode;
|
f@0
|
1215 final DiagramElement diagramElement = (DiagramElement)typeNode.getPrototype().clone();
|
f@0
|
1216 try {
|
f@0
|
1217 if(diagramElement instanceof Edge){
|
f@0
|
1218 Edge edge = (Edge)diagramElement;
|
f@0
|
1219 edge.connect(Arrays.asList(tree.getSelectedNodes()));
|
f@0
|
1220 iLog("insert edge",DiagramElement.toLogString(edge));
|
f@0
|
1221 modelUpdater.insertInTree(diagramElement);
|
f@0
|
1222
|
f@0
|
1223 /* remove the selections on the edge's nodes and release their lock */
|
f@0
|
1224 tree.clearNodeSelections();
|
f@0
|
1225 for(int i=0; i<edge.getNodesNum();i++){
|
f@0
|
1226 modelUpdater.yieldLock(edge, Lock.MUST_EXIST,new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.INSERT_EDGE,edge.getId(),edge.getName()));
|
f@0
|
1227 }
|
f@0
|
1228 }else{ // adding a Node
|
f@0
|
1229 iLog("insert node ",DiagramElement.toLogString(diagramElement));
|
f@0
|
1230 modelUpdater.insertInTree(diagramElement);
|
f@0
|
1231 }
|
f@0
|
1232 } catch (ConnectNodesException cne) {
|
f@0
|
1233 final String message = cne.getLocalizedMessage();
|
f@0
|
1234 SoundFactory.getInstance().play(SoundEvent.ERROR, new PlayerListener(){
|
f@0
|
1235 @Override
|
f@0
|
1236 public void playEnded() {
|
f@0
|
1237 NarratorFactory.getInstance().speak(message);
|
f@0
|
1238 }
|
f@0
|
1239 });
|
f@0
|
1240 SoundFactory.getInstance().play(SoundEvent.ERROR);
|
f@0
|
1241 iLog("insert edge error",message);
|
f@0
|
1242 }
|
f@0
|
1243 }else if(treeNode instanceof PropertyTypeMutableTreeNode){ //adding a property
|
f@0
|
1244 PropertyTypeMutableTreeNode propTypeNode = (PropertyTypeMutableTreeNode)treeNode;
|
f@0
|
1245 Node n = (Node)propTypeNode.getNode();
|
f@0
|
1246 if(!modelUpdater.getLock(n, Lock.PROPERTIES, new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.ADD_PROPERTY,n.getId(),n.getName()))){
|
f@0
|
1247 iLog("Could not get lock on node for add properties",DiagramElement.toLogString(n));
|
f@0
|
1248 SpeechOptionPane.showMessageDialog(this, resources.getString("dialog.lock_failure.properties"), SpeechOptionPane.INFORMATION_MESSAGE);
|
f@0
|
1249 SoundFactory.getInstance().play(SoundEvent.MESSAGE_OK);
|
f@0
|
1250 return;
|
f@0
|
1251 }
|
f@0
|
1252
|
f@0
|
1253 iLog("open insert property dialog","");
|
f@0
|
1254 final String propertyValue = SpeechOptionPane.showInputDialog(EditorFrame.this,
|
f@0
|
1255 MessageFormat.format(resources.getString("dialog.input.property.text"), propTypeNode.getName()),
|
f@0
|
1256 ""
|
f@0
|
1257 );
|
f@0
|
1258 if(propertyValue != null){
|
f@0
|
1259 if(!propertyValue.isEmpty()){ //check that the user didn't enter an empty string
|
f@0
|
1260 iLog("insert property ", propTypeNode.getType()+" "+propertyValue);
|
f@0
|
1261 modelUpdater.addProperty(n, propTypeNode.getType(), propertyValue, DiagramEventSource.TREE);
|
f@0
|
1262 }else{
|
f@0
|
1263 SoundFactory.getInstance().play(SoundEvent.EMPTY);
|
f@0
|
1264 iLog("insert property", "");
|
f@0
|
1265 }
|
f@0
|
1266 }else{
|
f@0
|
1267 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1268 iLog("cancel insert property dialog","");
|
f@0
|
1269 }
|
f@0
|
1270 modelUpdater.yieldLock(n, Lock.PROPERTIES,new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.ADD_PROPERTY,n.getId(),n.getName()));
|
f@0
|
1271 }else if(treeNode instanceof PropertyMutableTreeNode){ // edit modifiers
|
f@0
|
1272 iLog("open modifiers dialog","");
|
f@0
|
1273 PropertyTypeMutableTreeNode typeNode = (PropertyTypeMutableTreeNode)treeNode.getParent();
|
f@0
|
1274 Node n = (Node)typeNode.getNode();
|
f@0
|
1275 Modifiers modifiers = n.getProperties().getModifiers(typeNode.getType());
|
f@0
|
1276 if(modifiers.isNull()){
|
f@0
|
1277 iLog("error:no modifiers for this property","");
|
f@0
|
1278 NarratorFactory.getInstance().speak(MessageFormat.format(resources.getString("dialog.warning.null_modifiers"),typeNode.getType()));
|
f@0
|
1279 }else{
|
f@0
|
1280 if(!modelUpdater.getLock(n, Lock.PROPERTIES,new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.SET_MODIFIERS,n.getId(),n.getName()))){
|
f@0
|
1281 iLog("Could not get lock on node for set modifiers",DiagramElement.toLogString(n));
|
f@0
|
1282 SpeechOptionPane.showMessageDialog(this, resources.getString("dialog.lock_failure.properties"), SpeechOptionPane.INFORMATION_MESSAGE);
|
f@0
|
1283 SoundFactory.getInstance().play(SoundEvent.MESSAGE_OK);
|
f@0
|
1284 return;
|
f@0
|
1285 }
|
f@0
|
1286
|
f@0
|
1287 int index = typeNode.getIndex(treeNode);
|
f@0
|
1288 Set<Integer> result = SpeechOptionPane.showModifiersDialog(EditorFrame.this,
|
f@0
|
1289 MessageFormat.format(resources.getString("dialog.input.check_modifiers"),
|
f@0
|
1290 n.getProperties().getValues(typeNode.getType()).get(index)) ,
|
f@0
|
1291 modifiers.getTypes(),
|
f@0
|
1292 modifiers.getIndexes(index)
|
f@0
|
1293 );
|
f@0
|
1294 if(result == null){
|
f@0
|
1295 iLog("cancel modifiers dialog","");
|
f@0
|
1296 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1297 }else{
|
f@0
|
1298 iLog("edit modifiers",Arrays.toString(result.toArray()));
|
f@0
|
1299 modelUpdater.setModifiers(n, typeNode.getType(), index, result,DiagramEventSource.TREE);
|
f@0
|
1300 }
|
f@0
|
1301 modelUpdater.yieldLock(n, Lock.PROPERTIES,new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.SET_MODIFIERS,n.getId(),n.getName()));
|
f@0
|
1302 }
|
f@0
|
1303 }else{ //NodeReferenceMutableTreeNode = edit label and arrow head
|
f@0
|
1304 NodeReferenceMutableTreeNode nodeRef = (NodeReferenceMutableTreeNode)treeNode;
|
f@0
|
1305 Node n = (Node)nodeRef.getNode();
|
f@0
|
1306 Edge e = (Edge)nodeRef.getEdge();
|
f@0
|
1307 if(!modelUpdater.getLock(e, Lock.EDGE_END,new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.SET_ENDLABEL,e.getId(),e.getName()))){
|
f@0
|
1308 iLog("Could not get lock on edge for end label",DiagramElement.toLogString(e));
|
f@0
|
1309 SpeechOptionPane.showMessageDialog(this, resources.getString("dialog.lock_failure.end_label"), SpeechOptionPane.INFORMATION_MESSAGE);
|
f@0
|
1310 SoundFactory.getInstance().play(SoundEvent.MESSAGE_OK);
|
f@0
|
1311 return;
|
f@0
|
1312 }
|
f@0
|
1313 iLog("open edge operation selection dialog","");
|
f@0
|
1314
|
f@0
|
1315 boolean hasAvailArrowHeads = (e.getAvailableEndDescriptions().length > 0);
|
f@0
|
1316 String[] operations = new String[hasAvailArrowHeads ? 2 : 1];
|
f@0
|
1317 operations[0] = resources.getString("dialog.input.edge_operation.label");
|
f@0
|
1318 if(hasAvailArrowHeads)
|
f@0
|
1319 operations[1] = resources.getString("dialog.input.edge_operation.arrow_head");
|
f@0
|
1320 String choice = (String)SpeechOptionPane.showSelectionDialog(
|
f@0
|
1321 EditorFrame.this,
|
f@0
|
1322 resources.getString("dialog.input.edge_operation.select"),
|
f@0
|
1323 operations,
|
f@0
|
1324 operations[0]);
|
f@0
|
1325
|
f@0
|
1326 if(choice == null){
|
f@0
|
1327 iLog("cancel edge operation selection dialog","");
|
f@0
|
1328 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1329 modelUpdater.yieldLock(e, Lock.EDGE_END,
|
f@0
|
1330 new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.SET_ENDLABEL,e.getId(),e.getName()));
|
f@0
|
1331 return;
|
f@0
|
1332 }
|
f@0
|
1333 if(choice.equals(operations[0])){ //operations[0] = edit edge end-label
|
f@0
|
1334 iLog("open edge label dialog","");
|
f@0
|
1335 String label = SpeechOptionPane.showInputDialog(
|
f@0
|
1336 EditorFrame.this,
|
f@0
|
1337 MessageFormat.format(resources.getString("dialog.input.edge_label"),n.getType(), n.getName()),
|
f@0
|
1338 e.getEndLabel(n) );
|
f@0
|
1339 if(label != null){
|
f@0
|
1340 modelUpdater.setEndLabel(e, n, label,DiagramEventSource.TREE);
|
f@0
|
1341 SoundFactory.getInstance().play(SoundEvent.OK, new PlayerListener(){
|
f@0
|
1342 @Override
|
f@0
|
1343 public void playEnded() {
|
f@0
|
1344 NarratorFactory.getInstance().speak(tree.currentPathSpeech());
|
f@0
|
1345 }
|
f@0
|
1346 });
|
f@0
|
1347 }else{
|
f@0
|
1348 iLog("cancel edge label dialog","");
|
f@0
|
1349 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1350 }
|
f@0
|
1351 }else{//operations[1] = edit edge arrow head
|
f@0
|
1352 String[] endDescriptions = new String[e.getAvailableEndDescriptions().length+1];
|
f@0
|
1353 for(int i=0;i<e.getAvailableEndDescriptions().length;i++)
|
f@0
|
1354 endDescriptions[i] = e.getAvailableEndDescriptions()[i];
|
f@0
|
1355 endDescriptions[endDescriptions.length-1] = Edge.NO_ENDDESCRIPTION_STRING;
|
f@0
|
1356
|
f@0
|
1357 iLog("open edge arrow head dialog","");
|
f@0
|
1358 final String endDescription = (String)SpeechOptionPane.showSelectionDialog(
|
f@0
|
1359 EditorFrame.this,
|
f@0
|
1360 MessageFormat.format(resources.getString("dialog.input.edge_arrowhead"),n.getType(), n.getName()),
|
f@0
|
1361 endDescriptions,
|
f@0
|
1362 endDescriptions[0]
|
f@0
|
1363 );
|
f@0
|
1364 if(endDescription != null){
|
f@0
|
1365 int index = Edge.NO_END_DESCRIPTION_INDEX;
|
f@0
|
1366 for(int i=0;i<e.getAvailableEndDescriptions().length;i++)
|
f@0
|
1367 if(endDescription.equals(e.getAvailableEndDescriptions()[i])){
|
f@0
|
1368 index = i;
|
f@0
|
1369 break;
|
f@0
|
1370 }
|
f@0
|
1371 modelUpdater.setEndDescription(e, n, index,DiagramEventSource.TREE);
|
f@0
|
1372 }else{
|
f@0
|
1373 iLog("cancel edge arrow head dialog","");
|
f@0
|
1374 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1375 }
|
f@0
|
1376 }
|
f@0
|
1377 modelUpdater.yieldLock(e, Lock.EDGE_END,
|
f@0
|
1378 new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.SET_ENDLABEL,e.getId(),e.getName()));
|
f@0
|
1379 }
|
f@0
|
1380 }
|
f@0
|
1381
|
f@0
|
1382 /**
|
f@0
|
1383 * Prompts the user for an object deletion. The object can be a node, an edge, a property,
|
f@0
|
1384 * a modifier, an edge label, an edge arrow head. Which object is to be deleted depends on
|
f@0
|
1385 * the currently selected tree node on the tree.
|
f@0
|
1386 */
|
f@0
|
1387 public void delete(){
|
f@0
|
1388 DiagramPanel dPanel = getActiveTab();
|
f@0
|
1389 final DiagramTree tree = dPanel.getTree();
|
f@0
|
1390 final DiagramTreeNode treeNode = (DiagramTreeNode)tree.getSelectionPath().getLastPathComponent();
|
f@0
|
1391 DiagramModelUpdater modelUpdater = dPanel.getDiagram().getModelUpdater();
|
f@0
|
1392 if(treeNode instanceof DiagramElement){ //delete a diagram element
|
f@0
|
1393 final DiagramElement element = (DiagramElement)treeNode;
|
f@0
|
1394 boolean isNode = element instanceof Node;
|
f@0
|
1395 if(!modelUpdater.getLock(element,
|
f@0
|
1396 Lock.DELETE,
|
f@0
|
1397 new DiagramEventActionSource(DiagramEventSource.TREE,
|
f@0
|
1398 isNode ? Command.Name.REMOVE_NODE : Command.Name.REMOVE_EDGE,
|
f@0
|
1399 element.getId(),element.getName()))){
|
f@0
|
1400 iLog("Could not get lock on element for deletion",DiagramElement.toLogString(element));
|
f@0
|
1401 SpeechOptionPane.showMessageDialog(this, resources.getString("dialog.lock_failure.delete"), SpeechOptionPane.INFORMATION_MESSAGE);
|
f@0
|
1402 SoundFactory.getInstance().play(SoundEvent.MESSAGE_OK);
|
f@0
|
1403 return;
|
f@0
|
1404 }
|
f@0
|
1405 iLog("open delete "+ (isNode ? "node" : "edge") +" dialog","");
|
f@0
|
1406 int choice = SpeechOptionPane.showConfirmDialog(
|
f@0
|
1407 EditorFrame.this,
|
f@0
|
1408 MessageFormat.format(resources.getString("dialog.confirm.deletion"),element.getType(), element.getName()),
|
f@0
|
1409 SpeechOptionPane.OK_CANCEL_OPTION);
|
f@0
|
1410 if(choice != SpeechOptionPane.OK_OPTION){
|
f@0
|
1411 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1412 iLog("cancel delete " + (isNode ? "node" : "edge") +" dialog","");
|
f@0
|
1413 modelUpdater.yieldLock(element,
|
f@0
|
1414 Lock.DELETE,
|
f@0
|
1415 new DiagramEventActionSource(DiagramEventSource.TREE,
|
f@0
|
1416 isNode ? Command.Name.REMOVE_NODE : Command.Name.REMOVE_EDGE,
|
f@0
|
1417 element.getId(),
|
f@0
|
1418 element.getName()));
|
f@0
|
1419 return;
|
f@0
|
1420 }
|
f@0
|
1421 modelUpdater.takeOutFromTree(element);
|
f@0
|
1422 /* don't need to unlock because the object doesn't exist any more, but *
|
f@0
|
1423 * still need to make other users aware that the deletion process is finished */
|
f@0
|
1424 modelUpdater.sendAwarenessMessage(
|
f@0
|
1425 AwarenessMessage.Name.STOP_A,
|
f@0
|
1426 new DiagramEventActionSource(DiagramEventSource.TREE,
|
f@0
|
1427 isNode ? Command.Name.REMOVE_NODE : Command.Name.REMOVE_EDGE,
|
f@0
|
1428 element.getId(),element.getName())
|
f@0
|
1429 );
|
f@0
|
1430 }else if(treeNode.getParent() instanceof PropertyTypeMutableTreeNode){ //deleting a property
|
f@0
|
1431 PropertyTypeMutableTreeNode typeNode = (PropertyTypeMutableTreeNode)treeNode.getParent();
|
f@0
|
1432 Node n = (Node)typeNode.getNode();
|
f@0
|
1433 if(!modelUpdater.getLock(n,
|
f@0
|
1434 Lock.PROPERTIES,
|
f@0
|
1435 new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.REMOVE_PROPERTY,n.getId(),n.getName()))){
|
f@0
|
1436 SpeechOptionPane.showMessageDialog(this, resources.getString("dialog.lock_failure.properties"), SpeechOptionPane.INFORMATION_MESSAGE);
|
f@0
|
1437 iLog("Could not get lock for properties for deletion",DiagramElement.toLogString(n));
|
f@0
|
1438 SoundFactory.getInstance().play(SoundEvent.MESSAGE_OK);
|
f@0
|
1439 return;
|
f@0
|
1440 }
|
f@0
|
1441 iLog("open delete property dialog","");
|
f@0
|
1442 int choice = SpeechOptionPane.showConfirmDialog(
|
f@0
|
1443 EditorFrame.this,
|
f@0
|
1444 MessageFormat.format(resources.getString("dialog.confirm.deletion"),typeNode.getType(),treeNode.getName()),
|
f@0
|
1445 SpeechOptionPane.OK_CANCEL_OPTION);
|
f@0
|
1446 if(choice != SpeechOptionPane.OK_OPTION){
|
f@0
|
1447 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1448 iLog("cancel delete property dialog","");
|
f@0
|
1449 modelUpdater.yieldLock(n,
|
f@0
|
1450 Lock.PROPERTIES,
|
f@0
|
1451 new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.REMOVE_PROPERTY,n.getId(),n.getName()));
|
f@0
|
1452 return;
|
f@0
|
1453 }
|
f@0
|
1454 modelUpdater.removeProperty(n, typeNode.getType(), typeNode.getIndex(treeNode),DiagramEventSource.TREE);
|
f@0
|
1455 }else
|
f@0
|
1456 throw new IllegalStateException("Cannot delete a tree node of type: "+treeNode.getClass().getName());
|
f@0
|
1457 }
|
f@0
|
1458
|
f@0
|
1459 /**
|
f@0
|
1460 * Prompts the user for an object deletion. The object can be a node, an edge or a property.
|
f@0
|
1461 * Which object is to be renamed depends on the currently selected tree node on the tree.
|
f@0
|
1462 */
|
f@0
|
1463 public void rename(){
|
f@0
|
1464 DiagramPanel dPanel = getActiveTab();
|
f@0
|
1465 DiagramModelUpdater modelUpdater = dPanel.getDiagram().getModelUpdater();
|
f@0
|
1466 final DiagramTree tree = dPanel.getTree();
|
f@0
|
1467 DiagramTreeNode treeNode = (DiagramTreeNode)tree.getSelectionPath().getLastPathComponent();
|
f@0
|
1468 MessageFormat formatter = new MessageFormat(resources.getString("dialog.input.rename"));
|
f@0
|
1469 if(treeNode instanceof DiagramElement){
|
f@0
|
1470 DiagramElement element = (DiagramElement)dPanel.getTree().getSelectionPath().getLastPathComponent();
|
f@0
|
1471 Object arg[] = {element.getName()};
|
f@0
|
1472 boolean isNode = element instanceof Node;
|
f@0
|
1473 if(!modelUpdater.getLock(element,
|
f@0
|
1474 Lock.NAME,
|
f@0
|
1475 new DiagramEventActionSource(DiagramEventSource.TREE,
|
f@0
|
1476 isNode ? Command.Name.SET_NODE_NAME : Command.Name.SET_EDGE_NAME,element.getId(),element.getName()))){
|
f@0
|
1477 SpeechOptionPane.showMessageDialog(this, resources.getString("dialog.lock_failure.name"),SpeechOptionPane.INFORMATION_MESSAGE);
|
f@0
|
1478 iLog("Could not get lock on element for renaming",DiagramElement.toLogString(element));
|
f@0
|
1479 SoundFactory.getInstance().play(SoundEvent.MESSAGE_OK);
|
f@0
|
1480 return;
|
f@0
|
1481 }
|
f@0
|
1482 iLog("open rename "+(isNode ? "node" : "edge")+" dialog",DiagramElement.toLogString(element));
|
f@0
|
1483 String name = SpeechOptionPane.showInputDialog(EditorFrame.this,
|
f@0
|
1484 formatter.format(arg),
|
f@0
|
1485 element.getName());
|
f@0
|
1486 if(name != null){
|
f@0
|
1487 modelUpdater.setName(element,name,DiagramEventSource.TREE);
|
f@0
|
1488 }else{
|
f@0
|
1489 iLog("cancel rename "+(isNode ? "node" : "edge")+" dialog",DiagramElement.toLogString(element));
|
f@0
|
1490 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1491 }
|
f@0
|
1492 modelUpdater.yieldLock(element,
|
f@0
|
1493 Lock.NAME,
|
f@0
|
1494 new DiagramEventActionSource(
|
f@0
|
1495 DiagramEventSource.TREE,
|
f@0
|
1496 isNode ? Command.Name.SET_NODE_NAME : Command.Name.SET_EDGE_NAME,
|
f@0
|
1497 element.getId(),
|
f@0
|
1498 element.getName()));
|
f@0
|
1499 }else if(treeNode instanceof PropertyMutableTreeNode){
|
f@0
|
1500 PropertyTypeMutableTreeNode typeNode = (PropertyTypeMutableTreeNode)treeNode.getParent();
|
f@0
|
1501 Node n = (Node)typeNode.getNode();
|
f@0
|
1502 if(!modelUpdater.getLock(n,
|
f@0
|
1503 Lock.PROPERTIES,
|
f@0
|
1504 new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.SET_PROPERTY,n.getId(),n.getName()))){
|
f@0
|
1505 SpeechOptionPane.showMessageDialog(this, resources.getString("dialog.lock_failure.properties"), SpeechOptionPane.INFORMATION_MESSAGE);
|
f@0
|
1506 iLog("Could not get lock on properties for renaming",DiagramElement.toLogString(n));
|
f@0
|
1507 SoundFactory.getInstance().play(SoundEvent.MESSAGE_OK);
|
f@0
|
1508 return;
|
f@0
|
1509 }
|
f@0
|
1510 Object arg[] = {treeNode.getName()};
|
f@0
|
1511 iLog("open rename property dialog",treeNode.getName());
|
f@0
|
1512 String name = SpeechOptionPane.showInputDialog(EditorFrame.this,
|
f@0
|
1513 formatter.format(arg),
|
f@0
|
1514 treeNode.getName());
|
f@0
|
1515 if(name == null){
|
f@0
|
1516 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1517 iLog("cancel rename property dialog",treeNode.getName());
|
f@0
|
1518 return;
|
f@0
|
1519 }
|
f@0
|
1520 modelUpdater.setProperty(n, typeNode.getType(), typeNode.getIndex(treeNode), name,DiagramEventSource.TREE);
|
f@0
|
1521 modelUpdater.yieldLock(n,
|
f@0
|
1522 Lock.PROPERTIES,
|
f@0
|
1523 new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.SET_PROPERTY,n.getId(),n.getName()));
|
f@0
|
1524 }else
|
f@0
|
1525 throw new IllegalStateException("Cannot delete a tree node of type: "+treeNode.getClass().getName());
|
f@0
|
1526 }
|
f@0
|
1527
|
f@0
|
1528 /**
|
f@0
|
1529 * Prompts the user with a dialog to add or remove bookmarks on a tree node. Which node is to be
|
f@0
|
1530 * (un)bookmarked depends on the currently selected tree node on the tree.
|
f@0
|
1531 */
|
f@0
|
1532 public void editBookmarks(){
|
f@0
|
1533 boolean addBookmark = true;
|
f@0
|
1534 DiagramPanel dPanel = getActiveTab();
|
f@0
|
1535 final DiagramTree tree = dPanel.getTree();
|
f@0
|
1536 DiagramTreeNode treeNode = (DiagramTreeNode)tree.getLastSelectedPathComponent();
|
f@0
|
1537 DiagramModelUpdater modelUpdater = dPanel.getDiagram().getModelUpdater();
|
f@0
|
1538
|
f@0
|
1539 if(!modelUpdater.getLock(treeNode,
|
f@0
|
1540 Lock.BOOKMARK,
|
f@0
|
1541 DiagramEventActionSource.NULL)){
|
f@0
|
1542 iLog("Cannot get lock on tree node for bookmark", treeNode.getName());
|
f@0
|
1543 SpeechOptionPane.showMessageDialog(this, resources.getString("dialog.lock_failure.bookmark"), SpeechOptionPane.INFORMATION_MESSAGE);
|
f@0
|
1544 SoundFactory.getInstance().play(SoundEvent.MESSAGE_OK);
|
f@0
|
1545 return;
|
f@0
|
1546 }
|
f@0
|
1547
|
f@0
|
1548 if(!treeNode.getBookmarkKeys().isEmpty()){
|
f@0
|
1549 /* the are already bookmarks, thus we let the user chose whether they want to */
|
f@0
|
1550 /* add a new one or remove an old one */
|
f@0
|
1551 String[] options = {
|
f@0
|
1552 resources.getString("dialog.input.bookmark.select.add"),
|
f@0
|
1553 resources.getString("dialog.input.bookmark.select.remove")
|
f@0
|
1554 };
|
f@0
|
1555
|
f@0
|
1556 iLog("open select add/remove bookmark dialog","");
|
f@0
|
1557 String result = (String)SpeechOptionPane.showSelectionDialog(EditorFrame.this,
|
f@0
|
1558 resources.getString("dialog.input.bookmark.select.add_remove"),
|
f@0
|
1559 options,
|
f@0
|
1560 options[0]);
|
f@0
|
1561
|
f@0
|
1562 if(result == null){
|
f@0
|
1563 iLog("cancel select add/remove bookmark dialog","");
|
f@0
|
1564 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1565 modelUpdater.yieldLock(treeNode, Lock.BOOKMARK, DiagramEventActionSource.NULL);
|
f@0
|
1566 return;
|
f@0
|
1567 }
|
f@0
|
1568 if(result.equals(options[1]))
|
f@0
|
1569 addBookmark = false;
|
f@0
|
1570 }
|
f@0
|
1571
|
f@0
|
1572 if(addBookmark){
|
f@0
|
1573 boolean uniqueBookmarkChosen = false;
|
f@0
|
1574 while(!uniqueBookmarkChosen){
|
f@0
|
1575 iLog("open add bookmark dialog","");
|
f@0
|
1576 String bookmark = SpeechOptionPane.showInputDialog(EditorFrame.this, resources.getString("dialog.input.bookmark.text"),"");
|
f@0
|
1577 if(bookmark != null){
|
f@0
|
1578 if("".equals(bookmark)){
|
f@0
|
1579 iLog("error: entered empty bookmark","");
|
f@0
|
1580 SoundFactory.getInstance().play(SoundEvent.ERROR);// without listeners in order not to overwrite the speechdialog popping up again
|
f@0
|
1581 NarratorFactory.getInstance().speakWholeText(resources.getString("dialog.input.bookmark.text.empty"));
|
f@0
|
1582 }else if(tree.getModel().getBookmarks().contains(bookmark)){
|
f@0
|
1583 iLog("error: entered bookmark already existing",bookmark);
|
f@0
|
1584 SoundFactory.getInstance().play(SoundEvent.ERROR);
|
f@0
|
1585 NarratorFactory.getInstance().speakWholeText(resources.getString("dialog.input.bookmark.text.already_existing"));
|
f@0
|
1586 }else{
|
f@0
|
1587 tree.getModel().putBookmark(bookmark, treeNode,DiagramEventSource.TREE);
|
f@0
|
1588 uniqueBookmarkChosen = true;
|
f@0
|
1589 }
|
f@0
|
1590 }else{
|
f@0
|
1591 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1592 iLog("cancel add bookmark dialog","");
|
f@0
|
1593 break; //user no longer wants to choose, exit the dialog thus
|
f@0
|
1594 }
|
f@0
|
1595 }
|
f@0
|
1596 }else{ // removing a bookmark
|
f@0
|
1597 String[] bookmarksArray = new String[treeNode.getBookmarkKeys().size()];
|
f@0
|
1598 bookmarksArray = treeNode.getBookmarkKeys().toArray(bookmarksArray);
|
f@0
|
1599
|
f@0
|
1600 iLog("open remove bookmark dialog","");
|
f@0
|
1601 final String bookmark = (String)SpeechOptionPane.showSelectionDialog(
|
f@0
|
1602 EditorFrame.this,
|
f@0
|
1603 resources.getString("dialog.input.bookmark.delete"),
|
f@0
|
1604 bookmarksArray,
|
f@0
|
1605 bookmarksArray[0]
|
f@0
|
1606 );
|
f@0
|
1607
|
f@0
|
1608 if(bookmark != null){
|
f@0
|
1609 tree.getModel().removeBookmark(bookmark,DiagramEventSource.TREE);
|
f@0
|
1610 }else{
|
f@0
|
1611 iLog("cancel remove bookmark dialog","");
|
f@0
|
1612 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1613 }
|
f@0
|
1614 }
|
f@0
|
1615 modelUpdater.yieldLock(treeNode, Lock.BOOKMARK, DiagramEventActionSource.NULL);
|
f@0
|
1616 }
|
f@0
|
1617
|
f@0
|
1618 /**
|
f@0
|
1619 * Prompts the user with a dialog edit notes on a tree node. Which node is to be
|
f@0
|
1620 * noted depends on the currently selected tree node on the tree.
|
f@0
|
1621 */
|
f@0
|
1622 public void editNotes(){
|
f@0
|
1623 DiagramPanel dPanel = getActiveTab();
|
f@0
|
1624 DiagramTreeNode treeNode = (DiagramTreeNode)dPanel.getTree().getLastSelectedPathComponent();
|
f@0
|
1625 DiagramModelUpdater modelUpdater = dPanel.getDiagram().getModelUpdater();
|
f@0
|
1626 if(!modelUpdater.getLock(treeNode, Lock.NOTES, DiagramEventActionSource.NULL)){
|
f@0
|
1627 iLog("Could not get lock on tree node for notes",treeNode.getName());
|
f@0
|
1628 SpeechOptionPane.showMessageDialog(this, resources.getString("dialog.lock_failure.notes"), SpeechOptionPane.INFORMATION_MESSAGE);
|
f@0
|
1629 SoundFactory.getInstance().play(SoundEvent.MESSAGE_OK);
|
f@0
|
1630 return;
|
f@0
|
1631 }
|
f@0
|
1632
|
f@0
|
1633 String typeString = "";
|
f@0
|
1634 /* if the note is for a diagram element the dialog message is changed so that the type precedes the name */
|
f@0
|
1635 if(treeNode instanceof DiagramElement){
|
f@0
|
1636 typeString = ((DiagramElement)treeNode).getType() + " ";
|
f@0
|
1637 }
|
f@0
|
1638 /* if the note is for a property tree node the dialog message is changed so that the type precedes the name */
|
f@0
|
1639 if(treeNode instanceof PropertyMutableTreeNode){
|
f@0
|
1640 PropertyTypeMutableTreeNode parent = (PropertyTypeMutableTreeNode)treeNode.getParent();
|
f@0
|
1641 typeString = parent.getType() + " ";
|
f@0
|
1642 }
|
f@0
|
1643 iLog("open edit note dialog","");
|
f@0
|
1644 String result = SpeechOptionPane.showTextAreaDialog(EditorFrame.this, resources.getString("dialog.input.notes.text")+typeString+treeNode.getName() ,treeNode.getNotes());
|
f@0
|
1645 if(result != null){
|
f@0
|
1646 modelUpdater.setNotes(treeNode, result,DiagramEventSource.TREE);
|
f@0
|
1647 }else{
|
f@0
|
1648 iLog("cancel edit note dialog","");
|
f@0
|
1649 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1650 }
|
f@0
|
1651 modelUpdater.yieldLock(treeNode, Lock.NOTES,DiagramEventActionSource.NULL);
|
f@0
|
1652 }
|
f@0
|
1653
|
f@0
|
1654 /**
|
f@0
|
1655 * Starts the server on a background thread.
|
f@0
|
1656 */
|
f@0
|
1657 public void startServer(){
|
f@0
|
1658 iLog("server started","");
|
f@0
|
1659 /* If the awareness filter has not been created yet (by opening the awareness filter dialog) then create it */
|
f@0
|
1660 BroadcastFilter filter = BroadcastFilter.getInstance();
|
f@0
|
1661 if(filter == null)
|
f@0
|
1662 try{
|
f@0
|
1663 filter = BroadcastFilter.createInstance();
|
f@0
|
1664 }catch(IOException ioe){
|
f@0
|
1665 SpeechOptionPane.showMessageDialog(this, ioe.getLocalizedMessage());
|
f@0
|
1666 }
|
f@0
|
1667 /* create the server */
|
f@0
|
1668 server = Server.createServer();
|
f@0
|
1669 try{
|
f@0
|
1670 server.init();
|
f@0
|
1671 }catch(IOException ioe){
|
f@0
|
1672 SpeechOptionPane.showMessageDialog(
|
f@0
|
1673 editorTabbedPane,
|
f@0
|
1674 ioe.getLocalizedMessage());
|
f@0
|
1675 iLog("error: starting server",ioe.getLocalizedMessage());
|
f@0
|
1676 return;
|
f@0
|
1677 }
|
f@0
|
1678 server.start();
|
f@0
|
1679 startServerMenuItem.setEnabled(false);
|
f@0
|
1680 stopServerMenuItem.setEnabled(true);
|
f@0
|
1681 if(getActiveTab() != null && (!(getActiveTab().getDiagram() instanceof NetDiagram)))
|
f@0
|
1682 shareDiagramMenuItem.setEnabled(true);
|
f@0
|
1683 }
|
f@0
|
1684
|
f@0
|
1685 /**
|
f@0
|
1686 * Stops the running server
|
f@0
|
1687 */
|
f@0
|
1688 public void stopServer(){
|
f@0
|
1689 /* those network diagrams which are connected to the local server are reverted, *
|
f@0
|
1690 * that is the diagram panel is set with the delegate diagram of the network diagram */
|
f@0
|
1691 for(int i=0; i < editorTabbedPane.getTabCount(); i++){
|
f@0
|
1692 DiagramPanel dPanel = editorTabbedPane.getComponentAt(i);
|
f@0
|
1693 if(dPanel.getDiagram() instanceof NetDiagram){
|
f@0
|
1694 NetDiagram netDiagram = (NetDiagram)dPanel.getDiagram();
|
f@0
|
1695 if(netDiagram.getSocketChannel().equals(localSocket)){
|
f@0
|
1696 dPanel.setAwarenessPanelEnabled(false);
|
f@0
|
1697 dPanel.setDiagram(netDiagram.getDelegate());
|
f@0
|
1698 }
|
f@0
|
1699 }
|
f@0
|
1700 }
|
f@0
|
1701 server.shutdown(resources.getString("server.shutdown_msg"));
|
f@0
|
1702 server = null;
|
f@0
|
1703 if(localSocket != null){
|
f@0
|
1704 try{localSocket.close();}catch(IOException ioe){ioe.printStackTrace();}
|
f@0
|
1705 localSocket = null;
|
f@0
|
1706 }
|
f@0
|
1707 startServerMenuItem.setEnabled(true);
|
f@0
|
1708 stopServerMenuItem.setEnabled(false);
|
f@0
|
1709 shareDiagramMenuItem.setEnabled(false);
|
f@0
|
1710 if(getActiveTab() != null)
|
f@0
|
1711 fileCloseItem.setEnabled(true);
|
f@0
|
1712 iLog("server stopped","");
|
f@0
|
1713 }
|
f@0
|
1714
|
f@0
|
1715 /**
|
f@0
|
1716 * Makes a diagram shared on the server. When a diagram is shared, remote users can connect to the
|
f@0
|
1717 * server and edit it collaboratively with the local and the other connected users.
|
f@0
|
1718 */
|
f@0
|
1719 public void shareDiagram(){
|
f@0
|
1720 try{
|
f@0
|
1721 if(server == null)
|
f@0
|
1722 throw new DiagramShareException(resources.getString("server.not_running_exc"));
|
f@0
|
1723
|
f@0
|
1724 DiagramPanel dPanel = getActiveTab();
|
f@0
|
1725 Diagram diagram = dPanel.getDiagram();
|
f@0
|
1726 try {
|
f@0
|
1727 iLog("share diagram",diagram.getName());
|
f@0
|
1728 /* check if it's already connected to the local server (a.k.a. another diagram has been shared previously */
|
f@0
|
1729 if(localSocket == null){
|
f@0
|
1730 int port = Integer.parseInt(PreferencesService.getInstance().get("server.local_port",Server.DEFAULT_REMOTE_PORT));
|
f@0
|
1731 InetSocketAddress address = new InetSocketAddress("127.0.0.1",port);
|
f@0
|
1732 localSocket = SocketChannel.open(address);
|
f@0
|
1733 }
|
f@0
|
1734
|
f@0
|
1735 server.share(diagram);
|
f@0
|
1736 ProtocolFactory.newInstance().send(localSocket, new Command(Command.Name.LOCAL,diagram.getName(),DiagramEventSource.NONE));
|
f@0
|
1737 dPanel.setDiagram(NetDiagram.wrapLocalHost(diagram,localSocket,server.getLocalhostQueue(diagram.getName()),netLocalDiagramExceptionHandler));
|
f@0
|
1738 /* share a diagram once is enought :) */
|
f@0
|
1739 shareDiagramMenuItem.setEnabled(false);
|
f@0
|
1740 /* no close, there might be clients connected. unshare first. */
|
f@0
|
1741 fileCloseItem.setEnabled(false);
|
f@0
|
1742 /* only enabled for local diagram, otherwise changing the name *
|
f@0
|
1743 * of the diagram would messes up the network protocol */
|
f@0
|
1744 fileSaveAsItem.setEnabled(false);
|
f@0
|
1745 dPanel.setAwarenessPanelEnabled(true);
|
f@0
|
1746 } catch (IOException e) {
|
f@0
|
1747 iLog("error sharing diagram",diagram.getName()+" "+e.getLocalizedMessage());
|
f@0
|
1748 SpeechOptionPane.showMessageDialog(EditorFrame.this, e.getLocalizedMessage());
|
f@0
|
1749 return;
|
f@0
|
1750 }
|
f@0
|
1751 }catch(DiagramShareException dse){
|
f@0
|
1752 SpeechOptionPane.showMessageDialog(EditorFrame.this, dse.getLocalizedMessage());
|
f@0
|
1753 }
|
f@0
|
1754 }
|
f@0
|
1755
|
f@0
|
1756 /**
|
f@0
|
1757 * Prompts the user for a server address and connect to the server. The server is queried for the list
|
f@0
|
1758 * of the shared diagrams and the user is prompted with a selection dialog to chose a diagram to download.
|
f@0
|
1759 * The diagram is then downloaded and loaded into the diagram editor, ready for shared editing.
|
f@0
|
1760 *
|
f@0
|
1761 */
|
f@0
|
1762 public void openSharedDiagram(){
|
f@0
|
1763 iLog("open open share diagram dialog","");
|
f@0
|
1764 /* open the window prompting for the server address and make checks on the user input */
|
f@0
|
1765 String addr = SpeechOptionPane.showInputDialog(
|
f@0
|
1766 EditorFrame.this,
|
f@0
|
1767 resources.getString("dialog.share_diagram.enter_address"),
|
f@0
|
1768 PreferencesService.getInstance().get("server.address", ""));
|
f@0
|
1769 if(addr == null){
|
f@0
|
1770 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1771 iLog("cancel open share diagram dialog","");
|
f@0
|
1772 return;
|
f@0
|
1773 }else if(!ProtocolFactory.validateIPAddr(addr)){
|
f@0
|
1774 iLog("error:invalid IP address",addr);
|
f@0
|
1775 SpeechOptionPane.showMessageDialog(this, resources.getString("dialog.share_diagram.wrong_ip"));
|
f@0
|
1776 return;
|
f@0
|
1777 }else{
|
f@0
|
1778 PreferencesService.getInstance().put("server.address", addr);
|
f@0
|
1779 /* open the channel for the new diagram */
|
f@0
|
1780 SocketChannel channel = null;
|
f@0
|
1781 try {
|
f@0
|
1782 channel = SocketChannel.open();
|
f@0
|
1783 } catch (IOException e) {
|
f@0
|
1784 iLog("error:could not connect to the server","");
|
f@0
|
1785 SpeechOptionPane.showMessageDialog(EditorFrame.this, resources.getString("dialog.error.no_connection_to_server"));
|
f@0
|
1786 return;
|
f@0
|
1787 }
|
f@0
|
1788 /* download the diagram list */
|
f@0
|
1789 DiagramDownloader downloader = new DiagramDownloader(
|
f@0
|
1790 channel,
|
f@0
|
1791 addr,
|
f@0
|
1792 DiagramDownloader.CONNECT_AND_DOWNLOAD_LIST_TASK
|
f@0
|
1793 );
|
f@0
|
1794 iLog("open download diagram list dialog","");
|
f@0
|
1795 int option = SpeechOptionPane.showProgressDialog(EditorFrame.this, resources.getString("dialog.downloading_diagram_list"), downloader,500);
|
f@0
|
1796 if(option == SpeechOptionPane.CANCEL_OPTION){
|
f@0
|
1797 iLog("cancel download diagram list dialog","");
|
f@0
|
1798 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1799 try{channel.close();}catch(IOException ioe){ioe.printStackTrace();}
|
f@0
|
1800 }else{
|
f@0
|
1801 try{
|
f@0
|
1802 /* show the available diagram list */
|
f@0
|
1803 String result = downloader.get();
|
f@0
|
1804 if(result == null)
|
f@0
|
1805 throw new Exception(resources.getString("dialog.error.no_diagrams_on_server")); // go to the catch block
|
f@0
|
1806 String[] diagramsList = result.split("\n");
|
f@0
|
1807
|
f@0
|
1808 iLog("open select diagram to download dialog","");
|
f@0
|
1809 String diagramName = (String)SpeechOptionPane.showSelectionDialog(EditorFrame.this, "Select diagram to download", diagramsList, diagramsList[0]);
|
f@0
|
1810 if(diagramName == null){
|
f@0
|
1811 iLog("cancel select diagram to download dialog","");
|
f@0
|
1812 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1813 try{channel.close();}catch(IOException ioe){ioe.printStackTrace();}
|
f@0
|
1814 return;
|
f@0
|
1815 }
|
f@0
|
1816 /* there cannot be two diagrams with the same name open at the same time */
|
f@0
|
1817 if(editorTabbedPane.getDiagramNameTabIndex(diagramName) != -1)
|
f@0
|
1818 throw new IOException(resources.getString("dialog.error.same_file_name"));
|
f@0
|
1819 /* download the chosen diagram */
|
f@0
|
1820 downloader = new DiagramDownloader(channel,diagramName,DiagramDownloader.DOWNLOAD_DIAGRAM_TASK);
|
f@0
|
1821 iLog("open downloading diagram dialog",diagramName);
|
f@0
|
1822 option = SpeechOptionPane.showProgressDialog(EditorFrame.this, MessageFormat.format(resources.getString("dialog.downloading_diagram"), diagramName), downloader,500);
|
f@0
|
1823 if(option == SpeechOptionPane.CANCEL_OPTION){
|
f@0
|
1824 iLog("cancel downloading diagram dialog",diagramName);
|
f@0
|
1825 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
1826 try{channel.close();}catch(IOException ioe){ioe.printStackTrace();};
|
f@0
|
1827 }else{
|
f@0
|
1828 result = downloader.get();
|
f@0
|
1829
|
f@0
|
1830 if(clientConnectionManager == null || !clientConnectionManager.isAlive()){
|
f@0
|
1831 clientConnectionManager = new ClientConnectionManager(editorTabbedPane);
|
f@0
|
1832 clientConnectionManager.start();
|
f@0
|
1833 }
|
f@0
|
1834
|
f@0
|
1835 iLog("START READ NETWORK DIAGRAM "+diagramName);
|
f@0
|
1836 // FIXME no pd patches supported
|
f@0
|
1837 Diagram diagram = PersistenceManager.decodeDiagramInstance(new BufferedInputStream(new ByteArrayInputStream(result.getBytes("UTF-8"))));
|
f@0
|
1838 iLog("END READ NETWORK DIAGRAM "+diagramName);
|
f@0
|
1839 /* remove all the bookmarks in the server diagram model instance */
|
f@0
|
1840 for(String bookmarkKey : diagram.getTreeModel().getBookmarks())
|
f@0
|
1841 diagram.getTreeModel().removeBookmark(bookmarkKey,DiagramEventSource.TREE);
|
f@0
|
1842 Diagram newDiagram = NetDiagram.wrapRemoteHost(diagram,clientConnectionManager,channel);
|
f@0
|
1843 DiagramPanel dPanel = addTab(null,newDiagram);
|
f@0
|
1844 /* enable awareness on the new diagram */
|
f@0
|
1845 dPanel.setAwarenessPanelEnabled(true);
|
f@0
|
1846 /* make the network thread aware of the new shared diagram, from here on the messages received from the server will take effect */
|
f@0
|
1847 clientConnectionManager.addRequest(new ClientConnectionManager.AddDiagramRequest(channel, diagram));
|
f@0
|
1848 clientConnectionManager.addRequest(new SendAwarenessRequest(channel, new AwarenessMessage(
|
f@0
|
1849 AwarenessMessage.Name.USERNAME_A,
|
f@0
|
1850 newDiagram.getName(),
|
f@0
|
1851 AwarenessMessage.getDefaultUserName()
|
f@0
|
1852 )));
|
f@0
|
1853 }
|
f@0
|
1854 }catch(RuntimeException rte){
|
f@0
|
1855 throw new RuntimeException(rte);
|
f@0
|
1856 }catch(ExecutionException ee){
|
f@0
|
1857 try{channel.close();}catch(IOException ioe){ioe.printStackTrace();};
|
f@0
|
1858 /* if the exception happened in the DiagramDownloader then it's wrapped into an *
|
f@0
|
1859 * ExecutionException and we have to unwrap it to get a neat message for the user */
|
f@0
|
1860 SpeechOptionPane.showMessageDialog(
|
f@0
|
1861 editorTabbedPane,
|
f@0
|
1862 ee.getCause().getLocalizedMessage());
|
f@0
|
1863 iLog("error: "+ee.getCause().getMessage(),"");
|
f@0
|
1864 }catch(Exception exception){
|
f@0
|
1865 try{channel.close();}catch(IOException ioe){ioe.printStackTrace();};
|
f@0
|
1866 SpeechOptionPane.showMessageDialog(
|
f@0
|
1867 editorTabbedPane,
|
f@0
|
1868 exception.getLocalizedMessage());
|
f@0
|
1869 iLog("error: "+exception.getMessage(),"");
|
f@0
|
1870 }
|
f@0
|
1871 }
|
f@0
|
1872 }
|
f@0
|
1873 }
|
f@0
|
1874
|
f@0
|
1875 /**
|
f@0
|
1876 * Shows the awareness panel, a text pane where all the awareness informations received by the server
|
f@0
|
1877 * are displayed.
|
f@0
|
1878 */
|
f@0
|
1879 public void showAwarenessPanel(){
|
f@0
|
1880 DiagramPanel dPanel = getActiveTab();
|
f@0
|
1881 if(dPanel != null){
|
f@0
|
1882 dPanel.setAwarenessPanelVisible(true);
|
f@0
|
1883 NarratorFactory.getInstance().speak(resources.getString("speech.awareness_panel.open"));
|
f@0
|
1884 }
|
f@0
|
1885 }
|
f@0
|
1886
|
f@0
|
1887 /**
|
f@0
|
1888 * Hides the awareness panel, a text pane where all the awareness informations received by the server
|
f@0
|
1889 * are displayed.
|
f@0
|
1890 */
|
f@0
|
1891 public void hideAwarenessPanel(){
|
f@0
|
1892 DiagramPanel dPanel = getActiveTab();
|
f@0
|
1893 if(dPanel != null){
|
f@0
|
1894 dPanel.setAwarenessPanelVisible(false);
|
f@0
|
1895 NarratorFactory.getInstance().speak(resources.getString("speech.awareness_panel.close"));
|
f@0
|
1896 dPanel.getTree().requestFocus();
|
f@0
|
1897 }
|
f@0
|
1898 }
|
f@0
|
1899
|
f@0
|
1900 /**
|
f@0
|
1901 * Saves all the open diagram which have been modified since the last time they were saved into the
|
f@0
|
1902 * <i>backup</i> folder in the ccmi_editor_data directory.
|
f@0
|
1903 */
|
f@0
|
1904 public void backupOpenDiagrams(){
|
f@0
|
1905 SimpleDateFormat dateFormat = new SimpleDateFormat("EEE_d_MMM_yyyy_HH_mm_ss");
|
f@0
|
1906 String date = dateFormat.format(new Date());
|
f@0
|
1907 File backupDir = new File(new StringBuilder(backupDirPath)
|
f@0
|
1908 .append(System.getProperty("file.separator"))
|
f@0
|
1909 .append(date)
|
f@0
|
1910 .toString());
|
f@0
|
1911 backupDir.mkdir();
|
f@0
|
1912 for(int i=0; i<editorTabbedPane.getTabCount();i++){
|
f@0
|
1913 DiagramPanel dPanel = editorTabbedPane.getComponentAt(i);
|
f@0
|
1914 if(dPanel.isModified()||dPanel.getFilePath() == null){
|
f@0
|
1915 Diagram diagram = dPanel.getDiagram();
|
f@0
|
1916 File file = new File(backupDir,diagram.getName()+".ccmi");
|
f@0
|
1917 try {
|
f@0
|
1918 FileService.Save save = new FileService.DirectService().save((file));
|
f@0
|
1919 if(diagram instanceof PdDiagram){
|
f@0
|
1920 PdPersistenceManager.getInstance().encodeDiagramInstance(diagram, save.getOutputStream());
|
f@0
|
1921 }else {
|
f@0
|
1922 PersistenceManager.encodeDiagramInstance(diagram, save.getOutputStream());
|
f@0
|
1923 }
|
f@0
|
1924 } catch (IOException e) {
|
f@0
|
1925 e.printStackTrace();
|
f@0
|
1926 }
|
f@0
|
1927 }
|
f@0
|
1928 }
|
f@0
|
1929 }
|
f@0
|
1930
|
f@0
|
1931 /**
|
f@0
|
1932 Exports the current graph to an image file.
|
f@0
|
1933 */
|
f@0
|
1934 public void exportImage(){
|
f@0
|
1935 DiagramPanel dPanel = getActiveTab();
|
f@0
|
1936 if (dPanel == null)
|
f@0
|
1937 return;
|
f@0
|
1938 OutputStream out = null;
|
f@0
|
1939 try{
|
f@0
|
1940 String imageExtensions = resources.getString("files.image.extension");
|
f@0
|
1941 /* default save dir is the same as the diagram's or home/images otherwise */
|
f@0
|
1942 String path = dPanel.getFilePath();
|
f@0
|
1943 if(path == null)
|
f@0
|
1944 path = PreferencesService.getInstance().get("dir.images", ".");
|
f@0
|
1945 FileService.Save save = fileService.save(path, dPanel.getDiagram().getName(), exportFilter,
|
f@0
|
1946 defaultExtension, imageExtensions,null);
|
f@0
|
1947 out = save.getOutputStream();
|
f@0
|
1948 if (out != null){
|
f@0
|
1949 /* if the diagram has a name (has already been saved) then prompt the user with the name of
|
f@0
|
1950 * the diagram with a jpg extension. */
|
f@0
|
1951 String fileName = FileService.getFileNameFromPath(save.getPath(),true);
|
f@0
|
1952 String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
|
f@0
|
1953 if (!ImageIO.getImageWritersByFormatName(extension).hasNext()){
|
f@0
|
1954 throw new IOException(MessageFormat.format(
|
f@0
|
1955 resources.getString("dialog.error.unsupported_image"),
|
f@0
|
1956 extension
|
f@0
|
1957 ));
|
f@0
|
1958 }
|
f@0
|
1959 GraphPanel gPanel = dPanel.getGraphPanel();
|
f@0
|
1960 try{
|
f@0
|
1961 saveImage(gPanel, out, extension);
|
f@0
|
1962 speakFocusedComponent(resources.getString("dialog.file_saved"));
|
f@0
|
1963 }catch(IOException ioe){
|
f@0
|
1964 throw new IOException(resources.getString("dialog.error.save_image"),ioe);
|
f@0
|
1965 }
|
f@0
|
1966 }
|
f@0
|
1967 }
|
f@0
|
1968 catch (IOException ioe){
|
f@0
|
1969 SpeechOptionPane.showMessageDialog(editorTabbedPane,ioe.getMessage());
|
f@0
|
1970 }finally{
|
f@0
|
1971 if(out != null)
|
f@0
|
1972 try{out.close();}catch(IOException ioe){ioe.printStackTrace();}
|
f@0
|
1973 }
|
f@0
|
1974 }
|
f@0
|
1975
|
f@0
|
1976 /**
|
f@0
|
1977 Exports a current graph to an image file.
|
f@0
|
1978 @param graph the graph
|
f@0
|
1979 @param out the output stream
|
f@0
|
1980 @param format the image file format
|
f@0
|
1981
|
f@0
|
1982 @throws IOException if something goes wrong during the I/O operations
|
f@0
|
1983 */
|
f@0
|
1984 public static void saveImage(GraphPanel graph, OutputStream out, String format)
|
f@0
|
1985 throws IOException {
|
f@0
|
1986 // need a dummy image to get a Graphics to measure the size
|
f@0
|
1987 Rectangle2D bounds = graph.getBounds();
|
f@0
|
1988 BufferedImage image
|
f@0
|
1989 = new BufferedImage((int)bounds.getWidth() + 1,
|
f@0
|
1990 (int)bounds.getHeight() + 1,
|
f@0
|
1991 BufferedImage.TYPE_INT_RGB);
|
f@0
|
1992 Graphics2D g2 = (Graphics2D)image.getGraphics();
|
f@0
|
1993 g2.translate(-bounds.getX(), -bounds.getY());
|
f@0
|
1994 g2.setColor(Color.WHITE);
|
f@0
|
1995 g2.fill(new Rectangle2D.Double(
|
f@0
|
1996 bounds.getX(),
|
f@0
|
1997 bounds.getY(),
|
f@0
|
1998 bounds.getWidth() + 1,
|
f@0
|
1999 bounds.getHeight() + 1));
|
f@0
|
2000 g2.setColor(Color.BLACK);
|
f@0
|
2001 g2.setBackground(Color.WHITE);
|
f@0
|
2002 boolean hideGrid = graph.getHideGrid();
|
f@0
|
2003 graph.setHideGrid(true);
|
f@0
|
2004 graph.paintComponent(g2);
|
f@0
|
2005 graph.setHideGrid(hideGrid);
|
f@0
|
2006 ImageIO.write(image, format, out);
|
f@0
|
2007 }
|
f@0
|
2008
|
f@0
|
2009 /**
|
f@0
|
2010 * Shows the configuration dialog of the broadcast filter. The broadcast filter affects
|
f@0
|
2011 * which awareness informations are broadcasted from the server to the other clients.
|
f@0
|
2012 * If the local editor is not running the server, changes to the broadcast filter
|
f@0
|
2013 * will have no effect.
|
f@0
|
2014 */
|
f@0
|
2015 public void showAwarenessBroadcastDialog(){
|
f@0
|
2016 BroadcastFilter filter = BroadcastFilter.getInstance();
|
f@0
|
2017 if(filter == null)
|
f@0
|
2018 try{
|
f@0
|
2019 filter = BroadcastFilter.createInstance();
|
f@0
|
2020 }catch(IOException ioe){
|
f@0
|
2021 SpeechOptionPane.showMessageDialog(this, ioe.getLocalizedMessage());
|
f@0
|
2022 }
|
f@0
|
2023 filter.showDialog(this);
|
f@0
|
2024 }
|
f@0
|
2025
|
f@0
|
2026 /**
|
f@0
|
2027 * Shows the configuration dialog of the display filter. The display filter affects
|
f@0
|
2028 * which awareness informations are received from the server are actually displayed
|
f@0
|
2029 * to the user.
|
f@0
|
2030 */
|
f@0
|
2031 public void showAwarenessDisplayDialog(){
|
f@0
|
2032 DisplayFilter filter = DisplayFilter.getInstance();
|
f@0
|
2033 if(filter == null)
|
f@0
|
2034 try{
|
f@0
|
2035 filter = DisplayFilter.createInstance();
|
f@0
|
2036 }catch(IOException ioe){
|
f@0
|
2037 SpeechOptionPane.showMessageDialog(this, ioe.getLocalizedMessage());
|
f@0
|
2038 }
|
f@0
|
2039 filter.showDialog(this);
|
f@0
|
2040 }
|
f@0
|
2041
|
f@0
|
2042 /**
|
f@0
|
2043 * Prompts the user with a dialog to choose he awareness username. The username is used in the
|
f@0
|
2044 * awareness information to identify which client is doing the actions that are being notified.
|
f@0
|
2045 */
|
f@0
|
2046 public void showAwarnessUsernameDialog(){
|
f@0
|
2047 String oldName = AwarenessMessage.getDefaultUserName();
|
f@0
|
2048 String newName = SpeechOptionPane.showInputDialog(
|
f@0
|
2049 this,
|
f@0
|
2050 resources.getString("dialog.input.awerness_username"),
|
f@0
|
2051 oldName
|
f@0
|
2052 );
|
f@0
|
2053 if(newName == null){
|
f@0
|
2054 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
2055 return;
|
f@0
|
2056 }
|
f@0
|
2057
|
f@0
|
2058 if(newName.trim().isEmpty()){
|
f@0
|
2059 SoundFactory.getInstance().play(SoundEvent.ERROR, new PlayerListener(){
|
f@0
|
2060 @Override
|
f@0
|
2061 public void playEnded() {
|
f@0
|
2062 NarratorFactory.getInstance().speak(resources.getString("speech.empty_userame"));
|
f@0
|
2063 }
|
f@0
|
2064 });
|
f@0
|
2065 return;
|
f@0
|
2066 }
|
f@0
|
2067
|
f@0
|
2068 if(!newName.equals(oldName)){//if the name hasn't changed don't issue any message
|
f@0
|
2069 PreferencesService.getInstance().put("user.name", newName);
|
f@0
|
2070 AwarenessMessage.setDefaultUserName(newName);
|
f@0
|
2071 NarratorFactory.getInstance().speak(MessageFormat.format(
|
f@0
|
2072 resources.getString("dialog.feedback.awareness_username"),
|
f@0
|
2073 newName
|
f@0
|
2074 ));
|
f@0
|
2075 for(int i=0; i<editorTabbedPane.getTabCount(); i++){
|
f@0
|
2076 Diagram diagram = editorTabbedPane.getComponentAt(i).getDiagram();
|
f@0
|
2077 diagram.getModelUpdater().sendAwarenessMessage(
|
f@0
|
2078 AwarenessMessage.Name.USERNAME_A,
|
f@0
|
2079 newName);// send the new name only, the old name will be added by the server
|
f@0
|
2080 }
|
f@0
|
2081 }
|
f@0
|
2082 }
|
f@0
|
2083
|
f@0
|
2084 /**
|
f@0
|
2085 * Prompts the user with a dialog to choose the port number the local server will listen on.
|
f@0
|
2086 */
|
f@0
|
2087 public void showLocalServerPortDialog(){
|
f@0
|
2088 showServerPortDialog("server.local_port","dialog.input.local_server_port","dialog.feedback.local_server_port");
|
f@0
|
2089 }
|
f@0
|
2090
|
f@0
|
2091 /**
|
f@0
|
2092 * Prompts the user with a dialog to choose the remote server port number to connect to.
|
f@0
|
2093 */
|
f@0
|
2094 public void showRemoteServerPortDialog(){
|
f@0
|
2095 showServerPortDialog("server.remote_port","dialog.input.remote_server_port","dialog.feedback.remote_server_port");
|
f@0
|
2096 }
|
f@0
|
2097
|
f@0
|
2098 private void showServerPortDialog(String preferenceKey,String dialogMessage,String feedbackMessage){
|
f@0
|
2099 String oldPort = PreferencesService.getInstance().get(preferenceKey,Server.DEFAULT_LOCAL_PORT);
|
f@0
|
2100 String newPort = SpeechOptionPane.showInputDialog(this, resources.getString(dialogMessage), oldPort);
|
f@0
|
2101 if(newPort == null){
|
f@0
|
2102 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
2103 return;
|
f@0
|
2104 }
|
f@0
|
2105
|
f@0
|
2106 boolean badFormat = false;
|
f@0
|
2107 try {
|
f@0
|
2108 int port = Integer.parseInt(newPort);
|
f@0
|
2109 if(port <= 0 || port > 65535)
|
f@0
|
2110 badFormat = true;
|
f@0
|
2111 }catch(NumberFormatException nfe){
|
f@0
|
2112 badFormat = true;
|
f@0
|
2113 }
|
f@0
|
2114
|
f@0
|
2115 if(badFormat){
|
f@0
|
2116 SoundFactory.getInstance().play(SoundEvent.ERROR, new PlayerListener(){
|
f@0
|
2117 @Override
|
f@0
|
2118 public void playEnded() {
|
f@0
|
2119 NarratorFactory.getInstance().speak(resources.getString("speech.bad_format_port"));
|
f@0
|
2120 }
|
f@0
|
2121 });
|
f@0
|
2122 return;
|
f@0
|
2123 }
|
f@0
|
2124 PreferencesService.getInstance().put(preferenceKey,newPort);
|
f@0
|
2125 NarratorFactory.getInstance().speak(MessageFormat.format(
|
f@0
|
2126 resources.getString(feedbackMessage),newPort));
|
f@0
|
2127 }
|
f@0
|
2128
|
f@0
|
2129 /**
|
f@0
|
2130 Displays the About dialog box.
|
f@0
|
2131 */
|
f@0
|
2132 public void showAboutDialog(){
|
f@0
|
2133 String options[] = {resources.getString("dialog.ok_button")};
|
f@0
|
2134 SpeechSummaryPane.showDialog(this,
|
f@0
|
2135 resources.getString("dialog.about.title"),
|
f@0
|
2136 MessageFormat.format(resources.getString("dialog.about"),
|
f@0
|
2137 resources.getString("app.name"),
|
f@0
|
2138 resources.getString("app.version"),
|
f@0
|
2139 resources.getString("dialog.about.description"),
|
f@0
|
2140 resources.getString("dialog.about.license")),
|
f@0
|
2141 SpeechSummaryPane.OK_OPTION,
|
f@0
|
2142 options
|
f@0
|
2143 );
|
f@0
|
2144 }
|
f@0
|
2145
|
f@0
|
2146 /**
|
f@0
|
2147 * Displays the Software license in a dialog box.
|
f@0
|
2148 */
|
f@0
|
2149 public void showLicense() {
|
f@0
|
2150 BufferedReader reader = null;
|
f@0
|
2151 try{
|
f@0
|
2152 reader = new BufferedReader(
|
f@0
|
2153 new InputStreamReader(
|
f@0
|
2154 getClass().getResourceAsStream(
|
f@0
|
2155 "license.txt")));
|
f@0
|
2156 StringBuilder builder = new StringBuilder();
|
f@0
|
2157 String line;
|
f@0
|
2158 while ((line = reader.readLine()) != null){
|
f@0
|
2159 builder.append(line).append('\n');
|
f@0
|
2160 }
|
f@0
|
2161 String options[] = {resources.getString("dialog.ok_button")};
|
f@0
|
2162 SpeechSummaryPane.showDialog(editorTabbedPane,
|
f@0
|
2163 resources.getString("dialog.license.title"),
|
f@0
|
2164 builder.toString(),
|
f@0
|
2165 SpeechSummaryPane.OK_OPTION,options);
|
f@0
|
2166 }catch (IOException exception){
|
f@0
|
2167 SpeechOptionPane.showMessageDialog(this, resources.getString("dialog.error.license_not_found"));
|
f@0
|
2168 }finally{
|
f@0
|
2169 if(reader != null)
|
f@0
|
2170 try{reader.close();}catch(IOException ioe){ioe.printStackTrace();}
|
f@0
|
2171 }
|
f@0
|
2172 }
|
f@0
|
2173
|
f@0
|
2174 /**
|
f@0
|
2175 * Saves the diagram template in the <i>templates</i> folder.
|
f@0
|
2176 *
|
f@0
|
2177 * The template can then be reused to create new diagrams with the same type of nodes and
|
f@0
|
2178 * edges.
|
f@0
|
2179 *
|
f@0
|
2180 * @param diagram the diagram to get the template from
|
f@0
|
2181 * @throws IOException if something goes wrong with I/O when saving the file
|
f@0
|
2182 */
|
f@0
|
2183 public void saveDiagramTemplate(Diagram diagram) throws IOException {
|
f@0
|
2184 File file = new File(
|
f@0
|
2185 new StringBuilder(PreferencesService.getInstance().get("home", "."))
|
f@0
|
2186 .append(System.getProperty("file.separator"))
|
f@0
|
2187 .append(resources.getString("dir.templates"))
|
f@0
|
2188 .append(System.getProperty("file.separator"))
|
f@0
|
2189 .append(diagram.getName())
|
f@0
|
2190 .append(resources.getString("template.extension"))
|
f@0
|
2191 .toString()
|
f@0
|
2192 );
|
f@0
|
2193 PersistenceManager.encodeDiagramTemplate(diagram,file);
|
f@0
|
2194
|
f@0
|
2195 }
|
f@0
|
2196
|
f@0
|
2197 /**
|
f@0
|
2198 * Adds a diagram type to the File->New menu.
|
f@0
|
2199 *
|
f@0
|
2200 * @param diagram the diagram whose nodes and edges definition will be used as a template
|
f@0
|
2201 * for new diagrams creation.
|
f@0
|
2202 *
|
f@0
|
2203 */
|
f@0
|
2204 public void addDiagramType(final Diagram diagram){
|
f@0
|
2205 /* this is to prevent the user from creating other diagram prototypes with the same name */
|
f@0
|
2206 existingTemplateNames.add(diagram.getName());
|
f@0
|
2207 existingTemplates.add(diagram);
|
f@0
|
2208 JMenuItem newTypeItem = SpeechMenuFactory.getMenuItem(diagram.getName());
|
f@0
|
2209 newTypeItem.addActionListener(new ActionListener(){
|
f@0
|
2210 @Override
|
f@0
|
2211 public void actionPerformed(ActionEvent event){
|
f@0
|
2212 Diagram clone = (Diagram)diagram.clone();
|
f@0
|
2213 /* find a good unique name for the new tab */
|
f@0
|
2214 Pattern pattern = Pattern.compile("new "+clone.getName()+"( \\(([0-9]+)\\))?");
|
f@0
|
2215 int maxOpenDiagram = -1;
|
f@0
|
2216 for(int i=0;i<editorTabbedPane.getTabCount();i++){
|
f@0
|
2217 Matcher matcher = pattern.matcher(editorTabbedPane.getComponentAt(i).getDiagram().getName());
|
f@0
|
2218 if(matcher.matches()){
|
f@0
|
2219 if(matcher.group(1) == null)
|
f@0
|
2220 maxOpenDiagram = 0;
|
f@0
|
2221 else
|
f@0
|
2222 maxOpenDiagram = Math.max(maxOpenDiagram, Integer.parseInt(matcher.group(2)));
|
f@0
|
2223 }
|
f@0
|
2224 }
|
f@0
|
2225 if(maxOpenDiagram >= 0)
|
f@0
|
2226 clone.setName(String.format("new %s (%d)", clone.getName(),++maxOpenDiagram));
|
f@0
|
2227 else clone.setName("new "+clone.getName());
|
f@0
|
2228 addTab(null, clone);
|
f@0
|
2229 iLog("new diagram created of type: "+diagram.getName());
|
f@0
|
2230 }
|
f@0
|
2231 });
|
f@0
|
2232 newMenu.add(newTypeItem);
|
f@0
|
2233 }
|
f@0
|
2234
|
f@0
|
2235 /**
|
f@0
|
2236 * Saves the user preferences before exiting.
|
f@0
|
2237 */
|
f@0
|
2238 public void savePreferences(){
|
f@0
|
2239 String recent = "";
|
f@0
|
2240 for (int i = 0; i < Math.min(recentFiles.size(), maxRecentFiles); i++){
|
f@0
|
2241 if (recent.length() > 0) recent += "|";
|
f@0
|
2242 recent += recentFiles.get(i);
|
f@0
|
2243 }
|
f@0
|
2244 preferences.put("recent", recent);
|
f@0
|
2245 }
|
f@0
|
2246
|
f@0
|
2247 /**
|
f@0
|
2248 * Returns the currently selected tab's diagram panel.
|
f@0
|
2249 *
|
f@0
|
2250 * @return the currently selected tab's diagram panel or {@code null}
|
f@0
|
2251 * if no tab is open.
|
f@0
|
2252 */
|
f@0
|
2253 public DiagramPanel getActiveTab(){
|
f@0
|
2254 return (DiagramPanel)editorTabbedPane.getSelectedComponent();
|
f@0
|
2255 }
|
f@0
|
2256
|
f@0
|
2257 /**
|
f@0
|
2258 * Set the variable holding the node or edge that would be highlighted if
|
f@0
|
2259 * {@link #hHighlight()} is called. The menu item for highlight is also enabled
|
f@0
|
2260 * if {@code de} is not {@code null}.
|
f@0
|
2261 *
|
f@0
|
2262 * @param de the diagram element to be selected by {@code hHighlight()}
|
f@0
|
2263 * or {@code null} for no selection.
|
f@0
|
2264 */
|
f@0
|
2265 public void selectHapticHighligh(DiagramElement de){
|
f@0
|
2266 hapticHighlightDiagramElement = de;
|
f@0
|
2267 highlightMenuItem.setEnabled(de == null ? false : true);
|
f@0
|
2268 }
|
f@0
|
2269
|
f@0
|
2270 private DiagramPanel addTab(String path, Diagram diagram){
|
f@0
|
2271 DiagramPanel diagramPanel = new DiagramPanel(diagram,editorTabbedPane);
|
f@0
|
2272 diagramPanel.setFilePath(path);
|
f@0
|
2273 diagramPanel.getTree().addTreeSelectionListener(treeSelectionListener);
|
f@0
|
2274 diagramPanel.setAwarenessPanelListener(awarenessPanelListener);
|
f@0
|
2275 /* update the haptics */
|
f@0
|
2276 haptics.addNewDiagram(diagramPanel.getDiagram().getName());
|
f@0
|
2277 for(Node n : diagram.getCollectionModel().getNodes())
|
f@0
|
2278 haptics.addNode(n.getBounds().getCenterX(), n.getBounds().getCenterY(), System.identityHashCode(n),null);
|
f@0
|
2279 for(Edge e : diagram.getCollectionModel().getEdges()){
|
f@0
|
2280 Edge.PointRepresentation pr = e.getPointRepresentation();
|
f@0
|
2281 haptics.addEdge(System.identityHashCode(e),pr.xs,pr.ys,pr.adjMatrix,pr.nodeStart,e.getStipplePattern(),e.getNameLine(),null);
|
f@0
|
2282 }
|
f@0
|
2283 /* install the listener that handling the haptics device and the one handling the audio feedback */
|
f@0
|
2284 diagram.getCollectionModel().addCollectionListener(hapticTrigger);
|
f@0
|
2285 AudioFeedback audioFeedback = new AudioFeedback(diagramPanel.getTree());
|
f@0
|
2286 diagram.getCollectionModel().addCollectionListener(audioFeedback);
|
f@0
|
2287 diagram.getTreeModel().addDiagramTreeNodeListener(audioFeedback);
|
f@0
|
2288
|
f@0
|
2289 editorTabbedPane.add(diagramPanel);
|
f@0
|
2290 editorTabbedPane.setToolTipTextAt(editorTabbedPane.getTabCount()-1,path);//the new panel is at tabCount -1
|
f@0
|
2291 editorTabbedPane.setSelectedIndex(editorTabbedPane.getTabCount()-1);
|
f@0
|
2292 /* give the focus to the Content Pane, else it's grabbed by the rootPane
|
f@0
|
2293 and it does not work when adding a new tab with the tree focused */
|
f@0
|
2294 getContentPane().requestFocusInWindow();
|
f@0
|
2295 return diagramPanel;
|
f@0
|
2296 }
|
f@0
|
2297
|
f@0
|
2298 private void diagramPanelEnabledMenuUpdate(DiagramPanel dPanel){
|
f@0
|
2299 fileSaveItem.setEnabled(false);
|
f@0
|
2300 fileSaveAsItem.setEnabled(false);
|
f@0
|
2301 fileSaveCopyItem.setEnabled(false);
|
f@0
|
2302 fileCloseItem.setEnabled(false);
|
f@0
|
2303 shareDiagramMenuItem.setEnabled(false);
|
f@0
|
2304 graphExportItem.setEnabled(false);
|
f@0
|
2305 showAwarenessPanelMenuItem.setEnabled(false);
|
f@0
|
2306 hideAwarenessPanelMenuItem.setEnabled(false);
|
f@0
|
2307 if(dPanel == null)
|
f@0
|
2308 return;
|
f@0
|
2309
|
f@0
|
2310 fileSaveItem.setEnabled(true);
|
f@0
|
2311 fileSaveCopyItem.setEnabled(true);
|
f@0
|
2312 graphExportItem.setEnabled(true);
|
f@0
|
2313 if(dPanel.getDiagram() instanceof NetDiagram){
|
f@0
|
2314 if(dPanel.isAwarenessPanelVisible())
|
f@0
|
2315 hideAwarenessPanelMenuItem.setEnabled(true);
|
f@0
|
2316 else
|
f@0
|
2317 showAwarenessPanelMenuItem.setEnabled(true);
|
f@0
|
2318 }else{
|
f@0
|
2319 /* only enabled for local diagram, otherwise changing the name *
|
f@0
|
2320 * of the diagram would messes up the network protocol */
|
f@0
|
2321 fileSaveAsItem.setEnabled(true);
|
f@0
|
2322 }
|
f@0
|
2323
|
f@0
|
2324 boolean isSharedDiagram = dPanel.getDiagram() instanceof NetDiagram;
|
f@0
|
2325 if(server != null && !isSharedDiagram){
|
f@0
|
2326 shareDiagramMenuItem.setEnabled(true);
|
f@0
|
2327 }
|
f@0
|
2328
|
f@0
|
2329 if(!(isSharedDiagram && dPanel.getDiagram().getLabel().endsWith(NetDiagram.LOCALHOST_STRING)))
|
f@0
|
2330 fileCloseItem.setEnabled(true);
|
f@0
|
2331 }
|
f@0
|
2332
|
f@0
|
2333 private void treeEnabledMenuUpdate(TreePath path){
|
f@0
|
2334 canJumpRef = false;
|
f@0
|
2335 insertMenuItem.setEnabled(false);
|
f@0
|
2336 deleteMenuItem.setEnabled(false);
|
f@0
|
2337 renameMenuItem.setEnabled(false);
|
f@0
|
2338 editNotesMenuItem.setEnabled(false);
|
f@0
|
2339 bookmarkMenuItem.setEnabled(false);
|
f@0
|
2340 jumpMenuItem.setEnabled(false);
|
f@0
|
2341 locateMenuItem.setEnabled(false);
|
f@0
|
2342 selectMenuItem.setEnabled(false);
|
f@0
|
2343 if(path == null)
|
f@0
|
2344 return;
|
f@0
|
2345
|
f@0
|
2346 jumpMenuItem.setEnabled(true);
|
f@0
|
2347 editNotesMenuItem.setEnabled(true);
|
f@0
|
2348 bookmarkMenuItem.setEnabled(true);
|
f@0
|
2349
|
f@0
|
2350 /* jump to reference : a reference node must be selected */
|
f@0
|
2351 DiagramTreeNode treeNode = (DiagramTreeNode)path.getLastPathComponent();
|
f@0
|
2352
|
f@0
|
2353 /* root node */
|
f@0
|
2354 if((treeNode).getParent() == null)
|
f@0
|
2355 return;
|
f@0
|
2356
|
f@0
|
2357 if(treeNode instanceof EdgeReferenceMutableTreeNode)
|
f@0
|
2358 canJumpRef = true;
|
f@0
|
2359
|
f@0
|
2360 if(treeNode instanceof NodeReferenceMutableTreeNode){
|
f@0
|
2361 insertMenuItem.setEnabled(true);
|
f@0
|
2362 canJumpRef = true ;
|
f@0
|
2363 }
|
f@0
|
2364
|
f@0
|
2365 /* insert a node : the type node must be selected */
|
f@0
|
2366 if(treeNode instanceof TypeMutableTreeNode){
|
f@0
|
2367 insertMenuItem.setEnabled(true);
|
f@0
|
2368 }
|
f@0
|
2369
|
f@0
|
2370 /* it's a property node */
|
f@0
|
2371 if(treeNode instanceof PropertyMutableTreeNode){
|
f@0
|
2372 deleteMenuItem.setEnabled(true);
|
f@0
|
2373 renameMenuItem.setEnabled(true);
|
f@0
|
2374 insertMenuItem.setEnabled(true);
|
f@0
|
2375 }
|
f@0
|
2376
|
f@0
|
2377 if(treeNode instanceof PropertyTypeMutableTreeNode)
|
f@0
|
2378 insertMenuItem.setEnabled(true);
|
f@0
|
2379 if(treeNode instanceof DiagramElement){
|
f@0
|
2380 deleteMenuItem.setEnabled(true);
|
f@0
|
2381 renameMenuItem.setEnabled(true);
|
f@0
|
2382 if(HapticsFactory.getInstance().isAlive())
|
f@0
|
2383 locateMenuItem.setEnabled(true);
|
f@0
|
2384 if(treeNode instanceof Node)
|
f@0
|
2385 selectMenuItem.setEnabled(true);
|
f@0
|
2386 }
|
f@0
|
2387 }
|
f@0
|
2388
|
f@0
|
2389 private boolean readTemplateFiles(File[] files){
|
f@0
|
2390
|
f@0
|
2391 /* add the pd diagam type first */
|
f@0
|
2392 addDiagramType(new PdDiagram());
|
f@0
|
2393
|
f@0
|
2394 boolean someFilesNotRead = false;
|
f@0
|
2395 for(File file : files){
|
f@0
|
2396 try {
|
f@0
|
2397 Diagram d = PersistenceManager.decodeDiagramTemplate(file);
|
f@0
|
2398 addDiagramType(d);
|
f@0
|
2399 } catch (IOException e) {
|
f@0
|
2400 someFilesNotRead = true;
|
f@0
|
2401 e.printStackTrace();
|
f@0
|
2402 }
|
f@0
|
2403 }
|
f@0
|
2404 return someFilesNotRead;
|
f@0
|
2405 }
|
f@0
|
2406
|
f@0
|
2407 private void iLog(String action,String args){
|
f@0
|
2408 InteractionLog.log("TREE",action,args);
|
f@0
|
2409 }
|
f@0
|
2410
|
f@0
|
2411 private void iLog(String message){
|
f@0
|
2412 InteractionLog.log(message);
|
f@0
|
2413 }
|
f@0
|
2414
|
f@0
|
2415 private Server server;
|
f@0
|
2416 private SocketChannel localSocket;
|
f@0
|
2417 private ExceptionHandler netLocalDiagramExceptionHandler;
|
f@0
|
2418 private ClientConnectionManager clientConnectionManager;
|
f@0
|
2419 private Haptics haptics;
|
f@0
|
2420 private ResourceBundle resources;
|
f@0
|
2421 public EditorTabbedPane editorTabbedPane;
|
f@0
|
2422 private FileService.ChooserService fileService;
|
f@0
|
2423 private PreferencesService preferences;
|
f@0
|
2424 private HapticTrigger hapticTrigger;
|
f@0
|
2425 private DiagramElement hapticHighlightDiagramElement;
|
f@0
|
2426 private ArrayList<String> existingTemplateNames;
|
f@0
|
2427 private ArrayList<Diagram> existingTemplates;
|
f@0
|
2428 private AwarenessPanelEnablingListener awarenessPanelListener;
|
f@0
|
2429
|
f@0
|
2430 private JMenu newMenu;
|
f@0
|
2431 private JMenuItem jumpMenuItem;
|
f@0
|
2432 private boolean canJumpRef;
|
f@0
|
2433 private JMenuItem fileSaveItem;
|
f@0
|
2434 private JMenuItem graphExportItem;
|
f@0
|
2435 private JMenuItem fileSaveAsItem;
|
f@0
|
2436 private JMenuItem fileSaveCopyItem;
|
f@0
|
2437 private JMenuItem fileCloseItem;
|
f@0
|
2438 private JMenuItem insertMenuItem;
|
f@0
|
2439 private JMenuItem deleteMenuItem;
|
f@0
|
2440 private JMenuItem renameMenuItem;
|
f@0
|
2441 private JMenuItem selectMenuItem;
|
f@0
|
2442 private JMenuItem bookmarkMenuItem;
|
f@0
|
2443 private JMenuItem editNotesMenuItem;
|
f@0
|
2444 private JMenuItem locateMenuItem;
|
f@0
|
2445 private JMenuItem highlightMenuItem;
|
f@0
|
2446 private JMenuItem shareDiagramMenuItem;
|
f@0
|
2447 private JMenuItem startServerMenuItem;
|
f@0
|
2448 private JMenuItem stopServerMenuItem;
|
f@0
|
2449 private JMenuItem showAwarenessPanelMenuItem;
|
f@0
|
2450 private JMenuItem hideAwarenessPanelMenuItem;
|
f@0
|
2451 private TreeSelectionListener treeSelectionListener;
|
f@0
|
2452 private ChangeListener tabChangeListener;
|
f@0
|
2453 private String defaultExtension;
|
f@0
|
2454 private String backupDirPath;
|
f@0
|
2455 private ArrayList<String> recentFiles;
|
f@0
|
2456 private JMenu recentFilesMenu;
|
f@0
|
2457 private int maxRecentFiles = DEFAULT_MAX_RECENT_FILES;
|
f@0
|
2458
|
f@0
|
2459 private ExtensionFilter extensionFilter;
|
f@0
|
2460 private ExtensionFilter exportFilter;
|
f@0
|
2461
|
f@0
|
2462 private static final int DEFAULT_MAX_RECENT_FILES = 5;
|
f@0
|
2463 private static final double GROW_SCALE_FACTOR = Math.sqrt(2);
|
f@0
|
2464
|
f@0
|
2465 }
|