/*
 * Licensed Materials - Property of Rogue Wave Software, Inc. 
 * © Copyright Rogue Wave Software, Inc. 2014, 2015 
 * © 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 ilog.views.diagrammer.IlvDiagrammer;
import ilog.views.diagrammer.application.*;
import ilog.views.util.IlvProductUtil;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.HierarchyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.MessageFormat;

/**
 * This example shows how to build a simple multidocument diagram editor
 * using a diagram component, {@link ilog.views.diagrammer.IlvDiagrammer}.
 * <p>
 * This example shows that the components defined in the
 * {@link ilog.views.diagrammer.application} package make it very
 * easy to build Swing applications based on a diagram component.
 * <p>
 * The example is a simplified version of the predefined application
 * {@link ilog.views.diagrammer.application.IlvDiagrammerApplication}.
 * You can use this code as a basis to create your own customized
 * application.
 */
public class DiagramEditor extends JFrame
{
  // The desktop pane that contains the diagram components.
  private JDesktopPane desktopPane;
  // The style sheet to use.
  private URL styleSheet;
  
  // The default palette.
  private final static String PALETTE     = "file:data/palette.xml";
  // The default style sheet.
  private final static String STYLE_SHEET = "file:data/basic.css";
  // The title for new frames.
  private static final String UNNAMED_FORMAT = "unnamed ({0})";
  // The index used to differentiate new frames.
  private int unnamedCount = 1;
  
  /**
   * The main method of the application.
   */ 
  public static void main(String[] args)
  {
    // This sample uses JViews Diagrammer features. When deploying an
    // application that includes this code, you need to be in possession
    // of a Rogue Wave JViews Diagrammer Deployment license.
    IlvProductUtil.DeploymentLicenseRequired(
        IlvProductUtil.JViews_Diagrammer_Deployment);

    // Create an instance of the editor, and show it.
    //
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        new DiagramEditor().setVisible(true);
      }
    });
  }
  
  /**
   * Creates a new editor.
   */ 
  public DiagramEditor()
  {
    // Set up the frame.
    //
    super("Diagram Editor");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocation(100, 100);
    setSize(600, 400);
    
    // Create the palette URL.
    //
    URL paletteURL = null;
    try {
      paletteURL = new URL(PALETTE);
    } catch (MalformedURLException e) {
      e.printStackTrace();
    }
    
    // Create the style sheet URL.
    //
    try {
      styleSheet = new URL(STYLE_SHEET);
    } catch (MalformedURLException e) {
      e.printStackTrace();
    }
    
    // Create and add the desktop pane.
    //
    desktopPane = new JDesktopPane();
    
    getContentPane().setLayout(new BorderLayout());
    getContentPane().add(desktopPane, BorderLayout.CENTER);
    
    // Create a panel at the north of the frame, It will contain the edit toolbar
    // and the palette toolbar.
    //
    JPanel northPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
    getContentPane().add(northPanel, BorderLayout.NORTH);
    
    // Create the Edit toolbar.
    //
    IlvDiagrammerToolBar editToolBar = new IlvDiagrammerEditBar();
    
    // By default, the "New" action just clears the current diagram component.
    // Here, to create a new internal frame instead, the method overrides
    // the implementation of the _new action by adding a listener to it.
    //
    IlvDiagrammerAction._new.setHandler(new IlvDiagrammerAction.Handler(){
      public void perform(IlvDiagrammerAction action,
                          IlvDiagrammer diagrammer,
                          ActionEvent event) throws Exception
      {
        DiagramEditor.this.newDiagram();
      }
    });
    northPanel.add(editToolBar);
    
    // Create the palette toolbar and put it next to the edit toolbar.
    //
    try {
      IlvDiagrammerToolBar paletteBar = new IlvDiagrammerPaletteBar(paletteURL, styleSheet,
                                                                    JToolBar.HORIZONTAL);
      northPanel.add(paletteBar);
    } catch (Exception e) {
      e.printStackTrace();
    }
    
    // Create a View toolbar (to control zooming, panning, and so on), and
    // add it vertically on the left of the frame.
    //
    JToolBar controlToolBar = new IlvDiagrammerViewBar(JToolBar.VERTICAL);
    getContentPane().add(controlToolBar,
                         BorderLayout.WEST);
    
    // Create a standard Diagrammer menu bar.
    //
    JMenuBar menuBar = new IlvDiagrammerMenuBar();
    setJMenuBar(menuBar);
    
    // Once ready, create the initial frame.
    //
    SwingUtilities.invokeLater(new Runnable(){
      public void run(){
        newDiagram();
      }
    });
  }
  
  /**
   * Creates a new internal frame with a new diagram component in it.
   */ 
  public IlvDiagrammer newDiagram()
  {
    // Create and set up the new diagram component.
    //
    final IlvDiagrammer diagrammer = new IlvDiagrammer();
    diagrammer.setScrollable(true);
    diagrammer.setSelectMode(true);
    diagrammer.setEditingAllowed(true);
    
    // Set the style sheet.
    //
    try {
      diagrammer.setStyleSheet(styleSheet);
    } catch (Exception e) {
      e.printStackTrace();
    }
    
    // Compute the title of the new frame ("unnamed (x)").
    //
    String title = MessageFormat.format(UNNAMED_FORMAT, new Object[] { new Integer(unnamedCount++) });
    
    // Create the new internal frame, and add the diagram component to it.
    //
    final JInternalFrame frame =
            new JInternalFrame(title,
                               true, true, true, true);
    frame.getContentPane().add(diagrammer);
    frame.setSize(400, 300);
    
    // Watch changes to the diagram data file (through a PropertyChangeListener)
    // to update the frame title when necessary.
    //
    diagrammer.addPropertyChangeListener(new PropertyChangeListener(){
      public void propertyChange(PropertyChangeEvent evt)
      {
        if(evt.getPropertyName().equals("dataFile")){
          frame.setTitle(((URL)evt.getNewValue()).getPath());
        }
      }
    });
    
    // Add and show the new frame.
    //
    // Wait until the desktop pane is showing before we show the new frame,
    // this is to avoid a bug in JDK 1.3.1.
    if(desktopPane.isShowing()){
      desktopPane.add(frame);
      frame.setVisible(true);
    } else {
      desktopPane.addHierarchyListener(new HierarchyListener(){
        public void hierarchyChanged(HierarchyEvent e)
        {
          if(desktopPane.isShowing()){
            desktopPane.add(frame);
            frame.setVisible(true);
            desktopPane.removeHierarchyListener(this);
          }
        }
      });
    }
    
    // All done!
    //
    return diagrammer;
  }
}