gt:         saveAction = new TSAction("Save") {
context: // Copyright (C) 2001-2015 Tuma Solutions, LLC
  // Process Dashboard - Data Automation Tool for high-maturity processes
  //
  // This program is free software; you can redistribute it and/or
  // modify it under the terms of the GNU General Public License
  // as published by the Free Software Foundation; either version 3
  // of the License, or (at your option) any later version.
  //
  // Additional permissions also apply; see the README-license.txt
  // file in the project root directory for more information.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program; if not, see <http://www.gnu.org/licenses/>.
  //
  // The author(s) may be contacted at:
  //     processdash@tuma-solutions.com
  //     processdash-devel@lists.sourceforge.net
  
  
  package net.sourceforge.processdash.ev.ui;
  
  import java.awt.BasicStroke;
  import java.awt.BorderLayout;
  import java.awt.Color;
  import java.awt.Component;
  import java.awt.Dimension;
  import java.awt.Font;
  import java.awt.Frame;
  import java.awt.Graphics;
  import java.awt.Graphics2D;
  import java.awt.Image;
  import java.awt.Insets;
  import java.awt.Point;
  import java.awt.Stroke;
  import java.awt.Toolkit;
  import java.awt.datatransfer.Clipboard;
  import java.awt.datatransfer.ClipboardOwner;
  import java.awt.datatransfer.DataFlavor;
  import java.awt.datatransfer.StringSelection;
  import java.awt.datatransfer.Transferable;
  import java.awt.datatransfer.UnsupportedFlavorException;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.event.FocusEvent;
  import java.awt.event.FocusListener;
  import java.awt.event.MouseEvent;
  import java.awt.event.MouseListener;
  import java.awt.event.MouseMotionListener;
  import java.awt.event.WindowAdapter;
  import java.awt.event.WindowEvent;
  import java.awt.font.TextAttribute;
  import java.awt.image.BufferedImage;
  import java.awt.image.FilteredImageSource;
  import java.awt.image.ImageProducer;
  import java.awt.image.RGBImageFilter;
  import java.beans.PropertyChangeEvent;
  import java.beans.PropertyChangeListener;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.Date;
  import java.util.EventObject;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.prefs.Preferences;
  
  import javax.swing.AbstractAction;
  import javax.swing.AbstractButton;
  import javax.swing.AbstractCellEditor;
  import javax.swing.Action;
  import javax.swing.BorderFactory;
  import javax.swing.Box;
  import javax.swing.ButtonModel;
  import javax.swing.DefaultCellEditor;
  import javax.swing.Icon;
  import javax.swing.ImageIcon;
  import javax.swing.JButton;
  import javax.swing.JCheckBox;
  import javax.swing.JCheckBoxMenuItem;
  import javax.swing.JComboBox;
  import javax.swing.JComponent;
  import javax.swing.JFrame;
  import javax.swing.JLabel;
  import javax.swing.JList;
  import javax.swing.JMenu;
  import javax.swing.JMenuBar;
  import javax.swing.JMenuItem;
  import javax.swing.JOptionPane;
  import javax.swing.JPanel;
  import javax.swing.JPasswordField;
  import javax.swing.JPopupMenu;
  import javax.swing.JScrollPane;
  import javax.swing.JSplitPane;
  import javax.swing.JTable;
  import javax.swing.JTextArea;
  import javax.swing.JTextField;
  import javax.swing.JTree;
  import javax.swing.ListSelectionModel;
  import javax.swing.SwingConstants;
  import javax.swing.SwingUtilities;
  import javax.swing.ToolTipManager;
  import javax.swing.TransferHandler;
  import javax.swing.WindowConstants;
  import javax.swing.border.Border;
  import javax.swing.event.HyperlinkEvent;
  import javax.swing.event.HyperlinkListener;
  import javax.swing.event.ListSelectionEvent;
  import javax.swing.event.ListSelectionListener;
  import javax.swing.event.TableModelEvent;
  import javax.swing.event.TreeModelEvent;
  import javax.swing.event.TreeModelListener;
  import javax.swing.table.AbstractTableModel;
  import javax.swing.table.DefaultTableCellRenderer;
  import javax.swing.table.DefaultTableColumnModel;
  import javax.swing.table.TableCellEditor;
  import javax.swing.table.TableCellRenderer;
  import javax.swing.table.TableColumn;
  import javax.swing.table.TableColumnModel;
  import javax.swing.table.TableModel;
  import javax.swing.text.JTextComponent;
  import javax.swing.tree.TreeCellRenderer;
  import javax.swing.tree.TreeModel;
  import javax.swing.tree.TreePath;
  
  import org.w3c.dom.Element;
  
  import com.xduke.xswing.DataTipManager;
  
  import net.sourceforge.processdash.ApplicationEventListener;
  import net.sourceforge.processdash.ApplicationEventSource;
  import net.sourceforge.processdash.DashController;
  import net.sourceforge.processdash.DashboardContext;
  import net.sourceforge.processdash.Settings;
  import net.sourceforge.processdash.data.ListData;
  import net.sourceforge.processdash.ev.DefaultTaskLabeler;
  import net.sourceforge.processdash.ev.EVCalculator;
  import net.sourceforge.processdash.ev.EVDependencyCalculator;
  import net.sourceforge.processdash.ev.EVHierarchicalFilter;
  import net.sourceforge.processdash.ev.EVMetadata;
  import net.sourceforge.processdash.ev.EVMetrics;
  import net.sourceforge.processdash.ev.EVSchedule;
  import net.sourceforge.processdash.ev.EVSnapshot;
  import net.sourceforge.processdash.ev.EVTask;
  import net.sourceforge.processdash.ev.EVTaskFilter;
  import net.sourceforge.processdash.ev.EVTaskList;
  import net.sourceforge.processdash.ev.EVTaskListCached;
  import net.sourceforge.processdash.ev.EVTaskListData;
  import net.sourceforge.processdash.ev.EVTaskListRollup;
  import net.sourceforge.processdash.ev.Milestone;
  import net.sourceforge.processdash.ev.MilestoneList;
  import net.sourceforge.processdash.hier.HierarchyNote;
  import net.sourceforge.processdash.hier.HierarchyNoteManager;
  import net.sourceforge.processdash.hier.PropertyKey;
  import net.sourceforge.processdash.hier.ui.HierarchyNoteEditorDialog;
  import net.sourceforge.processdash.i18n.Resources;
  import net.sourceforge.processdash.net.cache.CachedObject;
  import net.sourceforge.processdash.net.cache.CachedURLObject;
  import net.sourceforge.processdash.templates.ExtensionManager;
  import net.sourceforge.processdash.ui.Browser;
  import net.sourceforge.processdash.ui.DashboardIconFactory;
  import net.sourceforge.processdash.ui.NodeSelectionDialog;
  import net.sourceforge.processdash.ui.help.PCSH;
  import net.sourceforge.processdash.ui.lib.DeferredSelectAllExecutor;
  import net.sourceforge.processdash.ui.lib.DropDownButton;
  import net.sourceforge.processdash.ui.lib.ErrorReporter;
  import net.sourceforge.processdash.ui.lib.GuiPrefs;
  import net.sourceforge.processdash.ui.lib.JDateTimeChooserCellEditor;
  import net.sourceforge.processdash.ui.lib.JDialogCellEditor;
  import net.sourceforge.processdash.ui.lib.JOptionPaneClickHandler;
  import net.sourceforge.processdash.ui.lib.JOptionPaneTweaker;
  import net.sourceforge.processdash.ui.lib.JTableColumnVisibilityAction;
  import net.sourceforge.processdash.ui.lib.JTableColumnVisibilityButton;
  import net.sourceforge.processdash.ui.lib.JTreeTable;
  import net.sourceforge.processdash.ui.lib.PaddedIcon;
  import net.sourceforge.processdash.ui.lib.PaintUtils;
  import net.sourceforge.processdash.ui.lib.TableUtils;
  import net.sourceforge.processdash.ui.lib.ToolTipTableCellRendererProxy;
  import net.sourceforge.processdash.ui.lib.ToolTipTimingCustomizer;
  import net.sourceforge.processdash.ui.lib.TreeModelWillChangeListener;
  import net.sourceforge.processdash.ui.lib.TreeTableModel;
  import net.sourceforge.processdash.ui.macosx.MacGUIUtils;
  import net.sourceforge.processdash.util.BooleanArray;
  import net.sourceforge.processdash.util.Disposable;
  import net.sourceforge.processdash.util.HTMLUtils;
  import net.sourceforge.processdash.util.PreferencesUtils;
  import net.sourceforge.processdash.util.StringUtils;
  
  
  public class TaskScheduleDialog implements EVTask.Listener,
          EVTaskList.RecalcListener, EVSchedule.Listener,
          ApplicationEventListener {
  
      /** Model for the JTreeTable */
      protected EVTaskList model;
      /** TreeTable displaying the task list */
      protected JTreeTable treeTable;
      /** table displaying the schedule */
      protected JTable scheduleTable;
      /** Frame containing everything */
      protected JFrame frame;
      /** object managing preferred sizes/states of GUI elements */
      protected GuiPrefs guiPrefs;
      /** the dashboard */
      protected DashboardContext dash;
      protected String taskListName;
  
      private EVTaskList.FlatTreeModel flatModel = null;
      private TreeTableModel mergedModel = null;
      private TableColumnModel treeColumnModel;
      private TableColumnModel flatColumnModel = null;
  
      private Milestone activeMilestone = null;
      private Set<Milestone> previousMilestones = null;
      private Date activeMilestoneDate = null;
      private int activeMilestoneDateRow = -1;
  
      private TSAction addTaskAction, deleteTaskAction, moveUpAction,
              moveDownAction, flatViewAction, mergedViewAction, addPeriodAction,
              insertPeriodAction, deletePeriodAction, chartAction, reportAction,
              closeAction, saveAction, errorAction, filteredChartAction,
              saveBaselineAction, collaborateAction, filteredReportAction,
              weekReportAction, scheduleOptionsAction, expandAllAction,
              showTimeLogAction, showDefectLogAction, copyTaskInfoAction;
      private List<TSAction> altReportActions;
  
      protected boolean disableTaskPruning;
  
      protected JFrame chartDialog = null;
  
      protected TaskScheduleOptions optionsDialog = null;
  
      protected static final Resources resources = Resources.getDashBundle("EV");
  
      private static Preferences preferences = Preferences.userNodeForPackage(TaskScheduleDialog.class);
      private static final String EXPANDED_NODES_KEY_SUFFIX = "_EXPANDEDNODES";
      private static final String EXPANDED_NODES_DELIMITER = Character.toString('\u0001');
  
      /**  The format of the string used to validate dates entered manually */
      private static final String DATE_FORMAT = "yyyy-MM-dd h:mm:ss aa";
  
      public TaskScheduleDialog(DashboardContext dash, String taskListName,
                                boolean createRollup) {
          this.dash = dash;
          this.taskListName = taskListName;
  
          if (dash instanceof ApplicationEventSource) {
              ((ApplicationEventSource) dash).addApplicationEventListener(this);
          }
  
          // Create the frame and set an appropriate icon
          frame = new JFrame(resources.getString("Window_Title"));
          DashboardIconFactory.setWindowIcon(frame);
          PCSH.enableHelpKey(frame, "UsingTaskSchedule");
  
          // Try to open an existing earned value model.
          model = EVTaskList.openExisting
              (taskListName, dash.getData(), dash.getHierarchy(),
               dash.getCache(), true);
  
          // If the earned value model doesn't already exist, create a new one.
          if (model == null) {
              if (createRollup)
                  model = new EVTaskListRollup
                      (taskListName, dash.getData(), dash.getHierarchy(),
                       dash.getCache(),true);
              else
                  model = new EVTaskListData
                      (taskListName, dash.getData(), dash.getHierarchy(), true);
          }
  
          EVDependencyCalculator depCalc = new EVDependencyCalculator(
                  dash.getData(), dash.getHierarchy(), dash.getCache());
          model.setDependencyCalculator(depCalc);
          model.setTaskLabeler(new DefaultTaskLabeler(dash.getHierarchy(), //
                  dash.getData(), model));
  
          model.recalc();
          model.setNodeListener(this);
          model.addRecalcListener(this);
          model.getSchedule().setListener(this);
  
          // Create the GUI preferences object
          guiPrefs = new GuiPrefs(TaskScheduleDialog.class, model.getID());
  
          // Create a JTreeTable to display the task list.
          treeTable = new TaskJTreeTable(model);
          treeTable.setShowGrid(true);
          treeTable.setIntercellSpacing(new Dimension(1, 1));
          treeTable.getSelectionModel().setSelectionMode
              (ListSelectionModel.SINGLE_INTERVAL_SELECTION);
                                  // add tool tips to the table header.
          ToolTipTableCellRendererProxy.installHeaderToolTips
              (treeTable, EVTaskList.toolTips);
                                  // set default widths for the columns
          List hiddenCols = new LinkedList();
          if (!Settings.getBool("ev.showCumulativeTaskData", false)) {
              hiddenCols.add(new Integer(EVTaskList.PLAN_CUM_TIME_COLUMN));
              hiddenCols.add(new Integer(EVTaskList.PLAN_CUM_VALUE_COLUMN));
          }
          if (!(model instanceof EVTaskListRollup))
              hiddenCols.add(new Integer(EVTaskList.ASSIGNED_TO_COLUMN));
  
          int totalWidth = 0;
          treeColumnModel = treeTable.getColumnModel();
          for (int i = treeColumnModel.getColumnCount();  i-- > 0; ) {
              TableColumn column = treeColumnModel.getColumn(i);
              if (hiddenCols.contains(new Integer(i))) {
                  treeColumnModel.removeColumn(column);
              } else {
                  column.setIdentifier(EVTaskList.COLUMN_KEYS[i].toLowerCase());
                  int width = EVTaskList.colWidths[i];
                  column.setPreferredWidth(width);
                  totalWidth += width;
              }
          }
          configureEditor(treeTable);
  
          if (!Settings.getBool("datatips.disabled", false)) {
              try {
                  DataTipManager.get().register(treeTable);
              } catch (Throwable t) {
                  // In some runtime environments, this call may fail with a
                  // security exception.  Gracefully degrade and display no
                  // datatips.
              }
          }
  
          model.addTreeModelWillChangeListener((TaskJTreeTable)treeTable);
          model.addTreeModelListener((TaskJTreeTable)treeTable);
  
          // Create a JTable to display the schedule list.
          scheduleTable = new ScheduleJTable(model.getSchedule());
                                  // add tool tips to the table header.
          ToolTipTableCellRendererProxy.installHeaderToolTips
              (scheduleTable, model.getSchedule().getColumnTooltips());
                                  // set default widths for the columns
          for (int i = 0;  i < EVSchedule.colWidths.length;  i++) {
              TableColumn column = scheduleTable.getColumnModel().getColumn(i);
              column.setIdentifier(EVSchedule.COLUMN_KEYS[i].toLowerCase());
              column.setPreferredWidth(EVSchedule.colWidths[i]);
          }
          configureEditor(scheduleTable);
  
          // hide columns such as direct time or labels if they aren't needed
          showHideColumns();
          flatColumnModel = createFlatColumnModel();
  
          // record user preference for pruning enablement
          disableTaskPruning = Settings.getBool("ev.disablePruning", false);
  
          boolean isRollup = isRollup();
          if (isRollup)
              frame.setTitle(resources.getString("Window_Rollup_Title"));
          maybeReadExpandedNodesPref(model.getID());
  
          JScrollPane sp;
          sp = new JScrollPane(treeTable,
                               JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                               JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
          sp.setPreferredSize(new Dimension(10, 10));
          sp.setCorner(JScrollPane.UPPER_RIGHT_CORNER,
              new JTableColumnVisibilityButton(treeTable, resources, " .*",
                      EVTaskList.TASK_COLUMN));
          Box topBox = newVBox
              (sp,
               Box.createVerticalStrut(2),
               buildTaskButtons(isRollup),
               Box.createVerticalStrut(2));
  
          sp = new JScrollPane(scheduleTable,
                               JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                               JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
          sp.setPreferredSize(new Dimension(10, 10));
          Box bottomBox = newVBox
              (sp,
               Box.createVerticalStrut(2),
               isRollup || Settings.isReadOnly() ? null : buildScheduleButtons(),
               isRollup || Settings.isReadOnly() ? null : Box.createVerticalStrut(2),
               buildMainButtons(isRollup));
  
          JSplitPane jsp = new JSplitPane
              (JSplitPane.VERTICAL_SPLIT, true, topBox, bottomBox);
          jsp.setResizeWeight(0.5);
          frame.getContentPane().add(jsp);
  
          frame.setJMenuBar(buildMenuBar());
  
          setDirty(false);
  
  
          frame.addWindowListener( new WindowAdapter() {
                  public void windowClosing(WindowEvent e) {
                      confirmClose(true); }});
          frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
  
          frame.setSize(new Dimension(totalWidth + 20, 600));
  
          guiPrefs.load("treeTable", treeTable);
          guiPrefs.load("scheduleTable", scheduleTable);
          guiPrefs.load(frame);
          guiPrefs.load(jsp);
          if (flatViewAction != null) {
              guiPrefs.load("flatView", flatViewAction.buttonModel);
              if (isFlatView()) toggleFlatView();
          }
  
          int currentWeek = model.getSchedule().getRowForEffectivePeriod();
          if (currentWeek >= 0 && currentWeek < scheduleTable.getRowCount()) {
              scheduleTable.addRowSelectionInterval(currentWeek, currentWeek);
              scheduleTable.scrollRectToVisible(scheduleTable.getCellRect(
                  currentWeek, 0, true));
          }
  
          frame.setVisible(true);
  
          // if the task list is empty, open the add task dialog immediately.
          if (((EVTask) model.getRoot()).isLeaf() && Settings.isReadWrite())
              addTask();
          else {
              if (getErrors() != null)
                  SwingUtilities.invokeLater(new Runnable() {
                          public void run() {
                              Map errors = getErrors();
                              highlightErrors(errors);
                              displayErrorDialog(errors);
                          } } );
          }
      }
  
  
      private boolean isRollup() {
          return (model instanceof EVTaskListRollup);
      }
  
      protected boolean isFlatView() {
          return (flatViewAction != null && flatViewAction.isSelected());
      }
  
      protected boolean isMergedView() {
          return (mergedViewAction != null && mergedViewAction.isSelected());
      }
  
      private boolean isDirty = false;
      protected void setDirty(boolean dirty) {
          isDirty = dirty;
          saveAction.setEnabled(isDirty);
          closeAction.setText(isDirty ? resources.getString("Cancel")
                                      : resources.getString("Close"));
          MacGUIUtils.setDirty(frame, isDirty);
      }
  
      private Set<EVTaskList> dirtySubschedules;
      void recordDirtySubschedule(EVTaskList tl) {
          if (dirtySubschedules == null)
              dirtySubschedules = new HashSet();
          dirtySubschedules.add(tl);
          setDirty(true);
      }
  
      protected Component buildTaskButtons(boolean isRollup) {
          Box result = Box.createHorizontalBox();
          result.add(Box.createHorizontalGlue());
          addTaskAction = new TSAction("Buttons.Add_Schedule", "Buttons.Add_Task") {
              public void actionPerformed(ActionEvent e) {
                  addTask(); }};
          if (Settings.isReadWrite())
              result.add(new JButton(addTaskAction));
          result.add(Box.createHorizontalGlue());
  
          // button margins: 2 pixels top and bottom, 14 left and right.
  
          deleteTaskAction = new TSAction("Buttons.Remove_Schedule",
                  "Buttons.Remove_Task") {
              public void actionPerformed(ActionEvent e) {
                  deleteTask(); }};
          deleteTaskAction.setEnabled(false);
          if (Settings.isReadWrite())
              result.add(new JButton(deleteTaskAction));
          result.add(Box.createHorizontalGlue());
  
  
          moveUpAction = new TSAction("Buttons.Move_Schedule_Up",
                  "Buttons.Move_Task_Up") {
              public void actionPerformed(ActionEvent e) {
                  moveTaskUp(); }};
          moveUpAction.setEnabled(false);
          moveUpAction.setMnemonic('U');
          if (Settings.isReadWrite())
              result.add(new JButton(moveUpAction));
          result.add(Box.createHorizontalGlue());
  
          moveDownAction = new TSAction("Buttons.Move_Schedule_Down",
                  "Buttons.Move_Task_Down") {
              public void actionPerformed(ActionEvent e) {
                  moveTaskDown(); }};
          moveDownAction.setEnabled(false);
          moveDownAction.setMnemonic('D');
          if (Settings.isReadWrite())
              result.add(new JButton(moveDownAction));
          result.add(Box.createHorizontalGlue());
  
          flatViewAction = mergedViewAction = null;
          if (!isRollup) {
              flatViewAction = new TSAction("Buttons.Flat_View") {
                  public void actionPerformed(ActionEvent e) {
                      toggleFlatView(); }};
              JCheckBox flatViewCheckbox = new JCheckBox(flatViewAction);
              flatViewCheckbox.setFocusPainted(false);
              flatViewAction.useButtonModel(flatViewCheckbox);
              flatViewAction.setSelected(false);
              result.add(flatViewCheckbox);
              result.add(Box.createHorizontalGlue());
          } else {
              mergedViewAction = new TSAction("Buttons.Merged_View") {
                  public void actionPerformed(ActionEvent e) {
                      toggleMergedView(); }};
              JCheckBox mergedViewCheckbox = new JCheckBox(mergedViewAction);
              mergedViewCheckbox.setFocusPainted(false);
              mergedViewAction.useButtonModel(mergedViewCheckbox);
              mergedViewAction.setSelected(false);
              result.add(mergedViewCheckbox);
              result.add(Box.createHorizontalGlue());
          }
  
          expandAllAction = new TSAction("Buttons.Expand_All") {
              public void actionPerformed(ActionEvent e) {
                  expandAllForSelectedItems(); }};
  
          treeTable.getSelectionModel().addListSelectionListener
              (new ListSelectionListener() {
                      public void valueChanged(ListSelectionEvent e) {
                          enableTaskButtons(e); }});
          return result;
      }
  
  
      protected Component buildScheduleButtons() {
          Box result = Box.createHorizontalBox();
          result.add(Box.createHorizontalGlue());
  
          addPeriodAction = new TSAction("Buttons.Add_Schedule_Row") {
              public void actionPerformed(ActionEvent e) {
                  addScheduleRow(); }};
          result.add(new JButton(addPeriodAction));
          result.add(Box.createHorizontalGlue());
  
          insertPeriodAction = new TSAction("Buttons.Insert_Schedule_Row") {
              public void actionPerformed(ActionEvent e) {
                  insertScheduleRow(); }};
          insertPeriodAction.setEnabled(false);
          result.add(new JButton(insertPeriodAction));
          result.add(Box.createHorizontalGlue());
  
          deletePeriodAction = new TSAction("Buttons.Delete_Schedule_Row") {
              public void actionPerformed(ActionEvent e) {
                  deleteScheduleRows(); }};
          deletePeriodAction.setEnabled(false);
          result.add(new JButton(deletePeriodAction));
          result.add(Box.createHorizontalGlue());
  
          scheduleTable.getSelectionModel().addListSelectionListener
              (new ListSelectionListener() {
                      public void valueChanged(ListSelectionEvent e) {
                          enableScheduleButtons(); }});
  
          return result;
      }
  
      protected Component buildMainButtons(boolean isRollup) {
          JPanel result = new JPanel(new BorderLayout());
          result.setBorder(BorderFactory.createRaisedBevelBorder());
  
          Box box = Box.createHorizontalBox();
          result.add(newVBox(Box.createVerticalStrut(2),
                             box,
                             Box.createVerticalStrut(2)), BorderLayout.CENTER);
          box.add(Box.createHorizontalGlue());
  
          JPopupMenu popupMenu = treeTable.getComponentPopupMenu();
  
          /*
          if (isRollup) {
              recalcButton = new JButton("Refresh");
              recalcButton.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      recalcAll(); }});
              box.add(recalcButton);
          }
          */
  
          errorAction = new TSAction("Buttons.Errors") {
              public void actionPerformed(ActionEvent e) {
                  displayErrorDialog(getErrors()); }};
          final JButton errorButton = new JButton(errorAction);
          errorButton.setBackground(Color.red);
          errorButton.setFocusPainted(false);
          errorAction.addPropertyChangeListener(new PropertyChangeListener(){
              public void propertyChange(PropertyChangeEvent evt) {
                  errorButton.setVisible(errorAction.isEnabled());
              }});
          errorAction.setEnabled(getErrors() != null);
          box.add(errorButton);
          box.add(Box.createHorizontalStrut(2));
  
          filteredChartAction = new TSAction("Buttons.Filtered_Chart") {
              public void actionPerformed(ActionEvent e) {
                  showFilteredChart(); }};
          filteredChartAction.setEnabled(false);
          addRenamedPopupMenuItem(popupMenu, filteredChartAction,
              "Buttons.View_Filtered_Chart");
          chartAction = new TSAction("Buttons.Chart") {
              public void actionPerformed(ActionEvent e) {
                  showChart(); }};
          box.add(makeDropDownButton(chartAction, filteredChartAction));
          box.add(Box.createHorizontalStrut(2));
  
          altReportActions = buildAltReportActions();
          weekReportAction = new TSAction("Buttons.Weekly_Report") {
              public void actionPerformed(ActionEvent e) {
                  showWeekReport(); }};
          filteredReportAction = new TSAction("Buttons.Filtered_Report") {
              public void actionPerformed(ActionEvent e) {
                  showFilteredHTML(); }};
          filteredReportAction.setEnabled(false);
          addRenamedPopupMenuItem(popupMenu, filteredReportAction,
              "Buttons.View_Filtered_Report");
          reportAction = new TSAction("Buttons.Report") {
              public void actionPerformed(ActionEvent e) {
                  showHTML(); }};
          box.add(makeDropDownButton(reportAction, weekReportAction,
              altReportActions, filteredReportAction));
          box.add(Box.createHorizontalStrut(2));
  
          closeAction = new TSAction("Close") {
              public void actionPerformed(ActionEvent e) {
                  confirmClose(true); }};
          box.add(new JButton(closeAction));
          box.add(Box.createHorizontalStrut(2));
  
  