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/BookEditor.java,v 1.6 2004/05/24 02:02:17 tj_willis Exp $ 019 */ 020 package net.sourceforge.bee; 021 022 import javax.swing.*; 023 import javax.swing.event.*; 024 import java.awt.*; 025 import java.awt.event.*; 026 import net.sourceforge.pavlov.library.*; 027 import net.sourceforge.pavlov.zipUtilities.XMLFileFilter; 028 import java.util.*; 029 import java.io.*; 030 import java.net.URL; 031 032 /** 033 * User interface for editing a book file. 034 * 035 * @author <a href="mailto:"></a> 036 * @version 1.0 037 */ 038 public class BookEditor 039 extends JInternalFrame 040 implements ActionListener, ListSelectionListener 041 { 042 private JLabel lTitle, lAuthor, lDescription; 043 private JTextField fTitle, fAuthor; 044 private JTextArea aDescription; 045 private JList lChapters; 046 private JButton bEdit, bUpdate; 047 private JMenuItem save, saveAs, close, edit, iNew, iCut, iCopy,iInsert,iDelete; 048 private Object clipboard; 049 private Book book, savedBook; 050 private Bee bee; 051 private Hashtable<String,ChapterEditor> editors; 052 private File loadFile; 053 private Container content; 054 private AbstractAction editChapterAction,deleteChapterAction,insertChapterAction; 055 private AbstractAction copyChapterAction,newChapterAction,closeAction,saveAsAction; 056 private AbstractAction saveAction; 057 058 059 /** 060 * Creates a new <code>BookEditor</code> instance. 061 * 062 * @param parent a <code>Bee</code> value 063 * @param aBook a <code>Book</code> value 064 * @param file a <code>File</code> value 065 */ 066 public BookEditor(Bee parent,Book aBook, File file) 067 { 068 super(); 069 content = getContentPane(); 070 content.setLayout(new BorderLayout()); 071 072 bee = parent; 073 book = aBook; 074 savedBook = book.deepCopy(); 075 editors = new Hashtable<String,ChapterEditor>(); 076 loadFile = file; 077 078 super.setTitle("Book Editor"); //Edit: Book: " + book.getName()); 079 setResizable(true); 080 081 Box box = new Box(BoxLayout.Y_AXIS); 082 083 Box b0 = new Box(BoxLayout.Y_AXIS); 084 085 JPanel pan1 = new JPanel(); 086 pan1.setLayout(new java.awt.GridLayout(2,1)); 087 088 Box b1 = new Box(BoxLayout.X_AXIS); 089 b1.setBorder( BorderFactory.createTitledBorder( "Title" ) ); 090 fTitle = new JTextField(); 091 fTitle.addActionListener(this); 092 b1.add(fTitle); 093 094 Box b2 = new Box(BoxLayout.X_AXIS); 095 b2.setBorder( BorderFactory.createTitledBorder( "Author" ) ); 096 fAuthor = new JTextField(); 097 fAuthor.addActionListener(this); 098 b2.add(fAuthor); 099 100 pan1.add(b1); 101 pan1.add(b2); 102 103 b0.add(pan1); 104 105 Box b3 = new Box(BoxLayout.X_AXIS); 106 b3.setBorder( BorderFactory.createTitledBorder( "Description" ) ); 107 aDescription = new JTextArea(); 108 aDescription.setLineWrap(true); 109 JScrollPane sp1 = new JScrollPane(aDescription); 110 sp1.setMinimumSize(new Dimension(360,80)); 111 bUpdate = new JButton("Update"); 112 bUpdate.addActionListener(this); 113 114 b3.add(sp1); 115 b3.add(bUpdate); 116 b0.add(b3); 117 box.add(b0); 118 119 Box b4 = new Box(BoxLayout.X_AXIS); 120 b4.setBorder( BorderFactory.createTitledBorder( "Chapters" ) ); 121 Vector<AbstractChapter> v = new Vector<AbstractChapter>(book.getValues()); 122 lChapters = new JList(v); 123 lChapters.addListSelectionListener(this); 124 JScrollPane sp = new JScrollPane(lChapters); 125 sp.setMinimumSize( new Dimension(360,360)); 126 127 b4.add(sp); 128 box.add(b4); 129 130 131 // DEFINE ACTIONS 132 saveAction = ( new AbstractAction() { 133 public void actionPerformed(ActionEvent e) { 134 save(); 135 } 136 } 137 ); 138 saveAction.putValue(Action.SHORT_DESCRIPTION,"Save This Book"); 139 saveAsAction = ( new AbstractAction() { 140 public void actionPerformed(ActionEvent e) { 141 saveAs(); 142 } 143 } 144 ); 145 saveAsAction.putValue(Action.SHORT_DESCRIPTION,"Save This Book To New File"); 146 147 closeAction = ( new AbstractAction() { 148 public void actionPerformed(ActionEvent e) { 149 close(); 150 } 151 } 152 ); 153 closeAction.putValue(Action.SHORT_DESCRIPTION,"Close This Book"); 154 155 newChapterAction = ( new AbstractAction() { 156 public void actionPerformed(ActionEvent e) { 157 newChapter(); 158 } 159 } 160 ); 161 newChapterAction.putValue(Action.SHORT_DESCRIPTION,"Create New Chapter"); 162 copyChapterAction = ( new AbstractAction() { 163 public void actionPerformed(ActionEvent e) { 164 copy(); 165 } 166 } 167 ); 168 copyChapterAction.putValue(Action.SHORT_DESCRIPTION,"Copy Selected Chapter"); 169 insertChapterAction = ( new AbstractAction() { 170 public void actionPerformed(ActionEvent e) { 171 insert(); 172 } 173 } 174 ); 175 insertChapterAction.putValue(Action.SHORT_DESCRIPTION,"Insert A Chapter"); 176 deleteChapterAction = ( new AbstractAction() { 177 public void actionPerformed(ActionEvent e) { 178 delete(); 179 } 180 } 181 ); 182 deleteChapterAction.putValue(Action.SHORT_DESCRIPTION,"Delete Selected Chapter"); 183 184 editChapterAction = ( new AbstractAction() { 185 public void actionPerformed(ActionEvent e) { 186 editChapter(); 187 } 188 } 189 ); 190 editChapterAction.putValue(Action.SHORT_DESCRIPTION,"Edit Selected Chapter"); 191 192 // DEFINE BUTTONS 193 194 195 196 //Box b5 = new Box(BoxLayout.X_AXIS); 197 //bEdit = makeJButton(editChapterAction,"Edit", "resources/icons/tb_edit.jpg"); 198 //b5.add(bEdit); 199 //b5.add(bClose); 200 //box.add(b5); 201 //bEdit.addActionListener(this); 202 203 204 content.add(box,BorderLayout.CENTER); 205 206 207 // DEFINE MENU ITEMS 208 JMenuBar menu = new JMenuBar(); 209 JMenu mFile = new JMenu("File"); 210 save = makeJMenuItem(saveAction,"Save","resources/icons/tb_save.jpg"); 211 saveAs = makeJMenuItem(saveAsAction,"Save As...","resources/icons/tb_save_as.jpg"); 212 close = makeJMenuItem(closeAction,"Close","resources/icons/tb_close.jpg"); 213 //save.addActionListener(this); 214 //saveAs.addActionListener(this); 215 //close.addActionListener(this); 216 mFile.add(save); 217 mFile.add(saveAs); 218 mFile.add(close); 219 menu.add(mFile); 220 221 JMenu mChapter = new JMenu("Chapter"); 222 edit = makeJMenuItem(editChapterAction,"Edit","resources/icons/tb_edit.jpg"); 223 iNew = makeJMenuItem(newChapterAction,"New","resources/icons/tb_new.jpg"); 224 //iCut = new JMenuItem("Cut"); 225 iCopy =makeJMenuItem(copyChapterAction,"Copy","resources/icons/tb_copy.jpg"); 226 //iPaste = new JMenuItem("Paste"); 227 iInsert = makeJMenuItem(insertChapterAction,"Insert","resources/icons/tb_insert.jpg"); 228 iDelete = makeJMenuItem(deleteChapterAction,"Delete","resources/icons/tb_delete.jpg"); 229 230 231 editChapterAction.setEnabled(false); 232 //iCut.setEnabled(false); 233 copyChapterAction.setEnabled(false); 234 deleteChapterAction.setEnabled(false); 235 insertChapterAction.setEnabled(false); 236 editChapterAction.setEnabled(false); 237 238 239 mChapter.add(iNew); 240 //mChapter.add(iCut); 241 mChapter.add(iCopy); 242 //mChapter.add(iPaste); 243 mChapter.add(iInsert); 244 mChapter.add(iDelete); 245 246 247 menu.add(mChapter); 248 setJMenuBar(menu); 249 250 JToolBar toolbar = new JToolBar("BookEditor Tools"); 251 toolbar.setRollover(true); 252 253 JButton s1 = makeJButton(saveAction,"Save","resources/icons/tb_save.jpg"); 254 JButton s2 = makeJButton(saveAsAction,"Save As...","resources/icons/tb_save_as.jpg"); 255 JButton s3 = makeJButton(closeAction,"Close","resources/icons/tb_close.jpg"); 256 257 JButton s4 = makeJButton(editChapterAction,"Edit","resources/icons/tb_edit.jpg"); 258 JButton s5 = makeJButton(newChapterAction,"New","resources/icons/tb_new.jpg"); 259 JButton s6 = makeJButton(copyChapterAction,"Copy","resources/icons/tb_copy.jpg"); 260 JButton s7 = makeJButton(insertChapterAction,"Insert","resources/icons/tb_insert.jpg"); 261 JButton s8 = makeJButton(deleteChapterAction,"Delete","resources/icons/tb_delete.jpg"); 262 263 //saveAs = makeJMenuItem(saveAsAction,"Save As...","resources/icons/tb_save_as.jpg"); 264 //close = makeJMenuItem(closeAction,"Close","resources/icons/tb_close.jpg"); 265 266 toolbar.add(s1); 267 toolbar.add(s2); 268 toolbar.add(s3); 269 toolbar.addSeparator(); 270 toolbar.add(s4); 271 toolbar.add(s5); 272 toolbar.add(s6); 273 toolbar.add(s7); 274 toolbar.add(s8); 275 content.add(toolbar,BorderLayout.PAGE_START); 276 277 setTitle(book.getName()); 278 setAuthor(book.getAuthor()); 279 setDescription(book.getDescription()); 280 281 pack(); 282 } 283 284 285 private void editChapter() 286 { 287 Chapter chapter = (Chapter) lChapters.getSelectedValue(); 288 if(chapter==null) return; 289 290 String cName = chapter.getName(); 291 if(editors.containsKey(cName) ) 292 { 293 ChapterEditor c = (ChapterEditor)editors.get(cName); 294 c.setVisible(true); 295 try { c.setSelected(true); } catch (Exception e) {} 296 return; 297 } 298 //Chapter c = book.getChapter(cName ); 299 300 ChapterEditor pan = new ChapterEditor(this,chapter); 301 editors.put(cName,pan); 302 bee.addInternalFrame(pan); 303 } 304 305 306 // conflicts with Frame.setTitle 307 /** 308 * Describe <code>setTitle</code> method here. 309 * 310 * @param t a <code>String</code> value 311 */ 312 public void setTitle(String t) 313 { 314 fTitle.setText(t); 315 } 316 private void setAuthor(String t) 317 { 318 fAuthor.setText(t); 319 } 320 private void setDescription(String t) 321 { 322 aDescription.setText(t); 323 } 324 325 private void newChapter() 326 { 327 Chapter c = Chapter.makeBlankChapter(); 328 String t = "New Chapter"; 329 330 Chapter x = null; 331 long i=0; 332 for(i=1;true;i++) 333 { 334 x = book.getChapter(t); 335 if(x==null) break; 336 t = "New Chapter " + i; 337 } 338 c.setName(t); 339 340 book.addChapter(c); 341 refreshChapterNames(); 342 lChapters.setSelectedValue(c,true); 343 } 344 345 private void copy() 346 { 347 Chapter chapter = (Chapter) lChapters.getSelectedValue(); 348 if(chapter==null) return; 349 Chapter c = chapter.deepCopy(); 350 c.setName("Copy of " + chapter.getName()); 351 clipboard = c; 352 insertChapterAction.setEnabled(true); 353 } 354 355 private void delete() 356 { 357 Chapter chapter = (Chapter) lChapters.getSelectedValue(); 358 if(chapter==null) return; 359 String msg = "Really delete chapter " + chapter.getName() + "?"; 360 int ret = 361 JOptionPane.showInternalConfirmDialog(getDesktopPane(), 362 msg, 363 "Delete Chapter", 364 JOptionPane.YES_NO_OPTION); 365 if( ret == JOptionPane.NO_OPTION) 366 return; 367 368 ChapterEditor cp = (ChapterEditor)editors.get(chapter.getName()); 369 if(cp!=null) cp.dispose(); 370 book.deleteChapter(chapter.getName()); 371 refreshChapterNames(); 372 insertChapterAction.setEnabled(false); 373 } 374 375 376 private void insert() 377 { 378 if(clipboard ==null) return; 379 Chapter c = (Chapter)clipboard; 380 book.addChapter(c); 381 refreshChapterNames(); 382 insertChapterAction.setEnabled(false); 383 } 384 385 private void save() 386 { 387 try { 388 book.saveAs(loadFile); 389 } catch (IOException e) { 390 bee.showError("Error saving book", e); 391 } 392 savedBook = book.deepCopy(); 393 } 394 395 private void saveAs() 396 { 397 JFileChooser chooser = new JFileChooser(); 398 // Note: source for ExampleFileFilter can be found in FileChooserDemo, 399 // under the demo/jfc directory in the Java 2 SDK, Standard Edition. 400 XMLFileFilter filter = new XMLFileFilter(); 401 chooser.setFileFilter(filter); 402 chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES ); 403 int returnVal = chooser.showSaveDialog(this); 404 if(returnVal != JFileChooser.APPROVE_OPTION) return; 405 File bookFile = chooser.getSelectedFile(); 406 if(bookFile==null) 407 { 408 bee.showError("Cannot open file",null); 409 return; 410 } 411 String fname = bookFile.getName(); 412 if(!bookFile.exists()) 413 { 414 try { 415 boolean tmp = bookFile.createNewFile(); 416 } catch (Exception e) { 417 bee.showError("Cannot create file " + fname,e); 418 return; 419 } 420 } 421 422 if(bee.hasEditorKey(bookFile)) 423 { 424 bee.showError("That file is already open for editing.",null); 425 return; 426 } 427 try{ 428 book.saveAs(bookFile); 429 } catch (IOException ex) { 430 bee.showError("Cannot save book file",ex); 431 return; 432 } 433 savedBook = book.deepCopy(); 434 if(loadFile!=bookFile) bee.changeEditorKey(loadFile,bookFile); 435 loadFile = bookFile; 436 } 437 438 private void close() 439 { 440 if(book != savedBook) 441 { 442 String msg = "Do you want to save book " + book.getName() + "?"; 443 int ret = JOptionPane.showInternalConfirmDialog(getDesktopPane(), msg); 444 if( ret == JOptionPane.CANCEL_OPTION) return; 445 if( ret == JOptionPane.YES_OPTION) 446 { 447 save(); 448 showInformationDialog("Saved book " + book.getName()); 449 } 450 } 451 Collection<ChapterEditor> col = editors.values(); 452 for (ChapterEditor targ: col) { 453 targ.dispose(); 454 } 455 bee.removeEditorKey(loadFile); 456 this.dispose(); 457 } 458 459 /** 460 * Describe <code>actionPerformed</code> method here. 461 * 462 * @param e an <code>ActionEvent</code> value 463 */ 464 public void actionPerformed(ActionEvent e) 465 { 466 //if(e.getSource().equals(bEdit)) 467 // editChapter(); 468 if(e.getSource().equals(close)) 469 close(); 470 else if(e.getSource().equals(save)) 471 save(); 472 else if(e.getSource().equals(saveAs)) 473 saveAs(); 474 else if(e.getSource().equals(iNew)) 475 newChapter(); 476 //else if(e.getSource().equals(iCut)) 477 // cut(); 478 else if(e.getSource().equals(iCopy)) 479 copy(); 480 //else if(e.getSource().equals(iPaste)) 481 // paste(); 482 else if(e.getSource().equals(iInsert)) 483 insert(); 484 else if(e.getSource().equals(iDelete)) 485 delete(); 486 else if(e.getSource().equals(fTitle)) 487 editTitle(); 488 else if(e.getSource().equals(fAuthor)) 489 editAuthor(); 490 else if(e.getSource().equals(aDescription)) 491 editDescription(); 492 else if(e.getSource().equals(bUpdate)) 493 editDescription(); 494 //else 495 //super.actionPerformed(e); 496 } 497 private void showInformationDialog(String msg) 498 { 499 showInformationDialog(msg,msg); 500 } 501 502 private void showInformationDialog(String title, String msg) 503 { 504 JOptionPane.showInternalMessageDialog(getDesktopPane(), 505 msg, 506 title, 507 JOptionPane.INFORMATION_MESSAGE); 508 509 } 510 511 private JMenuItem makeJMenuItem(Action ac, String txt, String url) 512 { 513 JMenuItem x = new JMenuItem(ac); 514 x.setText(txt); 515 try { 516 URL u = new URL("file:"+url);//getClass().getResource(url); 517 ImageIcon tmp = new ImageIcon(u); 518 x.setIcon(tmp ); 519 } catch (Exception e) {} 520 return x; 521 } 522 523 524 private JButton makeJButton(Action ac, String txt, String url) 525 { 526 JButton x = new JButton(ac); 527 x.setText(txt); 528 try { 529 URL u = new URL("file:"+url);//getClass().getResource(url); 530 ImageIcon tmp = new ImageIcon(u); 531 x.setIcon(tmp ); 532 Font g = x.getFont(); 533 int style = g.getStyle(); 534 String n = g.getFontName(); 535 Font f = new Font(n,style,8); 536 x.setFont(f); 537 x.setVerticalTextPosition(SwingConstants.BOTTOM); 538 x.setHorizontalTextPosition(SwingConstants.CENTER); 539 } catch (Exception e) {} 540 return x; 541 542 } 543 544 private void editTitle() 545 { 546 // TOFIX: check that it's unique 547 // reinit chapterselector 548 String t = fTitle.getText(); 549 if(!validCharacters(t)) 550 { 551 showInformationDialog("Invalid Characters in Title"); 552 return; 553 } 554 // TOFIX: have to do something like this, i think: 555 //bee.changeEditorKey(bName,t,cName); 556 // cName = t; 557 setTitle(t); 558 } 559 560 561 // chapter editor changed chapter's name 562 void changeEditorKey(String newn, String old) 563 { 564 ChapterEditor c = (ChapterEditor)editors.remove(old); 565 if(c==null) return; 566 editors.put(newn,c); 567 refreshChapterNames(); 568 } 569 570 void removeEditorKey(String theKey) 571 { 572 ChapterEditor c = (ChapterEditor)editors.remove(theKey); 573 c=null; 574 } 575 576 577 private void refreshChapterNames() 578 { 579 Vector<AbstractChapter> v = new Vector<AbstractChapter>(book.getValues()); 580 lChapters.setListData(v); 581 lChapters.repaint(); 582 } 583 584 private void editAuthor() 585 { 586 String t = fAuthor.getText(); 587 if(!validCharacters(t)) 588 { 589 showInformationDialog("Invalid Characters in Author"); 590 return; 591 } 592 setAuthor(t); 593 } 594 595 private void editDescription() 596 { 597 String t = aDescription.getText(); 598 if(!validCharacters(t)) 599 { 600 showInformationDialog("Invalid Characters in Description"); 601 return; 602 } 603 setDescription(t); 604 } 605 606 private boolean validCharacters(String s) 607 { 608 if(s.indexOf('<')>0) return false; 609 if(s.indexOf('&')>0) return false; 610 if(s.indexOf('\"')>0) return false; 611 return true; 612 } 613 614 /** 615 * Describe <code>valueChanged</code> method here. 616 * 617 * @param e a <code>ListSelectionEvent</code> value 618 */ 619 public void valueChanged(ListSelectionEvent e) 620 { 621 Chapter chapter = (Chapter) lChapters.getSelectedValue(); 622 if(chapter==null) 623 { 624 //edit.setEnabled(false); 625 //iCut.setEnabled(false); 626 copyChapterAction.setEnabled(false); 627 deleteChapterAction.setEnabled(false); 628 editChapterAction.setEnabled(false); 629 } else { 630 //edit.setEnabled(true); 631 //iCut.setEnabled(true); 632 copyChapterAction.setEnabled(true); 633 deleteChapterAction.setEnabled(true); 634 editChapterAction.setEnabled(true); 635 } 636 637 // handle menu enable/disables HERE 638 639 } 640 641 } 642 643 644 645 646 647 648