/*
 * Licensed Materials - Property of Perforce Software, Inc. 
 * © Copyright Perforce Software, Inc. 2014, 2021 
 * © Copyright IBM Corp. 2009, 2014
 * © Copyright ILOG 1996, 2009
 * All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:
 * The Software and Documentation were developed at private expense and
 * are "Commercial Items" as that term is defined at 48 CFR 2.101,
 * consisting of "Commercial Computer Software" and
 * "Commercial Computer Software Documentation", as such terms are
 * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
 * as applicable.
 */

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URL;
import java.util.Iterator;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import java.util.prefs.Preferences;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.filechooser.FileFilter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import ilog.views.dashboard.IlvDashboardAction;
import ilog.views.dashboard.IlvDashboardBackgroundBar;
import ilog.views.dashboard.IlvDashboardContext;
import ilog.views.dashboard.IlvDashboardDOM;
import ilog.views.dashboard.IlvDashboardDefaultStatusViewer;
import ilog.views.dashboard.IlvDashboardDiagram;
import ilog.views.dashboard.IlvDashboardEditBar;
import ilog.views.dashboard.IlvDashboardEditor;
import ilog.views.dashboard.IlvDashboardEditorFrame;
import ilog.views.dashboard.IlvDashboardException;
import ilog.views.dashboard.IlvDashboardExpandablePane;
import ilog.views.dashboard.IlvDashboardExpandableSplitPane;
import ilog.views.dashboard.IlvDashboardInteractor;
import ilog.views.dashboard.IlvDashboardKeySelectManager;
import ilog.views.dashboard.IlvDashboardMenuBar;
import ilog.views.dashboard.IlvDashboardPanel;
import ilog.views.dashboard.IlvDashboardPreferences;
import ilog.views.dashboard.IlvDashboardPropertyPanel;
import ilog.views.dashboard.IlvDashboardSymbolPalette;
import ilog.views.dashboard.IlvDashboardTabbedPane;
import ilog.views.dashboard.IlvDashboardTree;
import ilog.views.diagrammer.IlvDiagrammer;
import ilog.views.diagrammer.application.IlvDiagrammerAction;
import ilog.views.diagrammer.application.IlvDiagrammerMenu;
import ilog.views.diagrammer.application.IlvDiagrammerOverview;
import ilog.views.diagrammer.application.IlvDiagrammerPropertySheet;
import ilog.views.diagrammer.application.IlvDiagrammerToolBar;
import ilog.views.diagrammer.application.IlvDiagrammerTree;
import ilog.views.diagrammer.application.IlvDiagrammerViewBar;
import ilog.views.symbology.palettes.IlvPalette;
import ilog.views.symbology.palettes.IlvPaletteManager;
import ilog.views.util.IlvProductUtil;
import ilog.views.util.swing.IlvSwingUtil;
import ilog.views.util.swing.layout.IlvBetterFlowLayout;

/**
 * The class <code>DashboardEditor</code> implements 
 * a dashboard editor, using the Perforce JViews Diagrammer Dashboard
 * support.
 */
public class DashboardEditor extends IlvDashboardEditor {
  private IlvDashboardEditorFrame frame;
  private ResourceBundle bundle;
  private DashboardPreview previewAction;
  private IlvDashboardSymbolPalette palettePanel;
  private Preferences prefs;
  private String[] args;

  IlvDashboardExpandablePane overviewFrame;

  /**
   * The entry point of the application.
   * @param args The command line arguments.
   */
  public static void main(final String[] args) {
    // This sample uses JViews Diagrammer features. When deploying an
    // application that includes this code, you need to be in possession
    // of a Perforce JViews Diagrammer Deployment license.
    IlvProductUtil.DeploymentLicenseRequired(IlvProductUtil.JViews_Diagrammer_Deployment);
    // This sample uses JViews Charts features (through the Charts palette).
    // When deploying an application that includes this code, you need to
    // be in possession of a Perforce JViews Charts Deployment license.
    IlvProductUtil.DeploymentLicenseRequired(IlvProductUtil.JViews_Charts_Deployment);

    IlvSwingUtil.invokeAndWait(new Runnable() {
      Override
      public void run() {
        createGUIAndRun(args);
      }
    });
  }

