//----------------------------------------------------------------------------
// COMPONENT NAME: LPEX Editor
//
// © Copyright IBM Corporation 2005, 2007
// All Rights Reserved.
//
// DESCRIPTION:
// MouseReselect - sample SWT LPEX extension (mouse reselect)
//----------------------------------------------------------------------------

package com.ibm.lpex.samples;

import java.util.HashMap;

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.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;


/**
 * Sample class to make new drags of mouse button 1 start new selections.
 *
 * <p>LPEX non-stream selections are by default <i>extended</i> on mouse drags
 * in the same view.  They must be explicitly cleared (with, for example, Alt+U)
 * before marking a new block.  Installing this class changes the default behavior
 * of a view such that a new mouse drag action (mouse button 1 with no key modifiers)
 * will always start a new selection.</p>
 *
 * <p>Here is the MouseReselect <a href="doc-files/MouseReselect.java.html">source
 * code</a>.</p>
 *
 * <p>A user profile (such as {@link TestUserProfile}) can install this feature
 * in a document view by calling:
 * <pre>  MouseReselect.install(lpexView);</pre></p>
 *
 * <p>See also {@link BlockNewMarkToMouseAction} as an example of an editor
 * action that installs this feature when it is run for the first time.</p>
 *
 * @see com.ibm.lpex.samples All the samples
 */
public class MouseReselect extends LpexViewAdapter
             implements MouseListener, MouseMoveListener, DisposeListener
{
 private static HashMap<LpexView,MouseReselect> _mouseReselects =
  new HashMap<LpexView,MouseReselect>();

 private LpexView   _lpexView;
 private LpexWindow _lpexWindow;
 private boolean    _button1PressedLast;

 /**
  * Constructs a new mouse reselect for the specified view.
  */
 private MouseReselect(LpexView lpexView)
 {
  _lpexView = lpexView;
  _lpexView.addLpexViewListener(this);
  _mouseReselects.put(lpexView, this);
 }

 /**
  * Installs mouse reselection in the given document view.
  * Does nothing if already installed.
  */
 public static void install(LpexView lpexView)
 {
  if (lpexView != null && _mouseReselects.get(lpexView) == null)
   {
    new MouseReselect(lpexView);
   }
 }

 // N/U /** Uninstalls mouse reselection from the given view. */
 // public static void uninstall(LpexView lpexView) {
 //  MouseReselect mr = _mouseReselects.get(lpexView);
 //  if (mr != null)
 //   mr.uninstall();
 //  }

 // Removes this mouse reselection.
 private void uninstall()
 {
  if (_lpexView != null)
   {
    _lpexView.removeLpexViewListener(this);
    if (_lpexWindow != null)
     {
      _lpexWindow.textWindow().removeDisposeListener(this);
      _lpexWindow.textWindow().removeMouseListener(this);
      _lpexWindow.textWindow().removeMouseMoveListener(this);
      _lpexWindow = null;
     }

    _mouseReselects.remove(_lpexView);
    _lpexView = null;
   }
 }

 /**
  * View listener - the view has been refreshed.  Installs our mouse listeners
  * as soon as an LPEX window has been associated with the view.  Assumes that
  * the specified document view will only ever be shown in this window.
  */
 public void shown(LpexView lpexView)
 {
  if (_lpexWindow == null)
   {
    _lpexWindow = _lpexView.window();
    if (_lpexWindow != null)
     {
      _lpexWindow.textWindow().addDisposeListener(this);
      _lpexWindow.textWindow().addMouseListener(this);
      _lpexWindow.textWindow().addMouseMoveListener(this);
     }
   }
 }

 /**
  * View listener - the view is being disposed.
  * Uninstalls the mouse reselection from this view.
  */
 public void disposed(LpexView lpexView)
 { uninstall(); }

 /**
  * Text window dispose listener - the window is being disposed.
  * Uninstalls the mouse reselection.
  */
 public void widgetDisposed(DisposeEvent e)
 { uninstall(); }

 /** Mouse listener - button double click. */
 public void mouseDoubleClick(MouseEvent e) {}

 /** Mouse listener - button released. */
 public void mouseUp(MouseEvent e)
 { _button1PressedLast = false; }

 /**
  * Mouse listener - button pressed.
  * Records whether it is a sole button 1.
  */
 public void mouseDown(MouseEvent e)
 { _button1PressedLast = button1Pressed(e); }

 /**
  * Mouse move listener.
  * Clears any existing selection if a sole mouse button 1 (i.e., with no
  * key modifiers) was just pressed and is now dragged in our view's window.
  */
 public void mouseMove(MouseEvent e)
 {
  if (_button1PressedLast && button1Dragged(e) && _lpexWindow == _lpexView.window())
   {
    _button1PressedLast = false;
    _lpexView.triggerAction(_lpexView.actionId("blockUnmark"));
   }
 }

 // Returns whether the pressed mouse event is for a sole button 1.
 private boolean button1Pressed(MouseEvent e)
 {
  return e.button == 1 && (e.stateMask & SWT.MODIFIER_MASK) == 0;
 }

 // Returns whether the move mouse event is for a sole button 1 dragged.
 private boolean button1Dragged(MouseEvent e)
 {
  return (e.stateMask & (SWT.BUTTON_MASK | SWT.MODIFIER_MASK)) == SWT.BUTTON1;
 }
}