//----------------------------------------------------------------------------
// COMPONENT NAME: LPEX Editor
//
// (C) Copyright IBM Corporation 2000, 2004
// All Rights Reserved.
//
// DESCRIPTION:
// MinLpex - sample/test class for the SWT LPEX text-edit widget
//----------------------------------------------------------------------------

package com.ibm.lpex.samples;

import java.io.File;

import com.ibm.lpex.core.LpexAction;
import com.ibm.lpex.core.LpexCommand;
import com.ibm.lpex.core.LpexView;
import com.ibm.lpex.core.LpexViewAdapter;
import com.ibm.lpex.core.LpexWindow;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;


/**
 * Sample minimal stand-alone editor used to test the LPEX edit widget.
 * Modifying this sample allows you to test easily your extensions to the LPEX widget.
 *
 * <p>Here is the MinLpex <a href="doc-files/MinLpex.java.html">source code</a>.</p>
 *
 * <p>To run this sample from the command line:
 * <pre>
 *   java [<i>options</i>] com.ibm.lpex.samples.MinLpex [<i>filename</i>] </pre>
 * A possible Windows batch program is:
 * <pre>
 *   &#64;start /b java com.ibm.lpex.samples.MinLpex %1 </pre>
 * To disable the JIT compiler, run it with this option:
 * <pre>
 *   -Djava.compiler= </pre>
 * You can run MinLpex in a particular locale.  For example, in order to run it in
 * Simplified Chinese (zh_CN), use these two options:
 * <pre>
 *   -Duser.language=zh -Duser.region=CN </pre></p>
 *
 * Commands and actions defined in here:
 * <ul>
 *  <li><b>MinLpex</b> command - open a new MinLpex window
 *  <li><b>quit</b> command - unconditionally quit the MinLpex window.
 * </ul>
 *
 * <p>Example of opening a file with MinLpex via a user-defined editor command:</p>
 * <table bgcolor="#f0f0f0"><tr><td><pre>&nbsp;
 * lpexView.defineCommand(<font color="#800080">"MinLpex"</font>, <font color="#0000ff"><b>new</b></font> LpexCommand() {
 *  <font color="#0000ff"><b>public boolean</b></font> doCommand(LpexView view, <font color="#0000ff"><b>final</b></font> String parameters)
 *  {
 *   Display display = getDisplay();
 *   display.asyncExec(<font color="#0000ff"><b>new</b></font> Runnable() {
 *    <font color="#0000ff"><b>public void</b></font> run() {
 *     <font color="#0000ff"><b>try</b></font>
 *      {
 *       Class cl = Class.forName(<font color="#800080">"com.ibm.lpex.samples.MinLpex"</font>);
 *       Method mainMethod = cl.getDeclaredMethod(<font color="#800080">"main"</font>, <font color="#0000ff"><b>new</b></font> Class[] {String[].class});&nbsp;
 *       String[] args = <font color="#0000ff"><b>new</b></font> String[] {parameters};
 *       mainMethod.invoke(<font color="#0000ff"><b>null</b></font>, <font color="#0000ff"><b>new</b></font> Object[] {args});
 *      }
 *     <font color="#0000ff"><b>catch</b></font> (Exception e) {}
 *     }});
 *   <font color="#0000ff"><b>return true</b></font>;
 *  }
 * }); </pre></td></tr></table>
 *
 * @see com.ibm.lpex.samples All the samples
 */
public final class MinLpex
{
 private Shell _shell;
 private LpexWindow _lpexWindow;
 private LpexView _lpexView;

 /**
  * Entry point.
  */
 public static void main(String[] args)
 {
  new MinLpex((args.length == 0)? null : args[0], new Rectangle(10, 10, 648, 711)).run();
 }

