1 package fr.ove.openmath.mathematica;
2
3 import javax.swing.*;
4 import javax.swing.event.*;
5 import java.awt.*;
6 import java.util.*;
7 import fr.ove.openmath.mathematica.*;
8 import fr.ove.utils.*;
9 import java.io.*;
10 import fr.inria.openmath.omapi.*;
11 import fr.inria.openmath.omapi.implementation.*;
12 import fr.ove.openmath.mathematica.omparser.PipeParserHandler;
13
14 /***
15 * A work book.
16 * Is intended to be used to access different inner frames in a Desktop by means
17 * labelled tabs.
18 */
19 public class WorkBook extends JComponent implements InternalFrameListener, Savable {
20 /***
21 * The tabbed pane to acces the different elements
22 */
23 private JTabbedPane tabbedPane;
24
25 /***
26 * The Desktop.
27 */
28 private Desktop desktop;
29
30 /***
31 * Indicates if the instance need to be saved.
32 */
33 private boolean needed = true;
34
35 /***
36 * The list of listeners of the instance.
37 */
38 private EventListenerList listeners = new EventListenerList();
39
40 /***
41 * Only one ChangeEvent is needed per WorkBook instance since the
42 * event's only (read-only) state is the source property. The source
43 * of events generated here is always "this".
44 */
45 private transient ChangeEvent changeEvent = null;
46
47 /***
48 * A connection factory.
49 */
50 ConnectionFactory factory;
51
52 /***
53 * A file chooser
54 */
55 private WorkSheetFileChooser chooser;
56
57 /***
58 * A status bar
59 */
60 private StatusBar statusBar;
61
62 /***
63 * The Constructor.
64 */
65 public WorkBook(ConnectionFactory factory, StatusBar statusBar) {
66 setLayout(new BorderLayout());
67 desktop = new Desktop();
68
69 chooser = new WorkSheetFileChooser(this);
70 this.factory = factory;
71 this.statusBar = statusBar;
72 addChangeListener(statusBar);
73
74 add(desktop, BorderLayout.CENTER);
75
76 tabbedPane = new JTabbedPane(JTabbedPane.BOTTOM);
77 tabbedPane.addChangeListener(
78 new ChangeListener() {
79 public void stateChanged(ChangeEvent ce) {
80 JDesktopPaneWrapper comp = (JDesktopPaneWrapper) tabbedPane.getSelectedComponent();
81 if (comp != null) {
82 if (comp.getComponentCount() == 0)
83 comp.setJDesktopPane();
84
85 int index = tabbedPane.getSelectedIndex();
86 String title = tabbedPane.getTitleAt(index);
87 desktop.setSelected(title);
88 }
89 }
90 }
91 );
92 }
93
94 /***
95 * Adds a new tab (i.e. a new inner frame into the Desktop) to the WorkBook.
96 */
97 public void addTab() {
98 if (getComponent(0) == desktop) {
99 remove(desktop);
100 add(tabbedPane, BorderLayout.CENTER);
101 }
102
103 JInternalFrame jif = desktop.addNewInternalFrame(new OMWorkSheet(this, factory));
104 jif.addInternalFrameListener(this);
105 jif.addVetoableChangeListener(chooser);
106 tabbedPane.addTab(jif.getTitle(), new JDesktopPaneWrapper(desktop));
107 tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
108 fireStateChanged();
109 validate();
110 }
111
112 /***
113 * Adds a new palette to the desktop.
114 * @param paletteIdentifier the palette identfier.
115 * @param contentPan the palette (i.e. the content pane for the inner frame opened in the desktop)
116 */
117 public void addPalette(String paletteIdentifier, Container contentPane) {
118 desktop.addNewPaletteContentPane(paletteIdentifier, contentPane);
119 }
120 /***
121 * Shows the palette with the specified name identfier.
122 * @param identifier the palette identifier.
123 */
124 public void showPalette(String identifier) {
125 desktop.showPalette(identifier);
126 }
127
128 /***
129 * Removes the tab with the specified name.
130 * @param name the name of the tab.
131 */
132 public void removeTab(String name) {
133 JInternalFrame jif = desktop.removeInternalFrame(name);
134 if (jif != null) {
135 jif.removeInternalFrameListener(this);
136 int index = tabbedPane.indexOfTab(name);
137 tabbedPane.removeTabAt(index);
138 fireStateChanged();
139 }
140 }
141
142 /***
143 * Returns the active inner frame in the work book.
144 */
145 public JInternalFrame getActiveInternalFrame() {
146 return desktop.getActiveInternalFrame();
147 }
148
149 /***
150 * Returns the number of tab (i.e. inner frames) in the instance.
151 */
152 public int getTabCount() {
153 return tabbedPane.getTabCount();
154 }
155 /***
156 * Adds a ChangeListener to the instance.
157 * @param l the ChangeListener to add
158 * @see #fireStateChanged
159 * @see #removeChangeListener
160 */
161 public void addChangeListener(ChangeListener l) {
162 listeners.add(ChangeListener.class, l);
163 }
164
165 /***
166 * Cascade the frame in the desktop.
167 */
168 public void cascade() {
169 desktop.cascade();
170 }
171
172 /***
173 * Closes all the frames in the desktop.
174 */
175 public void closeAll() {
176 desktop.closeAll();
177 }
178
179 /***
180 * Removes a ChangeListener from the instance.
181 * @param l the ChangeListener to remove
182 * @see #fireStateChanged
183 * @see #addChangeListener
184 */
185 public void removeChangeListener(ChangeListener l) {
186 listeners.remove(ChangeListener.class, l);
187 }
188
189 /***
190 * Send a ChangeEvent, whose source is this tabbedpane, to
191 * each listener. This method method is called each time
192 * a ChangeEvent is received from the model.
193 * @see #addChangeListener
194 * @see EventListenerList
195 */
196 protected void fireStateChanged() {
197
198 Object[] tabListeners = listeners.getListenerList();
199
200
201 for (int i = tabListeners.length - 2; i >= 0; i -= 2) {
202 if (tabListeners[i] == ChangeListener.class) {
203
204 if (changeEvent == null)
205 changeEvent = new ChangeEvent(this);
206
207 ((ChangeListener) tabListeners[i+1]).stateChanged(changeEvent);
208 }
209 }
210 }
211
212 /***
213 * Returns the status bar.
214 */
215 public StatusBar getStatusBar() {
216 return statusBar;
217 }
218
219 /***
220 * Returns the icon with the specified image filename.
221 * @param filename the image filename
222 */
223 private ImageIcon getIcon(String filename) {
224 ImageIcon icon = null;
225
226 java.net.URL iconURL = ClassLoader.getSystemResource(filename);
227 if (iconURL != null)
228 icon = new ImageIcon(iconURL);
229
230 return icon;
231 }
232
233
234
235
236
237 public void internalFrameActivated(InternalFrameEvent e) {
238 JInternalFrame src = (JInternalFrame) e.getSource();
239 int index = tabbedPane.indexOfTab(src.getTitle());
240 tabbedPane.setSelectedIndex(index);
241 fireStateChanged();
242 }
243
244 public void internalFrameClosed(InternalFrameEvent e) {
245 JInternalFrame src = (JInternalFrame) e.getSource();
246 String name = src.getTitle();
247
248 removeTab(name);
249 JDesktopPaneWrapper wrapper = (JDesktopPaneWrapper) tabbedPane.getSelectedComponent();
250 if (wrapper != null) {
251 wrapper.setJDesktopPane();
252 int index = tabbedPane.getSelectedIndex();
253 name = tabbedPane.getTitleAt(index);
254 desktop.setSelected(name);
255 }
256 else {
257
258
259
260
261 remove(tabbedPane);
262 add(desktop, BorderLayout.CENTER);
263
264 }
265 fireStateChanged();
266 }
267
268 public void internalFrameClosing(InternalFrameEvent e) {
269 }
270
271 public void internalFrameDeactivated(InternalFrameEvent e) {
272 fireStateChanged();
273 }
274
275 public void internalFrameDeiconified(InternalFrameEvent e) {
276 }
277
278 public void internalFrameIconified(InternalFrameEvent e) {
279 }
280
281 public void internalFrameOpened(InternalFrameEvent e) {
282 }
283
284
285
286 /***
287 * Saves the instance.
288 * @returns the result of the save action. Should be <CODE>null</CODE> if nothing
289 * is expected after the save operation. The saved object otherwise.
290 * The instance is saved as the concatenation of all the OpenMath object request contained.
291 */
292 public Object save() {
293 MyJInternalFrame jif = (MyJInternalFrame) desktop.getActiveInternalFrame();
294 if (jif.isSaveNeeded()) {
295 File file;
296 String title = jif.getTitle();
297
298 statusBar.setStatus("Save " + title,
299 getIcon("fr/ove/openmath/mathematica/images/save.gif")
300 );
301
302
303 if (title.startsWith("Untitled")) {
304 int state = chooser.showSave();
305 file = chooser.getSelectedFile();
306 if ((file != null) && (state == JFileChooser.APPROVE_OPTION)) {
307 statusBar.setStatus("Please wait while saving the work sheet...",
308 getIcon("fr/ove/openmath/mathematica/images/sablier.gif")
309 );
310
311 jif.save(file);
312 setSaveNeeded(false);
313
314 try {
315 desktop.rename(title, file.getName());
316 }
317 catch (Exception e) {
318 }
319
320 tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), file.getName());
321
322 statusBar.setStatus("", getIcon("fr/ove/openmath/mathematica/images/worksheet.gif"));
323 }
324 }
325 else {
326 statusBar.setStatus("Please wait while saving the work sheet...",
327 getIcon("fr/ove/openmath/mathematica/images/sablier.gif")
328 );
329
330 file = new File(title);
331 jif.save(file);
332 setSaveNeeded(false);
333
334 statusBar.setStatus("", getIcon("fr/ove/openmath/mathematica/images/worksheet.gif"));
335 }
336 }
337
338 return null;
339 }
340
341 /***
342 * Saves the instance into the specified file.
343 * @returns the result of the save action. Should be <CODE>null</CODE> if nothing
344 * is expected after the save operation. The saved object otherwise.
345 */
346 public Object save(File file) {
347 return null;
348 }
349
350 /***
351 * Saves the instance with the specified name.
352 * @param name the specified name.
353 * @returns the result of the save action. Should be <CODE>null</CODE> if nothing
354 * is expected after the save operation. The saved object otherwise.
355 */
356 public Object saveAs(String name) {
357 return null;
358 }
359
360 /***
361 * Checks if the instance need to be saved.
362 * @return <CODE>true</CODE> if the instance need to be saved. <CODE>false</CODE> otherwise.
363 */
364 public boolean isSaveNeeded() {
365 return needed;
366 }
367
368 /***
369 * Sets if the instance need to be saved.
370 * @param needed <CODE>true</CODE> if the instance need to be saved. <CODE>false</CODE> otherwise.
371 */
372 public void setSaveNeeded(boolean needed) {
373 this.needed = needed;
374 }
375
376 /***
377 * Opens a file.
378 */
379 public void open() {
380 statusBar.setStatus("Select a work sheet to open...",
381 getIcon("fr/ove/openmath/mathematica/images/open.gif")
382 );
383
384 int state = chooser.showOpen();
385 File file = chooser.getSelectedFile();
386 if ((file != null) && (state == JFileChooser.APPROVE_OPTION)) {
387 statusBar.setStatus("Please wait while opening the work sheet...",
388 getIcon("fr/ove/openmath/mathematica/images/sablier.gif")
389 );
390
391 PipeParserHandler handler = new PipeParserHandler();
392 XMLParser parser = new XMLParser(handler);
393
394 Vector elems = new Vector();
395 try {
396 FileInputStream fis = new FileInputStream(file);
397 try {
398 String parsed;
399 while (fis.available() != 0) {
400 parser.initParse(fis);
401 parser.parseObject(fis);
402
403 parsed = handler.getOmObjectParsed();
404
405 if ((parsed != null) && (!parsed.equals("")))
406 elems.addElement(parsed);
407 }
408 fis.close();
409
410 addTab();
411 MyJInternalFrame jif = (MyJInternalFrame) desktop.getActiveInternalFrame();
412 try {
413 desktop.rename(jif.getTitle(), file.getName());
414 }
415 catch (Exception e) {
416 }
417 tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), file.getName());
418
419 if (elems.size() != 0) {
420 OMWorkSheet worksheet = (OMWorkSheet) jif.getContentPane();
421 boolean addNewElement = false;
422 for (Enumeration e = elems.elements(); e.hasMoreElements(); ) {
423 if (addNewElement)
424 worksheet.addNewElement();
425 worksheet.getCurrentElement().setOpenMathRequest((String) e.nextElement());
426 addNewElement = true;
427 }
428 jif.setSaveNeeded(false);
429 worksheet.setSaveNeeded(false);
430 }
431
432 statusBar.setStatus("", getIcon("fr/ove/openmath/mathematica/images/worksheet.gif"));
433
434 }
435 catch (IOException ioe) {
436 statusBar.setStatus("Something wrong occurs while reading the worksheet.",
437 getIcon("fr/ove/openmath/mathematica/images/oups.gif"));
438 }
439 }
440 catch (FileNotFoundException fnfe) {
441 statusBar.setStatus("Couldn't find the specified the worksheet.",
442 getIcon("fr/ove/openmath/mathematica/images/oups.gif"));
443 }
444 }
445 else {
446 if (getTabCount() != 0)
447 statusBar.setStatus("", getIcon("fr/ove/openmath/mathematica/images/worksheet.gif"));
448 else
449 statusBar.clear();
450 }
451 }
452 }