001 /* 002 * PAVLOV -- Multiple Choice Study System 003 * Copyright (C) 2000 - 2004 T.J. Willis 004 * 005 * This program is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU General Public License 007 * as published by the Free Software Foundation; either version 2 008 * of the License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU General Public License for more details. 014 * 015 * You should have received a copy of the GNU General Public License 016 * along with this program; if not, write to the Free Software 017 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. 018 * 019 * $Header: /cvsroot/pavlov/net/sourceforge/pavlov/main/standalone/SwingUIFactory.java,v 1.20 2004/07/01 09:03:43 tj_willis Exp $ 020 */ 021 package net.sourceforge.pavlov.main.standalone; 022 023 //import static net.sourceforge.pavlov.main.standalone.ResourceBroker; 024 //import static ResourceBroker; 025 import java.awt.*; 026 import java.awt.event.*; 027 import java.net.URL; 028 import java.util.Hashtable; 029 import javax.help.*; 030 import javax.swing.*; 031 import javax.swing.event.HyperlinkEvent; 032 import javax.swing.event.HyperlinkListener; 033 import net.sourceforge.pavlov.controllers.*; 034 import net.sourceforge.pavlov.event.*; 035 import net.sourceforge.pavlov.library.AbstractLibrary; 036 import net.sourceforge.pavlov.library.ChapterReference; 037 import net.sourceforge.pavlov.main.*; 038 import net.sourceforge.pavlov.pluglets.*; 039 import net.sourceforge.pavlov.pluglets.feedback.velocity.*; 040 import net.sourceforge.pavlov.pluglets.strategy.*; 041 import net.sourceforge.pavlov.randommedia.ImageIconUtilities; 042 import net.sourceforge.pavlov.startup.*; 043 import net.sourceforge.pavlov.swing.*; 044 import net.sourceforge.pavlov.user.*; 045 import net.sourceforge.sillyview.*; 046 import net.sourceforge.steelme.*; 047 import org.apache.log4j.*; 048 import java.beans.PropertyChangeListener; 049 import java.beans.PropertyChangeEvent; 050 051 /** 052 * The purpose of this class and AbstractUIFactory is to separate 053 * user-interface details and program logic so that Pavlov can easily be 054 * reimplemented in user interface environments other than Swing. As of 1.0 055 * that separation has not been accomplished. There needs to be a greater level 056 * of abstraction here and throughout the code. For example, many classes 057 * throughout Pavlov are subclasses of JI_nternalFrame and JComponent. 058 * Reimplementation of these classes as Model-View-Controller would allow 059 * porting to consist of writing a view, and a UIFactory that couples that view 060 * with the controller. 061 * 062 *@author <a href="mailto:tj_willis@users.sourceforge.net">T.J. Willis</a> 063 *@created June 26, 2004 064 *@version 1.0 065 */ 066 public class SwingUIFactory extends AbstractUIFactory 067 implements ActionListener, HyperlinkListener, LogonListener 068 { 069 // FIXED: broke startup window closing frame references removed 070 // FIXED: isolate login functionality in main.LoginController 071 // FIXED: remove old quizSelector 072 // FIXED: apparently don't need getSelectedChapterReference() 073 // FIXED: de-static all fields 074 // FIXED: minimize access all fields 075 // FIXED: move to standalone directory 076 // FIXED: remove frame reference 077 // FIXME: class-field JMenuItems should be replaced with actions 078 // FIXED: move in CVS 079 private LibraryController libController; 080 private HardcopyQuiz hardcopyQuiz; 081 private StartupWindow lstartup = null; 082 private ResourceBroker rb; 083 084 /** 085 * Describe variable <code>MYFRAME</code> here. 086 */ 087 protected final JFrame MYFRAME; 088 /** 089 * Describe variable <code>SPLITTER</code> here. 090 */ 091 protected final JSplitPane SPLITTER; 092 /** 093 * Describe variable <code>pavlov</code> here. 094 */ 095 protected final Pavlov pavlov; 096 /** 097 * Describe variable <code>quiz</code> here. 098 */ 099 protected Quiz quiz; 100 101 /** 102 * Describe variable <code>templateKit</code> here. 103 */ 104 private Skin templateKit; 105 private static Category cat = Category.getInstance(SwingUIFactory.class.getName()); 106 107 /** 108 * Describe variable <code>quizController</code> here. 109 */ 110 protected QuizController quizController; 111 112 /** 113 * Describe variable <code>theme</code> here. 114 */ 115 protected SteelmeTheme theme; 116 117 /** 118 * Describe variable <code>themeDirectory</code> here. 119 */ 120 protected java.io.File themeDirectory; 121 /** 122 * Describe variable <code>feedbackPlugins</code> here. 123 */ 124 protected PlugletLoader feedbackPlugins; 125 /** 126 * Describe variable <code>velocityPlugins</code> here. 127 */ 128 protected VelocityPlugletLoader velocityPlugins; 129 130 /** 131 * Describe variable <code>strategyPluglets</code> here. 132 */ 133 protected StrategyLoader strategyPluglets; 134 /** 135 * Describe variable <code>toolPluglets</code> here. 136 */ 137 protected PlugletLoader toolPluglets; 138 139 private JFrameView loginView; 140 private JMenuItem saveMenuItem, exitMenuItem; 141 private JRadioButtonMenuItem incorrectMenuItem; 142 private volatile JMenu feedbackMenu,strategyMenu, toolsMenu; 143 private JDialog incorrect; 144 private Incorrect ict; 145 146 /** 147 * Creates a new <code>SwingUIFactory</code> instance. 148 * 149 *@param thePavlov a <code>Pavlov</code> value 150 *@param base a <code>JComponent</code> value 151 */ 152 public SwingUIFactory(Pavlov thePavlov, JFrame base) 153 { 154 rb = ResourceBroker.getInstance(); 155 // FIXED: remove frame reference 156 MYFRAME = base; 157 pavlov = thePavlov; 158 try { 159 //FIXED: read from properties 160 java.io.File def = rb.getFile(rb.SKINS_DEFAULT_DIR); 161 templateKit = new Skin(def); 162 setTemplateToolkit(templateKit); 163 } 164 catch (Exception ex) { 165 error(rb.SKINS_ERROR_DEFAULT, ex); 166 } 167 //JInternalFrame jif = new JInternalFrame(); 168 169 SPLITTER = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true); 170 //SPLITTER.setRightComponent(tmp2); 171 SPLITTER.setOneTouchExpandable(true); 172 //jif.getContentPane().add(SPLITTER); 173 //addInternalFrame(jif); 174 //jif.setResizable(true); 175 //try { 176 // jif.setMaximum(true); 177 //} catch (java.beans.PropertyVetoException p) { 178 // screw it 179 //} 180 } 181 182 183 //FIXME: crappy name 184 /** 185 * Gets the main attribute of the SwingUIFactory object 186 * 187 *@return The main value 188 */ 189 public JComponent getMain() 190 { 191 return SPLITTER; 192 } 193 194 195 /** 196 * Description of the Method 197 * 198 *@param key Description of the Parameter 199 *@param except Description of the Parameter 200 */ 201 private void error(final String key, Exception except) 202 { 203 cat.error(rb.getString(key), except); 204 } 205 206 207 /** 208 * Describe <code>confirmQuit</code> method here. 209 * 210 *@return a <code>boolean</code> value 211 */ 212 public boolean confirmQuit() 213 { 214 int ret = showConfirmDialog(rb.getString(rb.QUIT)); 215 return (ret == JOptionPane.YES_OPTION); 216 } 217 218 219 /** 220 * Describe <code>setQuiz</code> method here. 221 * 222 *@param quiz The new quiz value 223 */ 224 public void setQuiz(Quiz quiz) 225 { 226 this.quiz = quiz; 227 } 228 229 230 /** 231 * Describe <code>getQuiz</code> method here. 232 * 233 *@return a <code>Quiz</code> value 234 */ 235 public Quiz getQuiz() 236 { 237 return quiz; 238 } 239 240 241 /** 242 * Describe <code>setFeedbackPluglets</code> method here. 243 * 244 *@param loader The new feedbackPluglets value 245 */ 246 public void setFeedbackPluglets(PlugletLoader loader) 247 { 248 this.feedbackPlugins = loader; 249 if(feedbackMenu==null){ 250 cat.error("Null feedbackMenu: race condition"); 251 } 252 feedbackPlugins.addToJMenuAsCheckboxes(feedbackMenu); 253 254 } 255 256 257 /** 258 * Describe <code>setVelocityPluglets</code> method here. 259 * 260 *@param loader The new velocityPluglets value 261 */ 262 public void setVelocityPluglets(VelocityPlugletLoader loader) 263 { 264 velocityPlugins = loader; 265 if(feedbackMenu==null){ 266 cat.error("Null feedbackMenu: race condition"); 267 } 268 velocityPlugins.addToJMenuAsCheckboxes(feedbackMenu); 269 } 270 271 /** 272 * Describe <code>setStrategyPluglets</code> method here. 273 * 274 *@param loader The new strategyPluglets value 275 */ 276 public void setStrategyPluglets(StrategyLoader loader) 277 { 278 strategyPluglets = loader; 279 if(strategyMenu==null){ 280 cat.error("Null strategyMenu: race condition"); 281 } 282 strategyPluglets.addToJMenuAsRadioButtons(strategyMenu); 283 //HERE 284 } 285 286 287 /** 288 * Describe <code>setToolPluglets</code> method here. 289 * 290 *@param loader The new toolPluglets value 291 */ 292 public void setToolPluglets(PlugletLoader loader) 293 { 294 toolPluglets = loader; 295 if(toolsMenu==null){ 296 cat.error("Null toolsMenu: race condition"); 297 } 298 toolPluglets.addToJMenuAsCheckboxes(toolsMenu); 299 } 300 301 302 /** 303 * Apply the current theme. 304 */ 305 public void applyTheme() 306 { 307 if (theme == null && templateKit != null) { 308 theme = templateKit.getTheme(); 309 } 310 if (theme != null) { 311 theme.setTarget(MYFRAME); 312 theme.applyTheme(MYFRAME); 313 } 314 } 315 316 317 /** 318 * Describe <code>setTemplateToolkit</code> method here. 319 * 320 *@param kit an <code>AbstractTemplateKit</code> value 321 */ 322 public void setTemplateToolkit(Skin kit) 323 { 324 theme = kit.getTheme(); 325 applyTheme(); 326 327 templateKit = kit; 328 if (libController != null) { 329 libController.setTemplate(kit.getLibraryTemplate(), kit.getBaseDir()); 330 } 331 if (quizController != null) { 332 quizController.setTemplate(kit.getQuizTemplate(), kit.getBaseDir()); 333 } 334 applyTheme(); 335 cat.info("Set kit"); 336 } 337 338 339 340 341 342 /** 343 * Gets the applicationWidth attribute of the SwingUIFactory object 344 * 345 *@return The applicationWidth value 346 */ 347 private int getApplicationWidth() 348 { 349 Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); 350 return (int) (dim.getWidth() * .9); 351 //^ 352 } 353 354 355 /** 356 * Gets the applicationHeight attribute of the SwingUIFactory object 357 * 358 *@return The applicationHeight value 359 */ 360 private int getApplicationHeight() 361 { 362 Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); 363 return (int) (dim.getHeight() * .9);//^ 364 } 365 366 367 /** 368 * Describe <code>createQuizSelector</code> method here. 369 * 370 *@param user an <code>User</code> value 371 *@param library an <code>AbstractLibrary</code> value 372 */ 373 public void createQuizSelector(User user, AbstractLibrary library) 374 { 375 // FIXED: LibraryController replaces quizSelector 376 377 libController = null; 378 String tmplt = null; 379 String welcomeTmplt = null; 380 VelocityModel welcomeModel = null; 381 try { 382 welcomeTmplt = templateKit.getWelcomeTemplate(); 383 welcomeModel = new VelocityModel(welcomeTmplt); 384 tmplt = templateKit.getLibraryTemplate(); 385 VelocityModel libMod = new VelocityModel(tmplt); 386 WidgetView libView = new JPanelView(libMod, JPanelView.HTMLPANE); 387 libController = new LibraryController(libView, library); 388 libController.setBaseDirectory(templateKit.getBaseDir()); 389 } 390 catch (Exception ex) { 391 error(rb.LIBRARY_ERROR, ex); 392 } 393 if (libController == null || tmplt == null) { 394 error(rb.LIBRARY_ERROR, null); 395 } 396 397 libController.setHyperlinkListener(this); 398 399 Dimension libSize = new Dimension((int) (getApplicationWidth() * .25), 400 getApplicationHeight());//^ 401 402 JPanelView libVu = (JPanelView) libController.getView(); 403 404 JScrollPane libScroll = new JScrollPane(libVu); 405 libScroll.setPreferredSize(libSize); 406 libScroll.setMinimumSize(libSize); 407 SPLITTER.setLeftComponent(libScroll); 408 409 410 HTMLPaneView welcomeVu = new HTMLPaneView(welcomeModel); 411 setRightView(welcomeVu); 412 /* 413 * JScrollPane sp2 = new JScrollPane(v2); 414 * SPLITTER.setRightComponent(sp2); 415 */ 416 applyTheme(); 417 } 418 419 420 /** 421 * Describe <code>startQuiz</code> method here. 422 * 423 *@param user an <code>User</code> value 424 *@param ref a <code>ChapterReference</code> value 425 */ 426 public void startQuiz(User user, ChapterReference ref) 427 { 428 if(user==null) throw new IllegalArgumentException("user is null"); 429 if(ref==null) throw new IllegalArgumentException("chapter reference is null"); 430 431 //assert user != null: rb.getString(rb.USER_NULL); 432 //assert ref!=null: rb.getString(rb.CHAPTER_NULL); 433 if (quiz != null) { 434 saveQuiz(); 435 } 436 437 quiz = new Quiz(pavlov, user, ref); 438 pavlov.setQuiz(quiz); 439 440 //============================================== 441 if (quizController != null) { 442 quizController.setQuiz(quiz); 443 } 444 else { 445 HTMLPaneView quizVu = (HTMLPaneView) getQuizView(); 446 setRightView(quizVu); 447 quizVu.setToken(JPanelView.HYPERLINK_LISTENER, this); 448 //ifv.setAutoDump(true); 449 try { 450 quizController = new QuizController(quiz, quizVu); 451 } 452 catch (Exception ex) { 453 error(rb.QUIZVIEW_ERROR_CREATE, ex); 454 } 455 setTemplateToolkit(templateKit); 456 } 457 //============================================== 458 quiz.newQuestion(); 459 } 460 461 462 /** 463 * Sets the rightView attribute of the SwingUIFactory object 464 * 465 *@param ifv The new rightView value 466 */ 467 private void setRightView(HTMLPaneView ifv) 468 { 469 Dimension g1 = new Dimension((int) (getApplicationWidth() * .6), 470 getApplicationHeight()); 471 ifv.setSize(g1); 472 ifv.setPreferredSize(g1); 473 ifv.invalidate(); 474 ifv.doLayout(); 475 JScrollPane sp = new JScrollPane(ifv); 476 sp.setPreferredSize(g1); 477 sp.setMinimumSize(g1); 478 SPLITTER.setRightComponent(sp); 479 SPLITTER.resetToPreferredSizes(); 480 } 481 482 483 /** 484 * Describe <code>getQuizView</code> method here. 485 * 486 *@return a <code>WidgetView</code> value 487 */ 488 private WidgetView getQuizView() 489 { 490 String tmplt = templateKit.getQuizTemplate(); 491 WidgetModel mod = null; 492 try { 493 mod = new VelocityModel(tmplt); 494 } 495 catch (Exception ex) { 496 error(rb.QUIZVIEW_ERROR_CREATE, ex); 497 } 498 return new HTMLPaneView(mod); 499 } 500 501 502 /** 503 * Saves the current quiz. 504 */ 505 public void saveQuiz() 506 { 507 try { 508 quiz.save(); 509 } 510 catch (Exception ex) { 511 error(rb.LOGIN_ERROR, ex); 512 } 513 } 514 515 516 /** 517 * Describe <code>getResourceString</code> method here. 518 * 519 *@param a a <code>String</code> value 520 *@param b a <code>String</code> value 521 *@return a <code>String</code> value 522 */ 523 public String getResourceString(String a, String b) 524 { 525 return rb.getString(a, b); 526 } 527 528 529 /** 530 * Null implementation here, since StartupWindow closes itself. 531 */ 532 public void closeSplashScreen() { } 533 534 535 /** 536 * The LoginController calls this when the user has finished logging in. 537 * 538 *@param event a <code>LogonEvent</code> value 539 */ 540 public void logonAttempt(final LogonEvent event) 541 { 542 if (loginView == null) { 543 return; 544 } 545 loginView.setVisible(false); 546 loginView = null; 547 } 548 549 550 /** 551 * Sets the message and status number in startup window. 552 * 553 *@param msg a <code>String</code> value 554 *@param percent The new status value 555 */ 556 public void setStatus(int percent, String msg) 557 { 558 if (lstartup == null) { 559 return; 560 } 561 lstartup.setStatus(percent, msg); 562 } 563 564 565 /** 566 * Creates the login widget and shows it to the user. 567 * 568 *@param lis a <code>LogonListener</code> value 569 */ 570 public void showLoginController(LogonListener lis) 571 { 572 try { 573 574 VelocityModel loginModel = new VelocityModel(templateKit.getLoginTemplate()); 575 loginView = new JFrameView(loginModel, JPanelView.HTMLPANE); 576 LoginController lc = new LoginController(loginView); 577 578 loginView.pack(); 579 Dimension d = loginView.getSize(); 580 Dimension d2 = Toolkit.getDefaultToolkit().getScreenSize(); 581 int x0 = (d2.width - d.width) / 2; 582 int y0 = (d2.height - d.height) / 2; 583 Point p = new Point(x0, y0); 584 loginView.setLocation(p); 585 loginView.setVisible(true); 586 lc.addLogonListener(this); 587 lc.addLogonListener(lis); 588 } 589 catch (Exception ex) { 590 error(rb.LOGIN_ERROR, ex); 591 //ex.printStackTrace(); 592 //showErrorDialog("Problem creating login view",ex); 593 } 594 } 595 596 597 /** 598 * Shows the startup window. 599 * 600 *@param frame Description of the Parameter 601 */ 602 public void showSplashScreen(JFrame frame) 603 { 604 // FIXED: this was why the window's not closing 605 //javax.swing.JFrame frame = pavlov.getFrame(); 606 // FIXME: get startup image from Resources file 607 try { 608 lstartup = new StartupWindow(rb.getString(rb.ABOUT_IMAGE), frame); 609 //"file:resources/AboutPavlov.jpg",frame); 610 } 611 catch (Exception ex) { 612 error(rb.ABOUT_IMAGE, ex); 613 //FIXME need a message string 614 } 615 } 616 617 618 /** 619 * Describe <code>showIncorrectDialog</code> method here. 620 * 621 *@param msg a <code>String</code> value 622 */ 623 public void showIncorrectDialog(String msg) 624 { 625 if(!incorrectMenuItem.isSelected()){ 626 if(incorrect!=null) incorrect.setVisible(false); 627 return; 628 } 629 //FIXME: rewrite as sillyview 630 if(incorrect==null){ 631 ict = new Incorrect(); 632 incorrect = ict.createDialog();//new IncorrectDialog(); 633 } 634 incorrect.setVisible(true); 635 ict.setText(msg); 636 //System.out.println("set msg to " + msg); 637 /* 638 String incor = getResourceString("IncorrectDialogTitle", "Incorrect"); 639 if(incorrect==null){ 640 incorrect = new JDialog(MYFRAME,incor); 641 } 642 JLabel lab = new JLabel(msg); 643 incorrect.getContentPane().add(lab); 644 incorrect.setVisible(true); 645 JTextArea bull = new JTextArea(msg,2,40); 646 bull.setLineWrap(true); 647 bull.setEditable(false); 648 JScrollPane sp = new JScrollPane(bull); 649 showMessageDialog(sp, incor,JOptionPane.INFORMATION_MESSAGE); 650 */ 651 } 652 653 654 655 /** 656 * Describe <code>showFileChooser</code> method here. 657 * 658 *@param chooser a <code>JFileChooser</code> value 659 *@param openMode a <code>boolean</code> value 660 *@return an <code>int</code> value 661 */ 662 public int showFileChooser(JFileChooser chooser, boolean openMode) 663 { 664 // FIXED: remove frame reference 665 //chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES ); 666 int retVal = JFileChooser.CANCEL_OPTION; 667 if (chooser == null || MYFRAME == null) { 668 return retVal; 669 } 670 if (openMode) { 671 return chooser.showOpenDialog(MYFRAME); 672 } 673 else { 674 return chooser.showSaveDialog(MYFRAME); 675 } 676 } 677 678 679 //==================================fixed============================ 680 681 /** 682 * Describe <code>makeImageIcon</code> method here. 683 * 684 *@param key a <code>String</code> value 685 *@param def a <code>String</code> value 686 *@param size an <code>int</code> value 687 *@return an <code>ImageIcon</code> value 688 */ 689 public ImageIcon makeImageIcon(String key, String def, int size) 690 { 691 String iFile = rb.getString(key, def); 692 return ImageIconUtilities.getNamedImageIcon(iFile, size); 693 } 694 695 696 /** 697 * Creates a menu, looking for the text in a properties file, and using the 698 * default if it can't be found. Also checks for mnemonics (accelerators) and 699 * tooltips. 700 * 701 *@param bar a <code>JMenuBar</code> value 702 *@param id a <code>String</code> value 703 *@param def a <code>String</code> value 704 *@return a <code>JMenu</code> value 705 */ 706 private JMenu makeMenu(JMenuBar bar, String id, String def) 707 { 708 JMenu newMenu = new JMenu(getResourceString(id, def)); 709 bar.add(newMenu); 710 return (newMenu); 711 } 712 713 714 /** 715 * Creates a menu item, looking for the text in a properties file, and using 716 * the default if it can't be found. Also checks for mnemonics (accelerators) 717 * and tooltips. 718 * 719 *@param bar a <code>JMenu</code> value 720 *@param id a <code>String</code> value 721 *@param def a <code>String</code> value 722 *@return a <code>JMenuItem</code> value 723 */ 724 private JMenuItem makeMenuItem(JMenu bar, String key, String def) 725 { 726 JMenuItem item = new JMenuItem(getResourceString(key, def)); 727 String tt = getResourceString(key + ".toolTip", null); 728 if (tt != null) { 729 item.setToolTipText(tt); 730 } 731 732 String mnemonic = getResourceString(key + ".mnemonic", null); 733 if (mnemonic != null) { 734 // FIXME: mnemonic apparently not be working 735 char foo[] = new char[1]; 736 mnemonic.getChars(0, 1, foo, 0); 737 item.setMnemonic(foo[0]); 738 System.out.println("Set mnemonic to " + foo); 739 } 740 bar.add(item); 741 return (item); 742 } 743 744 745 /** 746 * Describe <code>showConfirmDialog</code> method here. 747 * 748 *@param message an <code>Object</code> value 749 *@return an <code>int</code> value 750 */ 751 public int showConfirmDialog(Object message) 752 { 753 return JOptionPane.showConfirmDialog(MYFRAME, message); 754 } 755 756 757 /** 758 * Describe <code>showMessageDialog</code> method here. 759 * 760 *@param message an <code>Object</code> value 761 *@param title a <code>String</code> value 762 *@param messageType an <code>int</code> value 763 */ 764 public void showMessageDialog(Object message, String title, int messageType) 765 { 766 JOptionPane.showMessageDialog(MYFRAME, 767 message, 768 title, messageType); 769 } 770 771 772 /** 773 * Describe <code>showInputDialog</code> method here. 774 * 775 *@param message an <code>Object</code> value 776 *@param title a <code>String</code> value 777 *@param messageType an <code>int</code> value 778 *@return a <code>String</code> value 779 *@exception HeadlessException if an error occurs 780 */ 781 public String showInputDialog(Object message, 782 String title, 783 int messageType) 784 throws HeadlessException 785 { 786 // FIXED: remove frame reference 787 return JOptionPane.showInputDialog(MYFRAME, 788 message, 789 title, messageType); 790 } 791 792 793 /** 794 * Describe <code>showOptionDialog</code> method here. 795 * 796 *@param message an <code>Object</code> value 797 *@param title a <code>String</code> value 798 *@param optionType an <code>int</code> value 799 *@param messageType an <code>int</code> value 800 *@param icon an <code>Icon</code> value 801 *@param options an <code>Object[]</code> value 802 *@param initialValue an <code>Object</code> value 803 *@return an <code>int</code> value 804 *@exception HeadlessException if an error occurs 805 */ 806 public int showOptionDialog(Object message, 807 String title, 808 int optionType, 809 int messageType, 810 Icon icon, 811 Object[] options, 812 Object initialValue) 813 throws HeadlessException 814 { 815 // FIXED: remove frame reference 816 return JOptionPane.showOptionDialog(MYFRAME, 817 message, title, 818 optionType, messageType, 819 icon, options, initialValue); 820 } 821 822 823 /** 824 * Description of the Method 825 * 826 *@param message Description of the Parameter 827 *@param ex Description of the Parameter 828 */ 829 public void showErrorDialog(String message, Exception ex) 830 { 831 showMessageDialog(message + ex, "Error", JOptionPane.ERROR_MESSAGE); 832 } 833 834 835 /** 836 * Description of the Method 837 * 838 *@param msg Description of the Parameter 839 *@param title Description of the Parameter 840 */ 841 public void showInfoDialog(String msg, String title) 842 { 843 showMessageDialog(msg, title, JOptionPane.INFORMATION_MESSAGE); 844 } 845 846 847 848 /** 849 * Describe <code>createMenuBar</code> method here. 850 * 851 *@param rootPane Description of the Parameter 852 *@return Description of the Return Value 853 */ 854 public JMenuBar createMenuBar(JComponent rootPane) 855 { 856 //JRootPane root = MYFRAME.getRootPane(); 857 //assert root!=null: "RootPane is null"; 858 // FIXED: remove frame reference 859 JMenuBar menuBar = new JMenuBar(); 860 makeFileMenu(menuBar); 861 makeFeedbackMenu(menuBar); 862 makePreferencesMenu(menuBar, rootPane); 863 makeStrategyMenu(menuBar); 864 makeToolsMenu(menuBar); 865 makeHelpMenu(menuBar); 866 return menuBar; 867 //root.setJMenuBar(menuBar); 868 } 869 870 871 /** 872 * Describe <code>makeFileMenu</code> method here. 873 * 874 *@param menuBar Description of the Parameter 875 */ 876 protected void makeFileMenu(JMenuBar menuBar) 877 { 878 JMenu file = makeMenu(menuBar, "FileMenu", "File"); 879 saveMenuItem = makeMenuItem(file, "SaveMenuItem", "Save"); 880 exitMenuItem = makeMenuItem(file, "ExitMenuItem", "Exit"); 881 exitMenuItem.addActionListener(this); 882 saveMenuItem.addActionListener(this); 883 } 884 885 886 /** 887 * Describe <code>makeFeedbackMenu</code> method here. 888 * 889 *@param menuBar Description of the Parameter 890 */ 891 protected void makeFeedbackMenu(JMenuBar menuBar) 892 { 893 //HERE 894 feedbackMenu = makeMenu(menuBar, "FeedbackMenu", "Feedback"); 895 /* 896 if (feedbackPlugins != null) { 897 feedbackPlugins.addToJMenuAsCheckboxes(feedbackMenu); 898 } 899 if (velocityPlugins != null) { 900 velocityPlugins.addToJMenuAsCheckboxes(feedbackMenu); 901 } 902 */ 903 menuBar.add(feedbackMenu); 904 } 905 906 907 /** 908 * Describe <code>makeToolsMenu</code> method here. 909 * 910 *@param menuBar Description of the Parameter 911 */ 912 protected void makeToolsMenu(JMenuBar menuBar) 913 { 914 toolsMenu = makeMenu(menuBar, "ToolsMenu", "Tools"); 915 916 try { 917 hardcopyQuiz = new HardcopyQuiz(pavlov); 918 JMenuItem hc = makeMenuItem(toolsMenu, "HardcopyMenuItem", "Hardcopy Quiz"); 919 // FIXME: getResource 920 hc.addActionListener(hardcopyQuiz); 921 //toolsMenu.add(hc); 922 } 923 catch (Exception ex) { 924 error(rb.HARDCOPY_ERROR, ex); 925 } 926 menuBar.add(toolsMenu); 927 } 928 929 930 /** 931 * Describe <code>makePreferencesMenu</code> method here. 932 * 933 *@param menuBar Description of the Parameter 934 *@param targ Description of the Parameter 935 */ 936 protected void makePreferencesMenu(JMenuBar menuBar, JComponent targ) 937 { 938 // FIXED: remove frame reference 939 JMenu preferences = makeMenu(menuBar, "PreferencesMenu", "Preferences"); 940 incorrectMenuItem = new JRadioButtonMenuItem(rb.getString("IncorrectMenuItem"),true); 941 preferences.add(incorrectMenuItem); 942 incorrectMenuItem.addActionListener(this); 943 themeDirectory = rb.getFile(rb.THEMES_DEFAULT_DIR); 944 applyTheme(); 945 JMenu themeMenu = new ThemeMenu(targ, themeDirectory); 946 preferences.add(themeMenu); 947 makeSkinMenu(preferences); 948 } 949 950 951 /** 952 * Describe <code>makeSkinMenu</code> method here. 953 * 954 *@param men a <code>JMenu</code> value 955 */ 956 protected void makeSkinMenu(JMenu men) 957 { 958 new SkinSystem(this, men); 959 } 960 961 962 /** 963 * Describe <code>makeStrategyMenu</code> method here. 964 * 965 *@param menuBar Description of the Parameter 966 */ 967 protected void makeStrategyMenu(JMenuBar menuBar) 968 { 969 String stratString = getResourceString("strategyLabel", "Strategy"); 970 strategyMenu = new JMenu(stratString); 971 menuBar.add(strategyMenu); 972 } 973 974 975 /** 976 * Describe <code>makeHelpMenu</code> method here. 977 * 978 *@param menuBar Description of the Parameter 979 */ 980 protected void makeHelpMenu(JMenuBar menuBar) 981 { 982 HelpSystem helps = new HelpSystem(MYFRAME); 983 try { 984 HelpBroker hb; 985 HelpSet hs; 986 JMenuItem helpItem; 987 //FIXED: get helpset from Resources 988 URL hsURL = rb.getURL(rb.HELPSET_URL); 989 hs = new HelpSet(null, hsURL); 990 hb = hs.createHelpBroker(); 991 helpItem = new JMenuItem("Help Topics...");//^ 992 helpItem.addActionListener(new CSH.DisplayHelpFromSource(hb)); 993 helps.add(helpItem); 994 } 995 catch (Exception ee) { 996 // Say what the exception really is 997 cat.warn("Error Creating HelpSet ", ee); 998 } 999 // FIXME: these all got really, really ugly. HTMLInternalFrame is almost useless 1000 // and displays the pages very, very poorly 1001 boolean ret; 1002 //ret = helps.addItem("http://pavlov.sf.net/pavlov_demo/tour1.html", "Pavlov Tutorial (online)"); 1003 ret = helps.addItem("file:resources/aboutPavlov.html", "About Pavlov"); 1004 //helps.addSeparator(); 1005 //ret = helps.addItem("http://pavlov.sf.net/bee_demo/tour1.html", "Bee Tutorial (How To Write Questions - online)"); 1006 //ret = helps.addItem("http://pavlov.sf.net/howto/skins.html", "Writing Custom Skins (online)"); 1007 //ret = helps.addItem("http://pavlov.sf.net/howto/veloplug.html", "Writing Custom Feedback Pluglet Scripts (online)"); 1008 //FIXME: problem with formsubmitevents 1009 //helps.addSeparator(); 1010 //ret = helps.addItem("http://sourceforge.net/tracker/?atid=629249&group_id=101202&func=browse","Bug Reports (online)"); 1011 //ret = helps.addItem("http://sourceforge.net/tracker/?atid=629252&group_id=101202&func=browse","Feature Requests (online)"); 1012 //helps.addSeparator(); 1013 //ret = helps.addItem("http://pavlov.sf.net", "Pavlov Home Page (online)"); 1014 //ret = helps.addItem("http://sf.net/projects/pavlov", "Pavlov News (online)"); 1015 //ret = helps.addItem("http://freshmeat.net/rate/44809/", "Rate Pavlov at freshmeat.net"); 1016 1017 menuBar.add(helps); 1018 } 1019 1020 1021 /** 1022 * Describe <code>actionPerformed</code> method here. 1023 * 1024 *@param e a <code>java.awt.event.ActionEvent</code> value 1025 */ 1026 public void actionPerformed(java.awt.event.ActionEvent e) 1027 { 1028 if (e == null) { 1029 return; 1030 } 1031 Object src = e.getSource(); 1032 1033 if (src instanceof JMenuItem) { 1034 if (src.equals(exitMenuItem)) { 1035 pavlov.niceQuit(true); 1036 } 1037 else if (src.equals(saveMenuItem)) { 1038 saveQuiz(); 1039 } 1040 else if (src.equals(incorrectMenuItem)){ 1041 if(incorrect.isVisible() && 1042 !incorrectMenuItem.isSelected()){ 1043 incorrect.setVisible(false); 1044 } 1045 } 1046 } 1047 } 1048 1049 1050 //===============================end fixed=============================== 1051 1052 //FIXME: temporary hack only, for widget development 1053 /** 1054 * Describe <code>hyperlinkUpdate</code> method here. 1055 * 1056 *@param e a <code>HyperlinkEvent</code> value 1057 */ 1058 public void hyperlinkUpdate(HyperlinkEvent e) 1059 { 1060 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { 1061 try { 1062 java.net.URL u = e.getURL(); 1063 //cat.debug("Got url: " + u); 1064 String command = URLParser.getFilenameWithoutPath(u); 1065 //FIXME: tiger-style this hashtable 1066 Hashtable hash = URLParser.parseVariables(u); 1067 if (hash == null) { 1068 cat.warn("URL hashtable is null"); 1069 return; 1070 } 1071 if (QuizController.ANSWER_EVENT.equals(command)) { 1072 processAnswer(hash); 1073 } 1074 else if (LibraryController.START_QUIZ_COMMAND.equals(command)) { 1075 processStartQuiz(hash); 1076 } 1077 } 1078 catch (Exception ex) { 1079 cat.error("Error parsing command url", ex); 1080 } 1081 } 1082 } 1083 1084 1085 /** 1086 * Description of the Method 1087 * 1088 *@param h Description of the Parameter 1089 */ 1090 private void processAnswer(Hashtable hash) 1091 { 1092 boolean right = false; 1093 if (hash != null) { 1094 Object mode = hash.get(QuizController.ANSWER_MODE); 1095 if (mode != null) { 1096 String modeStr = mode.toString(); 1097 right = (QuizController.RIGHT.equals(modeStr)); 1098 } else { 1099 cat.error("mode is null"); 1100 } 1101 } 1102 AnswerEvent event = new AnswerEvent(right); 1103 //FIXME: in standalone, this works right. as a servlet, 1104 // i'm not so sure. i.e., say the user has two open browsers. 1105 // then quiz.question is not necessarily this question. quiz. 1106 // chapter might not even be right. so we can parse user, 1107 // book, chapter, blahblahblah here and forward it to quiz. 1108 // it seems like a lot of work, though... 1109 quiz.answerEvent(event); 1110 1111 } 1112 1113 1114 /** 1115 * Description of the Method 1116 * 1117 *@param h Description of the Parameter 1118 */ 1119 private void processStartQuiz(Hashtable hash) 1120 { 1121 if(hash==null) throw new IllegalArgumentException("command hashtable is null"); 1122 Object bookName = hash.get(LibraryController.BOOK_NAME); 1123 Object chapName = hash.get(LibraryController.CHAPTER_NAME); 1124 if (bookName == null) { 1125 error(rb.BOOK_NULL, null); 1126 } 1127 else if (chapName == null) { 1128 error(rb.CHAPTER_NULL, null); 1129 } 1130 else { 1131 ChapterReference ref = 1132 new ChapterReference(pavlov.getLibrary(), 1133 bookName.toString(), 1134 chapName.toString()); 1135 startQuiz(pavlov.getUser(), ref); 1136 } 1137 1138 } 1139 1140 private class Incorrect extends JOptionPane { 1141 private JTextArea msgArea; 1142 1143 public Incorrect(){ 1144 super(null,JOptionPane.INFORMATION_MESSAGE); 1145 msgArea = new JTextArea(2,40); 1146 msgArea.setLineWrap(true); 1147 msgArea.setEditable(false); 1148 JScrollPane sp = new JScrollPane(msgArea); 1149 setMessage(sp); 1150 } 1151 1152 public JDialog createDialog(){ 1153 JDialog jd = super.createDialog( SwingUIFactory.this.MYFRAME, 1154 getResourceString("IncorrectDialogTitle", "Incorrect")); 1155 jd.setModal(false); 1156 jd.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); 1157 return jd; 1158 } 1159 1160 public void setText(String txt){ 1161 msgArea.setText(txt); 1162 } 1163 1164 1165 } 1166 1167 /* 1168 private class IncorrectDialog extends JDialog { 1169 private JTextArea msgArea; 1170 private JOptionPane op; 1171 1172 public IncorrectDialog(){ 1173 this = JOptionPane.createDialog(SwingUIFactory.this.MYFRAME, 1174 getResourceString("IncorrectDialogTitle", "Incorrect")); 1175 setModal(false); 1176 1177 //super(SwingUIFactory.this.MYFRAME, 1178 // getResourceString("IncorrectDialogTitle", "Incorrect"), 1179 // false); 1180 msgArea = new JTextArea(2,40); 1181 msgArea.setLineWrap(true); 1182 msgArea.setEditable(false); 1183 JScrollPane sp = new JScrollPane(msgArea); 1184 op = new JOptionPane(sp,JOptionPane.INFORMATION_MESSAGE); 1185 op.addPropertyChangeListener( 1186 new PropertyChangeListener() { 1187 public void propertyChange(PropertyChangeEvent e) { 1188 System.out.println("Got PCE:" + e); 1189 String prop = e.getPropertyName(); 1190 1191 if (IncorrectDialog.this.isVisible() 1192 && (e.getSource() == IncorrectDialog.this.op)){ 1193 1194 IncorrectDialog.this.setVisible(false); 1195 IncorrectDialog.this.op.fireVetoableChange( 1196 e.getPropertyName(), 1197 e.getOldValue(), 1198 e.getNewValue() 1199 ); 1200 } 1201 } 1202 }); 1203 1204 getContentPane().add(op); 1205 System.out.println("Created incorD"); 1206 setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); 1207 pack(); 1208 } 1209 1210 public void setText(String txt){ 1211 msgArea.setText(txt); 1212 } 1213 1214 1215 } 1216 */ 1217 } 1218