  private static void createGUIAndRun(String[] args) {
    /**
     * For Japanese, set the preferred locale fonts to be used for the
     * Yen versus backslash character.
     */
    if ("ja".equals(Locale.getDefault().getLanguage())) {
      preferLocaleFonts();
    }

    try {
      String lnf = IlvSwingUtil.getDefaultAppropriateLookAndFeelClassName();
      UIManager.setLookAndFeel(lnf);
      // Always underline mnemonics (vs. having to press ALT key).
      UIManager.getDefaults().put("Button.showMnemonics", Boolean.TRUE);
    } catch (Exception e) {
    }
    DashboardEditor editor = new DashboardEditor();
    editor.init(args);
    editor.run();
  }

  private static void preferLocaleFonts() {
    GraphicsEnvironment.getLocalGraphicsEnvironment().preferLocaleFonts();
  }

  /**
   * Constructs a dashboard editor instance.
   *
   */
  public DashboardEditor() {
    prefs = Preferences.userNodeForPackage(IlvDashboardEditor.class);
    setPreferences(new IlvDashboardPreferences() {

      Override
      public String get(String key, String defaultValue) {
        return prefs.get(key, defaultValue);
      }

      Override
      public void put(String key, String value) {
        prefs.put(key, value);
      }

      Override
      public void remove(String key) {
        prefs.remove(key);
      }
    });
    bundle = ResourceBundle.getBundle("dashboarddemo");
  }

  /**
   * Creates editor components after calling the inherited method.
   * @proofread
   */
  Override
  public void init(String[] args) {
    super.init(args);
    frame = getFrame();

    this.args = args.clone();

    IlvDashboardMenuBar menuBar = new IlvDashboardMenuBar(this);

    // add the documentation command to the menubar
    addDocumentationMenuItem(menuBar);

    // override the help menu action
    IlvDiagrammerAction.Handler userManualHandler = new IlvDiagrammerAction.Handler() {
      Override
      public void perform(IlvDiagrammerAction action, IlvDiagrammer diagrammer, ActionEvent event)
          throws Exception {
        popUserManual();
      }

      Override
      public void update(IlvDiagrammerAction action, IlvDiagrammer diagrammer) throws Exception {
        action.setEnabled(true);
      }
    };
    IlvDiagrammerAction.help.setHandler(userManualHandler);

    previewAction = new DashboardPreview(bundle);
    IlvDiagrammerMenu menu = menuBar.getViewMenu();
    menu.insertSeparator(0);
    menu.insertAction(previewAction, 0);

    frame.setJMenuBar(menuBar);
    frame.setTopToolBarArea(createTopToolBarArea());
    frame.setStatusBar(createStatusBar());
    frame.setLeftArea(createLeftArea());
    frame.setRightArea(createRightArea());

    IlvDashboardTabbedPane tpane = new IlvDashboardTabbedPane(this);
    frame.setCenterArea(tpane);
    setDashboardContainer(tpane);

    frame.setVisible(true);

    overviewFrame.collapse();
  }

  protected JComponent createTopToolBarArea() {
    JPanel panel = new JPanel(new BorderLayout());

    JPanel panel1 = new JPanel(new IlvBetterFlowLayout(FlowLayout.LEADING, 0, 0));
    IlvDashboardEditBar editToolBar = new IlvDashboardEditBar();
    panel1.add(editToolBar);
    IlvDiagrammerViewBar viewToolBar = new IlvDiagrammerViewBar();
    viewToolBar.insertAction(previewAction, 0);
    panel1.add(viewToolBar);
    panel.add(panel1, BorderLayout.PAGE_START);

    final IlvDashboardBackgroundBar paletteToolBar = new IlvDashboardBackgroundBar(this);
    panel.add(paletteToolBar, BorderLayout.PAGE_END);

    return panel;
  }

  /*
   * (non-Javadoc)
   * 
   * @see ilog.views.dashboard.IlvDashboardEditor#createStatusBar()
   */
  protected JComponent createStatusBar() {
    IlvDashboardDefaultStatusViewer statusViewer = new IlvDashboardDefaultStatusViewer(this);
    setStatusViewer(statusViewer);
    return statusViewer;
  }


