package de.itemis.gmf.runtime.combolabel; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.emf.common.ui.celleditor.ExtendedComboBoxCellEditor; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.emf.edit.provider.IItemLabelProvider; import org.eclipse.emf.edit.provider.ComposedAdapterFactory.Descriptor; import org.eclipse.gef.editparts.ZoomManager; import org.eclipse.gef.tools.CellEditorLocator; import org.eclipse.gef.tools.DirectEditManager; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.ITextAwareEditPart; import org.eclipse.gmf.runtime.diagram.ui.label.ILabelDelegate; import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramGraphicalViewer; import org.eclipse.gmf.runtime.draw2d.ui.figures.FigureUtilities; import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil; import org.eclipse.jface.resource.DeviceResourceException; import org.eclipse.jface.resource.FontDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.ResourceManager; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ComboBoxCellEditor; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CCombo; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Scrollable; import de.itemis.gmf.runtime.extensions.Activator; public class ComboBoxDirectEditManager extends DirectEditManager { protected static final String UNSET = "<UNSET>"; /** * Copied from * {@link org.eclipse.gmf.runtime.diagram.ui.tools.TextDirectEditManager} */ private List<FontDescriptor> cachedFontDescriptors = new ArrayList<FontDescriptor>(); /** * Copied from * {@link org.eclipse.gmf.runtime.diagram.ui.tools.TextDirectEditManager} */ private Font zoomLevelFont; public ComboBoxDirectEditManager(ISemanticRedirectingEditPart source, CellEditorLocator locator) { super(source, ComboBoxCellEditor.class, locator); } /** * Copied from * {@link org.eclipse.gmf.runtime.diagram.ui.tools.TextDirectEditManager} */ public static CellEditorLocator getTextCellEditorLocator( final ITextAwareEditPart source) { final ILabelDelegate label = (ILabelDelegate) source .getAdapter(ILabelDelegate.class); if (label != null) { return new CellEditorLocator() { public void relocate(CellEditor celleditor) { Scrollable control = (Scrollable) celleditor.getControl(); Rectangle rect = label.getTextBounds().getCopy(); if (label.getText().length() <= 0) { // if there is no text, let's assume a default size // because it looks silly when the cell editor it tiny. rect.setSize(new Dimension(control.computeSize( SWT.DEFAULT, SWT.DEFAULT))); if (label.isTextWrapOn()) { // adjust the location of the cell editor based on // text // justification (i.e. where the cursor will be if (label.getTextJustification() == PositionConstants.RIGHT) { rect.translate(-rect.width, 0); } else if (label.getTextJustification() == PositionConstants.CENTER) { rect.translate(-rect.width / 2, 0); } } } if (label.isTextWrapOn()) { if (!control.getFont().isDisposed()) { // When zoomed in, the height of this rectangle is // not // sufficient because the text is shifted downwards // a // little bit. Add some to the height to compensate // for // this. I'm not sure why this is happening, but I // can // see the text shifting down even in a label on a // GEF // logic diagram when zoomed into 400%. int charHeight = FigureUtilities.getFontMetrics( control.getFont()).getHeight(); rect.resize(0, charHeight / 2); } } else { rect.setSize(new Dimension(control.computeSize( SWT.DEFAULT, SWT.DEFAULT))); // If SWT.WRAP is not passed in as a style of the // TextCellEditor, then for some reason the first // character disappears upon entering the second // character. This should be investigated and an // SWT bug logged. int avr = FigureUtilities.getFontMetrics( control.getFont()).getAverageCharWidth(); rect.setSize(new Dimension(control.computeSize( SWT.DEFAULT, SWT.DEFAULT)).expand(avr * 2, 0)); } org.eclipse.swt.graphics.Rectangle newRect = control .computeTrim(rect.x, rect.y, rect.width, rect.height); if (!newRect.equals(control.getBounds())) { control.setBounds(newRect.x, newRect.y, newRect.width, newRect.height); } } }; } // return a default figure locator return new CellEditorLocator() { public void relocate(CellEditor celleditor) { Control control = celleditor.getControl(); Rectangle rect = source.getFigure().getBounds().getCopy(); source.getFigure().translateToAbsolute(rect); if (!rect.equals(new Rectangle(control.getBounds()))) { control.setBounds(rect.x, rect.y, control.getSize().x, control.getSize().y); } } }; } @Override protected CellEditor createCellEditorOn(Composite composite) { List<?> choices = new ArrayList<Object>( ((ISemanticRedirectingEditPart) getEditPart()).getCandidates()); choices.add(0, null); ExtendedComboBoxCellEditor cellEditor = new ExtendedComboBoxCellEditor( composite, choices, getLabelProvider(), SWT.SIMPLE); return cellEditor; } private ILabelProvider getLabelProvider() { return new LabelProvider() { public Image getImage(Object element) { if (element == null) return null; IItemLabelProvider itemLabelProvider = getItemLabelProvider(element); return (Image) itemLabelProvider.getImage(element); } public String getText(Object element) { if (element == null) return UNSET; return getItemLabelProvider(element).getText(element); } private IItemLabelProvider getItemLabelProvider(Object element) { EObject eObject = (EObject) element; EClass eClass = eObject.eClass(); Descriptor descriptor = ComposedAdapterFactory.Descriptor.Registry.INSTANCE .getDescriptor(Arrays .asList(new Object[] { eClass.getEPackage().getNsURI(), "org.eclipse.emf.edit.provider.IItemLabelProvider" })); IItemLabelProvider itemLabelProvider = (IItemLabelProvider) descriptor .createAdapterFactory().adapt(eObject, IItemLabelProvider.class); return itemLabelProvider; } }; } protected EObject getSemanticElement() { IGraphicalEditPart editPart = (IGraphicalEditPart) getEditPart(); return editPart.resolveSemanticElement(); } @Override protected void initCellEditor() { IFigure label = getEditPart().getFigure(); ExtendedComboBoxCellEditor cellEditor = (ExtendedComboBoxCellEditor) getCellEditor(); CCombo comboBox = (CCombo) cellEditor.getControl(); // scale the font accordingly to the zoom level comboBox.setFont(getScaledFont(label)); cellEditor.setValue(((ISemanticRedirectingEditPart) getEditPart()) .getValue()); cellEditor.getControl().pack(); comboBox.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { super.widgetSelected(e); commit(); } }); } /** * Copied from * {@link org.eclipse.gmf.runtime.diagram.ui.tools.TextDirectEditManager} * * @param label * @return */ protected Font getScaledFont(IFigure label) { Font scaledFont = label.getFont(); FontData data = scaledFont.getFontData()[0]; Dimension fontSize = new Dimension(0, MapModeUtil.getMapMode(label) .DPtoLP(data.getHeight())); label.translateToAbsolute(fontSize); if (Math.abs(data.getHeight() - fontSize.height) < 2) fontSize.height = data.getHeight(); try { FontDescriptor fontDescriptor = FontDescriptor.createFrom(data); cachedFontDescriptors.add(fontDescriptor); return getResourceManager().createFont(fontDescriptor); } catch (DeviceResourceException e) { Activator.logError("Error getting scaled font", e); } return JFaceResources.getDefaultFont(); } /** * Copied from * {@link org.eclipse.gmf.runtime.diagram.ui.tools.TextDirectEditManager} */ protected ResourceManager getResourceManager() { return ((DiagramGraphicalViewer) getEditPart().getViewer()) .getResourceManager(); } /** * Copied from * {@link org.eclipse.gmf.runtime.diagram.ui.tools.TextDirectEditManager} */ protected void bringDown() { // myee - RATLC00523014: crashes when queued in asyncExec() eraseFeedback(); Display.getCurrent().asyncExec(new Runnable() { public void run() { // Content Assist hack - allow proper cleanup on childen // controls ComboBoxDirectEditManager.super.bringDown(); } }); for (Iterator<FontDescriptor> iter = cachedFontDescriptors.iterator(); iter .hasNext();) { getResourceManager().destroyFont((FontDescriptor) iter.next()); } cachedFontDescriptors.clear(); } /** * Copied from * {@link org.eclipse.gmf.runtime.diagram.ui.tools.TextDirectEditManager} */ private Font getZoomLevelFont(Font actualFont, Display display) { Object zoom = getEditPart().getViewer().getProperty( ZoomManager.class.toString()); if (zoom != null) { double zoomLevel = ((ZoomManager) zoom).getZoom(); if (zoomLevel == 1.0f) return actualFont; FontData[] fd = new FontData[actualFont.getFontData().length]; FontData tempFD = null; for (int i = 0; i < fd.length; i++) { tempFD = actualFont.getFontData()[i]; fd[i] = new FontData(tempFD.getName(), (int) (zoomLevel * tempFD.getHeight()), tempFD .getStyle()); } try { FontDescriptor fontDescriptor = FontDescriptor.createFrom(fd); cachedFontDescriptors.add(fontDescriptor); return getResourceManager().createFont(fontDescriptor); } catch (DeviceResourceException e) { Activator.logError("Error gettint zoom font", e); return actualFont; } } else return actualFont; } /** * Copied from * {@link org.eclipse.gmf.runtime.diagram.ui.tools.TextDirectEditManager} */ public void show() { super.show(); IFigure fig = getEditPart().getFigure(); Control control = getCellEditor().getControl(); this.zoomLevelFont = getZoomLevelFont(fig.getFont(), control .getDisplay()); control.setFont(this.zoomLevelFont); // since the font's have been resized, we need to resize the Text // control... getLocator().relocate(getCellEditor()); } @Override protected void commit() { setDirty(true); super.commit(); } }