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