Java tutorial
/* * Copyright 2014 London Knowledge Lab, Institute of Education. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package uk.ac.lkl.cram.ui; import java.awt.Cursor; import java.awt.Dialog; import java.awt.Dimension; import java.awt.Frame; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.text.MessageFormat; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JFileChooser; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.text.DefaultEditorKit; import javax.swing.undo.CompoundEdit; import javax.swing.undo.UndoableEdit; import javax.xml.bind.JAXBException; import org.docx4j.openpackaging.exceptions.Docx4JException; import org.jdesktop.swingx.JXTaskPane; import org.jfree.chart.ChartMouseEvent; import org.jfree.chart.ChartMouseListener; import org.jfree.chart.ChartPanel; import org.jfree.chart.entity.CategoryItemEntity; import org.jfree.chart.entity.PieSectionEntity; import org.openide.DialogDisplayer; import org.openide.WizardDescriptor; import org.openide.util.Utilities; import uk.ac.lkl.cram.model.AELMTest; import uk.ac.lkl.cram.model.LineItem; import uk.ac.lkl.cram.model.Module; import uk.ac.lkl.cram.model.ModuleLineItem; import uk.ac.lkl.cram.model.TLALineItem; import uk.ac.lkl.cram.model.UserTLALibrary; import uk.ac.lkl.cram.model.io.ModuleMarshaller; import uk.ac.lkl.cram.ui.chart.FeedbackChartMaker; import uk.ac.lkl.cram.ui.chart.HoursChartMaker; import uk.ac.lkl.cram.ui.chart.LearningExperienceChartMaker; import uk.ac.lkl.cram.ui.chart.LearningTypeChartMaker; import uk.ac.lkl.cram.ui.report.Report; import uk.ac.lkl.cram.ui.undo.NamedCompoundEdit; import uk.ac.lkl.cram.ui.undo.RemoveLineItemEdit; import uk.ac.lkl.cram.ui.undo.UndoHandler; import uk.ac.lkl.cram.ui.wizard.TLACreatorWizardIterator; /** * This class represents the window that displays the contents of a CRAM module. * It is made up of several internal panes, each of which display some view * of the CRAM module. It also holds the menubar and the menu items. The CRAMApplication * handles much of the menu item behaviour. * @see CRAMApplication * @version $Revision$ * @author Bernard Horan */ //$Date$ @SuppressWarnings("serial") public class ModuleFrame extends javax.swing.JFrame { private static final Logger LOGGER = Logger.getLogger(ModuleFrame.class.getName()); private final static Cursor HAND = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); private final static Cursor WAIT = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR); //The module rendered by this frame private final Module module; private File moduleFile; //Keeps track of the selection in the various tables in the frame private final LineItemSelectionModel sharedSelectionModel = new LineItemSelectionModel(); //Listens for double clicks on the various tables in the frame private final MouseListener doubleClickListener; //Manages undos for the module--one undo handler per module frame private final UndoHandler undoHandler; /** * Creates new form ModuleFrame * @param module the module that this window displays * @param file */ public ModuleFrame(final Module module, File file) { this.module = module; this.moduleFile = file; this.setTitle(module.getModuleName()); initComponents(); //Add undo mechanism undoHandler = new UndoHandler(); JMenuItem undoMI = editMenu.add(undoHandler.getUndoAction()); JMenuItem redoMI = editMenu.add(undoHandler.getRedoAction()); //Listen to the undo handler for when there is something to undo undoHandler.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { //We're assuming there's only one property //If the new value is true, then there's something to undo //And thus the save menu item should be enabled Boolean newValue = (Boolean) evt.getNewValue(); if (moduleFile != null) { saveMI.setEnabled(newValue); } } }); editMenu.addSeparator(); //Add cut, copy & paste menu items JMenuItem cutMI = editMenu.add(new JMenuItem(new DefaultEditorKit.CutAction())); cutMI.setText("Cut"); JMenuItem copyMI = editMenu.add(new JMenuItem(new DefaultEditorKit.CopyAction())); copyMI.setText("Copy"); JMenuItem pasteMI = editMenu.add(new JMenuItem(new DefaultEditorKit.PasteAction())); pasteMI.setText("Paste"); //Listen for changes to the shared selection model sharedSelectionModel.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { //Update the menu items modifyLineItemMI.setEnabled(evt.getNewValue() != null); removeLineItemMI.setEnabled(evt.getNewValue() != null); } }); doubleClickListener = new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { //If the user double clicks, then treat this as a shortcut to modify the selected line item if (e.getClickCount() == 2) { modifySelectedLineItem(); } } }; //Set Accelerator keys undoMI.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_Z, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); redoMI.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_Y, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); cutMI.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); copyMI.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); pasteMI.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); newMI.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); openMI.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); saveMI.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); quitMI.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_Q, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); //Remove quit menu item and separator from file menu on Mac if (Utilities.isMac()) { fileMenu.remove(quitSeparator); fileMenu.remove(quitMI); } leftTaskPaneContainer.add(createCourseDataPane()); leftTaskPaneContainer.add(createLineItemPane()); leftTaskPaneContainer.add(createTutorHoursPane()); leftTaskPaneContainer.add(createTutorCostPane()); rightTaskPaneContainer.add(createLearningTypeChartPane()); rightTaskPaneContainer.add(createLearningExperienceChartPane()); rightTaskPaneContainer.add(createLearnerFeedbackChartPane()); rightTaskPaneContainer.add(createHoursChartPane()); rightTaskPaneContainer.add(createTotalCostsPane()); } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; jScrollPane1 = new javax.swing.JScrollPane(); leftTaskPaneContainer = new org.jdesktop.swingx.JXTaskPaneContainer(); jScrollPane3 = new javax.swing.JScrollPane(); rightTaskPaneContainer = new org.jdesktop.swingx.JXTaskPaneContainer(); windowMenuBar = new javax.swing.JMenuBar(); fileMenu = new javax.swing.JMenu(); newMI = new javax.swing.JMenuItem(); openMI = new javax.swing.JMenuItem(); duplicateMI = new javax.swing.JMenuItem(); jSeparator1 = new javax.swing.JPopupMenu.Separator(); exportReportMI = new javax.swing.JMenuItem(); saveMI = new javax.swing.JMenuItem(); saveAsMI = new javax.swing.JMenuItem(); quitSeparator = new javax.swing.JPopupMenu.Separator(); quitMI = new javax.swing.JMenuItem(); editMenu = new javax.swing.JMenu(); moduleMenu = new javax.swing.JMenu(); addTLALineItemMI = new javax.swing.JMenuItem(); addModuleLineItemMI = new javax.swing.JMenuItem(); modifyLineItemMI = new javax.swing.JMenuItem(); removeLineItemMI = new javax.swing.JMenuItem(); windowMenu = new javax.swing.JMenu(); helpMenu = new javax.swing.JMenu(); openHelpMI = new javax.swing.JMenuItem(); setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); setMinimumSize(new java.awt.Dimension(730, 600)); setPreferredSize(new java.awt.Dimension(860, 930)); getContentPane().setLayout(new java.awt.GridBagLayout()); leftTaskPaneContainer.setPaintBorderInsets(false); org.jdesktop.swingx.VerticalLayout verticalLayout1 = new org.jdesktop.swingx.VerticalLayout(); verticalLayout1.setGap(14); leftTaskPaneContainer.setLayout(verticalLayout1); jScrollPane1.setViewportView(leftTaskPaneContainer); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.ipadx = 490; gridBagConstraints.ipady = 600; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 0.7; gridBagConstraints.weighty = 1.0; getContentPane().add(jScrollPane1, gridBagConstraints); org.jdesktop.swingx.VerticalLayout verticalLayout2 = new org.jdesktop.swingx.VerticalLayout(); verticalLayout2.setGap(14); rightTaskPaneContainer.setLayout(verticalLayout2); jScrollPane3.setViewportView(rightTaskPaneContainer); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.ipadx = 250; gridBagConstraints.ipady = 600; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 0.3; gridBagConstraints.weighty = 1.0; getContentPane().add(jScrollPane3, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(fileMenu, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.fileMenu.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(newMI, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.newMI.text")); // NOI18N fileMenu.add(newMI); org.openide.awt.Mnemonics.setLocalizedText(openMI, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.openMI.text")); // NOI18N fileMenu.add(openMI); org.openide.awt.Mnemonics.setLocalizedText(duplicateMI, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.duplicateMI.text")); // NOI18N fileMenu.add(duplicateMI); fileMenu.add(jSeparator1); org.openide.awt.Mnemonics.setLocalizedText(exportReportMI, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.exportReportMI.text")); // NOI18N exportReportMI.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { exportReportMIActionPerformed(evt); } }); fileMenu.add(exportReportMI); org.openide.awt.Mnemonics.setLocalizedText(saveMI, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.saveMI.text")); // NOI18N saveMI.setEnabled(false); saveMI.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { saveMIActionPerformed(evt); } }); fileMenu.add(saveMI); org.openide.awt.Mnemonics.setLocalizedText(saveAsMI, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.saveAsMI.text")); // NOI18N fileMenu.add(saveAsMI); fileMenu.add(quitSeparator); org.openide.awt.Mnemonics.setLocalizedText(quitMI, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.quitMI.text")); // NOI18N fileMenu.add(quitMI); windowMenuBar.add(fileMenu); org.openide.awt.Mnemonics.setLocalizedText(editMenu, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.editMenu.text")); // NOI18N windowMenuBar.add(editMenu); org.openide.awt.Mnemonics.setLocalizedText(moduleMenu, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.moduleMenu.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(addTLALineItemMI, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.addTLALineItemMI.text")); // NOI18N addTLALineItemMI.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { addTLALineItemMIActionPerformed(evt); } }); moduleMenu.add(addTLALineItemMI); org.openide.awt.Mnemonics.setLocalizedText(addModuleLineItemMI, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.addModuleLineItemMI.text")); // NOI18N addModuleLineItemMI.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { addModuleLineItemMIActionPerformed(evt); } }); moduleMenu.add(addModuleLineItemMI); org.openide.awt.Mnemonics.setLocalizedText(modifyLineItemMI, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.modifyLineItemMI.text")); // NOI18N modifyLineItemMI.setEnabled(false); modifyLineItemMI.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { modifyLineItemMIActionPerformed(evt); } }); moduleMenu.add(modifyLineItemMI); org.openide.awt.Mnemonics.setLocalizedText(removeLineItemMI, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.removeLineItemMI.text")); // NOI18N removeLineItemMI.setEnabled(false); removeLineItemMI.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { removeLineItemMIActionPerformed(evt); } }); moduleMenu.add(removeLineItemMI); windowMenuBar.add(moduleMenu); org.openide.awt.Mnemonics.setLocalizedText(windowMenu, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.windowMenu.text")); // NOI18N windowMenuBar.add(windowMenu); org.openide.awt.Mnemonics.setLocalizedText(helpMenu, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.helpMenu.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(openHelpMI, org.openide.util.NbBundle.getMessage(ModuleFrame.class, "ModuleFrame.openHelpMI.text")); // NOI18N helpMenu.add(openHelpMI); windowMenuBar.add(helpMenu); setJMenuBar(windowMenuBar); pack(); }// </editor-fold>//GEN-END:initComponents private void modifyLineItemMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_modifyLineItemMIActionPerformed modifySelectedLineItem(); }//GEN-LAST:event_modifyLineItemMIActionPerformed private void removeLineItemMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeLineItemMIActionPerformed removeSelectedLineItem(); }//GEN-LAST:event_removeLineItemMIActionPerformed private void addTLALineItemMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addTLALineItemMIActionPerformed addTLALineItem(); }//GEN-LAST:event_addTLALineItemMIActionPerformed private void addModuleLineItemMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addModuleLineItemMIActionPerformed addModuleLineItem(); }//GEN-LAST:event_addModuleLineItemMIActionPerformed private void saveMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveMIActionPerformed saveModule(); }//GEN-LAST:event_saveMIActionPerformed private void exportReportMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportReportMIActionPerformed exportReport(); }//GEN-LAST:event_exportReportMIActionPerformed /** * Used for testing purposes only. * @param args the command line arguments (ignored) */ public static void main(String args[]) { /* Create and display the form */ java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { new ModuleFrame(AELMTest.populateModule(), null).setVisible(true); } }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JMenuItem addModuleLineItemMI; private javax.swing.JMenuItem addTLALineItemMI; private javax.swing.JMenuItem duplicateMI; private javax.swing.JMenu editMenu; private javax.swing.JMenuItem exportReportMI; private javax.swing.JMenu fileMenu; private javax.swing.JMenu helpMenu; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane3; private javax.swing.JPopupMenu.Separator jSeparator1; private org.jdesktop.swingx.JXTaskPaneContainer leftTaskPaneContainer; private javax.swing.JMenuItem modifyLineItemMI; private javax.swing.JMenu moduleMenu; private javax.swing.JMenuItem newMI; private javax.swing.JMenuItem openHelpMI; private javax.swing.JMenuItem openMI; private javax.swing.JMenuItem quitMI; private javax.swing.JPopupMenu.Separator quitSeparator; private javax.swing.JMenuItem removeLineItemMI; private org.jdesktop.swingx.JXTaskPaneContainer rightTaskPaneContainer; private javax.swing.JMenuItem saveAsMI; private javax.swing.JMenuItem saveMI; private javax.swing.JMenu windowMenu; private javax.swing.JMenuBar windowMenuBar; // End of variables declaration//GEN-END:variables private JXTaskPane createCourseDataPane() { JXTaskPane courseDataPane = new JXTaskPane(); courseDataPane.setTitle("Module Data"); courseDataPane.setScrollOnExpand(true); courseDataPane.add(new ModulePanel(module, undoHandler)); return courseDataPane; } private JXTaskPane createLineItemPane() { JXTaskPane lineItemPane = new JXTaskPane(); lineItemPane.setTitle("Student Hours"); lineItemPane.setScrollOnExpand(true); LineItemPanel lineItemPanel = new LineItemPanel(module, sharedSelectionModel); JTable table = lineItemPanel.getTable(); table.addMouseListener(doubleClickListener); lineItemPane.add(lineItemPanel); return lineItemPane; } private JXTaskPane createTutorHoursPane() { JXTaskPane tutorHoursPane = new JXTaskPane(); tutorHoursPane.setScrollOnExpand(true); tutorHoursPane.setCollapsed(true); tutorHoursPane.setTitle("Tutor Hours"); TutorHoursPanel tutorHoursPanel = new TutorHoursPanel(module, sharedSelectionModel); JTable table = tutorHoursPanel.getTable(); table.addMouseListener(doubleClickListener); tutorHoursPane.add(tutorHoursPanel); return tutorHoursPane; } private JXTaskPane createTutorCostPane() { JXTaskPane tutorCostPane = new JXTaskPane(); tutorCostPane.setScrollOnExpand(true); tutorCostPane.setCollapsed(true); tutorCostPane.setTitle("Tutor Costs"); TutorCostPanel tutorCostPanel = new TutorCostPanel(module, sharedSelectionModel); JTable table = tutorCostPanel.getTable(); table.addMouseListener(doubleClickListener); tutorCostPane.add(tutorCostPanel); return tutorCostPane; } private JXTaskPane createLearningTypeChartPane() { JXTaskPane typeChartPane = new JXTaskPane(); typeChartPane.setTitle("Learning Types"); typeChartPane.setScrollOnExpand(true); final LearningTypeChartMaker maker = new LearningTypeChartMaker(module); final ChartPanel chartPanel = maker.getChartPanel(); //Add a mouse listener to the chart chartPanel.addChartMouseListener(new ChartMouseListener() { @Override public void chartMouseClicked(ChartMouseEvent cme) { //Get the mouse event MouseEvent trigger = cme.getTrigger(); //Test if the mouse event is a left-button if (trigger.getButton() == MouseEvent.BUTTON1 && trigger.getClickCount() == 2) { //Check that the mouse click is on a segment of the pie if (cme.getEntity() instanceof PieSectionEntity) { //Get the selected segment of the pie PieSectionEntity pieSection = (PieSectionEntity) cme.getEntity(); //Get the key that corresponds to that segment--this is a learning type String key = pieSection.getSectionKey().toString(); //Get the set of tlalineitems whose activity contains that learning type Set<TLALineItem> relevantTLAs = maker.getLearningTypeMap().get(key); //Create a pop up dialog containing that set of tlalineitems LearningTypePopupDialog popup = new LearningTypePopupDialog( (Frame) SwingUtilities.getWindowAncestor(chartPanel), true, relevantTLAs, key); //Set the title of the popup to indicate which learning type was selected popup.setTitle("Activities with \'" + key + "\'"); //Centre the popup at the location of the mouse click Point location = trigger.getLocationOnScreen(); int w = popup.getWidth(); int h = popup.getHeight(); popup.setLocation(location.x - w / 2, location.y - h / 2); popup.setVisible(true); int returnStatus = popup.getReturnStatus(); if (returnStatus == LearningTypePopupDialog.RET_OK) { modifyTLALineItem(popup.getSelectedTLALineItem(), 0); } } } } @Override public void chartMouseMoved(ChartMouseEvent cme) { //Set the cursor shape according to the location of the cursor if (cme.getEntity() instanceof PieSectionEntity) { chartPanel.setCursor(HAND); } else { chartPanel.setCursor(Cursor.getDefaultCursor()); } } }); chartPanel.setPreferredSize(new Dimension(150, 200)); typeChartPane.add(chartPanel); return typeChartPane; } private JXTaskPane createLearningExperienceChartPane() { JXTaskPane experienceChartPane = new JXTaskPane(); experienceChartPane.setScrollOnExpand(true); experienceChartPane.setTitle("Learning Experiences"); final LearningExperienceChartMaker maker = new LearningExperienceChartMaker(module); final ChartPanel chartPanel = maker.getChartPanel(); //Add a mouselistener, listening for a double click on a bar of the stacked bar chartPanel.addChartMouseListener(new ChartMouseListener() { @Override public void chartMouseClicked(ChartMouseEvent cme) { //Get the mouse event MouseEvent trigger = cme.getTrigger(); //Test if the mouse event is a left-button if (trigger.getButton() == MouseEvent.BUTTON1 && trigger.getClickCount() == 2) { //Get the selected segment of the pie CategoryItemEntity bar = (CategoryItemEntity) cme.getEntity(); //Get the row key that corresponds to that segment--this is a learning experience String key = bar.getRowKey().toString(); //Get the set of tlalineitems whose activity contains that learning type Set<TLALineItem> relevantTLAs = maker.getLearningExperienceMap().get(key); //Create a pop up dialog containing that set of tlalineitems LearningExperiencePopupDialog popup = new LearningExperiencePopupDialog( (Frame) SwingUtilities.getWindowAncestor(chartPanel), true, relevantTLAs); //Set the title of the popup to indicate which learning type was selected popup.setTitle("Activities with \'" + key + "\'"); //Centre the popup at the location of the mouse click Point location = trigger.getLocationOnScreen(); int w = popup.getWidth(); int h = popup.getHeight(); popup.setLocation(location.x - w / 2, location.y - h / 2); popup.setVisible(true); int returnStatus = popup.getReturnStatus(); if (returnStatus == LearningTypePopupDialog.RET_OK) { modifyTLALineItem(popup.getSelectedTLALineItem(), 0); } } } @Override public void chartMouseMoved(ChartMouseEvent cme) { //Set the cursor shape according to the location of the cursor if (cme.getEntity() instanceof CategoryItemEntity) { chartPanel.setCursor(HAND); } else { chartPanel.setCursor(Cursor.getDefaultCursor()); } } }); chartPanel.setPreferredSize(new Dimension(125, 75)); chartPanel.setMinimumDrawHeight(75); experienceChartPane.add(chartPanel); return experienceChartPane; } private JXTaskPane createLearnerFeedbackChartPane() { JXTaskPane feedbackChartPane = new JXTaskPane(); feedbackChartPane.setScrollOnExpand(true); feedbackChartPane.setTitle("Learner Feedback"); FeedbackChartMaker maker = new FeedbackChartMaker(module); final ChartPanel chartPanel = maker.getChartPanel(); //Add a mouselistener, listening for a double click on a bar of the stacked bar chartPanel.addChartMouseListener(new ChartMouseListener() { @Override public void chartMouseClicked(ChartMouseEvent cme) { //Get the mouse event MouseEvent trigger = cme.getTrigger(); //Test if the mouse event is a left-button if (trigger.getButton() == MouseEvent.BUTTON1 && trigger.getClickCount() == 2) { //Create a pop up dialog containing that the tlalineitems FeedbackPopupDialog popup = new FeedbackPopupDialog( (Frame) SwingUtilities.getWindowAncestor(chartPanel), true, module.getTLALineItems()); //Set the title of the popup popup.setTitle("All Activities"); //Centre the popup at the location of the mouse click Point location = trigger.getLocationOnScreen(); int w = popup.getWidth(); int h = popup.getHeight(); popup.setLocation(location.x - w / 2, location.y - h / 2); popup.setVisible(true); int returnStatus = popup.getReturnStatus(); if (returnStatus == LearningTypePopupDialog.RET_OK) { modifyTLALineItem(popup.getSelectedTLALineItem(), 1); } } } @Override public void chartMouseMoved(ChartMouseEvent cme) { //Set the cursor shape according to the location of the cursor if (cme.getEntity() instanceof CategoryItemEntity) { chartPanel.setCursor(HAND); } else { chartPanel.setCursor(Cursor.getDefaultCursor()); } } }); chartPanel.setPreferredSize(new Dimension(150, 200)); feedbackChartPane.add(chartPanel); return feedbackChartPane; } private JXTaskPane createHoursChartPane() { JXTaskPane hoursChartPane = new JXTaskPane(); hoursChartPane.setTitle("Teacher Time (hours)"); hoursChartPane.setScrollOnExpand(true); ChartPanel chartPanel = (new HoursChartMaker(module)).getChartPanel(); chartPanel.setPreferredSize(new Dimension(200, 200)); hoursChartPane.add(chartPanel); return hoursChartPane; } private JXTaskPane createTotalCostsPane() { JXTaskPane costPane = new JXTaskPane(); costPane.setScrollOnExpand(true); costPane.setTitle("Summary"); costPane.add(new CostPanel(module)); costPane.setCollapsed(true); return costPane; } private void modifySelectedLineItem() { LineItem selectedLineItem = sharedSelectionModel.getSelectedLineItem(); if (selectedLineItem instanceof TLALineItem) { modifyTLALineItem((TLALineItem) selectedLineItem, 2); } else if (selectedLineItem instanceof ModuleLineItem) { //Create a compound edit that can be used later for undo NamedCompoundEdit cEdit = new NamedCompoundEdit("Modify Module Activity"); ModuleActivityDialog dialog = new ModuleActivityDialog(this, true, module, (ModuleLineItem) selectedLineItem, cEdit); dialog.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL); dialog.setTitle("Modify Module Activity for " + module.getModuleName() + " module"); dialog.setVisible(true); dialog.toFront(); //If the user clicked OK, create an edit that can be undone if (dialog.getReturnStatus() == ModuleActivityDialog.RET_OK) { undoHandler.addEdit(cEdit); } } else { LOGGER.warning("Unable to edit this line item"); } } private void modifyTLALineItem(TLALineItem lineItem, int index) { //Create a compound edit that can be used later for undo NamedCompoundEdit cEdit = new NamedCompoundEdit("Modify TLA"); TLAOkCancelDialog dialog = new TLAOkCancelDialog(ModuleFrame.this, true, module, lineItem, cEdit); dialog.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL); dialog.setTitle("Modify TLA for " + module.getModuleName() + " module"); dialog.setSelectedIndex(index); dialog.setVisible(true); //If the user clicked OK, create an edit that can be undone if (dialog.getReturnStatus() == TLAOkCancelDialog.RET_OK) { undoHandler.addEdit(cEdit); } } private void removeSelectedLineItem() { LineItem selectedLineItem = sharedSelectionModel.getSelectedLineItem(); if (selectedLineItem != null) { int reply = JOptionPane.showConfirmDialog(this, "Are you sure you want to remove \'" + selectedLineItem.getName() + "\'?", "Remove TLA", JOptionPane.YES_NO_OPTION); if (reply == JOptionPane.YES_OPTION) { int i = selectedLineItem.removeFrom(module); UndoableEdit edit = new RemoveLineItemEdit(module, selectedLineItem, i); undoHandler.addEdit(edit); } else { LOGGER.info("Remove cancelled"); } } else { LOGGER.warning("Unable to remove this line item"); } } private void addTLALineItem() { //Disable the menu item addTLALineItemMI.setEnabled(false); TLACreatorWizardIterator iterator = new TLACreatorWizardIterator(module); WizardDescriptor wizardDescriptor = new WizardDescriptor(iterator); iterator.initialize(wizardDescriptor); // {0} will be replaced by WizardDescriptor.Panel.getComponent().getName() // {1} will be replaced by WizardDescriptor.Iterator.name() wizardDescriptor.setTitleFormat(new MessageFormat("{0} ({1})")); wizardDescriptor.setTitle("TLA Creator Wizard for " + module.getModuleName() + " module"); Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor); //Modeless within the document dialog.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL); dialog.setVisible(true); dialog.toFront(); boolean cancelled = wizardDescriptor.getValue() != WizardDescriptor.FINISH_OPTION; //LOGGER.info("Cancelled: " + cancelled); if (!cancelled) { //Get the newly created line item TLALineItem lineItem = iterator.getLineItem(); //If the user created a new TLA, add it to their preferences if (iterator.isVanilla()) { UserTLALibrary.getDefaultLibrary().addActivity(lineItem.getActivity()); } module.addTLALineItem(lineItem); //No undo support here--assume user will just remove the line item } //Enable the menu item addTLALineItemMI.setEnabled(true); } private void addModuleLineItem() { //Disable the menu item addModuleLineItemMI.setEnabled(false); ModuleLineItem li = new ModuleLineItem(); //Give the dialog a null parent so that the document modal works properly ModuleActivityDialog dialog = new ModuleActivityDialog(null, true, module, li, new CompoundEdit()); dialog.setSize(dialog.getPreferredSize()); dialog.setTitle("Add Module Activity for " + module.getModuleName() + " module"); //Modeless within the document dialog.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL); dialog.setVisible(true); dialog.toFront(); if (dialog.getReturnStatus() == ModuleActivityDialog.RET_OK) { module.addModuleItem(li); //No undo support here--assume user will just remove the line item } //Enable the menu item addModuleLineItemMI.setEnabled(true); } JMenu getWindowMenu() { return windowMenu; } JMenuItem getNewMenuItem() { return newMI; } JMenuItem getOpenMenuItem() { return openMI; } JMenuItem getQuitMenuItem() { return quitMI; } JMenuItem getSaveAsMenuItem() { return saveAsMI; } JMenuItem getDuplicateMenuItem() { return duplicateMI; } Module getModule() { return module; } JMenuItem getOpenHelpMenuItem() { return openHelpMI; } void discardEdits() { undoHandler.discardAllEdits(); saveMI.setEnabled(false); } private void saveModule() { try { //Create a marshaller to marshall the module ModuleMarshaller marshaller = new ModuleMarshaller(moduleFile); //Marshall the module marshaller.marshallModule(module); discardEdits(); } catch (JAXBException ioe) { LOGGER.log(Level.SEVERE, "Failed to save file", ioe); JOptionPane.showMessageDialog(this, ioe.getLocalizedMessage(), "Unable to save module", JOptionPane.ERROR_MESSAGE); } } private void exportReport() { JFileChooser jfc = new JFileChooser(); jfc.setAcceptAllFileFilterUsed(false); jfc.setDialogTitle("Export CRAM Module"); FileFilter filter = new FileNameExtensionFilter("Word Document", "docx"); jfc.setFileFilter(filter); jfc.setSelectedFile(new File(module.getModuleName() + ".docx")); //Open the dialog and wait for the user to provide a name for the file int returnVal = jfc.showSaveDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { File file = jfc.getSelectedFile(); //Add the file extension if (!jfc.getSelectedFile().getAbsolutePath().endsWith(".docx")) { file = new File(jfc.getSelectedFile() + ".docx"); } try { this.setCursor(WAIT); Report report = new Report(module); report.save(file); } catch (Docx4JException ex) { LOGGER.log(Level.SEVERE, "Failed to export report", ex); JOptionPane.showMessageDialog(this, ex.getLocalizedMessage(), "Failed to export report", JOptionPane.ERROR_MESSAGE); } finally { this.setCursor(Cursor.getDefaultCursor()); } } } void setModuleFile(File file) { moduleFile = file; } }