/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.mapping.ui.editor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.draw2d.CoordinateListener;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.ui.IWorkbenchPart;
import org.teiid.core.designer.util.I18nUtil;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.diagram.ui.DiagramUiPlugin;
import org.teiid.designer.diagram.ui.editor.DiagramController;
import org.teiid.designer.diagram.ui.editor.DiagramEditor;
import org.teiid.designer.diagram.ui.editor.DiagramSelectionHandler;
import org.teiid.designer.diagram.ui.editor.DiagramViewer;
import org.teiid.designer.diagram.ui.model.DiagramModelNode;
import org.teiid.designer.diagram.ui.notation.uml.model.UmlClassifierNode;
import org.teiid.designer.diagram.ui.notation.uml.part.UmlClassifierEditPart;
import org.teiid.designer.mapping.factory.IMappableTree;
import org.teiid.designer.mapping.factory.ITreeToRelationalMapper;
import org.teiid.designer.mapping.factory.ModelMapperFactory;
import org.teiid.designer.mapping.factory.TreeMappingAdapter;
import org.teiid.designer.mapping.ui.PluginConstants;
import org.teiid.designer.mapping.ui.UiConstants;
import org.teiid.designer.mapping.ui.UiPlugin;
import org.teiid.designer.mapping.ui.diagram.MappingDiagramSelectionHandler;
import org.teiid.designer.mapping.ui.diagram.MappingDiagramUtil;
import org.teiid.designer.mapping.ui.model.MappingDiagramModelFactory;
import org.teiid.designer.mapping.ui.part.MappingDiagramEditPart;
import org.teiid.designer.mapping.ui.part.MappingDiagramEditPart.TopAndBottomClassifierInfo;
import org.teiid.designer.metamodels.diagram.Diagram;
import org.teiid.designer.metamodels.transformation.InputSet;
import org.teiid.designer.metamodels.transformation.MappingClass;
import org.teiid.designer.metamodels.transformation.MappingClassColumn;
import org.teiid.designer.ui.common.eventsupport.SelectionUtilities;
import org.teiid.designer.ui.common.viewsupport.UiBusyIndicator;
import org.teiid.designer.ui.event.IRevealHideListener;
import org.teiid.designer.ui.viewsupport.ModelUtilities;
/**
* @since 8.0
*/
public class MappingDiagramController
implements DiagramController, ISelectionChangedListener, IRevealHideListener, UiConstants {
DocumentTreeController documentController;
DiagramEditor diagramEditor;
int scrollBarYPosition = 0;
int treeYOrigin = 0;
private ScrollBar scrollBar = null;
private int mappingType = PluginConstants.COARSE_MAPPING;
private SelectionAdapter verticalScrollAdapter;
private DocumentNotificationHandler notificationHandler;
private CoordinateListener coordinateListener;
private Diagram currentDiagram;
boolean limitAutoScroll = false;
private static final int SCROLL_OBJECT_LIMIT = 100;
private static final int SCROLL_EXTENT_LIMIT = 40;
static final String PREFIX = I18nUtil.getPropertyPrefix(MappingDiagramController.class);
private List visibleMappingClasses = new ArrayList();
private boolean bSynchronizeInProgress = false;
private MappingDiagramBehavior mappingDiagramBehavior;
private IDoubleClickListener dclDocumentTreeDoubleClickListener;
public MappingDiagramController( DiagramEditor editor ) {
super();
this.diagramEditor = editor;
this.documentController = new DocumentTreeController(this);
documentController.createControl((Composite)diagramEditor.getPrimaryControl().getSashForm());
documentController.getControl().moveAbove(diagramEditor.getDiagramViewer().getControl());
diagramEditor.getPrimaryControl().setControllerControl(documentController.getControl());
diagramEditor.getModelObjectSelectionProvider().addSelectionChangedListener(documentController);
}
@Override
public void setDiagramEditor( DiagramEditor editor ) {
diagramEditor = editor;
}
public ModelResource getCurrentModelResource() {
ModelResource mr = null;
if (diagramEditor != null && diagramEditor.getDiagram() != null) {
mr = ModelUtilities.getModelResourceForModelObject(diagramEditor.getDiagram());
}
return mr;
}
public EObject getDocumentEObject() {
EObject targetEO = null;
if (getMappingType() == PluginConstants.DETAILED_MAPPING) {
MappingClass mappingClassEO = (MappingClass)currentDiagram.getTarget();
targetEO = mappingClassEO.getMappingClassSet().getTarget();
} else targetEO = currentDiagram.getTarget();
return targetEO;
}
/**
* @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart,
* org.eclipse.jface.viewers.ISelection)
*/
@Override
public void selectionChanged( IWorkbenchPart part,
ISelection selection ) {
// System.out.println("[MappingDiagramController.selectionChanged(IWorkbenchPart part, ISelection selection)] TOP!!!");
List selectedEObjects = SelectionUtilities.getSelectedEObjects(selection);
if (!selectedEObjects.isEmpty()) {
getDocumentTreeController().setSelection(selection);
}
}
/**
* @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
*/
@Override
public void selectionChanged( SelectionChangedEvent event ) {
// System.out.println("[MappingDiagramController.selectionChanged(SelectionChangedEvent event)] TOP!!!");
ISelection selection = event.getSelection();
List selectedEObjects = SelectionUtilities.getSelectedEObjects(selection);
if (!selectedEObjects.isEmpty()) {
diagramEditor.getDiagramViewer().getSelectionHandler().select(selection);
// Now we need to tell the extents to reposition themselves because the selection may have auto-scrolled the diagram.
if (diagramEditor.getControl() != null && !diagramEditor.getControl().isDisposed()) {
documentController.resetExtentsFromDocument();
}
}
}
/**
* @see org.teiid.designer.diagram.ui.editor.DiagramController#wireDiagram(org.teiid.designer.metamodels.diagram.Diagram)
*/
@Override
public void wireDiagram( Diagram theInput ) {
// System.out.println("[MappingDiagramController.wireDiagram] TOP!!!");
try {
currentDiagram = theInput;
// Let's set mapping type;
if (theInput.getType() != null && theInput.getType().equals(PluginConstants.MAPPING_TRANSFORMATION_DIAGRAM_TYPE_ID)) setMappingType(PluginConstants.DETAILED_MAPPING);
else setMappingType(PluginConstants.COARSE_MAPPING);
addVerticalScrollListener();
addCoordinateListener();
// Let's get the diagram's target and that should be the input to the viewer
// This needs to be the document. If diagram is "Detailed" we need to find the document from this.
EObject targetEO = null;
if (getMappingType() == PluginConstants.DETAILED_MAPPING) {
MappingClass mappingClassEO = (MappingClass)theInput.getTarget();
targetEO = mappingClassEO.getMappingClassSet().getTarget();
// jh Defect 18919: Set up double click listening on the document tree
addDocumentTreeListener();
} else targetEO = theInput.getTarget();
if (targetEO != null) {
documentController.getViewer().setXmlMappingTarget(targetEO);
DocumentContentProvider provider = new DocumentContentProvider(this);
documentController.getViewer().setContentProvider(provider);
documentController.addSelectionChangedListener(this);
documentController.getViewer().setInput(targetEO);
// ExpandAll only if the MappingClass count is less than 20, otherwise only expand to first level.
documentController.getViewer().getControl().setRedraw(false);
// System.out.println("[MappingDiagramController.wireDiagram] About to call: diagramEditor.getDiagramViewForm().setRedraw( false ) ");
// diagram
diagramEditor.getDiagramViewForm().setRedraw(false);
/*
* jh research for Defect 18038: applying a previous Expanded State to the Mapping tree
* == This appears to be the point of expanding the tree when
* == setting the tree up for the first time.
*
* == The enhancement would be to
* 0. if the type is 'coarse':
* 1. discover if we have previously saved an expanded state
* for this XML model
* diagramEditor
* diagramEditor.getCurrentModel()
* 2. if so, apply it to the viewer like this:
* viewer.setExpandedElements( oExpandedElements );
*
* 3. if not, do expandAll()
*
*/
/*
* jh Lyra enh:
* Further Issue: Should this autoexpand be done in a separate thread to
* avoid some looping problem??????? Or should we turn some listening off
* before we do it??????????
*/
if (getMappingType() == PluginConstants.COARSE_MAPPING) {
Object[] oExpandedElements = (Object[])diagramEditor.getTreeStatesMap().get(getDocumentEObject());
if (oExpandedElements != null) {
documentController.getViewer().setExpandedElements(oExpandedElements);
} else {
doDefaultExpansion();
}
} else {
doDefaultExpansion();
}
// tree
// System.out.println("[MappingDiagramController.wireDiagram] About to call: diagramEditor.getDiagramViewForm().setRedraw( true ) ");
documentController.getViewer().getControl().setRedraw(true);
// diagram
diagramEditor.getDiagramViewForm().setRedraw(true);
ITreeToRelationalMapper mapper = ModelMapperFactory.createModelMapper(targetEO);
notificationHandler = new DocumentNotificationHandler(this, mapper.getMappableTree());
documentController.getViewer().setMappingType(getMappingType());
// jh Lyra enh: REDUNDANT, DUPLICATES LINE 177!:
// documentController.getViewer().setXmlMappingTarget(targetEO);
documentController.getViewer().getTree().getVerticalBar().setSelection(0);
}
} catch (Exception ex) {
Util.log(IStatus.ERROR, ex, ex.getClass().getName());
}
refresh(false);
// if(getMappingType() == PluginConstants.DETAILED_MAPPING ) {
// // Let's find the mappingClass eObject here and tell the diagram to select it!
// // Should be diagram target
//
// EObject mappingClassEObject = ((Diagram)theInput).getTarget();
// diagramEditor.getDiagramViewer().getSelectionHandler().select(mappingClassEObject);
// }
// System.out.println("[MappingDiagramController.wireDiagram] BOT!!!");
}
private void addDocumentTreeListener() {
if (dclDocumentTreeDoubleClickListener == null) {
dclDocumentTreeDoubleClickListener = new IDoubleClickListener() {
@Override
public void doubleClick( DoubleClickEvent event ) {
IStructuredSelection sel = (IStructuredSelection)event.getSelection();
Object element = sel.getFirstElement();
if (element instanceof EObject) {
EObject selectedEObject = (EObject)element;
// get MappingClass for this treenode
// 1. See if this node is a Mapping Class Root
MappingClass mc = getMappingAdapter().getMappingClass(selectedEObject);
if (mc == null) {
mc = getMappingAdapter().getStagingTable(selectedEObject);
}
// 2. if not a root, see if it is a mappable column, and get the Mapping Class it is capable of mapping
// to.
// (This should work whether or not the column is currently mapped.)
if (mc == null) {
mc = getMappingAdapter().getMappingClass(selectedEObject);
}
// if we found a Mapping Class using one of the two methods, open the Detailed diagram on that mc
if (mc != null) {
MappingDiagramSelectionHandler mdsh = (MappingDiagramSelectionHandler)diagramEditor.getDiagramViewer().getSelectionHandler();
mdsh.handleDoubleClick(mc);
}
}
}
};
}
documentController.getViewer().addDoubleClickListener(dclDocumentTreeDoubleClickListener);
}
private void removeDocumentTreeListener() {
if (dclDocumentTreeDoubleClickListener != null) {
documentController.getViewer().removeDoubleClickListener(dclDocumentTreeDoubleClickListener);
}
}
private void doDefaultExpansion() {
// System.out.println("[MappingDiagramController.doDefaultExpansion] TOP");
/*
* jh Lyra enh: Why are we hardcoding true here? Why aren't we listening to the events and keeping
* our internal state up to date, so we do not have to rebuild it from scratch everytime someone
* expands a tree node?????
*
* Note: Changing true to false here and one other place Seems To Be Working!
*/
TreeMappingAdapter mappingAdapter = documentController.getViewer().getMappingAdapterFilter(false).getMappingAdapter();
List mappingClasses = mappingAdapter.getAllMappingClasses();
/*
* jhTODO Lyra enh: We will at least formalize Mark's performance fix as a preference. For now,
* I am adjusting it downward to assist my own testing (to avoid expandall).
*/
if (mappingClasses.size() < getLargeMappingClassBreakpointPreference()) {
documentController.getViewer().expandAll();
} else {
documentController.getViewer().expandToLevel(getExpandLevelPreference());
}
}
private int getExpandLevelPreference() {
// set last-ditch default, in case pref is not available
int iResult = 1;
String sExpandLevelVal = UiPlugin.getDefault().getPreferenceStore().getString(PluginConstants.Prefs.AUTO_EXPAND_TARGET_LEVEL);
try {
Integer IVal = new Integer(sExpandLevelVal);
if (IVal.intValue() > 0) {
iResult = IVal.intValue();
}
} catch (Exception e) {
// no action
}
return iResult;
}
private int getLargeMappingClassBreakpointPreference() {
// set last-ditch default, in case pref is not available
int iResult = 20;
String sMaxMappingVal = UiPlugin.getDefault().getPreferenceStore().getString(PluginConstants.Prefs.AUTO_EXPAND_MAX_MAPPING_CLASSES);
try {
Integer IVal = new Integer(sMaxMappingVal);
if (IVal.intValue() > 0) {
iResult = IVal.intValue();
}
} catch (Exception e) {
// no action
}
return iResult;
}
@Override
public void deactivate() {
diagramEditor.getModelObjectSelectionProvider().removeSelectionChangedListener(documentController);
removeVerticalScrollListener();
removeCoordinateListener();
/*
* jh research for Defect 18038: saving the Expanded State from the Mapping tree
* == This ( deactivete() appears to be the point at which we should
* == save the expanded state of the tree.
*
* Code will look like this:
* Object[] oExpandedElements = viewer.getExpandedElements();
*
* Still need to determine where we can persist this info and for what
* lifecycle period (Session; or between sessions).
*
*/
if (getMappingType() == PluginConstants.COARSE_MAPPING) {
Object[] oExpandedElements = documentController.getViewer().getExpandedElements();
diagramEditor.getTreeStatesMap().put(getDocumentEObject(), oExpandedElements);
}
// jh Defect 18919: Remove double click listening on the document tree
removeDocumentTreeListener();
}
@Override
public void dispose() {
// Tell DocumentTreeController to clean up it's listeners....
// Defect 22290 reflects memory (leaks) issues within designer.
// Need to tell controller to clean up somehow. Added method dispose() to controller.
documentController.dispose();
}
/**
* @return
*/
public int getMappingType() {
return mappingType;
}
public DocumentTreeController getDocumentTreeController() {
return documentController;
}
/**
* @param i
*/
public void setMappingType( int i ) {
mappingType = i;
}
void refreshDiagram( IProgressMonitor theMonitor,
boolean forceMappingClassReconcile ) {
IProgressMonitor monitor = theMonitor;
try {
boolean showProgress = (monitor != null);
if (showProgress) {
monitor.subTask(Util.getString(PREFIX + "monitorRefreshDiagram")); //$NON-NLS-1$
}
if (diagramEditor.getDiagram() != null && diagramEditor.getCurrentModel() != null) {
/*
* jh Lyra enh: Why are we hard-coding this to true? Try false.
*/
MappingAdapterFilter mappingFilter = documentController.getViewer().getMappingAdapterFilter(false);
MappingDiagramModelFactory modelFactory = (MappingDiagramModelFactory)DiagramUiPlugin.getDiagramTypeManager().getDiagram(PluginConstants.MAPPING_DIAGRAM_TYPE_ID).getModelFactory();
if (showProgress) {
showProgress = !mappingFilter.getMappingAdapter().getAllMappingClasses().isEmpty();
}
if (!showProgress) {
monitor = new NullProgressMonitor();
}
// -------------------------------------------------
// Let's wrap this in a transaction!!! that way all constructed objects and layout properties
// will result in only one transaction?
// -------------------------------------------------
boolean requiredStart = ModelerCore.startTxn(false, false, "Refresh Diagram", this); //$NON-NLS-1$
boolean succeeded = false;
try {
if (showProgress) {
monitor.subTask(Util.getString(PREFIX + "taskRefreshDiagram")); //$NON-NLS-1$
monitor.worked(20);
}
modelFactory.refresh(diagramEditor.getCurrentModel(),
diagramEditor.getDiagram(),
mappingFilter,
forceMappingClassReconcile,
monitor);
// Make a call to synch. up the extents and new scrollbar in diagram.
if (showProgress) {
monitor.subTask(Util.getString(PREFIX + "taskAutolayout")); //$NON-NLS-1$
monitor.worked(10);
}
updateForAutoLayout();
/*
* jh Lyra enh/defect 20457: Losing selection: The following code is explicitly selecting
* the current MAPPING CLASS. no wonder I cannot get an extent selection
* to persist. Dropping this.
*/
// if( getMappingType() == PluginConstants.DETAILED_MAPPING ) {
// EObject mappingClassEObject = diagramEditor.getDiagram().getTarget();
// diagramEditor.getDiagramViewer().getSelectionHandler().select(mappingClassEObject);
// }
MappingDiagramUtil.hiliteUnconnectedExtents(diagramEditor.getCurrentModel());
succeeded = true;
} finally {
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
// -------------------------------------------------
}
} catch (Exception ex) {
UiConstants.Util.log(IStatus.ERROR, ex, ex.getClass().getName());
} finally {
limitAutoScroll = false;
if (diagramEditor != null && diagramEditor.getCurrentModel() != null
&& diagramEditor.getCurrentModel().getChildren() != null) {
int nExt = getNumberOfExtents(diagramEditor.getCurrentModel());
limitAutoScroll = (diagramEditor.getCurrentModel().getChildren().size() > SCROLL_OBJECT_LIMIT)
|| nExt > SCROLL_EXTENT_LIMIT;
}
}
// System.out.println("\n[MappingDiagramController.refreshDiagram] BOT" );
}
/**
* Determine if mapping classes have changed since last refresh.
*
* @return true if mappingClasses have changed, false if not
*/
private boolean mappingClassesChanged() {
// System.out.println("\n[MappingDiagramController.mappingClassesChanged] TOP ");
boolean haveChanged = true;
// Get Current MappingClass list
/*
* jh Lyra enh: Why are we hardcoding true here? Why aren't we listening to the events and keeping
* our internal state up to date, so we do not have to rebuild it from scratch everytime someone
* expands a tree node?????
*
* Note: Changing true to false here and one other place Seems To Be Working!
* Wait...The 'getMappingAdapterFilter( true )' call may have been the only way for us to update
* the inventory of visible mapping classes. Try setting it back to true.
* Ok, 'true' gets us back into the situation where all components subordinate to the MappingAdapterFilter
* are recreated many times. Instead let's fix MAFilter so we can get it to refresh Mapping Classes
* by calling a method. Duh.
*/
// MappingAdapterFilter mappingFilter = documentController.getViewer().getMappingAdapterFilter(false);
// Ok, this is a low-frequency call, so we can try using TRUE
/*
* jhTODO jh Lyra enh: This is the heart of our performance improvement. If we can ensure that we only set this arg to true
* when something has been added or removed, that would be best.
*/
// System.out.println("[MappingDiagramController.mappingClassesChanged] About to call 'getMappingAdapterFilter(true)' ");
// jh Lyra enh: debugging 1 27 2006: we are creating TreeMappingAdapter multiple times;
// try setting this to false:
// MappingAdapterFilter mappingFilter = documentController.getViewer().getMappingAdapterFilter( true );
MappingAdapterFilter mappingFilter = documentController.getViewer().getMappingAdapterFilter(false);
List currentMappingClasses = mappingFilter.getMappedClassifiers();
// if list sizes are the same, do further checking between the saved list and current list.
if (!visibleMappingClasses.isEmpty() && visibleMappingClasses.size() == currentMappingClasses.size()) {
boolean allSame = true;
Iterator currIter = currentMappingClasses.iterator();
while (currIter.hasNext()) {
// If difference found, set false and break
if (!visibleMappingClasses.contains(currIter.next())) {
allSame = false;
break;
}
}
// if allSame, set overall status false - no changes detected
if (allSame) {
haveChanged = false;
}
}
// Update stored MappingClass List
visibleMappingClasses = currentMappingClasses;
// System.out.println("\n[MappingDiagramController.mappingClassesChanged] About to return: " + haveChanged);
return haveChanged;
}
private int getNumberOfExtents( Object diagramModelNode ) {
MappingDiagramModelFactory modelFactory = (MappingDiagramModelFactory)DiagramUiPlugin.getDiagramTypeManager().getDiagram(PluginConstants.MAPPING_DIAGRAM_TYPE_ID).getModelFactory();
if (modelFactory != null) return modelFactory.getNumberOfMappingExtents(diagramModelNode);
return 0;
}
public void refresh( boolean forceMappingClassReconcile ) {
// System.out.println("[MappingDiagramController.refresh] TOP; forceMappingClassReconcile is: " +
// forceMappingClassReconcile );
// Check if document object exists or not (i.e. there may have been a delete model)
if (getDocumentEObject() == null || getDocumentEObject().eResource() == null) {
return;
}
/*
* jh Lyran enh: Important fix: Adding a 'force' flag to this method and the ones
* it calls fixed the problem of a new staging table not being displayed
* in the diagram until you collapsed and re expanded its parent in the tree.
*/
MappingAdapterFilter filter = getMappingFilter(forceMappingClassReconcile);
final boolean reconcileMappingClasses = (forceMappingClassReconcile) ? true : mappingClassesChanged();
if (filter != null) {
// -----------------------------
// Defect 23360
// this little block of code was throwing NPE because it was outside the filter != null above.
if (forceMappingClassReconcile) {
filter.setTreeExpansionMonitorStale();
}
int nVisibleObjects = filter.getNumberVisibleNodes();
if (nVisibleObjects < 60) {
UiBusyIndicator.showWhile(Display.getCurrent(), new Runnable() {
@Override
public void run() {
refreshDiagram(null, reconcileMappingClasses);
}
});
} else {
final IRunnableWithProgress op = new IRunnableWithProgress() {
@Override
public void run( final IProgressMonitor monitor ) {
monitor.beginTask(Util.getString(PREFIX + "taskMappingDiagram"), 100); //$NON-NLS-1$
diagramEditor.getDiagramViewForm().setRedraw(false);
refreshDiagram(monitor, reconcileMappingClasses);
diagramEditor.getDiagramViewForm().setRedraw(true);
}
};
try {
final ProgressMonitorDialog dlg = new ProgressMonitorDialog(documentController.getControl().getShell());
dlg.run(false, true, op);
if (dlg.getProgressMonitor().isCanceled()) {
return;
}
} catch (final InterruptedException ignored) {
} catch (final Exception err) {
}
}
}
}
// Method used by DocumentTree
public void resetExtentLocations( int newY ) {
final int tempY = newY;
if (diagramEditor.getDiagram() != null) {
final Diagram thisDiagram = diagramEditor.getDiagram();
final DiagramModelNode diagramNode = diagramEditor.getCurrentModel();
if (thisDiagram != null && diagramNode != null) {
UiBusyIndicator.showWhile(Display.getCurrent(), new Runnable() {
@Override
public void run() {
MappingAdapterFilter mappingFilter = documentController.getMappingAdapterFilter();
MappingDiagramModelFactory modelFactory = (MappingDiagramModelFactory)DiagramUiPlugin.getDiagramTypeManager().getDiagram(PluginConstants.MAPPING_DIAGRAM_TYPE_ID).getModelFactory();
modelFactory.resetExtentLocations(diagramNode, thisDiagram, mappingFilter, tempY);
}
});
}
}
}
// Method used by DocumentTree
public void resetExtentLocationsFromDocument( int newY ) {
final int tempY = newY;
UiBusyIndicator.showWhile(Display.getCurrent(), new Runnable() {
@Override
public void run() {
// System.out.println("[MappingtDiagramConotroller.resetExtentLocationsFromDocument$run]");
treeYOrigin = tempY;
ScrollingGraphicalViewer scrolledViewer = diagramEditor.getDiagramViewer();
FigureCanvas scrolledCanvas = (FigureCanvas)scrolledViewer.getControl();
int viewportY = scrolledCanvas.getViewport().getViewLocation().y;
int yValue = tempY + viewportY;// scrollBarYPosition;
resetExtentLocations(yValue);
}
});
}
public int getScrollOffset() {
return treeYOrigin;
}
// Method used by DocumentTree
public void resetExtentLocationsFromDiagram( int newY ) { // NO_UCD
final int tempY = newY;
UiBusyIndicator.showWhile(Display.getCurrent(), new Runnable() {
@Override
public void run() {
// System.out.println("[MappingtDiagramConotroller.resetExtentLocationsFromDiagram$run]");
scrollBarYPosition = tempY;
int yValue = tempY + treeYOrigin;
int minY = getDiagramYMin();
int maxY = getDiagramYMax();
int currentCanvasHeight = maxY - minY;
if (minY < 0 && treeYOrigin < 0) {
// we are already in negative territory, so let's get the current.
// We want to be at treeYOrigin
// Current Y = minY
// Desired Y = Delta from total difference
int deltaYSB = scrollBarYPosition + treeYOrigin;
// Then we move to minY - delta
yValue = minY + deltaYSB;
// scrollBar will change
scrollBarYPosition = scrollBarYPosition * (currentCanvasHeight + yValue) / currentCanvasHeight;
}
resetExtentLocations(yValue);
}
});
}
private void addVerticalScrollListener() {
final DiagramViewer scrolledViewer = diagramEditor.getDiagramViewer();
FigureCanvas scrolledCanvas = (FigureCanvas)scrolledViewer.getControl();
scrollBar = scrolledCanvas.getVerticalBar();
verticalScrollAdapter = new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent theEvent ) {
// don't process drag events since there are so many of them. another event
// is received when the drag is done
if (theEvent.detail != SWT.DRAG) {
autoScrollToReveal();
// System.out.println("[MappingDiagramController.addVerticalScrollListener$widgetSelected]");
documentController.resetExtentsFromDocument();
}
if (!limitAutoScroll || (limitAutoScroll && (theEvent.detail != SWT.DRAG))) {
// jh Defect 21263
documentController.resetExtentsFromDocument();
}
}
};
scrollBar.addSelectionListener(verticalScrollAdapter);
}
private void removeVerticalScrollListener() {
if (verticalScrollAdapter != null && diagramEditor.getDiagramViewer().isValidViewer()) {
ScrollingGraphicalViewer scrolledViewer = diagramEditor.getDiagramViewer();
FigureCanvas scrolledCanvas = (FigureCanvas)scrolledViewer.getControl();
scrollBar = scrolledCanvas.getVerticalBar();
scrollBar.removeSelectionListener(verticalScrollAdapter);
}
}
// ===========================================================
// jh Defect 21263: added coordinate listener to reset extents when user drags mapping
// class beyond viewport (effectively enlarging the viewport).
private void addCoordinateListener() {
if (coordinateListener == null) {
coordinateListener = new CoordinateListener() {
@Override
public void coordinateSystemChanged( IFigure f ) {
// System.out.println("[MappingDiagramController.addCoordinateControlListener$coordinateSystemChanged]");
documentController.resetExtentsFromDocument();
}
};
}
final DiagramViewer scrolledViewer = diagramEditor.getDiagramViewer();
FigureCanvas scrolledCanvas = (FigureCanvas)scrolledViewer.getControl();
scrolledCanvas.getViewport().addCoordinateListener(coordinateListener);
}
private void removeCoordinateListener() {
if (coordinateListener != null && diagramEditor.getDiagramViewer().isValidViewer()) {
ScrollingGraphicalViewer scrolledViewer = diagramEditor.getDiagramViewer();
FigureCanvas scrolledCanvas = (FigureCanvas)scrolledViewer.getControl();
scrolledCanvas.getViewport().removeCoordinateListener(coordinateListener);
}
}
/**
* @see org.teiid.designer.diagram.ui.editor.DiagramController#getSelectionSource()
*/
@Override
public ISelectionProvider getSelectionSource() {
return this.documentController;
}
/**
* @see org.teiid.designer.diagram.ui.editor.DiagramController#handleNotification(org.eclipse.emf.common.notify.Notification)
*/
@Override
public void handleNotification( Notification notification ) {
if (notificationHandler != null) notificationHandler.handleNotification(notification);
}
void autoScrollToReveal() {
EditPart diagramEditPart = diagramEditor.getDiagramViewer().getContents();
// only autoscroll if a mapping diagram:
if (diagramEditPart instanceof MappingDiagramEditPart) {
// determine if classifiers are visible:
Rectangle vpRect = ((FigureCanvas)diagramEditor.getDiagramViewer().getControl()).getViewport().getBounds();
Point vpLoc = diagramEditor.getDiagramViewer().getViewportLocation();
MappingDiagramEditPart mdep = (MappingDiagramEditPart)diagramEditPart;
TopAndBottomClassifierInfo info = mdep.getTopAndBottomClassifierInfo();
if (info.bottomY < vpLoc.y) {
if (info.bottomPart != null) diagramEditor.getDiagramViewer().reveal(info.bottomPart);
} else if (info.topY > vpLoc.y + vpRect.height) {
if (info.topPart != null) diagramEditor.getDiagramViewer().reveal(info.topPart);
}
}
}
/**
* @see org.teiid.designer.diagram.ui.editor.DiagramController#isControllerOK(org.teiid.designer.metamodels.diagram.Diagram)
*/
@Override
public boolean maintainControl( Diagram newDiagram ) {
boolean isSameDocument = false;
try {
// Let's set mapping type;
int newMappingType = PluginConstants.COARSE_MAPPING;
if (newDiagram.getType() != null
&& newDiagram.getType().equals(PluginConstants.MAPPING_TRANSFORMATION_DIAGRAM_TYPE_ID)) newMappingType = PluginConstants.DETAILED_MAPPING;
// Let's get the diagram's target and that should be the input to the viewer
// This needs to be the document. If diagram is "Detailed" we need to find the document from this.
EObject targetEO = null;
if (newMappingType == PluginConstants.DETAILED_MAPPING) {
MappingClass mappingClassEO = (MappingClass)newDiagram.getTarget();
targetEO = mappingClassEO.getMappingClassSet().getTarget();
} else targetEO = newDiagram.getTarget();
EObject currentTargetEO = (EObject)documentController.getViewer().getInput();
if (targetEO != null && currentTargetEO != null && targetEO.equals(currentTargetEO)) isSameDocument = true;
} catch (Exception ex) {
UiConstants.Util.log(IStatus.ERROR, ex, ex.getClass().getName());
}
return isSameDocument;
}
@Override
public void rewireDiagram( Diagram newDiagram ) {
if (newDiagram.getType() != null && newDiagram.getType().equals(PluginConstants.MAPPING_TRANSFORMATION_DIAGRAM_TYPE_ID)) setMappingType(PluginConstants.DETAILED_MAPPING);
else setMappingType(PluginConstants.COARSE_MAPPING);
// This was not being set, so the currentDiagram was really never set to "Detailed"
currentDiagram = newDiagram;
documentController.getViewer().setMappingType(getMappingType());
refresh(true);
if (getMappingType() == PluginConstants.DETAILED_MAPPING) {
// jh Defect 18919: Set up double click listenening on the document tree
addDocumentTreeListener();
}
}
public MappingAdapterFilter getMappingFilter( boolean bForceRecreate ) {
MappingAdapterFilter filter = this.documentController.getMappingAdapterFilter(bForceRecreate);
if (filter == null) {
// Log an error here with any info you can find
String message = "Current diagram = " + currentDiagram.getName() + //$NON-NLS-1$
" Document Input = " + documentController.getViewer().getInput(); //$NON-NLS-1$
if (currentDiagram.getType().equals(PluginConstants.MAPPING_TRANSFORMATION_DIAGRAM_TYPE_ID)) message = message
+ " Mapping Class = " + currentDiagram.getTarget();//$NON-NLS-1$
Util.log(IStatus.ERROR, new Exception("Mapping Filter Not Found"), message); //$NON-NLS-1$
}
return filter;
}
public MappingAdapterFilter getMappingFilter() {
MappingAdapterFilter filter = this.documentController.getMappingAdapterFilter();
if (filter == null) {
// Log an error here with any info you can find
String message = "Current diagram = " + currentDiagram.getName() + //$NON-NLS-1$
" Document Input = " + documentController.getViewer().getInput(); //$NON-NLS-1$
if (currentDiagram.getType().equals(PluginConstants.MAPPING_TRANSFORMATION_DIAGRAM_TYPE_ID)) message = message
+ " Mapping Class = " + currentDiagram.getTarget();//$NON-NLS-1$
Util.log(IStatus.ERROR, new Exception("Mapping Filter Not Found"), message); //$NON-NLS-1$
}
return filter;
}
public TreeMappingAdapter getMappingAdapter() {
MappingAdapterFilter filter = getMappingFilter();
if (filter != null) return filter.getMappingAdapter();
return null;
}
public IMappableTree getMappableTree() {
MappingAdapterFilter filter = getMappingFilter();
if (filter != null) return filter.getMappableTree();
return null;
}
int getDiagramYMin() {
int minY = 0;
EditPart diagramEditPart = diagramEditor.getDiagramViewer().getContents();
if (diagramEditPart instanceof MappingDiagramEditPart) {
minY = ((MappingDiagramEditPart)diagramEditPart).getLowestYValue();
}
return minY;
}
int getDiagramYMax() {
int maxY = 0;
EditPart diagramEditPart = diagramEditor.getDiagramViewer().getContents();
if (diagramEditPart instanceof MappingDiagramEditPart) {
maxY = ((MappingDiagramEditPart)diagramEditPart).getHighestYValue();
}
return maxY;
}
/**
* @see org.teiid.designer.diagram.ui.editor.DiagramController#clearDiagramSelection()
*/
@Override
public void clearDiagramSelection() {
diagramEditor.getDiagramViewer().clearAllSelections(false);
}
/**
* @see org.teiid.designer.diagram.ui.editor.DiagramController#updateForAutoLayout()
*/
@Override
public void updateForAutoLayout() {
autoScrollToReveal();
// jh Defect 21263 - call resetExtents on tree
documentController.resetExtentsFromDocument();
}
/**
* @see org.teiid.designer.diagram.ui.editor.DiagramController#handleZoomChanged()
* @since 4.2
*/
@Override
public void handleZoomChanged() {
if (diagramEditor.getControl() != null && !diagramEditor.getControl().isDisposed()) {
documentController.resetExtentsFromDocument();
}
}
public Diagram getCurrentDiagram() {
return currentDiagram;
}
@Override
public void notifyElementsRevealed( Object oSource,
List lstElements ) {
if (bSynchronizeInProgress) {
return;
}
if (oSource instanceof UmlClassifierEditPart) {
revealElementsInTree(lstElements);
} else if (oSource instanceof DocumentTreeController) {
revealElementsInDiagram(lstElements);
}
}
@Override
public boolean isRevealHideBehaviorEnabled() {
boolean bFeatureIsOn = MappingDiagramUtil.getCurrentMappingDiagramBehavior().getSyncTreeAndDiagramState();
return bFeatureIsOn;
}
public IRevealHideListener getRevealHideListener() {
return this;
}
@Override
public void notifyElementsHidden( Object oSource,
List lstElements ) {
if (bSynchronizeInProgress) {
return;
}
if (oSource instanceof UmlClassifierEditPart) {
hideElementsInTree(lstElements);
} else if (oSource instanceof DocumentTreeController) {
hideElementsInDiagram(lstElements);
}
}
public void revealElementsInTree( List lstElements ) {
List lstResultNodes = getTreeNodesForMappingClassColumns(lstElements);
Iterator itResultNodes = lstResultNodes.iterator();
// Set visible to FALSE so we don't see the expanding tree
documentController.getViewer().getTree().setVisible(false);
while (itResultNodes.hasNext()) {
Object oTemp = itResultNodes.next();
documentController.getViewer().reveal(oTemp);
}
// let's set the first one to keep the window from scrolling to bottom
if (!lstResultNodes.isEmpty()) documentController.getViewer().reveal(lstResultNodes.get(0));
// Set visible to TRUE so we DO see the expanded tree
documentController.getViewer().getTree().setVisible(true);
}
public List getTreeNodesForMappingClassColumns( List lstElements ) {
TreeMappingAdapter mappingAdapter = documentController.getViewer().getMappingAdapterFilter(false).getMappingAdapter();
List lstNodes = new ArrayList();
Iterator it = lstElements.iterator();
ArrayList arylResultNodes = new ArrayList();
while (it.hasNext()) {
MappingClassColumn mccTemp = (MappingClassColumn)it.next();
lstNodes = mappingAdapter.getMappingClassColumnOutputLocations(mccTemp);
Iterator itNodes = lstNodes.iterator();
while (itNodes.hasNext()) {
Object oTemp = itNodes.next();
if (!arylResultNodes.contains(oTemp)) {
arylResultNodes.add(oTemp);
}
}
}
return arylResultNodes;
}
public void hideElementsInTree( List lstElements ) {
/*
* Strategy: - find the corresponding element in the tree
* - determine whether or not ALL of its siblings are in the 'hidden' list
* - if ALL are in the list, (recursively!?!!?), we can close this element's
* parent node.
*/
ITreeContentProvider cp = (ITreeContentProvider)documentController.getViewer().getContentProvider();
// 1. get the tree nodes that map to these Mapping Class Columns
List lstResultNodes = getTreeNodesForMappingClassColumns(lstElements);
Iterator it = lstResultNodes.iterator();
while (it.hasNext()) {
EObject eoTemp = (EObject)it.next();
// default this flag to true
boolean bOkToCollapseParent = true;
// System.out.println("[MappingDiagramController.hideElementsInTree] element: " + eoTemp );
// get this object's parent in the tree
Object oParent = cp.getParent(eoTemp);
if (oParent != null && oParent instanceof EObject) {
// get all of this parent's children
Object[] children = cp.getChildren(oParent);
// determine whether or not ALL of this parent's children are in our list
for (int i = 0; i < children.length; i++) {
if (!(children[i] instanceof InputSet) && !lstResultNodes.contains(children[i])) {
// if any of this parent's children are NOT in our collapse list,
// we cannot collapse this parent:
bOkToCollapseParent = false;
break;
}
}
/*
* jhTODO jh Lyra enh: Figure out if collapsing treenode(s) because
* the user collapsed a Mapping Class is even possible.
*
*/
if (bOkToCollapseParent) {
// get the Item for this EObject?
documentController.getViewer().setExpandedState(oParent, false);
}
}
}
}
public void revealElementsInDiagram( List lstElements ) {
ArrayList arylParentsToExpand = new ArrayList();
List lstMCCols = getMappingClassColumnsForTreeNodes(lstElements);
Iterator it = lstMCCols.iterator();
while (it.hasNext()) {
MappingClassColumn mccTemp = (MappingClassColumn)it.next();
MappingClass mc = mccTemp.getMappingClass();
if (!arylParentsToExpand.contains(mc)) {
arylParentsToExpand.add(mc);
}
}
// now expand the parent Mapping Classes
if (arylParentsToExpand.size() > 0) {
DiagramSelectionHandler dsh = new DiagramSelectionHandler(diagramEditor.getDiagramViewer());
Iterator itMCs = arylParentsToExpand.iterator();
while (itMCs.hasNext()) {
MappingClass mcTemp = (MappingClass)itMCs.next();
// expand this Mapping Class
EditPart ep = dsh.findEditPart(mcTemp, false);
if (ep instanceof UmlClassifierEditPart) {
bSynchronizeInProgress = true;
UmlClassifierNode node = (UmlClassifierNode)((UmlClassifierEditPart)ep).getModel();
node.expand();
bSynchronizeInProgress = false;
}
}
// try doing this at the end of the process, instead of once for each MC
diagramEditor.doRefreshDiagram();
}
}
public List getMappingClassColumnsForTreeNodes( List lstElements ) {
TreeMappingAdapter mappingAdapter = documentController.getViewer().getMappingAdapterFilter(false).getMappingAdapter();
Iterator it = lstElements.iterator();
ArrayList arylResultNodes = new ArrayList();
while (it.hasNext()) {
EObject eoTemp = (EObject)it.next();
Object oMCCol = mappingAdapter.getMappingClassColumn(eoTemp);
if (oMCCol != null) {
arylResultNodes.add(oMCCol);
}
}
return arylResultNodes;
}
public void hideElementsInDiagram( List lstElements ) {
ArrayList arylParentsToCollapse = new ArrayList();
List lstMCCols = getMappingClassColumnsForTreeNodes(lstElements);
Iterator it = lstMCCols.iterator();
while (it.hasNext()) {
MappingClassColumn mccTemp = (MappingClassColumn)it.next();
MappingClass mc = mccTemp.getMappingClass();
if (!arylParentsToCollapse.contains(mc)) {
arylParentsToCollapse.add(mc);
}
}
// now expand the parent Mapping Classes
if (arylParentsToCollapse.size() > 0) {
DiagramSelectionHandler dsh = new DiagramSelectionHandler(diagramEditor.getDiagramViewer());
Iterator itMCs = arylParentsToCollapse.iterator();
while (itMCs.hasNext()) {
MappingClass mcTemp = (MappingClass)itMCs.next();
// expand this Mapping Class
EditPart ep = dsh.findEditPart(mcTemp, false);
if (ep instanceof UmlClassifierEditPart) {
bSynchronizeInProgress = true;
UmlClassifierNode node = (UmlClassifierNode)((UmlClassifierEditPart)ep).getModel();
node.collapse();
bSynchronizeInProgress = false;
}
}
}
}
public MappingDiagramBehavior getMappingDiagramBehavior() {
if (mappingDiagramBehavior == null) {
mappingDiagramBehavior = new MappingDiagramBehavior();
}
return mappingDiagramBehavior;
}
}