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