001 /* BEE - Book Editing Environment for PAVLOV
002 * Copyright (C) 2004 T.J. Willis
003 *
004 * This program is free software; you can redistribute it and/or
005 * modify it under the terms of the GNU General Public License
006 * as published by the Free Software Foundation; either version 2
007 * of the License, or (at your option) any later version.
008 *
009 * This program is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012 * GNU General Public License for more details.
013 *
014 * You should have received a copy of the GNU General Public License
015 * along with this program; if not, write to the Free Software
016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
017 *
018 * $Header: /cvsroot/pavlov/net/sourceforge/bee/Bee.java,v 1.20 2004/06/24 07:56:15 tj_willis Exp $
019 */
020 package net.sourceforge.bee;
021
022 import java.util.Hashtable;
023 import java.awt.*;
024 import java.awt.event.*;
025 import javax.help.*;
026 import javax.swing.*;
027 import net.sourceforge.pavlov.startup.*;
028 import net.sourceforge.pavlov.library.*;
029 import net.sourceforge.steelme.*;
030 import net.sourceforge.pavlov.swing.HelpSystem;
031 import net.sourceforge.pavlov.randommedia.ImageIconUtilities;
032 import net.sourceforge.pavlov.zipUtilities.XMLFileFilter;
033 import java.io.*;
034 import java.net.URL;
035 import org.xml.sax.*;
036 import org.xml.sax.helpers.*;
037
038 /**
039 * Main class for BEE Editor for Pavlov.
040 *
041 * @author <a href="mailto:tj_willis@users.sourceforge.net">T.J. Willis</a>
042 * @version $Revision: 1.20 $
043 */
044 public class Bee extends JFrame
045 implements ActionListener
046 {
047 // FIXME: Bee really should have a single-document interface
048 // FIXME: investigate http://txt2xml.sf.net for importing delimited text files
049 // FIXME: test save on exit when manually closing frame
050 // FIXME: does java automatically convert special chars to XML entities, i.e. &-> &
051 /**
052 * Bee Editor's JDesktopPane.
053 *
054 */
055 protected JDesktopPane desktop;
056 /**
057 * Describe variable <code>iOpenBook</code> here.
058 *
059 */
060 protected JMenuItem iOpenBook, iNewBook, iExit, iUnicode;
061 /**
062 * Keeps track of book editors that are active.
063 *
064 */
065 protected Hashtable<String,BookEditor> editors;
066 private UnicodeCharInputPanel.UnicodeCharJDialog unicode;
067
068 /**
069 * Creates a new <code>Bee</code> instance.
070 *
071 */
072 public Bee(){
073
074 super("Bee Editor For PAVLOV");
075 //Frame ref = JOptionPane.getRootFrame(); //new Frame(); // this might be why the window's not closing
076 //lstartup = new StartupWindow("file:resources/aboutBee.jpg",ref);
077
078 //lstartup.setMainApp(this);
079
080
081
082 javax.swing.ToolTipManager.sharedInstance().setEnabled(true);
083
084 ImageIcon logo = ImageIconUtilities.getNamedImageIcon("file:resources/B.png",50);
085 if(logo!=null)
086 {
087 java.awt.Image imm = logo.getImage();
088 setIconImage(imm);
089 }
090
091
092
093 desktop = new JDesktopPane();
094 //desktop.setLayout(new BorderLayout());
095 setContentPane(desktop);
096
097 editors = new Hashtable<String,BookEditor>();
098 setSize( new Dimension(705,685));
099
100 JMenuBar menubar = new JMenuBar();
101
102 JMenu file = new JMenu("File");
103 iOpenBook = new JMenuItem("Open Book");
104 iOpenBook.addActionListener(this);
105 file.add(iOpenBook);
106
107 iNewBook = new JMenuItem("New Book");
108 iNewBook.addActionListener(this);
109
110 iExit = new JMenuItem("Exit");
111 iExit.addActionListener(this);
112
113 file.add(iOpenBook);
114 file.add(iNewBook);
115 file.add(iExit);
116
117 menubar.add(file);
118
119 JMenu tools = new JMenu("Tools");
120 iUnicode = new JMenuItem("Unicode Characters...");
121 iUnicode.addActionListener(this);
122 tools.add(iUnicode);
123 menubar.add(tools);
124
125 // JToolBar toolbar = new JToolBar("Bee Tools");
126 // toolbar.add( new AbstractAction() {
127 // public void actionPerformed(ActionEvent e) {
128 // System.out.println("clicked the btn");
129 // }
130 // }
131 // );
132 // desktop.add(toolbar,BorderLayout.PAGE_START);
133 //PavlovMetalTheme t = new PavlovMetalTheme();//f);
134 //t.setTarget(this);
135
136 //menubar.add(t.getThemeMenu(g));
137
138 // java.io.File g = new java.io.File("resources/themes");
139 // ThemeMenu theme = new ThemeMenu(this, g);
140 // menubar.add(theme);
141
142
143 HelpSystem h = new HelpSystem(desktop);
144 try {
145 HelpBroker hb;
146 HelpSet hs;
147 JMenuItem menu_help;
148 //FIXME: get helpset from Resources
149 URL hsURL = new URL("file:resources/beehs/main.hs");
150 hs = new HelpSet(null, hsURL);
151 hb = hs.createHelpBroker();
152 menu_help = new JMenuItem("Help Topics...");
153 menu_help.addActionListener(new CSH.DisplayHelpFromSource( hb ));
154 h.add(menu_help);
155 } catch (Exception ee) {
156 // Say what the exception really is
157 System.out.println( "Error Creating HelpSet " + ee);
158 }
159
160 boolean ret;// = h.addItem("file:resources/help/beeHelp.html","Help Topics");
161 ret = h.addItem("file:resources/help/aboutBee.html","About Bee");
162 h.addSeparator();
163 ret = h.addItem("http://pavlov.sourceforge.net","Pavlov Home Page (online)");
164 ret = h.addItem("http://pavlov.sourceforge.net/bdem/tour1.html","Bee Tutorial (online)");
165 menubar.add(h);
166 setJMenuBar(menubar);
167 setVisible(true);
168
169
170
171
172 //Quit this app when the big window closes.
173 addWindowListener(new WindowAdapter() {
174 public void windowClosing(WindowEvent e) {
175 niceQuit(false);
176 }
177 }
178 );
179
180 WelcomeDialog wd = new WelcomeDialog(this);
181 addInternalFrame(wd);
182
183 //FIXME: attach unicode to a button/menu item
184 //unicode = new UnicodeCharInputPanel.UnicodeCharJFrame();
185 //UnicodeCharInputPanel ucip = unicode.getUnicodeCharInputPanel();
186
187 //unicode = new UnicodeCharInputPanel.UnicodeCharJFrame();
188 UnicodeCharInputPanel ucip = new UnicodeCharInputPanel();
189 unicode = ucip.getJDialog(this);
190 ucip.setPostGlobally(true);
191 //addInternalFrame(unicode);
192
193 }
194
195
196 /**
197 * User wants to open a book, but hasn't provided the filename.
198 *
199 */
200 public void openBook()
201 {
202 JFileChooser chooser = new JFileChooser();
203 XMLFileFilter filter = new XMLFileFilter();
204 chooser.setFileFilter(filter);
205 chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES );
206 int returnVal = chooser.showOpenDialog(this);
207 if(returnVal != JFileChooser.APPROVE_OPTION) return;
208 File bookFile = chooser.getSelectedFile();
209 openBook(bookFile);
210 }
211
212 /**
213 * Opens the given file for editing.
214 *
215 * @param bookFile a <code>File</code> value
216 */
217 public void openBook(File bookFile)
218 {
219 if(bookFile==null)
220 {
221 showError("Cannot open file",null);
222 return;
223 }
224 String fname = bookFile.getName();
225 if(!bookFile.exists())
226 {
227 showError("File " + fname + " doesn't exist",null);
228 return;
229 }
230 if(!bookFile.isFile())
231 {
232 showError("File " + fname + " is not a book file",null);
233 return;
234 }
235 if(!bookFile.canRead())
236 {
237 showError("File " + fname + " is read-protected",null);
238 return;
239 }
240
241 /*
242 BookXMLHandler br = new BookXMLHandler();
243 XMLReader xr = null;
244 Book b = null;
245 try {
246 xr = XMLReaderFactory.createXMLReader();
247 } catch (Exception e) {
248 showError("Cannot Create XML Reader",e);
249 return;
250 }
251
252 xr.setContentHandler(br);
253
254 try {
255 //HERE
256 FileReader fr = new FileReader(bookFile);
257 InputSource is = new InputSource(fr);
258 is.setEncoding("UTF8");
259 xr.parse(is);
260 } catch (Exception e) {
261 showError("Cannot Parse File " + fname,e);
262 }
263
264 //System.out.println("file name = " + fname.toString());
265 */
266 Book b = Book.loadFrom(bookFile);
267
268 if(b==null) System.out.println("Book is null");
269 //else System.out.println(b.getTitle());
270
271 addBookEditor(b,bookFile);
272 }
273
274
275 /**
276 * Creates a new book, saves it to user selected file, opens it for editing.
277 *
278 */
279 public void newBook()
280 {
281 JFileChooser chooser = new JFileChooser();
282 XMLFileFilter filter = new XMLFileFilter();
283 chooser.setFileFilter(filter);
284 chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES );
285 int returnVal = chooser.showSaveDialog(this);
286 if(returnVal != JFileChooser.APPROVE_OPTION) return;
287 File bookFile = chooser.getSelectedFile();
288 newBook(bookFile,null);
289 }
290
291 /**
292 * User wants to create a new book. Makes a new book and saves it to the
293 * given file.
294 *
295 * @param bookFile a <code>File</code> value
296 * @param book a <code>Book</code> value
297 */
298 public void newBook(File bookFile, Book book)
299 {
300 if(bookFile==null)
301 {
302 showError("Cannot open file",null);
303 return;
304 }
305 String fname = bookFile.getName();
306 if(bookFile.exists()){
307 int ret =
308 JOptionPane.showInternalConfirmDialog(getContentPane(),
309 "Overwrite Existing File " +fname +"?",
310 "File Exists",
311 JOptionPane.YES_NO_OPTION);
312 if(ret==JOptionPane.NO_OPTION) return;
313 } else {
314 try {
315 boolean tmp = bookFile.createNewFile();
316 } catch (Exception e) {
317 showError("Cannot create file " + fname,e);
318 return;
319 }
320 }
321 Book b = null;
322 if(book!=null)
323 b = book;
324 else
325 b = new Book();
326
327 try {
328 b.saveAs(bookFile);
329 } catch (Exception e) {
330 showError("Cannot create file " + fname,e);
331 return;
332 }
333 addBookEditor(b,bookFile);
334 }
335
336
337 /**
338 * Adds a BookEditor instance to this editing session.
339 *
340 * @param bk a <code>Book</code> value
341 * @param bf a <code>File</code> value
342 */
343 public void addBookEditor(Book bk,File bf)
344 {
345 String key = bf.getAbsolutePath();
346 if(editors.containsKey(key) )
347 {
348 BookEditor c = (BookEditor)editors.get(key);
349 c.setVisible(true);
350 try { c.setSelected(true); } catch (Exception e) {}
351 return;
352 }
353
354 BookEditor ed = new BookEditor(this,bk,bf);
355 editors.put(key,ed);
356 addInternalFrame(ed);
357 }
358
359
360
361 /**
362 * Nice error/exception reporting to user.
363 *
364 * @param text a <code>String</code> value
365 * @param e an <code>Exception</code> value
366 */
367 public void showError(String text, Exception e)
368 {
369 JOptionPane.showInternalMessageDialog(getContentPane(),
370 text,
371 "Error",
372 JOptionPane.ERROR_MESSAGE);
373 }
374
375 /**
376 * Returns true if an editor for the given book file is open.
377 *
378 * @param f a <code>File</code> value
379 * @return a <code>boolean</code> value
380 */
381 public boolean hasEditorKey(File f)
382 {
383 String key = f.getAbsolutePath();
384 return editors.containsKey(key);
385 }
386
387 /**
388 * Removes the reference for an open editor for the given book file.
389 *
390 * @param f a <code>File</code> value
391 */
392 public void removeEditorKey(File f)
393 {
394 String key = f.getAbsolutePath();
395 editors.remove(key);
396 }
397
398 /**
399 * User tries to rename book from oldFile to newFile. Checks that no
400 * editor for newFile is currently open. If one is open, returns quietly
401 * without renaming. Otherwise, renames the book and updates the
402 * hashtable reference.
403 *
404 * @param oldFile a <code>File</code> value
405 * @param newFile a <code>File</code> value
406 */
407 public void changeEditorKey(File oldFile, File newFile)
408 {
409 String oldKey = oldFile.getAbsolutePath();
410 String newKey = newFile.getAbsolutePath();
411
412 if(editors.containsKey(newKey) )
413 return;
414
415 // this was ChapterEditor for some reason...
416 BookEditor c = (BookEditor)editors.remove(oldKey);
417 if(c==null) return;
418 editors.put(newKey,c);
419 }
420
421 /**
422 * Convenience method for adding a JInternalFrame to the editor nicely.
423 *
424 * @param jif a <code>JInternalFrame</code> value
425 */
426 public void addInternalFrame(JInternalFrame jif) {
427 if(jif==null) return;
428 jif.setVisible(true);
429 jif.pack();
430 desktop.add(jif);
431 try {
432 jif.setSelected(true);
433 } catch (java.beans.PropertyVetoException e) {}
434 jif.repaint(); // bug-workaround
435 }
436
437 /**
438 * Handles menu events.
439 *
440 * @param e an <code>ActionEvent</code> value
441 */
442 public void actionPerformed(ActionEvent e)
443 {
444 if(e.getSource().equals(iOpenBook))
445 openBook();
446 else if(e.getSource().equals(iExit))
447 niceQuit(true);
448 else if(e.getSource().equals(iNewBook))
449 newBook();
450 else if(e.getSource().equals(iUnicode))
451 unicode.setVisible(!unicode.isVisible());
452 }
453
454 /**
455 * Runs the BEE Editor for Pavlov.
456 *
457 * @param args[] a <code>String</code> value
458 */
459 public static void main(String args[])
460 {
461 Bee bee = new Bee();
462 bee.setVisible(true);
463 }
464
465
466 /**
467 * If confirm is true, asks user if he wants to quit. Otherwise quits.
468 *
469 * @param confirm a <code>boolean</code> value
470 */
471 public void niceQuit(boolean confirm)
472 {
473 if(confirm)
474 if( !confirmQuit()) return;
475
476 //saveUsers();
477 System.exit(0);
478 }
479
480 /**
481 * Asks user if he really wants to exit the application.
482 *
483 * @return a <code>boolean</code> value
484 */
485 public boolean confirmQuit()
486 {
487 int ret = JOptionPane.showInternalConfirmDialog(getContentPane(), "Really Quit Bee?");
488 if (ret == JOptionPane.YES_OPTION) return true;
489 return false;
490 }
491
492 }
493