blob: f308cbd0fc25125f4bfbe0f3121c23e486eb5380 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 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.gef.internal.ui.palette.editparts;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.widgets.Display;
import org.eclipse.draw2d.Border;
import org.eclipse.draw2d.BorderLayout;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FocusEvent;
import org.eclipse.draw2d.ImageFigure;
import org.eclipse.draw2d.ImageUtilities;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.rap.swt.SWT;
import org.eclipse.draw2d.text.FlowPage;
import org.eclipse.draw2d.text.ParagraphTextLayout;
import org.eclipse.draw2d.text.TextFlow;
import org.eclipse.gef.ui.palette.PaletteMessages;
import org.eclipse.gef.ui.palette.PaletteViewerPreferences;
/**
* A customized figure used to represent entries in the GEF Palette.
*
* @author Pratik Shah
*/
public class DetailedLabelFigure extends Figure {
private static final FontCache FONTCACHE = new FontCache();
private static final Border PAGE_BORDER = new MarginBorder(0, 1, 0, 1);
private SelectableImageFigure image;
private FlowPage page;
private TextFlow nameText, descText;
private Font boldFont;
private boolean selectionState;
private int layoutMode = -1;
private Font cachedFont;
/**
* Constructor
*/
public DetailedLabelFigure() {
image = new SelectableImageFigure();
image.setAlignment(PositionConstants.NORTH);
page = new FlowPage();
page.setBorder(PAGE_BORDER);
nameText = new TextFlow();
nameText.setLayoutManager(new ParagraphTextLayout(nameText,
ParagraphTextLayout.WORD_WRAP_TRUNCATE));
descText = new TextFlow();
descText.setLayoutManager(new ParagraphTextLayout(descText,
ParagraphTextLayout.WORD_WRAP_TRUNCATE));
page.add(nameText);
add(image);
add(page);
BorderLayout layout = new BorderLayout();
layout.setHorizontalSpacing(2);
layout.setVerticalSpacing(0);
setLayoutManager(layout);
}
/**
* @see org.eclipse.draw2d.Figure#addNotify()
*/
public void addNotify() {
super.addNotify();
updateFont(layoutMode);
}
/**
* Releases any OS resources used by the figure.
*/
protected void dispose() {
if (boldFont != null) {
nameText.setFont(null);
FONTCACHE.checkIn(boldFont);
boldFont = null;
}
if (image != null) {
image.disposeShadedImage();
}
}
/**
* @see org.eclipse.draw2d.IFigure#handleFocusGained(FocusEvent)
*/
public void handleFocusGained(FocusEvent event) {
super.handleFocusGained(event);
updateImage();
}
/**
* @see org.eclipse.draw2d.Figure#handleFocusLost(FocusEvent)
*/
public void handleFocusLost(FocusEvent event) {
super.handleFocusLost(event);
updateImage();
}
/**
* @return whether the name is truncated
*/
public boolean isNameTruncated() {
return nameText.isTextTruncated();
}
/**
* @return whether this figure is selected or not
*/
public boolean isSelected() {
return selectionState;
}
/**
* @param s
* The description for this entry
*/
public void setDescription(String s) {
String str = ""; //$NON-NLS-1$
if (s != null && !s.trim().equals("") //$NON-NLS-1$
&& !s.trim().equals(nameText.getText().trim())) {
str = " " + PaletteMessages.NAME_DESCRIPTION_SEPARATOR //$NON-NLS-1$
+ " " + s; //$NON-NLS-1$
}
if (descText.getText().equals(str)) {
return;
}
descText.setText(str);
}
/**
* Sets the icon for this figure
*
* @param icon
* The new image
*/
public void setImage(Image icon) {
image.setImage(icon);
}
/**
* @param layoutMode
* the palette layout (any of the
* PaletteViewerPreferences.LAYOUT_XXXX options)
*/
public void setLayoutMode(int layoutMode) {
updateFont(layoutMode);
if (layoutMode == this.layoutMode)
return;
this.layoutMode = layoutMode;
add(page);
if (descText.getParent() == page)
page.remove(descText);
BorderLayout layout = (BorderLayout) getLayoutManager();
if (layoutMode == PaletteViewerPreferences.LAYOUT_COLUMNS) {
page.setHorizontalAligment(PositionConstants.CENTER);
layout.setConstraint(image, BorderLayout.TOP);
layout.setConstraint(page, BorderLayout.CENTER);
} else if (layoutMode == PaletteViewerPreferences.LAYOUT_ICONS) {
layout.setConstraint(image, BorderLayout.CENTER);
remove(page);
} else if (layoutMode == PaletteViewerPreferences.LAYOUT_LIST) {
page.setHorizontalAligment(PositionConstants.LEFT);
layout.setConstraint(image, BorderLayout.LEFT);
layout.setConstraint(page, BorderLayout.CENTER);
} else if (layoutMode == PaletteViewerPreferences.LAYOUT_DETAILS) {
/*
* Fix for Bug# 39130 Earlier, descText was only being added to the
* page if the description was not an empty String. Now, it's always
* added. This fixes the case mentioned in 39130. The undesirable
* side-effect is that the descText will be added to the page even
* when it's empty. However, that shouldn't affect anything because
* the descText will be empty (even in the case where the
* description is not empty, but is equal to the name -- see
* setDescription()).
*/
page.add(descText);
page.setHorizontalAligment(PositionConstants.LEFT);
layout.setConstraint(image, BorderLayout.LEFT);
layout.setConstraint(page, BorderLayout.CENTER);
}
}
/**
* @param str
* The new name for this entry
*/
public void setName(String str) {
if (nameText.getText().equals(str)) {
return;
}
nameText.setText(str);
}
/**
* @param state
* <code>true</code> if this entry is to be set as selected
*/
public void setSelected(boolean state) {
selectionState = state;
updateImage();
}
private void updateImage() {
if (isSelected()) {
if (hasFocus()) {
image.useShadedImage();
} else {
image.disposeShadedImage();
}
} else {
image.disposeShadedImage();
}
}
private void updateFont(int layout) {
boolean layoutChanged = (layoutMode != layout);
boolean fontChanged = (cachedFont == null || cachedFont != getFont());
cachedFont = getFont();
if (layoutChanged || fontChanged) {
if (boldFont != null) {
FONTCACHE.checkIn(boldFont);
boldFont = null;
}
if (layout == PaletteViewerPreferences.LAYOUT_DETAILS
&& cachedFont != null)
boldFont = FONTCACHE.checkOut(cachedFont);
nameText.setFont(boldFont);
}
}
private static class SelectableImageFigure extends ImageFigure {
private Image shadedImage;
protected void useShadedImage() {
disposeShadedImage();
if (super.getImage() != null) {
ImageData data = ImageUtilities
.createShadedImage(super.getImage(),
ColorConstants.menuBackgroundSelected);
// UNSUPPORTED - Create image using RAP supported constructor
// shadedImage = new Image(null, data,
// data.getTransparencyMask());
shadedImage = new Image(null, data);
}
}
protected void disposeShadedImage() {
if (shadedImage != null) {
shadedImage.dispose();
shadedImage = null;
}
}
public Image getImage() {
if (shadedImage != null)
return shadedImage;
return super.getImage();
}
public void setImage(Image image) {
if (image == super.getImage())
return;
boolean wasShaded = shadedImage != null;
disposeShadedImage();
super.setImage(image);
if (wasShaded)
useShadedImage();
}
}
private static class FontCache {
private Hashtable table = new Hashtable();
private static class FontInfo {
private Font boldFont;
private int refCount;
}
/*
* Clients should only check in fonts that they checked out from this
* cache, and should do only one check-in per checkout. If the given
* font is not found, a null pointer exception will be encountered.
*/
public void checkIn(Font boldFont) {
FontInfo info = null;
Map.Entry entry = null;
Collection values = table.entrySet();
for (Iterator iter = values.iterator(); iter.hasNext();) {
Map.Entry tempEntry = (Map.Entry) iter.next();
FontInfo tempInfo = (FontInfo) tempEntry.getValue();
if (tempInfo.boldFont == boldFont) {
info = tempInfo;
entry = tempEntry;
break;
}
}
info.refCount--;
if (info.refCount == 0) {
boldFont.dispose();
table.remove(entry.getKey());
}
}
public Font checkOut(Font font) {
FontInfo info = null;
FontData key = font.getFontData()[0];
Object obj = table.get(key);
if (obj != null) {
info = (FontInfo) obj;
} else {
info = new FontInfo();
FontData[] boldDatas = font.getFontData();
for (int i = 0; i < boldDatas.length; i++) {
boldDatas[i].setStyle(SWT.BOLD);
}
info.boldFont = new Font(Display.getCurrent(), boldDatas);
table.put(key, info);
}
info.refCount++;
return info.boldFont;
}
}
}