/*******************************************************************************
* Copyright © 2008, 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.edt.ide.rui.visualeditor.internal.editor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.Status;
import org.eclipse.edt.ide.rui.document.utils.IVEConstants;
import org.eclipse.edt.ide.rui.visualeditor.internal.actions.EvActionWidgetDelete;
import org.eclipse.edt.ide.rui.visualeditor.internal.actions.EvActionWidgetMove;
import org.eclipse.edt.ide.rui.visualeditor.internal.actions.EvActionWidgetProperties;
import org.eclipse.edt.ide.rui.visualeditor.internal.nl.Messages;
import org.eclipse.edt.ide.rui.visualeditor.internal.preferences.EvPreferences;
import org.eclipse.edt.ide.rui.visualeditor.internal.properties.PropertyChange;
import org.eclipse.edt.ide.rui.visualeditor.internal.util.ColorUtil;
import org.eclipse.edt.ide.rui.visualeditor.internal.views.dataview.model.PageDataNode;
import org.eclipse.edt.ide.rui.visualeditor.internal.widget.WidgetDescriptor;
import org.eclipse.edt.ide.rui.visualeditor.internal.widget.WidgetDescriptorRegistry;
import org.eclipse.edt.ide.rui.visualeditor.internal.widget.WidgetManager;
import org.eclipse.edt.ide.rui.visualeditor.internal.widget.WidgetPart;
import org.eclipse.edt.ide.rui.visualeditor.internal.widget.WidgetPropertyDescriptor;
import org.eclipse.edt.ide.rui.visualeditor.internal.widget.WidgetPropertyValue;
import org.eclipse.edt.ide.rui.visualeditor.internal.widget.layout.RootWidgetLayout;
import org.eclipse.edt.ide.rui.visualeditor.internal.widget.layout.WidgetLayout;
import org.eclipse.edt.ide.rui.visualeditor.internal.widget.layout.WidgetLayoutRegistry;
import org.eclipse.edt.ide.rui.visualeditor.internal.wizards.insertwidget.EvInsertWidgetWizardDialog;
import org.eclipse.edt.ide.rui.visualeditor.internal.wizards.insertwidget.InsertWidgetWizard;
import org.eclipse.edt.ide.rui.visualeditor.plugin.Activator;
import org.eclipse.gef.dnd.TemplateTransfer;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
/**
* The overlay sits on top of the browser widget within the design area of the design page.
* Its role is to draw widget selection indicators and handle drag/drop and mouse events.
*/
public class EvDesignOverlay extends Composite implements DisposeListener, DropTargetListener, FocusListener, IMenuListener, KeyListener, MouseListener, MouseMoveListener, MouseTrackListener, PaintListener, TraverseListener {
public final static int DROP_THICKNESS = 5;
protected Cursor _cursorWait = null;
protected EvActionWidgetDelete _actionWidgetDelete = null;
protected EvActionWidgetMove _actionWidgetMove = null;
protected EvActionWidgetProperties _actionWidgetProperties = null;
protected boolean _bShowInstructions = false;
protected Color _colorDropTargetPotential = null;
protected Color _colorDropTargetSelected = null;
protected Color _colorWidgetSelected = null;
protected EvDesignOverlayDropLocation _dropLocation = null;
protected Image _imageDoubleBuffer = null;
protected int _iTransparencyAmount = EvConstants.PREFERENCE_DEFAULT_SEMITRANSPARENCY_AMOUNT;
protected int _iTransparencyMode = EvConstants.PREFERENCE_DEFAULT_SEMITRANSPARENCY_MODE;
protected Collection _listDropLocations = null;
protected ArrayList _listSelectionHierarchy = new ArrayList(); // A list of integers reflecting the selection hierarchy
protected EvDesignPage _pageDesign = null;
protected EvDesignOverlayPainter _painter = null;
protected Point _ptDragOffset = new Point( 0, 0 );
protected Collection _ptDropLocations = null;
protected Point _ptMouse = new Point( 0, 0 );
protected Point _ptMouseDown = new Point( 0, 0 );
protected WidgetPart _widgetDragging = null; // A widget that is being dragged
protected WidgetPart _widgetDropLocation = null; // A widget that is being dragged
protected WidgetPart _widgetMouseDown = null; // The widget under the mouse during mouse down
protected WidgetPart _widgetNextSelection = null; // The widget that indicates it will be selected if a person clicks on it.
protected WidgetPart _widgetSelected = null; // Temporary for single selection only.
protected Collection _listClickableAreas = new ArrayList();
protected MenuManager _menuManager = null;
protected Point _mouseDownPoint = null;
/**
* Constructor.
*/
public EvDesignOverlay( Composite compositeParent, EvDesignPage pageDesign ) {
super( compositeParent, pageDesign._bGraphicsTransparencyAvailable == true ? SWT.TRANSPARENT : SWT.NO_BACKGROUND );
_pageDesign = pageDesign;
_painter = new EvDesignOverlayPainter( this );
// Initialize colors
//------------------
updateColors();
// Initialize transparency
//------------------------
initializeTransparency();
// Build context menu
//-------------------
createContextMenu();
// Listeners
//----------
addDisposeListener( this );
addDropSupport();
addFocusListener( this );
addKeyListener( this );
addMouseListener( this );
addMouseMoveListener( this );
addMouseTrackListener( this );
addPaintListener( this );
addTraverseListener( this );
EvHelp.setHelp( this, EvHelp.DESIGN_AREA );
EvHelp.setHelp( compositeParent, EvHelp.DESIGN_AREA );
EvHelp.setHelp( compositeParent.getParent(), EvHelp.DESIGN_AREA );
}
/**
* Adds support for dropping items onto this composite.
* @see org.eclipse.swt.dnd.DND
*/
protected void addDropSupport() {
int iOperations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK;
DropTarget dropTarget = new DropTarget( this, iOperations );
Transfer[] types = new Transfer[] { TemplateTransfer.getInstance() };
dropTarget.setTransfer( types );
dropTarget.addDropListener( this );
}
/**
* Creates the pop-up context menu for the design area
*/
protected void createContextMenu() {
_menuManager = new MenuManager( EvConstants.DESIGN_AREA_CONTEXT_MENU_ID, EvConstants.DESIGN_AREA_CONTEXT_MENU_ID );
_menuManager.addMenuListener( this );
Menu menu = _menuManager.createContextMenu( this );
setMenu( menu );
IWorkbenchPart workbenchPart = _pageDesign.getEditor().getSite().getPart();
// Undo
//-----
IAction actionUndo = _pageDesign.getEditor().getPageSource().getAction( ActionFactory.UNDO.getId() );
_menuManager.add( actionUndo );
// Redo
//-----
IAction actionRedo = _pageDesign.getEditor().getPageSource().getAction( ActionFactory.REDO.getId() );
_menuManager.add( actionRedo );
_menuManager.add( new Separator() );
// Save
//-----
IWorkbenchAction actionWorkbenchSave = ActionFactory.SAVE.create( workbenchPart.getSite().getWorkbenchWindow() );
_menuManager.add( actionWorkbenchSave );
_menuManager.add( new Separator() );
// Delete widget
//--------------
IWorkbenchAction actionWorkbenchDelete = ActionFactory.DELETE.create( workbenchPart.getSite().getWorkbenchWindow() );
_actionWidgetDelete = new EvActionWidgetDelete( this );
_actionWidgetDelete.setId(actionWorkbenchDelete.getId());
_actionWidgetDelete.setText( actionWorkbenchDelete.getText() );
_actionWidgetDelete.setAccelerator( actionWorkbenchDelete.getAccelerator() );
_actionWidgetDelete.setImageDescriptor( actionWorkbenchDelete.getImageDescriptor() );
_actionWidgetDelete.setDescription( actionWorkbenchDelete.getDescription() );
_actionWidgetDelete.setDisabledImageDescriptor( actionWorkbenchDelete.getDisabledImageDescriptor() );
_menuManager.add( _actionWidgetDelete );
// Widget move
//------------
_actionWidgetMove = new EvActionWidgetMove( workbenchPart, this );
_actionWidgetMove.setId(EvActionWidgetMove.ID);
_actionWidgetMove.setText( Messages.NL_Move );
_menuManager.add( _actionWidgetMove );
_menuManager.add( new Separator() );
// Widget properties
//------------------
IWorkbenchAction actionWorkbenchProperties = ActionFactory.PROPERTIES.create( workbenchPart.getSite().getWorkbenchWindow() );
_actionWidgetProperties = new EvActionWidgetProperties( this );
_actionWidgetProperties.setId(ActionFactory.PROPERTIES.getId());
_actionWidgetProperties.setText( actionWorkbenchProperties.getText() );
_actionWidgetProperties.setAccelerator( actionWorkbenchProperties.getAccelerator() );
_actionWidgetProperties.setImageDescriptor( actionWorkbenchProperties.getImageDescriptor() );
_actionWidgetProperties.setDescription( actionWorkbenchProperties.getDescription() );
_actionWidgetProperties.setDisabledImageDescriptor( actionWorkbenchProperties.getDisabledImageDescriptor() );
_menuManager.add( _actionWidgetProperties );
}
protected void refreshMenu() {
IContributionItem deleteContributionItem = _menuManager.find(ActionFactory.DELETE.getId());
if(deleteContributionItem == null){
_menuManager.insertBefore(ActionFactory.PROPERTIES.getId(), _actionWidgetDelete);
}
IContributionItem removeContributionItem = _menuManager.find(EvActionWidgetMove.ID);
if(removeContributionItem == null){
_menuManager.insertBefore(ActionFactory.PROPERTIES.getId(), _actionWidgetMove);
_menuManager.insertBefore(ActionFactory.PROPERTIES.getId(), new Separator() );
}
Collection<EvWidgetContextMenuProvider> _widgetContextMenuProviders = EvWidgetContextMenuProviderRegister.getInstance().getEvWidgetContextMenuProviders().values();
Iterator<EvWidgetContextMenuProvider> iterator = _widgetContextMenuProviders.iterator();
while(iterator.hasNext()){
iterator.next().refreshContextMenu(_widgetSelected, _menuManager, this, _mouseDownPoint);
}
}
/**
* Deletes the selected widget
*/
public void deleteSelected() {
if( _widgetSelected != null ) {
if( _widgetNextSelection == _widgetSelected )
_widgetNextSelection = null;
if(!isCellInGridLayout(_widgetSelected)){
doOperationWidgetDelete( _widgetSelected );
redraw();
}
}
}
private boolean isCellInGridLayout(WidgetPart _widgetSelected){
if ( _widgetSelected == null || !( "org.eclipse.edt.rui.widgets".equals( _widgetSelected.getPackageName() ) && "GridLayout".equals( _widgetSelected.getTypeName() )) ) {
return false;
}
String extrainfo = _widgetSelected.getExtraInfo( "LayoutInfo" );
if ( extrainfo == null || extrainfo.length() == 0 ) {
return false;
}
String[] tdInfo = extrainfo.split(":");
int row = -1, column = -1;
try {
int index = 0;
int[] cellInfo = new int[7];
for ( int i = 0; i < tdInfo.length; i ++ ) {
index = i % 7;
cellInfo[index] = Integer.parseInt( tdInfo[i] );
if(_mouseDownPoint != null){
if ( index == 6 && cellInfo[2] < _mouseDownPoint.x && cellInfo[3] < _mouseDownPoint.y && cellInfo[4] > _mouseDownPoint.x - cellInfo[2] && cellInfo[5] > _mouseDownPoint.y - cellInfo[3] ) {
row = cellInfo[0];
column = cellInfo[1];
break;
}
}
}
} catch ( Exception e ) {
Activator.getDefault().getLog().log(new Status(Status.ERROR,Activator.PLUGIN_ID,"GridLayoutWidgetContextMenuProvider: Error parse LayoutInfo",e));
}
if ( row >= 0 && column >= 0 ) {
return true;
}else{
return false;
}
}
/**
* Creates a widget at the specified drop location. The selection hierarchy of the new
* widget is determined and remembered. The selection hierarchy is restored after receiving
* a new set of widgets.
*/
public void doOperationWidgetCreate( WidgetDescriptor descriptor, EvDesignOverlayDropLocation location ) {
if( _cursorWait == null )
_cursorWait = new Cursor( getDisplay(), SWT.CURSOR_WAIT );
setCursor( _cursorWait );
rememberSelectionHierarchyForOperation( location.widgetParent, location.iIndex );
_pageDesign.doOperationWidgetCreate( descriptor, location );
setCursor( null );
}
/**
* Deletes a widget
*/
public void doOperationWidgetDelete( WidgetPart widget ) {
if( _cursorWait == null )
_cursorWait = new Cursor( getDisplay(), SWT.CURSOR_WAIT );
setCursor( _cursorWait );
rememberSelectionHierarchyForOperationDelete( widget );
_pageDesign.doOperationWidgetDelete( widget );
setCursor( null );
}
/**
* Moves the widget to the specified drop location. The selection hierarchy of the new widget
* location is determined and remembered. The selection hierarchy is restored after receiving
* a new set of widgets.
*/
public void doOperationWidgetMove( WidgetPart widget, EvDesignOverlayDropLocation location ) {
if( _cursorWait == null )
_cursorWait = new Cursor( getDisplay(), SWT.CURSOR_WAIT );
setCursor( _cursorWait );
rememberSelectionHierarchyForOperation( location.widgetParent, location.iIndex );
_pageDesign.doOperationWidgetMove( widget, location );
setCursor( null );
}
/**
* Notifies the design page of a set of property changes.
*/
protected void doOperationWidgetPropertyValueChanges( List listPropertyChanges ) {
if( _cursorWait == null )
_cursorWait = new Cursor( getDisplay(), SWT.CURSOR_WAIT );
setCursor( _cursorWait );
_pageDesign.doOperationWidgetPropertyValueChanges( listPropertyChanges );
setCursor( null );
}
/**
* Notifies the design page of a click event.
*/
protected void doOperationWidgetOnclick( EvDesignOverylayClickableArea area ) {
try {
int index = Integer.parseInt( area.propertyValue );
rememberSelectionHierarchyForOperation( area.widget, index - 1 );
} catch ( Exception e ) {
//needn't do anything
}
_pageDesign.doOperationWidgetOnclick( area.widget, area.propertyName, area.propertyValue );
}
public void doSourceOperation(EvSourceOperation operation) {
if( _widgetSelected != null ) {
if( _widgetNextSelection == _widgetSelected )
_widgetNextSelection = null;
if( _cursorWait == null )
_cursorWait = new Cursor( getDisplay(), SWT.CURSOR_WAIT );
setCursor( _cursorWait );
_pageDesign.doSourceOperation( operation );
setCursor( null );
redraw();
}
}
/**
* Declared in DragDropListener. Checks for a GEF transfer template.
* If found, the drop locations are shown.
*/
public void dragEnter( DropTargetEvent event ) {
// Do nothing if there is no RUI handler
//-------------------------------------------------------------------
EvEditor editor = _pageDesign.getEditor();
boolean bAllowDrop = editor.isRuiHandler() == true;
if( bAllowDrop == false )
return;
DropTarget dropTarget = (DropTarget)event.getSource();
Transfer[] transfer = dropTarget.getTransfer();
if( transfer.length == 0 )
return;
if( transfer[ 0 ] instanceof TemplateTransfer == false )
return;
// Check for GEF template transfer
//--------------------------------
TemplateTransfer templateTransfer = (TemplateTransfer)transfer[ 0 ];
if( templateTransfer.getObject() instanceof String == false )
return;
// Turn on auto scrolling
//-----------------------
_pageDesign.getScroller().activate();
return;
}
/**
* Declared in DragDropListener
*/
public void dragLeave( DropTargetEvent event ) {
// Do nothing if there is no RUI handler
//-------------------------------------------------------------------
EvEditor editor = _pageDesign.getEditor();
boolean bAllowDrop = editor.isRuiHandler() == true;
if( bAllowDrop == false )
return;
_ptDropLocations = null;
_listDropLocations = null;
_pageDesign.getScroller().deactivate();
// Do not nullify the drop location
// This leave method is called just before the drop method
//--------------------------------------------------------
redraw();
}
/**
* Declared in DragDropListener. Does nothing.
*/
public void dragOperationChanged( DropTargetEvent event ) {
}
/**
* Declared in DragDropListener
*/
public void dragOver( DropTargetEvent event ) {
// Do nothing if there is no RUI handler
//-------------------------------------------------------------------
EvEditor editor = _pageDesign.getEditor();
boolean bAllowDrop = editor.isRuiHandler() == true;
if( bAllowDrop == false )
return;
// Compute the drop locations
// Use the display's mouse position instead of the event x and y
// to work around chinese linux problem
//--------------------------------------------------------------
Point ptMouse = Display.getCurrent().getCursorLocation();
ptMouse = toControl( ptMouse );
// Auto scroll the design area
//----------------------------
_pageDesign.getScroller().autoScroll( ptMouse.x, ptMouse.y );
setupDropLocations( ptMouse.x, ptMouse.y );
setupNextDropLocation( ptMouse.x, ptMouse.y );
redraw();
}
/**
* Declared in DragDropListener.
* A new widget instance is created at the drop location.
*/
public void drop( DropTargetEvent event ) {
// Do nothing if there is no RUI handler
//-------------------------------------------------------------------
EvEditor editor = _pageDesign.getEditor();
boolean bAllowDrop = editor.isRuiHandler() == true;
if( bAllowDrop == false )
return;
// Create a new widget
// We receive an ID which is a concatenation of:
// widget project name, a separator, widget type
//-------------------------------------------------
if ( _dropLocation != null ) {
if( event.data instanceof String == true ) {
String strWidgetID = event.data.toString();
WidgetDescriptor descriptor = WidgetDescriptorRegistry.getInstance(this.getDesignPage().getEditor().getProject()).getDescriptor( strWidgetID );
doOperationWidgetCreate( descriptor, _dropLocation );
} else if( event.data instanceof PageDataNode){
PageDataNode pageDataNode = (PageDataNode)event.data;
InsertWidgetWizard insertWidgetWizard = new InsertWidgetWizard(pageDataNode, this, _dropLocation);
Shell shell = Display.getCurrent().getActiveShell();
EvInsertWidgetWizardDialog evInsertWidgetWizardDialog = new EvInsertWidgetWizardDialog(shell, insertWidgetWizard);
evInsertWidgetWizardDialog.setPageSize(800,400);
evInsertWidgetWizardDialog.open();
}
}
_ptDropLocations = null;
_listDropLocations = null;
_dropLocation = null;
_widgetDropLocation = null;
redraw();
}
/**
* Declared in DragDropListener
*/
public void dropAccept( DropTargetEvent event ) {
}
/**
* Ends a widget move operation. Either a mouse up, or an enter key press has occurred.
*/
protected void endWidgetMove(){
// Moving a statement
//-------------------
if( _dropLocation != null ) {
doOperationWidgetMove( _widgetDragging, _dropLocation );
}
// Non-static positioning when dragging a widget
// If a widget being dragged has position that is absolute
// we assume that the user wants to relocate
// the widget position and not the widget statement.
// Determine whether to move the statement or the widget position
//---------------------------------------------------------------
WidgetPropertyValue positionValue = _pageDesign.getEditor().getPropertyValue( _widgetDragging, "position", IVEConstants.STRING_TYPE );
ArrayList listValues = null;
if( positionValue != null )
listValues = positionValue.getValues();
String strType = null;
if( listValues != null && listValues.size() > 0 )
strType = (String)listValues.get( 0 );
if( strType != null ) {
// Absolute: Relative to the top /right corner of the web page
// Relative: Relative to where the widget would normally be positioned
//--------------------------------------------------------------------
if( strType.equalsIgnoreCase( "absolute" ) || strType.equalsIgnoreCase( "fixed" ) || strType.equalsIgnoreCase( "relative" ) ) {
// Modify the x and y widget properties
//-------------------------------------
WidgetDescriptorRegistry registry = WidgetDescriptorRegistry.getInstance(this.getDesignPage().getEditor().getProject());
WidgetDescriptor widgetDescriptor = registry.getDescriptor( _widgetDragging.getTypeID() );
if( widgetDescriptor != null ) {
// Obtain the x property value
//----------------------------
String strOldX = null;
WidgetPropertyDescriptor descriptorX = widgetDescriptor.getPropertyDescriptor( "x" );
WidgetPropertyValue valueOldX = _pageDesign.getEditor().getPropertyValue( _widgetDragging, "x", IVEConstants.INTEGER_TYPE );
ArrayList listX = null;
if( valueOldX != null )
listX = valueOldX.getValues();
if( listX != null && listX.size() > 0 )
strOldX = (String)listX.get( 0 );
// Obtain the y property value
//----------------------------
String strOldY = null;
WidgetPropertyDescriptor descriptorY = widgetDescriptor.getPropertyDescriptor( "y" );
WidgetPropertyValue valueOldY = _pageDesign.getEditor().getPropertyValue( _widgetDragging, "y", IVEConstants.INTEGER_TYPE );
ArrayList listY = null;
if( valueOldY != null )
listY = valueOldY.getValues();
if( listY != null && listY.size() > 0 )
strOldY = (String)listY.get( 0 );
int iX = 0;
int iY = 0;
// For "fixed", we use the mouse position
// Fixed is relative to the browser window independent of scrolling
//-----------------------------------------------------------------
if( strType.equalsIgnoreCase( "fixed" ) == true ) {
Rectangle rectDragging = _widgetDragging.getBoundsDragging();
iX = rectDragging.x;
iY = rectDragging.y;
}
// For "relative" and "absolute" we can compute
// the delta relative to where the widget was before
// Relative is relative to its normal position
// Absolute is relative to its container
//--------------------------------------------------
else {
Point ptWidget = _widgetDragging.getBoundsOrigin();
Rectangle rectDragging = _widgetDragging.getBoundsDragging();
int iDeltaX = rectDragging.x - ptWidget.x;
int iDeltaY = rectDragging.y - ptWidget.y;
int iOldX = 0;
int iOldY = 0;
if( strOldX != null ) {
try {
iOldX = Integer.valueOf( strOldX ).intValue();
}
catch( NumberFormatException ex ) {
}
}
if( strOldY != null ) {
try {
iOldY = Integer.valueOf( strOldY ).intValue();
}
catch( NumberFormatException ex ) {
}
}
iX = iOldX + iDeltaX;
iY = iOldY + iDeltaY;
}
// Create a list of changes for one undo operation
//------------------------------------------------
ArrayList listPropertyChanges = new ArrayList();
// x
//--
WidgetPropertyValue valueNew = new WidgetPropertyValue( Integer.toString( iX ) );
PropertyChange change = new PropertyChange();
change.strPropertyID = descriptorX.getID();
change.strPropertyType = descriptorX.getType();
change.valueNew = valueNew;
change.valueOld = valueOldX;
change.widget = _widgetDragging;
listPropertyChanges.add( change );
// y
//--
valueNew = new WidgetPropertyValue( Integer.toString( iY ) );
change = new PropertyChange();
change.strPropertyID = descriptorY.getID();
change.strPropertyType = descriptorY.getType();
change.valueNew = valueNew;
change.valueOld = valueOldY;
change.widget = _widgetDragging;
listPropertyChanges.add( change );
doOperationWidgetPropertyValueChanges( listPropertyChanges );
}
}
}
}
/**
* For a given mouse coordinate, finds the smallest parent part (Box, VBox, HBox).
*/
protected WidgetPart findDropLocationWidget( int iX, int iY ) {
WidgetManager widgetManager = _pageDesign.getWidgetManager();
if( widgetManager == null )
return null;
WidgetPart widgetRoot = widgetManager.getWidgetRoot();
if( widgetManager.getWidgetCount() == 0 )
return widgetRoot;
// Do the root children
//---------------------
WidgetPart widgetParent = findDropLocationWidgetRecursive( widgetRoot, iX, iY );
return widgetParent != null ? widgetParent : widgetRoot;
}
/**
* For a given mouse coordinate, finds the lowest child in the widget hierarchy that contains the coordinate.
*/
protected WidgetPart findDropLocationWidgetRecursive( WidgetPart widget, int iX, int iY ) {
if( widget == _widgetDragging )
return null;
WidgetPart widgetOut = null;
// Recursively do the children first
//----------------------------------
List listChildren = widget.getChildren();
for( int i = 0; i < listChildren.size(); ++i ) {
WidgetPart widgetChild = (WidgetPart)listChildren.get( i );
widgetOut = findDropLocationWidgetRecursive( widgetChild, iX, iY );
if( widgetOut != null )
return widgetOut;
}
// A child was not found to contain the point.
// See if the point is within the widget itself
//---------------------------------------------
if( widget.getBounds().contains( iX, iY ) == true )
return widget;
return null;
}
/**
* Returns the next widget in the list, or the current one if there are no more, or
* the first one if the specified widget is not in the list.
*/
protected WidgetPart findNextWidgetInList( WidgetPart widget, Collection listWidgets ) {
// Find the currently selected widget in the list
//-----------------------------------------------
int iIndex = -1;
WidgetPart[] widgets = new WidgetPart[listWidgets.size()];
System.arraycopy( listWidgets.toArray(), 0, widgets, 0, listWidgets.size() );
for( int i = 0; i < widgets.length; ++i ) {
if( widgets[ i ] == widget ) {
iIndex = i;
break;
}
}
// The widget is not found in the list
// Select the first one in the list
//------------------------------------
if( iIndex == -1 )
return widgets[ 0 ];
// The widget is found in the list
// Select the next one in the list
// Wrap around if exceeded size
//--------------------------------
else if( iIndex >= 0 ) {
if( ++iIndex >= widgets.length )
iIndex = 0;
return widgets[ iIndex ];
}
// There are no more widgets in the list
// Return the original widget
//--------------------------------------
return widget;
}
/**
* Declared in FocusListener.
* Notifies the design page so it can paint the focus indicator.
*/
public void focusGained( FocusEvent e ) {
_pageDesign.overlayFocusChanged( true );
redraw();
}
/**
* Declared in FocusListener.
* Notifies the design page so it can paint the focus indicator.
*/
public void focusLost( FocusEvent e ) {
resetMouseDownPoint();
_pageDesign.overlayFocusChanged( false );
redraw();
}
/**
*
*/
public IAction getAction( String strActionId ) {
if( strActionId.equals( ActionFactory.DELETE.getId() ) == true )
return _actionWidgetDelete;
if( strActionId.equals( ActionFactory.PROPERTIES.getId() ) == true )
return _actionWidgetProperties;
return null;
}
/**
* Returns the parent design page.
*/
public EvDesignPage getDesignPage(){
return _pageDesign;
}
/**
* Returns the entire list of widgets sorted by statement location.
*/
protected Iterator getWidgets() {
WidgetManager widgetManager = _pageDesign.getWidgetManager();
return widgetManager.getWidgetList().iterator();
}
/**
* Returns the widget parts under the mouse position
*/
protected List getWidgetsAtPoint( Point point ) {
WidgetManager widgetManager = _pageDesign.getWidgetManager();
return widgetManager.getWidgets( point );
}
/**
*
*/
public WidgetPart getWidgetSelected() {
return _widgetSelected;
}
/**
* Called by the move action when a person selects the context menu "Move" menu item.
*/
public void initializeMoveWidgetWithKeyboard(){
_widgetMouseDown = _widgetSelected;
_widgetDragging = _widgetSelected;
_ptDragOffset.x = 0;
_ptDragOffset.y = 0;
Rectangle rectDragging = _widgetSelected.getBounds(); // The call returns a new Rectangle
_widgetSelected.setBoundsDragging( rectDragging );
mouseMoved( rectDragging.x + 8, rectDragging.y + 8 );
}
/**
* Initializes the overlay's transparency.
*/
protected void initializeTransparency() {
int iTransparencyMode = EvPreferences.getInt( EvConstants.PREFERENCE_SEMITRANSPARENCY_MODE );
int iTransparencyAmount = EvPreferences.getInt( EvConstants.PREFERENCE_SEMITRANSPARENCY_AMOUNT );
setTransparency( iTransparencyMode, iTransparencyAmount );
}
/**
* Returns whether a widget type is a container.
*/
protected boolean isContainer( WidgetPart widget ){
// Legacy support for widgets prior to 1.0.2
if( widget.getTypeName().equalsIgnoreCase( "div" ) || widget.getTypeName().equalsIgnoreCase( "span" ) || widget.getTypeName().equalsIgnoreCase( "grouping" ) || widget.getTypeName().equalsIgnoreCase( "treenode" ) || widget.getTypeName().equalsIgnoreCase( "tree" ) ){
return true;
}
WidgetDescriptor descriptor = WidgetDescriptorRegistry.getInstance(_pageDesign.getEditor().getProject()).getDescriptor( widget.getTypeID() );
if(descriptor != null){
return descriptor.isContainer();
}
return false;
}
/**
* Returns whether a widget type can be moved to a new location.
*/
public boolean isDraggable( String strType ){
if( strType.equalsIgnoreCase( "DojoTreeNode" ) )
return false;
return true;
}
/**
* Declared in KeyListener. Does nothing.
*/
public void keyPressed( KeyEvent event ) {
if( _widgetDragging == null )
return;
if( event.keyCode == SWT.ARROW_DOWN ){
Rectangle rectDragging = _widgetDragging.getBoundsDragging();
Rectangle rectMove = new Rectangle( rectDragging.x, rectDragging.y + 8, 8, 8 );
mouseMoved( rectMove.x, rectMove.y );
showRectangle( rectMove );
}
if( event.keyCode == SWT.ARROW_LEFT ){
Rectangle rectDragging = _widgetDragging.getBoundsDragging();
Rectangle rectMove = new Rectangle( rectDragging.x - 8, rectDragging.y, 8, 8 );
mouseMoved( rectMove.x, rectMove.y );
showRectangle( rectMove );
}
if( event.keyCode == SWT.ARROW_RIGHT ){
Rectangle rectDragging = _widgetDragging.getBoundsDragging();
Rectangle rectMove = new Rectangle( rectDragging.x + 8, rectDragging.y, 8, 8 );
mouseMoved( rectMove.x, rectMove.y );
showRectangle( rectMove );
}
else if( event.keyCode == SWT.ARROW_UP ){
Rectangle rectDragging = _widgetDragging.getBoundsDragging();
Rectangle rectMove = new Rectangle( rectDragging.x, rectDragging.y - 8, 8, 8 );
mouseMoved( rectMove.x, rectMove.y );
showRectangle( rectMove );
}
}
/**
* Declared in KeyListener.
* Handles page up and page down, because the traverse listener doesn't receive them.
*/
public void keyReleased( KeyEvent event ) {
if( event.keyCode == SWT.PAGE_DOWN ){
ScrolledComposite scroll = (ScrolledComposite)getParent().getParent();
Rectangle rectClient = scroll.getClientArea();
Point ptOrigin = scroll.getOrigin();
scroll.setOrigin( ptOrigin.x, ptOrigin.y + rectClient.height / 2 );
_pageDesign.capture();
}
else if( event.keyCode == SWT.PAGE_UP ){
ScrolledComposite scroll = (ScrolledComposite)getParent().getParent();
Rectangle rectClient = scroll.getClientArea();
Point ptOrigin = scroll.getOrigin();
scroll.setOrigin( ptOrigin.x, ptOrigin.y - rectClient.height / 2 );
_pageDesign.capture();
}
// End widget dragging
//------------------------------
else if( event.character == SWT.ESC ){
if( _widgetDragging != null ){
_widgetDragging.setBoundsDragging( new Rectangle( 0, 0, 0, 0 ) );
_widgetMouseDown = null;
_widgetDragging = null;
_ptDropLocations = null;
_listDropLocations = null;
_dropLocation = null;
redraw();
}
}
}
/**
* Declared in TraverseListener.
* Traverses to and selects the next or previous widget in the hierarchy.
* Traverses to the next and previous tab widgets.
* Note: TRAVERSE_PAGE_PREVIOUS and TRAVERSE_PAGE_NEXT do not happen.
*/
public void keyTraversed( TraverseEvent event ) {
// Navigate to previous widget
//----------------------------
if( event.detail == SWT.TRAVERSE_ARROW_PREVIOUS ){
if( _widgetSelected == null )
return;
if( _widgetDragging != null )
return;
WidgetPart widgetPrevious = _pageDesign.getWidgetManager().getWidgetPrevious( _widgetSelected );
if( widgetPrevious == _widgetSelected )
return;
selectWidget( widgetPrevious );
showWidget( _widgetSelected );
redraw();
}
// Navigate to next widget
//------------------------
else if( event.detail == SWT.TRAVERSE_ARROW_NEXT ){
if( _widgetSelected == null )
return;
if( _widgetDragging != null )
return;
WidgetPart widgetNext = _pageDesign.getWidgetManager().getWidgetNext( _widgetSelected );
if( widgetNext == _widgetSelected )
return;
selectWidget( widgetNext );
showWidget( _widgetSelected );
redraw();
}
// Enter key press: Complete widget dragging
//------------------------------------------
else if( event.detail == SWT.TRAVERSE_RETURN ){
if( _widgetDragging != null )
endWidgetMove();
}
// Tab previous to the tool bar
//-----------------------------
else if( event.detail == SWT.TRAVERSE_TAB_PREVIOUS ){
_pageDesign._toolbar.setFocus();
}
// Tab next no-op
//---------------
else if( event.detail == SWT.TRAVERSE_TAB_NEXT ){
}
}
/**
* Declared in IMenuListener.
* This method enables and disables the context menu items just before the pop-up menu is shown.
*/
public void menuAboutToShow( IMenuManager manager ) {
refreshMenu();
// Ensure that the overlay has focus.
// Otherwise a widget move using keyboard will not function
//---------------------------------------------------------
setFocus();
// Enable the actions if a widget is selected
//-------------------------------------------
_actionWidgetDelete.setEnabled( _widgetSelected != null );
_actionWidgetProperties.setEnabled( _widgetSelected != null );
boolean bMoveable = false;
if( _widgetSelected != null )
if( isDraggable( _widgetSelected.getTypeName() ) == true )
bMoveable = true;
_actionWidgetMove.setEnabled( bMoveable );
// When the context menu is showing, we do not receive
// mouse move notifications, so the next selection widget
// may become invalid
//-------------------------------------------------------
_widgetNextSelection = null;
}
/**
* Declared in MouseListener.
*/
public void mouseDoubleClick( MouseEvent e ) {
}
public void resetMouseDownPoint(){
_mouseDownPoint = null;
}
/**
* Declared in MouseListener.
* Determines which widget is to be used if a mouse move occurs while the mouse is down (drag).
* The selected widget is chosen first if it is under the mouse. Otherwise the widget that is
* the mouse over widget is chosen.
*/
public void mouseDown( MouseEvent event ) {
//This is a right-click, the mouse position info needs to be remembered for the use in context menu.
if ( event.button == 1 || event.button == 3 ) {
_mouseDownPoint = new Point( event.x, event.y );
}
if( event.button != 1 )
return;
// Remember for mouse move
//------------------------
_ptMouseDown.x = event.x;
_ptMouseDown.y = event.y;
// User may start dragging the selected widget
//--------------------------------------------
if( _widgetSelected != null ) {
_widgetMouseDown = null;
Collection widgetsUnderMouse = getWidgetsAtPoint( new Point( event.x, event.y ) );
if( widgetsUnderMouse.contains( _widgetSelected ) == true ) {
_widgetMouseDown = _widgetSelected;
Point ptWidget = _widgetSelected.getBoundsOrigin();
_ptDragOffset.x = ptWidget.x - event.x;
_ptDragOffset.y = ptWidget.y - event.y;
}
}
// Use the next widget to be selected that the mouse is
// currently over as the one that will be dragged if a
// mouse move occurs while the mouse is still down.
//-----------------------------------------------------
if( _widgetMouseDown == null && _widgetNextSelection != null ) {
_widgetMouseDown = _widgetNextSelection;
Point ptWidget = _widgetMouseDown.getBoundsOrigin();
_ptDragOffset.x = ptWidget.x - event.x;
_ptDragOffset.y = ptWidget.y - event.y;
}
}
/**
* Declared in MouseTrackListener. Does nothing.
*/
public void mouseEnter( MouseEvent e ) {
}
/**
* Declared in MouseTrackListener. When the mouse leaves the overlay, the next selection widget is reset to null.
*/
public void mouseExit( MouseEvent e ) {
if( _widgetNextSelection != null ) {
_widgetNextSelection.setMouseOver( false );
_widgetNextSelection = null;
redraw();
}
}
/**
* Declared in MouseTrackListener. Does nothing.
*/
public void mouseHover( MouseEvent e ) {
}
/**
* Declared in MouseMoveListener.
*/
public void mouseMove( MouseEvent event ) {
mouseMoved( event.x, event.y );
}
/**
* Called by the method above, and by the ScrolledCompositeScroller
* which scrolls the overlay within its scrolled composite while
* a widget is being dragged. This affects the position of the
* dragging rectangle, even though the mouse may not have physically
* moved.
*/
public void mouseMoved( int iMouseX, int iMouseY ) {
// A mouse move happens if a mouse down occurs, even if
// the mouse hasn't really moved. This workaround checks
// to see whether the mouse has actually moved or not.
//-------------------------------------------------------
if( _ptMouseDown.x == iMouseX && _ptMouseDown.y == iMouseY )
return;
_ptMouseDown.x = 0;
_ptMouseDown.y = 0;
// Mouse is not down. Find the next selection widget
//--------------------------------------------------
if( _widgetMouseDown == null ) {
Iterator iter = _listClickableAreas.iterator();
while( iter.hasNext() == true ) {
EvDesignOverylayClickableArea area = (EvDesignOverylayClickableArea)iter.next();
if ( area.clickableRect.contains( iMouseX, iMouseY ) ) {
setCursor( getDisplay().getSystemCursor( SWT.CURSOR_HAND ) );
return;
}
}
setCursor( getDisplay().getSystemCursor( SWT.CURSOR_ARROW ) );
setupNextSelectionWidget( iMouseX, iMouseY );
redraw();
return;
}
// Prevent dragging if there is only one widget
//---------------------------------------------
WidgetManager widgetManager = _pageDesign.getWidgetManager();
if( widgetManager.getWidgetCount() < 2 )
return;
// Prevent dragging if this is this is the only top level widget
//--------------------------------------------------------------
WidgetPart widgetParent = _widgetMouseDown.getParent();
if( widgetParent.getTypeName().equals( WidgetLayoutRegistry.ROOT ) == true )
if( widgetParent.getChildren().size() == 1 )
return;
// See if it is constrained by the where the widget is declared
//-------------------------------------------------------------
if( _widgetMouseDown.getMoveable() == false )
return;
if( isDraggable( _widgetMouseDown.getTypeName() ) == false )
return;
_widgetDragging = _widgetMouseDown;
// Initialize the dragging rectangle
//----------------------------------
if( _widgetDragging.getBoundsDragging().isEmpty() )
_widgetDragging.setBoundsDragging( _widgetDragging.getBounds() );
// Set the dragging position relative to the mouse position
//---------------------------------------------------------
int iX = iMouseX + _ptDragOffset.x;
int iY = iMouseY + _ptDragOffset.y;
_widgetDragging.setBoundsDraggingOrigin( new Point( iX, iY ) );
// Select the widget being dragged if it isn't selected
//-----------------------------------------------------
if( _widgetDragging != _widgetSelected )
selectWidget( _widgetDragging );
// Setup drop location feedback for object being dragged
//------------------------------------------------------
if( _ptDropLocations == null || _listDropLocations == null )
setupDropLocations( iMouseX, iMouseY );
setupNextDropLocation( iMouseX, iMouseY );
redraw();
return;
}
/**
* Declared in MouseListener.
*/
public void mouseUp( MouseEvent event ) {
if( event.button != 1 )
return;
// If we are not dragging a widget
//--------------------------------
if( _widgetDragging == null ) {
Iterator iter = _listClickableAreas.iterator();
while( iter.hasNext() == true ) {
EvDesignOverylayClickableArea area = (EvDesignOverylayClickableArea)iter.next();
if ( area.clickableRect.contains( event.x, event.y ) ) {
doOperationWidgetOnclick( area );
_widgetMouseDown = null;
return;
}
}
List listWidgets = getWidgetsAtPoint( new Point( event.x, event.y ) );
// If there is no widget under the mouse,
// do not deselect the currently selected one
// (selectWidget( null );)
//-------------------------------------------
if( listWidgets.size() == 0 ){
// Do nothing
}
// If there is only one widget under the mouse, select it
//-------------------------------------------------------
else if( listWidgets.size() == 1 ) {
WidgetPart widget = (WidgetPart)listWidgets.get( 0 );
if( widget != _widgetSelected )
selectWidget( widget );
}
// Otherwise, select the next selection widget
//--------------------------------------------
else if( _widgetNextSelection != null ) {
selectWidget( _widgetNextSelection );
}
}
// Dragging a widget
//------------------
else {
endWidgetMove();
}
if( _widgetDragging != null ){
_widgetDragging.setBoundsDragging( new Rectangle( 0, 0, 0, 0 ) );
_widgetDragging = null;
}
_widgetMouseDown = null;
_ptDropLocations = null;
_listDropLocations = null;
_widgetDropLocation = null;
_dropLocation = null;
// Indicate the widget that will be selected if the mouse is over multiple widgets
//--------------------------------------------------------------------------------
setupNextSelectionWidget( event.x, event.y );
redraw();
}
/**
* Paints the overlay.
*/
public void paintControl( PaintEvent event ) {
// Not a RUI Handler
//------------------
if( _pageDesign.getEditor().isRuiHandler() == false ){
_painter.paintBlank( event.gc );
return;
}
// Transparency is available
//--------------------------
if( _pageDesign._bGraphicsTransparencyAvailable == true ) {
if( _pageDesign.getBrowser() == null ){
_painter.paintBlank( event.gc );
return;
}
_painter.paintOpaque( event.gc );
_painter.setMouseDownPoint(_mouseDownPoint);
_painter.paintWidgets( event.gc );
_painter.paintInstructions( event.gc );
_painter.paintDropLocations( event.gc );
_painter.paintWidgetDragging( event.gc );
_painter.paintHierarchy( event.gc );
return;
}
// Transparency is not available
// Do nothing if a screen capture of the web browser is occurring
//---------------------------------------------------------------
EvDesignCaptureInformation captureInfo = _pageDesign.getCaptureInformation();
if( captureInfo.bCaptureRunning == true )
return;
// Double buffering, otherwise the widget indicators flicker
// since the browser image is drawn first.
// Create an image buffer
//----------------------------------------------------------
Rectangle rectBounds = getBounds();
if( _imageDoubleBuffer != null ){
Rectangle rectImage = _imageDoubleBuffer.getBounds();
if( rectBounds.width != rectImage.width || rectBounds.height != rectImage.height ){
_imageDoubleBuffer.dispose();
_imageDoubleBuffer = null;
}
}
if( _imageDoubleBuffer == null )
_imageDoubleBuffer = new Image( getDisplay(), rectBounds.width, rectBounds.height );
GC gc = null;
// Sometimes the image still has its memory context
// and the creation of the graphics context throws an exception
// Delete the image and try again.
//-------------------------------------------------------------
try{
gc = new GC( _imageDoubleBuffer );
}
catch( IllegalArgumentException ex ){
if( _imageDoubleBuffer != null && _imageDoubleBuffer.isDisposed() == false )
_imageDoubleBuffer.dispose();
_imageDoubleBuffer = new Image( getDisplay(), rectBounds.width, rectBounds.height );
gc = new GC( _imageDoubleBuffer );
}
gc.fillRectangle( rectBounds );
// The screen capture captures more than just the web browser.
// In order not to draw the stuff around the web browser, we
// restrict the drawing to the part of the design area that was
// showing when the screen capture took place.
//-------------------------------------------------------------
gc.setClipping( captureInfo.rectCapture );
// Paint the screen capture of the web browser
//--------------------------------------------
Image imageBrowser = captureInfo.imageBrowser;
if( imageBrowser != null ){
Rectangle r = captureInfo.rectCapture;
try{
// An exception is thrown if the source width/height is greater than the image width/height
// The source and destination origin are always zero.
//-----------------------------------------------------------------------------------------
int iWidth = Math.min( imageBrowser.getBounds().width, r.width );
int iHeight = Math.min( imageBrowser.getBounds().height, r.height );
gc.drawImage( imageBrowser, r.x, r.y, iWidth, iHeight, r.x, r.y, iWidth, iHeight );
}
catch( IllegalArgumentException ex ){
}
}
// Paint our things
//-----------------
_painter.paintOpaque( gc );
_painter.setMouseDownPoint(_mouseDownPoint);
_painter.paintWidgets( gc );
_painter.paintInstructions( gc );
_painter.paintDropLocations( gc );
_painter.paintWidgetDragging( gc );
_painter.paintHierarchy( gc );
// Paint the image buffer
//-----------------------
event.gc.drawImage( _imageDoubleBuffer, 0, 0 );
// Dispose of the double buffer graphics context
// This has to be done after the drawing, otherwise
// we will be unable to create another one
//-------------------------------------------------
gc.dispose();
}
/**
* Called from selectWidget.
* Creates a widget selection hierarchy of child indices.
* The root is not included in the hierarchy of numbers.
* The first number is the index of one of the root's children.
* The second number is the index of one of the root's grand children and so on.
* Zero indicates the first child in the list of children.
* One indicates the second child in the list of children and so on.
*/
protected void rememberSelectionHierarchy() {
_listSelectionHierarchy.clear();
if( _widgetSelected == null )
return;
WidgetManager widgetManager = _pageDesign.getWidgetManager();
WidgetPart widgetRoot = widgetManager.getWidgetRoot();
rememberSelectionHierarchyRecursive( widgetRoot );
}
/**
* Creates the selection hierarchy given a parent widget and a child index.
* This is used for the create and move widget operations.
*/
protected void rememberSelectionHierarchyForOperation( WidgetPart widgetParent, int iIndex ) {
// Go backward through the hierarchy until the root is found
//----------------------------------------------------------
ArrayList listHierarchy = new ArrayList();
listHierarchy.add( new Integer( iIndex ) );
boolean bFound = rememberSelectionHierarchyForOperationRecursive( widgetParent, listHierarchy );
// Remember the hierarchy if it is valid
//--------------------------------------
if( bFound == true )
_listSelectionHierarchy = listHierarchy;
}
/**
* Creates the selection hierarchy given a parent widget and a child index.
* This is used for the delete widget operation.
* The selection moves to a child with lower index if there is one, or
* if this is an only child, the selection moves to the parent.
* Otherwise, the index is untouched so a child who inherits the
* same index as the deleted child will be selected.
*/
protected void rememberSelectionHierarchyForOperationDelete( WidgetPart widget ) {
// The last index in the hierarchy list is always the index of the selected widget within its parent
//--------------------------------------------------------------------------------------------------
int iListIndex = _listSelectionHierarchy.size() - 1;
// Do nothing if the list is empty (should never occur)
//-----------------------------------------------------
if( iListIndex < 0 )
return;
WidgetPart widgetParent = widget.getParent();
int iNumberOfChildren = widgetParent.getChildren().size();
// The last child is being removed
// Select the parent by removing the child level from the list
//------------------------------------------------------------
if( iNumberOfChildren == 1 ) {
_listSelectionHierarchy.remove( iListIndex );
return;
}
// If this is the last child in the list,
// select the previous child
//---------------------------------------
int iWidgetIndex = widgetParent.getChildIndex( widget );
if( iWidgetIndex == iNumberOfChildren - 1 ) {
_listSelectionHierarchy.remove( iListIndex );
_listSelectionHierarchy.add( new Integer( iWidgetIndex - 1 ) );
return;
}
}
/**
* Returns true if child is found within the parent.
*/
protected boolean rememberSelectionHierarchyForOperationRecursive( WidgetPart widget, ArrayList listHierarchy ) {
if( widget == null )
return false;
WidgetPart widgetParent = widget.getParent();
// Stop if the widget is the root
//-------------------------------
if( widgetParent == null )
return true;
// Determine the index of the widget within its parent
//----------------------------------------------------
int iIndex = widgetParent.getChildIndex( widget );
if( iIndex < 0 )
return false;
// Prepend the index to the hierarchy
//-----------------------------------
listHierarchy.add( 0, new Integer( iIndex ) );
// Recursively do the parent widget
//----------------------------------
return rememberSelectionHierarchyForOperationRecursive( widgetParent, listHierarchy );
}
/**
* Returns whether the widget was found in the hierarchy and the list is complete.
*/
protected boolean rememberSelectionHierarchyRecursive( WidgetPart widget ) {
boolean bFound = false;
List listChildren = widget.getChildren();
for( int i = 0; i < listChildren.size(); i++ ) {
WidgetPart widgetChild = (WidgetPart)listChildren.get( i );
// The selected widget is found
// Save its index into the empty array
//------------------------------------
if( widgetChild.getSelected() == true ) {
_listSelectionHierarchy.add( new Integer( i ) );
return true;
}
// The selected widget has been found as a descendant
// Prepend the parent index to the array
//---------------------------------------------------
else {
bFound = rememberSelectionHierarchyRecursive( widgetChild );
if( bFound == true ) {
_listSelectionHierarchy.add( 0, new Integer( i ) );
return true;
}
}
}
return false;
}
/**
* Attempts to restore the widget selection based on a previously saved hierarchy.
*/
protected void restoreSelectionHierarchy() {
WidgetManager widgetManager = _pageDesign.getWidgetManager();
// If there is no widget, select none
//-----------------------------------
if( widgetManager.getWidgetCount() == 0 ){
selectWidget( null );
return;
}
// If there is a newly created single widget, select it
//-----------------------------------------------------
if( widgetManager.getWidgetCount() == 1 && _listSelectionHierarchy.size() == 0 )
_listSelectionHierarchy.add( new Integer( 0 ) );
if( _listSelectionHierarchy.size() == 0 )
return;
WidgetPart widgetRoot = widgetManager.getWidgetRoot();
restoreSelectionHierarchyRecursive( widgetRoot, 0 );
}
/**
* Attempts to restore the widget selection based on a previously saved hierarchy.
*/
protected void restoreSelectionHierarchyRecursive( WidgetPart widgetParent, int iHierarchyListIndex ) {
List listChildren = widgetParent.getChildren();
int iChildIndex = ( (Integer)_listSelectionHierarchy.get( iHierarchyListIndex ) ).intValue();
// Child no longer exists, select another widget
//----------------------------------------------
if( iChildIndex >= listChildren.size() ) {
// Select the previous child
//--------------------------
if( iChildIndex - 1 >= 0 && ( iChildIndex - 1 < listChildren.size() ) )
selectWidget( (WidgetPart)listChildren.get( iChildIndex - 1 ) );
// Select the first child
//-----------------------
else if( listChildren.size() > 0 )
selectWidget( (WidgetPart)listChildren.get( 0 ) );
// Select the parent if it is not the root
//----------------------------------------
else if( widgetParent.getParent() != null )
selectWidget( widgetParent );
return;
}
WidgetPart widgetChild = (WidgetPart)listChildren.get( iChildIndex );
// End of the array has been reached and the selected widget has been located
//---------------------------------------------------------------------------
if( iHierarchyListIndex == _listSelectionHierarchy.size() - 1 )
selectWidget( widgetChild );
else {
restoreSelectionHierarchyRecursive( widgetChild, iHierarchyListIndex + 1 );
}
}
/**
* Changes the selected widget to the specified widget. If the specified widget is null, all widgets are deselected.
*/
protected void selectWidget( WidgetPart widget ) {
// Scenario: Last widget is deleted, update properties view
//---------------------------------------------------------
if( widget == _widgetSelected ){
if( widget == null )
_pageDesign.widgetSelectedFromDesignCanvas( null );
return;
}
if( widget == null && _widgetSelected != null ) {
_widgetSelected.setSelected( false );
_widgetSelected = null;
}
else if( widget != null && _widgetSelected == null ) {
widget.setSelected( true );
_widgetSelected = widget;
}
else {
_widgetSelected.setSelected( false );
widget.setSelected( true );
_widgetSelected = widget;
}
rememberSelectionHierarchy();
_pageDesign.widgetSelectedFromDesignCanvas( _widgetSelected );
// _actionWidgetDelete.setEnabled( _widgetSelected != null );
// _actionWidgetProperties.setEnabled( _widgetSelected != null );
showWidget( widget );
}
/**
* Sets the transparency mode and amount of the design area based on the toolbar controls.
*/
public void setTransparency( int iTransparencyMode, int iTransparencyAmount ) {
_iTransparencyMode = iTransparencyMode;
_iTransparencyAmount = iTransparencyAmount;
redraw();
}
/**
*
*/
protected void setupDropLocations( int iMouseX, int iMouseY ) {
WidgetManager widgetManager = _pageDesign.getWidgetManager();
if( widgetManager == null )
return;
// Drop onto a RUI handler
//------------------------
if( widgetManager.getWidgetCount() == 0 ) {
_listDropLocations = new ArrayList();
// Compute bounds which is the client area that is showing minus margins
//----------------------------------------------------------------------
ScrolledComposite sc = (ScrolledComposite)getParent().getParent();
WidgetLayout handlerLayout = WidgetLayoutRegistry.getInstance().getWidgetLayout( "VE-HANDLER", false );
if ( handlerLayout != null ) {
handlerLayout.initialize( sc, null, _widgetDragging, widgetManager, WidgetDescriptorRegistry.getInstance(_pageDesign.getEditor().getProject()), _pageDesign.getEditor().getEditorProvider() );
handlerLayout.setupDropLocations(_listDropLocations);
}
return;
}
// Non-static positioning when dragging a widget
// If a widget being dragged has position that is absolute
// we assume that the user wants to relocate
// the widget position and not the widget statement.
// So we do not show drop locations
//--------------------------------------------------
if( _widgetDragging != null ) {
WidgetPropertyValue positionValue = _pageDesign.getEditor().getPropertyValue( _widgetDragging, "position", IVEConstants.STRING_TYPE );
String strType = null;
ArrayList listValues = null;
if( positionValue != null )
listValues = positionValue.getValues();
if( listValues != null && listValues.size() > 0 )
strType = (String)listValues.get( 0 );
if( strType != null ) {
if( strType.equalsIgnoreCase( "absolute" ) || strType.equalsIgnoreCase( "relative" ) || strType.equalsIgnoreCase( "Fixed" ) )
return;
}
}
// Static positioning: Drop onto a widget or RUI Handler
// Find the container that we are over
//------------------------------------------------------
WidgetPart widget = findDropLocationWidget( iMouseX, iMouseY );
// Optimization
//-------------
if( widget == _widgetDropLocation && _listDropLocations != null )
return;
_widgetDropLocation = widget;
_dropLocation = null;
_listDropLocations = new ArrayList();
// Do itself and its parent hierarchy
//-----------------------------------
while( widget != null ) {
setupDropLocationsForWidget( widget, _listDropLocations );
widget = widget.getParent();
}
}
/*
* setup the clickable area list.
*/
protected void setupClickableAreas() {
Iterator iterWidgets = getWidgets();
_listClickableAreas.clear();
while( iterWidgets.hasNext() == true ) {
WidgetPart widget = (WidgetPart)iterWidgets.next();
String clickableInfo = widget.getExtraInfo( "ClickableAreas" );
if ( clickableInfo == null || clickableInfo.length() == 0 ) {
continue;
}
String[] areas = clickableInfo.split(":");
if ( areas == null || areas.length == 0 ) {
return;
}
try {
String selectionProperty = areas[0];
for ( int i = 1; i < areas.length; i ++ ) {
int x = Integer.parseInt( areas[i] );
int y = Integer.parseInt( areas[++i] );
int w = Integer.parseInt( areas[++i] );
int h = Integer.parseInt( areas[++i] );
String value = areas[++i];
EvDesignOverylayClickableArea ca = new EvDesignOverylayClickableArea();
ca.clickableRect = new Rectangle( x, y, w ,h );
ca.propertyName = selectionProperty;
ca.propertyValue = value;
ca.widget = widget;
_listClickableAreas.add( ca );
}
} catch ( Exception e ) {
//do nothing
}
}
}
/**
* Creates drop locations for a widget container, such as a Box.
*/
protected void setupDropLocationsForWidget( WidgetPart widget, Collection listDropLocations ) {
// A dragged widget cannot become a sibling of its children
//---------------------------------------------------------
if( widget == _widgetDragging )
return;
WidgetLayout widgetLayout = WidgetLayoutRegistry.getInstance().getWidgetLayout( WidgetLayoutRegistry.getLayoutName(widget), isContainer( widget ) );
if ( widgetLayout != null ) {
WidgetManager widgetManager = _pageDesign.getWidgetManager();
ScrolledComposite sc = (ScrolledComposite)getParent().getParent();
widgetLayout.initialize( sc, widget, _widgetDragging, widgetManager, WidgetDescriptorRegistry.getInstance(_pageDesign.getEditor().getProject()), _pageDesign.getEditor().getEditorProvider() );
// only setup drop location when it is not root widget in RUIWidget
if(!((widgetLayout instanceof RootWidgetLayout) && getDesignPage().getEditor().getEditorProvider().isRUIWidget())){
widgetLayout.setupDropLocations(listDropLocations);
}
}
}
/**
* Determines the drop location that contains the given mouse position.
* The rectangle is painted in paintDropLocations.
*/
protected void setupNextDropLocation( int iX, int iY ) {
if( _listDropLocations == null )
return;
// Compute the drop rectangle
//---------------------------
_dropLocation = null;
// Remember for the overlay painter
//---------------------------------
_ptMouse.x = iX;
_ptMouse.y = iY;
// Test for the mouse over a drop location
//----------------------------------------
Iterator iterLocations = _listDropLocations.iterator();
while( iterLocations.hasNext() == true ) {
EvDesignOverlayDropLocation location = (EvDesignOverlayDropLocation)iterLocations.next();
if( location.rectDrop.contains( iX, iY ) == true ) {
_dropLocation = location;
break;
}
}
if( _dropLocation != null )
return;
// Proximity test
//---------------
iterLocations = _listDropLocations.iterator();
while( iterLocations.hasNext() == true ) {
EvDesignOverlayDropLocation location = (EvDesignOverlayDropLocation)iterLocations.next();
Rectangle rectProximity = new Rectangle( location.rectDrop.x - 8, location.rectDrop.y - 8, location.rectDrop.width + 16, location.rectDrop.height + 16 );
if( rectProximity.contains( iX, iY ) == true ) {
_dropLocation = location;
break;
}
}
if( _dropLocation != null )
return;
/* The nearsst drop lacation search will cuase some unexpected results, see WI 66498
// Find the nearest drop location center
//--------------------------------------
double dMinimum = Double.MAX_VALUE;
EvDesignOverlayDropLocation locationMinimum = null;
iterLocations = _listDropLocations.iterator();
while( iterLocations.hasNext() == true ) {
EvDesignOverlayDropLocation location = (EvDesignOverlayDropLocation)iterLocations.next();
int iAbsoluteDeltaX = Math.abs( iX - ( location.rectDrop.x + location.rectDrop.width / 2 ) );
int iAbsoluteDeltaY = Math.abs( iY - ( location.rectDrop.y + location.rectDrop.height / 2 ) );
double dDistanceSquared = (double)iAbsoluteDeltaX * (double)iAbsoluteDeltaX + (double)iAbsoluteDeltaY * (double)iAbsoluteDeltaY;
double dDistance = Math.sqrt( dDistanceSquared );
if( dDistance < dMinimum ) {
dMinimum = dDistance;
locationMinimum = location;
}
}
// Allow for not dropping
//-----------------------
if( dMinimum < 64 )
_dropLocation = locationMinimum;
*/
}
/**
* Sets the widget that the mouse is over based on the current selection, and the current widget that the mouse is over.
*/
protected void setupNextSelectionWidget( int iX, int iY ) {
List listWidgets = getWidgetsAtPoint( new Point( iX, iY ) );
WidgetPart widget = null;
// Mouse is no longer over a widget
//---------------------------------
if( listWidgets.size() == 0 ) {
// No widget in the list
}
// If the currently selected widget is in the list, select the next one
// If not in the list, select the first in the list
//---------------------------------------------------------------------
else if( _widgetSelected != null )
widget = findNextWidgetInList( _widgetSelected, listWidgets );
// Use the widget with the greatest origin
//----------------------------------------
else
widget = (WidgetPart)listWidgets.get( 0 );
// Do nothing if the widget found is the same as the current one
//--------------------------------------------------------------
if( widget == _widgetNextSelection )
return;
// Deactivate any existing mouse over widget
//------------------------------------------
if( _widgetNextSelection != null ) {
_widgetNextSelection.setMouseOver( false );
_widgetNextSelection = null;
}
// Activate the new mouse over widget
//-----------------------------------
if( widget != null ) {
widget.setMouseOver( true );
_widgetNextSelection = widget;
}
}
/**
* Ensures that the specified rectangle is displayed within the design area.
*/
protected void showRectangle( Rectangle rectShow ){
ScrolledComposite scroll = (ScrolledComposite)getParent().getParent();
Rectangle rectClient = scroll.getClientArea();
Point ptOrigin = scroll.getOrigin();
rectClient.x = ptOrigin.x;
rectClient.y = ptOrigin.y;
if( rectShow.width < 1 )
rectShow.width = 1;
if( rectShow.height < 1 )
rectShow.height = 1;
// See if the center portion of the widget is seen
//------------------------------------------------
if( rectClient.intersects( rectShow ) == false ){
final int PADDING = 20;
if( rectShow.x < rectClient.x )
rectClient.x = rectShow.x - PADDING;
else
rectClient.x = rectShow.x + rectShow.width - rectClient.width + PADDING;
if( rectShow.y < rectClient.y )
rectClient.y = rectShow.y - PADDING;
else
rectClient.y = rectShow.y + rectShow.height - rectClient.height + PADDING;
scroll.setOrigin( rectClient.x, rectClient.y );
// _pageDesign.capture();
}
}
/**
* Ensures that the specified widget is displayed within the design area
*/
protected void showWidget( WidgetPart widget ) {
if( widget == null )
return;
// Use the center portion of the widget
//-------------------------------------
Rectangle rectWidget = widget.getBounds();
Rectangle newRectWidget = new Rectangle(0, 0, 0, 0 );
newRectWidget.x = rectWidget.x + 4;
newRectWidget.y = rectWidget.y + 4;
newRectWidget.width = rectWidget.width - 8;
newRectWidget.height = rectWidget.height - 8;
showRectangle( rectWidget );
}
/**
* Called by this constructor, and by the design page whenever the selection color preference has changed.
*/
public void updateColors() {
// Potential drop target
//----------------------
String strColor = EvPreferences.getString( EvConstants.PREFERENCE_COLOR_DROP_LOCATION_POTENTIAL );
// Convert from 255, 255, 255 to a color
//--------------------------------------
Color color = ColorUtil.getColorFromRGBString( Display.getCurrent(), strColor );
if( color != null ) {
// Dispose of any existing color
//------------------------------
if( _colorDropTargetPotential != null && _colorDropTargetPotential.isDisposed() == false )
_colorDropTargetPotential.dispose();
// Establish the new color
//------------------------
_colorDropTargetPotential = color;
}
// Selected drop target
//---------------------
strColor = EvPreferences.getString( EvConstants.PREFERENCE_COLOR_DROP_LOCATION_SELECTED );
// Convert from 255, 255, 255 to a color
//--------------------------------------
color = ColorUtil.getColorFromRGBString( Display.getCurrent(), strColor );
if( color != null ) {
// Dispose of any existing color
//------------------------------
if( _colorDropTargetSelected != null && _colorDropTargetSelected.isDisposed() == false )
_colorDropTargetSelected.dispose();
// Establish the new color
//------------------------
_colorDropTargetSelected = color;
}
// Widget selection
//-----------------
strColor = EvPreferences.getString( EvConstants.PREFERENCE_COLOR_SELECTION );
// Convert from 255, 255, 255 to a color
//--------------------------------------
color = ColorUtil.getColorFromRGBString( Display.getCurrent(), strColor );
if( color == null )
return;
// Dispose of any existing color
//------------------------------
if( _colorWidgetSelected != null && _colorWidgetSelected.isDisposed() == false )
_colorWidgetSelected.dispose();
// Establish the new color
//------------------------
_colorWidgetSelected = color;
_painter.updateColors();
redraw();
}
/**
* Declared in DisposeListener.
* Called when this composite is disposed. All colors are disposed.
*/
public void widgetDisposed( DisposeEvent e ) {
if( _colorDropTargetPotential != null && _colorDropTargetPotential.isDisposed() == false ) {
_colorDropTargetPotential.dispose();
_colorDropTargetPotential = null;
}
if( _colorDropTargetSelected != null && _colorDropTargetSelected.isDisposed() == false ) {
_colorDropTargetSelected.dispose();
_colorDropTargetSelected = null;
}
if( _colorWidgetSelected != null && _colorWidgetSelected.isDisposed() == false ) {
_colorWidgetSelected.dispose();
_colorWidgetSelected = null;
}
if( _cursorWait != null && _cursorWait.isDisposed() == false ){
_cursorWait.dispose();
_cursorWait = null;
}
if( _imageDoubleBuffer != null && _imageDoubleBuffer.isDisposed() == false ){
_imageDoubleBuffer.dispose();
_imageDoubleBuffer = null;
}
}
/**
* The widget manager has a widget set.
*/
public void widgetsChanged() {
_widgetDragging = null;
_widgetMouseDown = null;
_widgetNextSelection = null;
_widgetSelected = null;
_ptDropLocations = null;
_listDropLocations = null;
_dropLocation = null;
// If there are no widgets, display the start instruction when painting
// and scroll the window to the top left corner so the user can see it
//---------------------------------------------------------------------
_bShowInstructions = getWidgets().hasNext() == false;
if( _bShowInstructions == true ){
ScrolledComposite scroll = (ScrolledComposite)getParent().getParent();
scroll.setOrigin( 0, 0 );
}
setupClickableAreas();
restoreSelectionHierarchy();
showWidget( _widgetSelected );
_pageDesign.capture();
// Repaint
//--------
Display display = getDisplay();
if( !display.isDisposed() ) {
display.asyncExec( new Runnable() {
public void run() {
redraw();
}
} );
}
}
}