 /**
  * Constructor.
  * @param filename file name
  * @param bounds   size and position for the window
  */
 public MinLpex(String filename, Rectangle bounds)
 {
  // ensure canonical file name
  if (filename != null)
   {
    if (filename.trim().length() == 0)
     {
      filename = null;
     }
    else
     {
      try
       {
        filename = new File(filename).getCanonicalPath();
       }
      catch(Exception e) {}
     }
   }

  // create an LpexView for the given file, do the "updateProfile" later
  _lpexView = new LpexView(filename, "" /*auto-detect encoding*/, false);

  // create a new Shell, set its title
  _shell = new Shell();
  String name = _lpexView.query("name");
  if (name == null)
   {
    name = "Untitled Document " + _lpexView.query("documentId");
   }
  _shell.setText("SWT MinLpex - " + name);

  // create & set a window for our LpexView
  _lpexWindow = new LpexWindow(_shell);
  _lpexView.setWindow(_lpexWindow);

  // add an LpexViewListener to handle all the LPEX listening needed here
  _lpexView.addLpexViewListener(new LpexViewAdapter() {
   // called after an "updateProfile" command was run
   public void updateProfile(LpexView lpexView)
   { MinLpex.this.updateProfile(lpexView); }
   // called when the LpexView is disposed
   public void disposed(LpexView lpexView)
   { _lpexView = null; }
  });

  // run the "updateProfile" command
  _lpexView.doDefaultCommand("updateProfile");

  // listen to a few Shell events
  _shell.addListener(SWT.Close, new Listener() {
     public void handleEvent(Event event) { closeShell(event); }});
  _shell.addListener(SWT.Dispose, new Listener() {
     public void handleEvent(Event event) { disposeShell(event); }});
  _shell.addListener(SWT.Resize, new Listener() {
     public void handleEvent(Event event) { resizeShell(event); }});

  // set Shell's position & size, open it
  _shell.setBounds(bounds);
  _shell.open();

  // display view, set input focus in the edit area
  //_lpexView.doDefaultCommand("screenShow");
  //_lpexWindow.textWindow().setFocus();
 }

 private void run()
 {
  Display display = _shell.getDisplay();
  while (!_shell.isDisposed())
   {
    if (!display.readAndDispatch())
     {
      display.sleep();
     }
   }

  _shell = null;
 }

 /*======================*/
 /*  LPEX notifications  */
 /*======================*/
 // Defines editor commands, actions, and associated keys.
 // Called whenever the "updateProfile" command has been processed.
 private void updateProfile(LpexView lpexView)
 {
  // "MinLpex" command - open a MinLpex window
  lpexView.defineCommand("MinLpex", new LpexCommand() {
   public boolean doCommand(LpexView view, String parameters)
   { return newWindow(parameters); } });

  // "quit" command - unconditionally quit this MinLpex window
  // (also used by base profile vi's ":q" commands)
  lpexView.defineCommand("quit", new LpexCommand() {
   public boolean doCommand(LpexView view, String parameters)
   { view.dispose(); _shell.dispose(); return true; } });
 }

 // Creates a new MinLpex window for a file.
 private boolean newWindow(final String filename)
 {
  _shell.getDisplay().asyncExec(new Runnable() { // à la SwingUtilities#invokeLater()
   public void run()
   {
    Rectangle newBounds = _shell.getBounds();
    newBounds.x += 20;
    newBounds.y += 20;
    new MinLpex(filename, newBounds).run();
   }
  });

  return true;
 }

 /*=============================*/
 /*  Shell event notifications  */
 /*=============================*/
 // Shell being disposed.
 private void disposeShell(Event event)
 {
  // dispose of our view & its resources (document parser, etc.)
  if (_lpexView != null)
   {
    _lpexView.dispose();
   }
 }

 // Shell size was set / Shell was resized.
 private void resizeShell(Event event)
 {
  Rectangle rect = _shell.getClientArea();
  _lpexWindow.setBounds(0, 0, rect.width, rect.height);
 }

 // Shell close request.
 private void closeShell(Event event)
 {
  event.doit = closeWindow();
 }

 // Check whether this MinLpex window can be safely closed (saved / user-abandoned).
 private boolean closeWindow()
 {
  boolean close = true;

  if (_lpexView != null && (_lpexView.queryInt("changes") != 0 || _lpexView.queryOn("dirty")))
   {
    String document = _lpexView.query("name");
    if (document == null)
     {
      document = "document";
     }
    MessageBox box = new MessageBox(_shell, SWT.ICON_QUESTION | SWT.YES | SWT.NO | SWT.CANCEL);
    box.setText(_shell.getText());
    box.setMessage ("Save latest changes to " + document + "?");
    int rc = box.open();

    if (rc == SWT.YES)
     {
      _lpexView.doCommand("save");
      if (_lpexView.query("status") != null) // save failed / was cancelled
       {
        close = false;
       }
     }
    else if (rc == SWT.CANCEL)
     {
      close = false;
     }
   }

  return close;
 }
}