  /*
   * (non-Javadoc)
   * 
   * @see ilog.views.dashboard.IlvDashboardEditor#createRightArea()
   */
  protected JComponent createRightArea() {
    URL url = IlvDiagrammerOverview.class.getResource("images/overview.gif");
    ImageIcon icon = new ImageIcon(url);
    IlvDiagrammerOverview overview = new IlvDiagrammerOverview();
    String overviewTitle =
        getString("Diagrammer.Overview.DialogTitle", "ilog.views.diagrammer.application.overview");
    overviewFrame = new IlvDashboardExpandablePane(overviewTitle, icon, overview);

    url = IlvDiagrammerPropertySheet.class.getResource("images/psheet.gif");
    icon = new ImageIcon(url);

    palettePanel = new IlvDashboardSymbolPalette(this);
    String palettesTitle =
        getString("Dashboard.Palette.Panel.Title", "ilog.views.dashboard.dashboard");
    IlvDashboardExpandablePane paletteFrame =
        new IlvDashboardExpandablePane(palettesTitle, icon, palettePanel);
    try {
      loadPalettes();
    } catch (Exception e) {
      e.printStackTrace();
    }

    IlvDashboardExpandableSplitPane split =
        new IlvDashboardExpandableSplitPane(overviewFrame, paletteFrame);
    split.setResizeWeight(0.75);
    split.setDividerLocation(150);

    return split;
  }

  private String getString(String key, String bundleName) {
    return ResourceBundle.getBundle(bundleName).getString(key);

  }

  /**
   * Load the default symbol palettes when starting the dashboard editor.
   * @throws IlvDashboardException
   */
  protected void loadDefaultPalettes() throws IlvDashboardException {
    // Load the Links palette
    IlvPalette linkPalette = loadPalette("ilog/views/palettes/links/");
    if (linkPalette == null) {
      throw new IlvDashboardException("Palette not found");
    }
    // The link palette should not be closed, because it is not in a
    // palette jar.
    palettePanel.setClosable(linkPalette, false);

    // Load the common palette from the libraries
    // contained in the class path

    // If JViews Charts is present...
    boolean chartsPresent = false;
    try {
      Class.forName("ilog.views.chart.IlvChart");
      chartsPresent = true;
    } catch (ClassNotFoundException e) {
    } catch (ClassFormatError e) {
    }
    if (chartsPresent) {
      // ... then load the Charts palette:
      loadPalette("ilog/views/palettes/charts/");
    }

    // Load the Control and Shared Palettes
    loadPalette("ilog/views/palettes/controls/");
    loadPalette("ilog/views/palettes/shared/");

    // You can also use the following code to load these same two palettes
    // from a jar files.
    // M is the major version number of your JViews product
    // m is the minor version number of your JViews product
    // loadPalette(new URL("file:palettes/jviews-palette-controls-M.m.jar"));
    // loadPalette(new URL("file:palettes/jviews-palette-shared-symbols-M.m.jar"));
  }

