/* * 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.transformation.ui.editors; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.eclipse.emf.ecore.EObject; import org.eclipse.jface.util.TransferDropTargetListener; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DropTarget; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Display; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.metamodels.transformation.SqlTransformationMappingRoot; import org.teiid.designer.query.sql.ISQLConstants; import org.teiid.designer.transformation.ui.actions.ITransformationDiagramActionConstants; import org.teiid.designer.transformation.ui.actions.TransformationSourceManager; import org.teiid.designer.transformation.ui.editors.sqleditor.SqlEditorPanel; import org.teiid.designer.transformation.util.SqlAspectHelper; import org.teiid.designer.transformation.util.TransformationHelper; import org.teiid.designer.ui.common.viewsupport.UiBusyIndicator; import org.teiid.designer.ui.util.EObjectTransfer; import org.teiid.query.ui.sqleditor.component.DisplayNodeConstants; /** * @since 8.0 */ public class SqlPanelDropTargetListener implements TransferDropTargetListener { private static final Transfer[] tranfers = new Transfer[] {EObjectTransfer.getInstance()}; private SqlEditorPanel sqlPanel; private SqlTransformationMappingRoot transformation; private Object txnSource; /** * * @since 4.3 */ public SqlPanelDropTargetListener(SqlEditorPanel sqlPanel, SqlTransformationMappingRoot transformation, Object txnSource) { super(); this.sqlPanel = sqlPanel; this.transformation = transformation; this.txnSource = txnSource; } /** * @see org.eclipse.ui.texteditor.ITextEditorDropTargetListener#getTransfers() * @since 4.3 */ @Override public Transfer getTransfer() { return EObjectTransfer.getInstance(); } public Transfer[] getTransfers() { return tranfers; } /** * @see org.eclipse.swt.dnd.DropTargetListener#dragEnter(org.eclipse.swt.dnd.DropTargetEvent) * @since 4.3 */ @Override public void dragEnter(DropTargetEvent event) { // System.out.println("SQLPDTL.dragEnter()"); } /** * @see org.eclipse.swt.dnd.DropTargetListener#dragLeave(org.eclipse.swt.dnd.DropTargetEvent) * @since 4.3 */ @Override public void dragLeave(DropTargetEvent event) { // System.out.println("SQLPDTL.dragLeave()"); } /** * @see org.eclipse.swt.dnd.DropTargetListener#dragOperationChanged(org.eclipse.swt.dnd.DropTargetEvent) * @since 4.3 */ @Override public void dragOperationChanged(DropTargetEvent event) { // System.out.println("SQLPDTL.dragOperationChanged()"); } /** * @see org.eclipse.swt.dnd.DropTargetListener#dragOver(org.eclipse.swt.dnd.DropTargetEvent) * @since 4.3 */ @Override public void dragOver(DropTargetEvent event) { if( isEnabled(event) && isInsertOK(event) ) { event.detail = DND.DROP_COPY; } else { event.detail = DND.DROP_NONE; } } private Point getMousePoint(DropTargetEvent event) { Point thePoint = Display.getCurrent().map(sqlPanel.getShell(), sqlPanel.getTextViewer().getTextWidget(), event.x, event.y); //Point startingPt = new Point(thePoint.x, thePoint.y); Point correctionPt = getXYPanelOffset(); thePoint.x = thePoint.x - sqlPanel.getShell().getBounds().x - correctionPt.x; thePoint.y = thePoint.y - sqlPanel.getShell().getBounds().y - correctionPt.y; //Point eventPt = new Point(event.x, event.y); //System.out.println(" SqlPanel final Pt = " + thePoint + " event = " + eventPt + " Start" + startingPt + // " Corr Pt = " + correctionPt + " sqlPanelShell = " + sqlPanel.getShell().getBounds()); return thePoint; } // Note that this is a HACK!!!. For some reason, the SqlEditorPanel's composite isn't nested correctly // so the Display.map() method can't determine the real offset. SO we have to manually walk up three parents // as well as start off with an initial offset. This'll break, I'm sure based on some UI resolution setting, so be prepared. protected Point getXYPanelOffset() { Point newPt = new Point(3, 8); newPt.y = newPt.y + sqlPanel.getLocation().y; newPt.y = newPt.y + sqlPanel.getParent().getLocation().y; newPt.y = newPt.y + sqlPanel.getParent().getParent().getLocation().y; newPt.y = newPt.y + sqlPanel.getParent().getParent().getParent().getLocation().y; // newPt.y = newPt.y + sqlPanel.getParent().getParent().getParent().getParent().getLocation().y; return newPt; } // Really just checks if "columns" case, that it's OK to insert // FROM case is more relaxed protected boolean isInsertOK(DropTargetEvent event) { if( dragSourcesAreTables(event) ) { if( isMouseInFrom(event) || sqlIsEmpty() ) { return true; } return false; } if( dragSourcesAreColumns(event) && isMouseInSelect(event) ) { int offset = sqlPanel.getCorrectedCaretOffset(getDropOffset(event)); return sqlPanel.isInsertOK(offset); } return false; } public boolean isMouseInFrom(DropTargetEvent event) { int offset = 0; try { offset = sqlPanel.getCorrectedCaretOffset(getDropOffset(event)); if( sqlPanel.isIndexWithin(offset, DisplayNodeConstants.FROM) ) { return true; } } catch (IllegalArgumentException ex ) { // we expect this exception whenever the mouse is not within a DisplayComponent (i.e. Over some text object in // Sql Editor text widget. } return false; } private int getDropOffset(DropTargetEvent event) throws IllegalArgumentException { return sqlPanel.getTextViewer().getTextWidget().getOffsetAtLocation(getMousePoint(event)); } public boolean isMouseInSelect(DropTargetEvent event) { int offset = 0; try { offset = sqlPanel.getCorrectedCaretOffset(getDropOffset(event)); if( sqlPanel.isIndexWithin(offset, DisplayNodeConstants.SELECT) ) { return true; } } catch (IllegalArgumentException ex ) { // we expect this exception whenever the mouse is not within a DisplayComponent (i.e. Over some text object in // Sql Editor text widget. } return false; } private boolean dragSourcesAreTables(DropTargetEvent event) { boolean result = false; List eObjList = getEventEObjects(event); if( !eObjList.isEmpty() ) { result = TransformationSourceManager.canAdd(transformation, eObjList, this); } return result; } private boolean dragSourcesAreColumns(DropTargetEvent event) { boolean result = false; List eObjList = getEventEObjects(event); if( !eObjList.isEmpty() ) { EObject nextEObj = null; result = true; for (Iterator iter = eObjList.iterator(); iter.hasNext(); ) { nextEObj = (EObject)iter.next(); if( !org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isColumn(nextEObj) || SqlAspectHelper.isInputParameter(nextEObj) ) { result = false; break; } } } return result; } public List getEventEObjects(DropTargetEvent event) { Transfer[] transfers = ((DropTarget)event.getSource()).getTransfer(); for( int i=0; i<transfers.length; i++ ) { if( transfers[i] instanceof EObjectTransfer ) { EObjectTransfer transfer = (EObjectTransfer)transfers[i]; if( transfer.getObject() != null && transfer.getObject() instanceof List) { return (List)transfer.getObject(); } return Collections.EMPTY_LIST; } } return Collections.EMPTY_LIST; } public boolean sqlIsEmpty() { String sqlText = sqlPanel.getText(); if( sqlText== null || sqlText.length() == 0 || sqlText.equals(ISQLConstants.BLANK)) { return true; } return false; } /** * @see org.eclipse.swt.dnd.DropTargetListener#drop(org.eclipse.swt.dnd.DropTargetEvent) * @since 4.3 */ @Override public void drop(DropTargetEvent event) { // System.out.println("SQLPDTL.drop()"); event.detail = DND.DROP_COPY; final DropTargetEvent dtEvent = event; if( dragSourcesAreTables(event) ) { if( isMouseInFrom(event) || sqlIsEmpty() ) { UiBusyIndicator.showWhile(null, new Runnable() { @Override public void run() { executeDropInFrom(getEventEObjects(dtEvent)); } }); } } else if( dragSourcesAreColumns(event) && isMouseInSelect(event) ) { boolean requiredStart = ModelerCore.startTxn(true, true, "Add To Select", txnSource); //$NON-NLS-1$ boolean succeeded = false; try { // Add each source succeeded = executeDropInSelect(getEventEObjects(event), event); } finally { //if we started the txn, commit it. if(requiredStart){ if(succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } } /** * @see org.eclipse.swt.dnd.DropTargetListener#dropAccept(org.eclipse.swt.dnd.DropTargetEvent) * @since 4.3 */ @Override public void dropAccept(DropTargetEvent event) { } /** * @see org.eclipse.jface.util.TransferDropTargetListener#isEnabled(org.eclipse.swt.dnd.DropTargetEvent) * @since 4.3 */ @Override public boolean isEnabled(DropTargetEvent event) { if( dragSourcesAreTables(event) ) { if( isMouseInFrom(event) ) { return true; } if( sqlIsEmpty() ) { return true; } return false; } if( dragSourcesAreColumns(event) && isMouseInSelect(event) ) { return true; } return false; } public void executeDropInFrom(List dropList) { if( dropList.isEmpty() ) return; // We need to see if we can add the list of objects to the transformation boolean canAdd = false; if( transformation != null ) canAdd = TransformationSourceManager.canAdd(transformation, dropList, this); if( canAdd ) { //start txn boolean canUndo = ITransformationDiagramActionConstants.DiagramActions.UNDO_ADD_TRANSFORMATION_SOURCE; boolean requiredStart = ModelerCore.startTxn(true, canUndo, "Add Sources", null); //$NON-NLS-1$ boolean succeeded = false; try { // Add each source TransformationSourceManager.addSources(transformation, dropList); succeeded = true; } finally { //if we started the txn, commit it. if(requiredStart){ if(succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } else { // Need to throw up a dialog stating that user can't add these objects to the TransformationSourceManager.warnUserAboutInvalidSources(dropList); } } public boolean executeDropInSelect(List dropList, DropTargetEvent event) { if( dropList.isEmpty() ) return false; // If any are not columns, disable and break List elemNames = new ArrayList(dropList.size()); List parentNames = new ArrayList(dropList.size()); Iterator iter = dropList.iterator(); while(iter.hasNext()) { EObject eObj = (EObject)iter.next(); // Column fullname String elemFullName = TransformationHelper.getSqlEObjectFullName(eObj); // Table fullname EObject parentEObj = eObj.eContainer(); String groupFullName = TransformationHelper.getSqlEObjectFullName(parentEObj); // Add the element and table names to the lists if(elemFullName!=null && groupFullName!=null) { elemNames.add(elemFullName); parentNames.add(groupFullName); } } // If editor cursor is within the SELECT, add elements at the cursor, otherwise add to end // Get Offset try { int offset = sqlPanel.getCorrectedCaretOffset(getDropOffset(event)); if(sqlPanel.isIndexWithin(offset, DisplayNodeConstants.SELECT)) { sqlPanel.insertElements(elemNames,parentNames,offset,null); } else { sqlPanel.insertElementsAtEndOfSelect(elemNames,parentNames,null); } } catch (IllegalArgumentException ex ) { return false; } return true; } /** * @param transformation The transformation to set. * @since 4.3 */ public void setTransformation(SqlTransformationMappingRoot transformation) { this.transformation = transformation; } public SqlTransformationMappingRoot getTransformation() { return this.transformation; } }