/* * 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.diagram.ui.notation.uml.figure; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.draw2d.ActionEvent; import org.eclipse.draw2d.ActionListener; import org.eclipse.draw2d.Button; import org.eclipse.draw2d.ColorConstants; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.ImageFigure; import org.eclipse.draw2d.Label; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.SimpleRaisedBorder; import org.eclipse.draw2d.Triangle; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.emf.ecore.EObject; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.teiid.designer.diagram.ui.DiagramUiConstants; import org.teiid.designer.diagram.ui.DiagramUiPlugin; import org.teiid.designer.diagram.ui.PluginConstants; import org.teiid.designer.diagram.ui.figure.AbstractDiagramFigure; import org.teiid.designer.diagram.ui.figure.ExpandableFigure; import org.teiid.designer.diagram.ui.model.DiagramModelNode; import org.teiid.designer.diagram.ui.notation.uml.model.UmlClassifierNode; import org.teiid.designer.diagram.ui.util.colors.ColorPalette; import org.teiid.designer.diagram.ui.util.directedit.DirectEditFigure; import org.teiid.designer.ui.editors.ModelEditorManager; /** * UmlClassifierFigure * * @since 8.0 */ public class UmlClassifierFigure extends AbstractDiagramFigure implements DirectEditFigure, ExpandableFigure { // =========================================================================================================================== // Constants private static final String COLLAPSE_TOOLTIP = DiagramUiConstants.Util.getString("UmlClassifierFigure.collapseTooltip.text"); // //$NON-NLS-1$ private static final String EXPAND_TOOLTIP = DiagramUiConstants.Util.getString("UmlClassifierFigure.expandTooltip.text"); // //$NON-NLS-1$ // =========================================================================================================================== // Static Variables private static int ySpacing = 2; // =========================================================================================================================== // Variables private Triangle topLeftArrow; private boolean expandable = false; private UmlClassifierHeader header; private UmlClassifierFooter footer; private ImageFigure errorIcon; private ImageFigure warningIcon; private ImageFigure extraImage; private int extraImagePosition = DiagramUiConstants.Position.UPPER_RIGHT; private Button editButton; // =========================================================================================================================== // Constructors /** * Construct an instance of UmlClassifierFigure. */ public UmlClassifierFigure( String stereotype, String name, String location, Image icon, ColorPalette colorPalette ) { super(colorPalette); init(stereotype, name, location, icon); createComponent(); } public UmlClassifierFigure( DiagramModelNode diagramNode, String stereotype, String name, String location, Image icon, ColorPalette colorPalette ) { super(diagramNode, colorPalette); init(stereotype, name, location, icon); createComponent(); } // =========================================================================================================================== // Methods @Override public void addEditButton( Image image ) { if (image != null) { if (editButton != null) this.remove(editButton); editButton = new Button(image); editButton.setSize(new Dimension(image.getImageData().width + 6, image.getImageData().height + 4)); editButton.addActionListener(new ActionListener() { @Override public void actionPerformed( ActionEvent event ) { // We need to call some generic edit event here // swj: yes we do! I don't like that this button knows about recursion. if (getDiagramModelNode() != null) { final Object modelObject = getDiagramModelNode().getModelObject(); final String editorID = getDiagramModelNode().getEditorID(); if (modelObject != null && modelObject instanceof EObject && ModelEditorManager.canEdit((EObject)modelObject)) { Display.getCurrent().asyncExec(new Runnable() { @Override public void run() { if (editorID != null) ModelEditorManager.edit((EObject)modelObject, editorID); else ModelEditorManager.edit((EObject)modelObject); } }); } } } }); this.add(editButton); // firstOverlayIcon.setSize(firstOverlayIcon.getPreferredSize()); header.setLeftButton(true); this.layoutFigure(); int iX = 3 + this.getExpansionFigure().getSize().width; // editButton.setLocation(new Point(5, 5)); editButton.setLocation(new Point(iX, 4)); } else { if (editButton != null) { this.remove(editButton); header.setLeftButton(false); this.layoutFigure(); } editButton = null; } } private void addExpandControl() { topLeftArrow = new Triangle(); UmlClassifierNode ucNode = (UmlClassifierNode)getDiagramModelNode(); if (ucNode != null && ucNode.isExpanded()) { // System.out.println("[UmlClassifierFigure.addExpandControl] About to set direction SOUTH"); topLeftArrow.setDirection(PositionConstants.SOUTH); } else { // System.out.println("[UmlClassifierFigure.addExpandControl] About to set direction EAST"); topLeftArrow.setDirection(PositionConstants.EAST); } this.add(topLeftArrow); topLeftArrow.setBackgroundColor(ColorConstants.black); topLeftArrow.setForegroundColor(ColorConstants.black); topLeftArrow.setLineWidth(1); topLeftArrow.setSize(11, 9); topLeftArrow.setLocation(new Point(1, 2)); topLeftArrow.setToolTip(createToolTip(EXPAND_TOOLTIP)); topLeftArrow.setVisible(expandable); } @Override public void addImage( Image image, int position ) { if (image != null) { if (extraImage != null) this.remove(extraImage); extraImage = new ImageFigure(image); this.add(extraImage); extraImage.setSize(extraImage.getPreferredSize()); extraImagePosition = position; setExtraImageLocation(); } else { if (extraImage != null) this.remove(extraImage); extraImage = null; } } @Override public void collapse() { // System.out.println("[UmlClassifierFigure.collapse] About to set direction EAST"); topLeftArrow.setDirection(PositionConstants.EAST); topLeftArrow.setBackgroundColor(ColorConstants.black); topLeftArrow.setToolTip(createToolTip(EXPAND_TOOLTIP)); topLeftArrow.setSize(11, 9); topLeftArrow.setLocation(new Point(0, 2)); // this.setSize(new Dimension(defWidth, defHeight)); this.repaint(); } private double containerHeightRatio( UmlClassifierContainerFigure someContainer ) { // Num objects in this container int nObjects = someContainer.getContentsPane().getChildren().size(); if (nObjects == 0) nObjects = 1; int totalObjects = 0; List childFigures = getChildren(); Iterator iter = childFigures.iterator(); Object nextObject = null; while (iter.hasNext()) { nextObject = iter.next(); if (nextObject instanceof UmlClassifierContainerFigure) { totalObjects += ((UmlClassifierContainerFigure)nextObject).getContentsPane().getChildren().size(); } } if (totalObjects == 0) totalObjects = 1; double returnRatio = (double)nObjects / (double)totalObjects; return returnRatio; } private void createComponent() { int finalWidth = header.getSize().width; int finalHeight = header.getSize().height + 20; this.setSize(finalWidth, finalHeight); header.setSize(finalWidth, header.getSize().height); header.setLocation(new Point(0, 0)); footer.setSize(finalWidth, footer.getSize().height); footer.setLocation(new Point(0, header.getSize().height)); } @Override public void expand() { // System.out.println("[UmlClassifierFigure.expand] About to set direction SOUTH"); topLeftArrow.setDirection(PositionConstants.SOUTH); topLeftArrow.setBackgroundColor(ColorConstants.blue); topLeftArrow.setToolTip(createToolTip(COLLAPSE_TOOLTIP)); topLeftArrow.setSize(10, 12); topLeftArrow.setLocation(new Point(3, 0)); // this.setSize(new Dimension(100, defHeight)); this.repaint(); } private IFigure getContainerFigure( int type ) { Iterator iter = getChildren().iterator(); Object nextObject = null; while (iter.hasNext()) { nextObject = iter.next(); if (nextObject instanceof UmlClassifierContainerFigure) { int contType = ((UmlClassifierContainerFigure)nextObject).getStackOrderValue(); if (contType == type) return (IFigure)nextObject; } } return null; } public Button getEditButton() { return this.editButton; } @Override public IFigure getExpansionFigure() { return this.topLeftArrow; } @Override public Label getLabelFigure() { return header.getNameLabel(); } private int getMinimumContainersHeight() { // Num objects in this container int totalHeight = 0; List childFigures = getChildren(); Iterator iter = childFigures.iterator(); Object nextObject = null; while (iter.hasNext()) { nextObject = iter.next(); if (nextObject instanceof UmlClassifierContainerFigure) { UmlClassifierContainerFigure fig = (UmlClassifierContainerFigure)nextObject; if (fig.getDiagramModelNode().isHeightFixed()) { totalHeight += fig.getDiagramModelNode().getFixedHeight(); } else { totalHeight += ((UmlClassifierContainerFigure)nextObject).getMinimumHeight(); } } } return totalHeight; } public IFigure getNameFigure() { if (header != null) { return header.getNameFigure(); } return null; } private List getOrderedContainerFigures() { List returnList = new ArrayList(); for (int i = 0; i < 4; i++) { IFigure containerFigure = getContainerFigure(i); if (containerFigure != null) { returnList.add(containerFigure); } } return returnList; } /** * @see org.teiid.designer.diagram.ui.figure.DiagramFigure#hiliteBackground(org.eclipse.swt.graphics.Color) */ @Override public void hiliteBackground( Color hiliteColor ) { header.hiliteBackground(hiliteColor); } private void init( String stereotype, String name, String location, Image icon ) { header = new UmlClassifierHeader(stereotype, name, location, icon, getColor(ColorPalette.SECONDARY_BKGD_COLOR_ID)); this.add(header); footer = new UmlClassifierFooter(); this.add(footer); this.setBorder(new SimpleRaisedBorder(2)); this.setForegroundColor(ColorConstants.darkBlue); this.setBackgroundColor(getColor(ColorPalette.SECONDARY_BKGD_COLOR_ID)); // DiagramUiUtilities.GROUP_BKGRND_COLOR); header.setDefaultBkgdColor(getColor(ColorPalette.PRIMARY_BKGD_COLOR_ID)); footer.setDefaultBkgdColor(getColor(ColorPalette.SECONDARY_BKGD_COLOR_ID)); addExpandControl(); header.setExpandControl(getExpansionFigure()); } @Override public boolean isExpandable() { return expandable; } @Override public void layoutFigure() { // let's get all container children and stack below header. int minWidth = 10; // Let's get the header minimum size here Dimension minHeaderSize = header.getInitialMinimumSize(); int currentY = header.getSize().height + header.getLocation().y; minWidth = Math.max(minWidth, minHeaderSize.width); int leftX = 0; List containerFigures = getOrderedContainerFigures(); Iterator iter = containerFigures.iterator(); Object nextObject = null; while (iter.hasNext()) { nextObject = iter.next(); if (nextObject instanceof UmlClassifierContainerFigure) { ((UmlClassifierContainerFigure)nextObject).setLocation(new Point(leftX, currentY)); currentY += ((UmlClassifierContainerFigure)nextObject).getSize().height; minWidth = Math.max(minWidth, ((UmlClassifierContainerFigure)nextObject).getSize().width + ySpacing * 2); } } footer.setLocation(new Point(0, currentY)); currentY += footer.getSize().height; header.setSize(minWidth, header.getSize().height); header.layoutThisFigure(); // Reset currentY Location currentY = header.getSize().height + header.getLocation().y; iter = containerFigures.iterator(); nextObject = null; UmlClassifierContainerFigure nextFigure = null; while (iter.hasNext()) { nextObject = iter.next(); if (nextObject instanceof UmlClassifierContainerFigure) { nextFigure = (UmlClassifierContainerFigure)nextObject; nextFigure.setLocation(new Point(leftX, currentY)); currentY += nextFigure.getSize().height; int currentH = nextFigure.getSize().height; nextFigure.setSize(minWidth, currentH); } } footer.setSize(minWidth, footer.getSize().height); footer.setLocation(new Point(0, currentY)); currentY += footer.getSize().height; resetIconLocations(); this.setSize(minWidth, currentY); } @Override public void paint( Graphics graphics ) { graphics.pushState(); graphics.setForegroundColor(getLocalBackgroundColor()); graphics.setBackgroundColor(getLocalForegroundColor()); graphics.fillGradient(this.getBounds(), true); super.paint(graphics); paintSeparators(graphics); graphics.popState(); graphics.restoreState(); } private void paintSeparators( Graphics graphics ) { int orgX = this.getBounds().x; int orgY = this.getBounds().y; int width = this.getBounds().width; // Draw header/container separator int currentY = orgY; graphics.setLineWidth(1); graphics.setForegroundColor(ColorConstants.darkGray); List containerFigures = getOrderedContainerFigures(); for (Iterator iter = containerFigures.iterator(); iter.hasNext();) { IFigure nextFigure = (Figure)iter.next(); currentY = orgY + nextFigure.getBounds().y + 1; graphics.drawLine(orgX + 1, currentY, orgX + width - 2, currentY); } currentY = orgY + footer.getBounds().y + 2; graphics.drawLine(orgX + 1, currentY, orgX + width - 2, currentY); } /** * @see org.teiid.designer.diagram.ui.figure.DiagramFigure#refreshFont() */ @Override public void refreshFont() { super.refreshFont(); header.refreshFont(); layoutFigure(); updateForSize(this.getSize()); } private void resetIconLocations() { if (((Label)header.getNameFigure()).getIcon() != null) { Rectangle iconBounds = ((Label)header.getNameFigure()).getIconBounds(); if (warningIcon != null) { int newX = iconBounds.x; int newY = iconBounds.y + iconBounds.height - warningIcon.getBounds().height; warningIcon.setLocation(new Point(newX, newY)); } if (errorIcon != null) { int newX = iconBounds.x; int newY = iconBounds.y + iconBounds.height - errorIcon.getBounds().height; errorIcon.setLocation(new Point(newX, newY)); } } setExtraImageLocation(); } @Override public void setExpandable( boolean expandable ) { this.expandable = expandable; topLeftArrow.setVisible(expandable); // jh Lyra enh / defect 20421: Now that expanded state is controlled by a user preferece // it no longer makes sense to unconditionally expand or collapse here // if( expandState ) // expand(); // else // collapse(); this.repaint(); } private void setExtraImageLocation() { if (extraImage != null) { int newX = 0; int newY = 0; int iWidth = extraImage.getSize().width; int iHeight = extraImage.getSize().height; int thisWidth = getSize().width; int thisHeight = getSize().height; switch (extraImagePosition) { case DiagramUiConstants.Position.UPPER_LEFT: { newX = 4; newY = 2; } break; case DiagramUiConstants.Position.UPPER_CENTER: { newX = thisWidth / 2 - iWidth / 2; newY = 2; } break; case DiagramUiConstants.Position.UPPER_RIGHT: { newX = thisWidth - 4 - iWidth; newY = 2; } break; case DiagramUiConstants.Position.CENTER_LEFT: { newX = 4; newY = thisHeight / 2 - iHeight / 2; } break; case DiagramUiConstants.Position.CENTER_CENTER: { newX = thisWidth / 2 - iWidth / 2; newY = thisHeight / 2 - iHeight / 2; } break; case DiagramUiConstants.Position.CENTER_RIGHT: { newX = thisWidth - 2 - iWidth; newY = thisHeight / 2 - iHeight / 2; } break; case DiagramUiConstants.Position.LOWER_LEFT: { newX = 4; newY = thisHeight - 2 - iHeight; } break; case DiagramUiConstants.Position.LOWER_CENTER: { newX = thisWidth / 2 - iWidth / 2; newY = thisHeight - 2 - iHeight; } break; case DiagramUiConstants.Position.LOWER_RIGHT: { newX = thisWidth - 4 - iWidth; newY = thisHeight - 2 - iHeight; } break; default: { newX = 2; newY = 2; } break; } extraImage.setLocation(new Point(newX, newY)); } } public void setNameFontStyle( int style ) { header.setNameFontStyle(style); header.refreshFont(); } @Override public void showSelected( boolean selected ) { if (selected) this.setForegroundColor(getColor(ColorPalette.SELECTION_COLOR_ID)); else this.setForegroundColor(getColor(ColorPalette.SECONDARY_BKGD_COLOR_ID)); } private void stackFigure() { // let's get all container children and stack below header. int currentY = header.getSize().height + header.getLocation().y; int leftX = 0; List containerFigures = getOrderedContainerFigures(); Iterator iter = containerFigures.iterator(); Object nextObject = null; while (iter.hasNext()) { nextObject = iter.next(); if (nextObject instanceof UmlClassifierContainerFigure) { ((UmlClassifierContainerFigure)nextObject).setLocation(new Point(leftX, currentY)); currentY += ((UmlClassifierContainerFigure)nextObject).getSize().height; } } footer.setLocation(new Point(0, currentY)); } @Override public void updateForError( boolean hasErrors ) { if (hasErrors) { if (errorIcon == null) { errorIcon = new ImageFigure(DiagramUiPlugin.getDefault().getImage(PluginConstants.Images.ERROR_ICON)); if (errorIcon != null) { this.add(errorIcon); errorIcon.setSize(errorIcon.getPreferredSize()); } } } else if (errorIcon != null) { this.remove(errorIcon); errorIcon = null; } resetIconLocations(); } @Override public void updateForName( String newName ) { header.refreshName(newName); } public void updateForPath( String newPath ) { header.refreshPath(newPath); } @Override public void updateForSize( Dimension newSize ) { int leftoverHeight = newSize.height; header.setSize(newSize.width, header.getSize().height); leftoverHeight -= header.getSize().height; header.layoutThisFigure(); boolean scrollingNeeded = true; int minimumContainerHeight = getMinimumContainersHeight(); if (minimumContainerHeight < leftoverHeight) scrollingNeeded = false; int newWidth = newSize.width; List childFigures = getChildren(); Iterator iter = childFigures.iterator(); Object nextObject = null; UmlClassifierContainerFigure nextFigure = null; if (scrollingNeeded) { int availableHeight = leftoverHeight - 5; while (iter.hasNext()) { nextObject = iter.next(); if (nextObject instanceof UmlClassifierContainerFigure) { nextFigure = (UmlClassifierContainerFigure)nextObject; int newH = (int)(availableHeight * containerHeightRatio(nextFigure)); nextFigure.setSize(newWidth, newH); leftoverHeight -= newH; } } } else { while (iter.hasNext()) { nextObject = iter.next(); if (nextObject instanceof UmlClassifierContainerFigure) { nextFigure = (UmlClassifierContainerFigure)nextObject; int newH = nextFigure.getMinimumHeight(); if (nextFigure.getDiagramModelNode().isHeightFixed()) { newH = nextFigure.getDiagramModelNode().getFixedHeight(); } nextFigure.setSize(newWidth, newH); leftoverHeight -= newH; } } } if (leftoverHeight < 10) leftoverHeight = 10; footer.setSize(newWidth, leftoverHeight); stackFigure(); resetIconLocations(); } @Override public void updateForWarning( boolean hasWarnings ) { if (hasWarnings) { if (warningIcon == null) { warningIcon = new ImageFigure(DiagramUiPlugin.getDefault().getImage(PluginConstants.Images.WARNING_ICON)); if (warningIcon != null) { this.add(warningIcon); warningIcon.setSize(warningIcon.getPreferredSize()); } } } else if (warningIcon != null) { this.remove(warningIcon); warningIcon = null; } resetIconLocations(); } /** * @see org.eclipse.draw2d.Figure#paintFigure(org.eclipse.draw2d.Graphics) * @since 5.0 protected void paintFigure(Graphics theGraphics) { super.paintFigure(theGraphics); this.getParent().repaint(); } */ }