  /**
   * Loade the symbol palettes when starting the dashboard editor.
   * @throws IlvDashboardException
   */
  protected void loadPalettes() throws IlvDashboardException {
    boolean loadDefault = true;
    boolean cleanMode = hasArg("-clean");
    Iterator<IlvPalette> palettes = null;

    if (!cleanMode) {
      try {
        palettes = loadInitialPalettes();
        if (palettes != null && palettes.hasNext()) {
          loadDefault = false;
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    if (loadDefault) {
      loadDefaultPalettes();
    }
  }

  private boolean hasArg(String arg) {
    for (String a : args) {
      if (a.equals(arg)) {
        return true;
      }
    }
    return false;
  }

  /*
   * (non-Javadoc)
   * 
   * @see ilog.views.dashboard.IlvDashboardEditor#createLeftArea()
   */
  protected JComponent createLeftArea() {
    URL url = IlvDiagrammerTree.class.getResource("images/tree.gif");
    ImageIcon icon = new ImageIcon(url);
    IlvDashboardTree tree = new IlvDashboardTree();
    JScrollPane treeScrollPane = new JScrollPane(tree);
    String treeTitle =
        getString("Diagrammer.Tree.DialogTitle", "ilog.views.diagrammer.application.tree");
    IlvDashboardExpandablePane treeFrame =
        new IlvDashboardExpandablePane(treeTitle, icon, treeScrollPane);

    url = IlvDiagrammerPropertySheet.class.getResource("images/psheet.gif");
    icon = new ImageIcon(url);
    IlvDashboardPropertyPanel ppanel = new IlvDashboardPropertyPanel(this);
    String psheetTitle =
        getString("Dashboard.PropertyPanel.Title", "ilog.views.dashboard.dashboard");
    IlvDashboardExpandablePane psheetFrame =
        new IlvDashboardExpandablePane(psheetTitle, icon, ppanel);

    IlvDashboardExpandableSplitPane split =
        new IlvDashboardExpandableSplitPane(treeFrame, psheetFrame);
    split.setResizeWeight(0.5);
    split.setDividerLocation(300);
    return split;

  }

  /**
   * Pop the browser with the HTML file.
   *
   * @param fileName The localized name of the file to look up.
   * @param fallback The name of the file to fall back on if the
   *                 localized file does not exist.
   * @param missingFileErrorMsg The error message if the file can not be found.
   *                 This will be formatted with the file name as arg 0.
   * @param failedErrorMsg The error message if we failed to pop the browser
   *                 for any reason.
   *                 This will be formatted with the file name as arg 0.
   */
  private void popBrowser(String fileName, String fallback, String missingFileErrorMsg,
      String failedErrorMsg) {
    File file = null;
    // run the users browser on the given file
    try {
      // first check the language-specific file if the string is not null
      if ((fileName != null) && (fileName.trim().length() > 0)) {
        file = new File(fileName.trim()).getAbsoluteFile();
      }
      if ((file == null) || !file.exists()) {
        // fallback
        fileName = fallback;
        file = new File(fileName.trim()).getAbsoluteFile();
      }
      if (!file.exists()) {
        Object[] args = {file};
        String err = java.text.MessageFormat.format(missingFileErrorMsg, args);
        // pop error dialog
        showStatus(err);
        return;
      }
      ilog.views.util.internal.IlvPopUserBrowser.pop(file);
    } catch (Exception e) {
      Object[] args = {file};
      String err = java.text.MessageFormat.format(failedErrorMsg, args);
      // pop error dialog
      String exMsg = e.getMessage();
      if ((exMsg == null) || (exMsg.trim().length() < 1)) {
        exMsg = e.toString();
      }
      showStatus(err + '\n' + exMsg);
    }
  }

  /**
   * Pop the user manual for the dashboard editor if the documentation
   * is installed in the correct relative directory.
   */
  public void popUserManual() {
    popBrowser(bundle.getString("Help.Menu.Help.File"),
        bundle.getString("Help.Menu.Help.Fallback.File"),
        bundle.getString("Help.Menu.Help.File.Missing"), bundle.getString("Help.Menu.Help.Failed"));
  }

  /**
   * Add the documentation menu item to the menu.
   * @param menuBar The dashboard editor menu bar.
   */
  private void addDocumentationMenuItem(IlvDashboardMenuBar menuBar) {
    IlvDiagrammerMenu menu = menuBar.getToolsMenu();
    if (menu != null) {
      menu.addSeparator();
      menu.addAction(new ReportingAction(bundle));
    }
  }

  /**
   * This class implement the Dashboard Reporting Panel
   */
  private static class ReportingPanel extends IlvDashboardPanel {

    private JScrollPane scrollPane;
    private JEditorPane textEditor;
    private boolean saveEnabled;
    private JFileChooser fileChooser;
    ResourceBundle bundle;

    private final static String PANEL_ID = "ReportingPanel";

    private final class RefreshAction extends IlvDiagrammerAction {

      RefreshAction(ResourceBundle bundle) {
        super("Dashboard.Demo.Action.Reporting.Refresh", bundle);
      }

      Override
      public void perform(ActionEvent e, IlvDiagrammer diagrammer) throws Exception {
        refresh();
      }

      Override
      protected boolean isEnabled(IlvDiagrammer diagrammer) throws Exception {
        return true;
      }
    }

    private final class SaveHTMLAction extends IlvDiagrammerAction {

      SaveHTMLAction(ResourceBundle bundle) {
        super("Dashboard.Demo.Action.Reporting.SaveHTML", bundle);
      }

      Override
      protected boolean isEnabled(IlvDiagrammer diagrammer) throws Exception {
        return saveEnabled;
      }

      Override
      public void perform(ActionEvent e, IlvDiagrammer diagrammer) throws Exception {
        saveReport();
      }

    }

    private final class HtmlFileFilter extends FileFilter {
      private final String extension =
          bundle.getString("Dashboard.Demo.Reporting.Panel.Html.Extension");
      private final String description =
          bundle.getString("Dashboard.Demo.Reporting.Panel.Html.Description");

      public HtmlFileFilter() {}

      /**
       * We accept directories (so that we can go down easily into
       * a directory as well as files with our extension.
       */
      Override
      public boolean accept(File f) {
        return (f.isDirectory() || f.getName().toLowerCase().endsWith(extension));
      }

      Override
      public String getDescription() {
        return description;
      }
    }

    ReportingPanel(IlvDashboardEditor editor, ResourceBundle bundle) {
      super(editor, PANEL_ID);
      this.bundle = bundle;
      this.saveEnabled = false;
      createEditorPane();
      createToolBar();
    }

    private int getResourceLong(String name, int def) {
      String res = bundle.getString(name);
      try {
        return Integer.parseInt(res);
      } catch (NumberFormatException e) {
        return def;
      }
    }

    private void createEditorPane() {
      textEditor = new JEditorPane();
      HyperlinkListener hyperlinkListener = new HyperlinkListener() {
        Override
        public void hyperlinkUpdate(HyperlinkEvent e) {
          if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
            JEditorPane pane = (JEditorPane) e.getSource();
            pane.scrollToReference(e.getDescription().substring(1));
          }
        }
      };
      textEditor.addHyperlinkListener(hyperlinkListener);
      textEditor.setContentType("text/html");
      // text.setText(html);
      textEditor.setEditable(false);
      scrollPane = new JScrollPane() {
        Override
        public Dimension getPreferredSize() {
          int width = getResourceLong("Dashboard.Demo.Reporting.Panel.Width", 400);
          int height = getResourceLong("Dashboard.Demo.Reporting.Panel.Height", 600);
          return new Dimension(width, height);
        }
      };
      scrollPane.getViewport().add(textEditor);
      setLayout(new BorderLayout());
      add(scrollPane);
    }

    private void createToolBar() {
      IlvDiagrammerToolBar toolBar = new IlvDiagrammerToolBar();
      toolBar.addAction(new RefreshAction(bundle));
      toolBar.addAction(new SaveHTMLAction(bundle));
      add(BorderLayout.PAGE_START, toolBar);
    }

    void saveReport() {
      File file = selectOutputFile();
      if (file != null) {
        try {
          FileWriter writer = new FileWriter(file);
          writer.write(textEditor.getText());
          writer.write('\n');
          writer.close();
        } catch (IOException e) {
        }
      }
    }

    void refresh() {
      try {
        IlvDashboardDiagram diagram = getDiagram();
        String text = diagram == null ? "" : makeText(getDiagram());
        textEditor.setText(text);
        textEditor.setCaretPosition(0);
        saveEnabled = diagram.iterator().hasNext();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }

    /**
     * Creates the report text.
     * @return The report text.
     * @throws Exception any exception.
     */
    private static String makeText(IlvDashboardDiagram diagram) throws Exception {
      DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = dbFactory.newDocumentBuilder();
      Document document = builder.newDocument();
      Element dashboardDOM = IlvDashboardDOM.buildDashboardDOM(document, diagram);
      document.appendChild(dashboardDOM);
      DOMSource domSource = new DOMSource(document);

      TransformerFactory factory = TransformerFactory.newInstance();
      URL outputXSL = getXSLT();
      StreamSource xslt = new StreamSource(outputXSL.toExternalForm());
      Transformer transformer = factory.newTransformer(xslt);
      transformer.setParameter("Lang", Locale.getDefault());
      StringWriter htmlres = new StringWriter();
      StreamResult result = new StreamResult(htmlres);
      transformer.transform(domSource, result);
      String html = htmlres.toString();

      // Remove the meta statement, not supported.
      StringBuffer lines = new StringBuffer();
      StringTokenizer st = new StringTokenizer(html, "\n");
      while (st.hasMoreTokens()) {
        String token = st.nextToken().trim();
        if (!token.startsWith("<META")) {
          lines.append(token);
          lines.append('\n');
        }
      }
      return lines.toString();
    }

    /**
     * Get the URL of the XSLT that will create the HTML. This will
     * try to find a language-specific XSLT first if it exists.
     */
    private static URL getXSLT() {
      Locale locale = Locale.getDefault();
      if (locale.getVariant().length() > 0) {
        URL url = DashboardEditor.class.getResource("outputdoc_" + locale.getLanguage() + "_"
            + locale.getCountry() + "_" + locale.getVariant() + ".xslt");
        if (url != null) {
          return url;
        }
      }
      if (locale.getCountry().length() > 0) {
        URL url = DashboardEditor.class
            .getResource("outputdoc_" + locale.getLanguage() + "_" + locale.getCountry() + ".xslt");
        if (url != null) {
          return url;
        }
      }
      URL url = DashboardEditor.class.getResource("outputdoc_" + locale.getLanguage() + ".xslt");
      if (url != null) {
        return url;
      }
      return DashboardEditor.class.getResource("outputdoc.xslt");
    }

    private File selectOutputFile() {
      if (fileChooser == null) {
        String title = bundle.getString("Dashboard.Demo.Reporting.Panel.Title");

        fileChooser = new JFileChooser();
        fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
        fileChooser.setCurrentDirectory(new File("."));
        fileChooser.setDialogTitle(title);
        fileChooser.resetChoosableFileFilters();
        fileChooser.setAcceptAllFileFilterUsed(true);
        FileFilter fileFilter = new HtmlFileFilter();
        fileChooser.addChoosableFileFilter(fileFilter);
        fileChooser.setFileFilter(fileFilter);
      }

      File result = null;

      if (fileChooser.showSaveDialog(getEditor().getFrame()) == JFileChooser.APPROVE_OPTION) {
        result = fileChooser.getSelectedFile();
        if (result.getName().indexOf('.') < 0) {
          // add the default file extension.
          result = new File(result.getPath() + ".html");
        }
        if (result.exists()) {
          try {
            String confirmMsg = bundle.getString("Dashboard.Demo.Reporting.Panel.Confirm.Message");
            String confirmTitle = bundle.getString("Dashboard.Demo.Reporting.Panel.Confirm.Title");
            int overwrite = JOptionPane.showConfirmDialog(getEditor().getFrame(), confirmMsg,
                confirmTitle, JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
            if (overwrite == JOptionPane.NO_OPTION) {
              result = null;
            }
          } catch (java.awt.HeadlessException ignored) {
          }
        }
      }

      return result;
    }

  }


  /**
   * This class implements the action that pops an
   * HTML description of the model.
   */
  private class ReportingAction extends IlvDiagrammerAction {
    private ReportingPanel reportingPanel;
    private JFrame reportingFrame;

    ReportingAction(ResourceBundle bundle) {
      super("Dashboard.Demo.Action.Reporting", bundle);
    }


    /**
     * Perform the action by creating an HTML description of the
     * model and popping it in a dialog.
     */
    Override
    public void perform(ActionEvent e, IlvDiagrammer diagrammer) throws Exception {
      if (reportingFrame == null) {
        makePanel();
        if (diagrammer instanceof IlvDashboardDiagram) {
          reportingPanel.setDiagram((IlvDashboardDiagram) diagrammer);
        }
      }
      reportingPanel.refresh();
      IlvDiagrammerAction.updateActions(reportingPanel, diagrammer);
      if (!reportingFrame.isVisible()) {
        reportingFrame.setVisible(true);
      } else {
        reportingFrame.toFront();
      }

    }

    private void makePanel() {
      String title = bundle.getString("Dashboard.Demo.Reporting.Panel.Title");
      reportingFrame = new JFrame(title);
      reportingFrame.setIconImage(getFrame().getIconImage());
      reportingFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
      reportingFrame.setBounds(0, 0, 500, 600);
      reportingFrame.setLocationRelativeTo(getFrame());
      reportingPanel = new ReportingPanel(DashboardEditor.this, getResourceBundle());
      Container container = reportingFrame.getContentPane();
      container.setLayout(new BorderLayout());
      container.add(BorderLayout.CENTER, reportingPanel);
    }


    /**
     * This command is enabled if there is a selected diagram. 
     */
    Override
    protected boolean isEnabled(IlvDiagrammer diagrammer) throws Exception {
      return true;
    }

  }

  /**
   * A Swing Action based on the Perforce JViews IlvDiagrammerAction that
   * previews the edited dashboard diagram. 
   */
  private static class DashboardPreview extends IlvDashboardAction {
    private JFrame frame;

    /**
     * Constructs this Action instance with the given Resource Bundle.
     * @param bundle The Resource Bundle where the properties of the action 
     *               are defined.
     */
    DashboardPreview(ResourceBundle bundle) {
      super("Dashboard.Demo.Action.Preview", bundle);
    }

    Override
    public boolean isSelectable() {
      return true;
    }

    Override
    protected boolean isSelected(IlvDiagrammer diagrammer) throws Exception {
      return (frame != null);
    }

    /**
     * Returns true if this action is enabled. This action is enabled when
     * the dashboard diagram is not empty.
     * @return true if the dashboard diagram is not empty. 
     */
    Override
    protected boolean isEnabled(IlvDiagrammer diagrammer) throws Exception {
      return (diagrammer instanceof IlvDashboardDiagram
          && !((IlvDashboardDiagram) diagrammer).isEmpty());
    }

    /**
     * Performs the action.
     */
    Override
    public void perform(ActionEvent e, IlvDiagrammer diagrammer) throws Exception {
      if (frame == null) {
        if (diagrammer instanceof IlvDashboardDiagram) {
          showPreview((IlvDashboardDiagram) diagrammer);
        }
      } else {
        hidePreview();
      }
    }

    private void showPreview(IlvDashboardDiagram source)
        throws IOException, IlvDashboardException, ClassNotFoundException {
      // Create a Dashboard Context
      IlvDashboardContext context = new IlvDashboardContext();

      // Load the palettes
      IlvPaletteManager sourcePM = source.getContext().getPaletteManager();
      IlvPaletteManager dstPM = context.getPaletteManager();
      for (int ndx = 0; ndx < sourcePM.getPaletteCount(); ndx++) {
        IlvPalette sourceP = sourcePM.getPalette(ndx);
        if (dstPM.load(sourceP.getPackageName()) == null) {
          URL palURL = sourceP.getJarURL();
          if (palURL != null) {
            dstPM.load(palURL);
          }
        }
      }

      // Create a Dashboard Diagram with that same context.
      IlvDashboardDiagram dashboard = new IlvDashboardDiagram(context);

      // Binary read/write version
      ByteArrayOutputStream baout = new ByteArrayOutputStream();
      source.writeBinary(baout);
      ByteArrayInputStream bain = new ByteArrayInputStream(baout.toByteArray());
      dashboard.setURL(source.getURL());
      dashboard.readBinary(bain);

      // Manage view interactor
      dashboard.getView().setInteractor(new IlvDashboardInteractor());

      // To manage the keyboard focus-like selection
      dashboard.setSelectManager(new IlvDashboardKeySelectManager(dashboard));

      // Create a frame that will contain the Dashboard.
      makeFrame(dashboard, source);
      frame.setVisible(true);

      // Close the preview dashboard when the user press Esc key
      KeyListener keyListener = new KeyAdapter() {
        Override
        public void keyPressed(KeyEvent e) {
          if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
            hidePreview();
          }
        }
      };
      frame.addKeyListener(keyListener);
      dashboard.getView().addKeyListener(keyListener);
    }

    private void hidePreview() {
      frame.dispose();
      frame = null;
      setSelected(false);
    }

    private void makeFrame(IlvDashboardDiagram dashboard, IlvDashboardDiagram source) {
      frame = new JFrame();
      frame.getContentPane().add(dashboard);
      Dimension screen = dashboard.getToolkit().getScreenSize();
      int width = Math.min(source.getWidth() + 10, screen.width);
      int height = Math.min(source.getHeight() + 30, screen.height);
      int x = (screen.width - width) / 2;
      int y = (screen.height - height) / 2;
      frame.setBounds(x, y, width, height);
      String title = getResourceBundle().getString("Dashboard.Demo.Action.Preview.WindowTitle");
      URL url = source.getURL();
      if (url != null) {
        title = title + ": " + new File(url.getPath()).getName();
      }
      frame.setTitle(title);
      frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
      frame.addWindowListener(new WindowAdapter() {
        Override
        public void windowClosing(WindowEvent e) {
          hidePreview();
        }
      });
    }


  }
}