/**
* Copyright (c) 2011 Stefan Henss.
* 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:
* Stefan Henss - initial API and implementation.
* Olav Lenz - externalize Strings.
*/
package org.eclipse.recommenders.internal.apidocs.rcp;
import static java.text.MessageFormat.format;
import static org.eclipse.recommenders.rcp.JavaElementSelectionEvent.JavaElementSelectionLocation.METHOD_DECLARATION;
import static org.eclipse.recommenders.rcp.utils.JdtUtils.findTypeFromSignature;
import static org.eclipse.swt.SWT.*;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.ILocalVariable;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.recommenders.internal.apidocs.rcp.l10n.Messages;
import org.eclipse.recommenders.rcp.JavaElementResolver;
import org.eclipse.recommenders.rcp.JavaElementSelectionEvent;
import org.eclipse.recommenders.utils.Bags;
import org.eclipse.recommenders.utils.names.IMethodName;
import org.eclipse.recommenders.utils.names.Names;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import com.google.common.base.Optional;
import com.google.common.collect.Multiset;
import com.google.common.collect.Multiset.Entry;
import com.google.common.eventbus.EventBus;
/**
* Several shortcuts for creating SWT components in the Augmented Docs view default style.
*/
// TODO: Review these methods. not sure they are still the defaults
public final class ApidocsViewUtils {
public static final Font CODEFONT = JFaceResources.getTextFont();
public static final Font BOLDFONT = JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT);
public static final Map<Integer, Color> COLORCACHE = new HashMap<Integer, Color>();
private ApidocsViewUtils() {
}
public static void disposeChildren(Composite parent) {
for (Control c : parent.getChildren()) {
c.dispose();
}
}
public static void setInfoBackgroundColor(final Control c) {
final Display display = c.getDisplay();
final Color color = display.getSystemColor(COLOR_INFO_BACKGROUND);
c.setBackground(color);
}
public static void setInfoForegroundColor(final Control c) {
final Display display = c.getDisplay();
final Color color = display.getSystemColor(SWT.COLOR_INFO_FOREGROUND);
c.setForeground(color);
}
public static Composite createGridComposite(final Composite parent, final int columns, final int hSpacing,
final int vSpacing, final int hMargin, final int vMargin) {
final Composite composite = new Composite(parent, SWT.NONE);
setInfoBackgroundColor(composite);
final GridLayout layout = GridLayoutFactory.swtDefaults().numColumns(columns).margins(hMargin, vMargin)
.spacing(hSpacing, vSpacing).create();
composite.setLayout(layout);
composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
return composite;
}
static void createSeparator(final Composite parent) {
final Label separator = new Label(parent, SWT.HORIZONTAL | SWT.SEPARATOR);
separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
}
public static Table renderMethodDirectivesBlock(final Composite parent, final Multiset<IMethodName> methods,
final int total, final EventBus bus, final JavaElementResolver resolver, final String middlePhrase) {
final Table table = new Table(parent, SWT.NONE | SWT.HIDE_SELECTION);
table.setBackground(createColor(COLOR_INFO_BACKGROUND));
table.setForeground(createColor(COLOR_INFO_FOREGROUND));
table.setLayoutData(GridDataFactory.fillDefaults().indent(10, 0).create());
final TableColumn column1 = new TableColumn(table, SWT.NONE);
final TableColumn column2 = new TableColumn(table, SWT.NONE);
final TableColumn column3 = new TableColumn(table, SWT.NONE);
final TableColumn column4 = new TableColumn(table, SWT.NONE);
for (final Entry<IMethodName> method : Bags.orderedByCount(methods)) {
final int frequency = method.getCount();
final double percentage = frequency / (double) total;
if (percentage < 0.05) {
continue;
}
final String phraseText = percentageToRecommendationPhrase((int) Math.round(100 * percentage));
final String stats = format(Messages.TABLE_CELL_SUFFIX_FREQUENCIES, percentage, frequency);
final Link bar = createMethodLink(table, method.getElement(), resolver, bus);
final TableItem item = new TableItem(table, SWT.NONE);
item.setText(new String[] { phraseText, middlePhrase, bar.getText(), stats });
bold(item, 0);
final TableEditor editor = new TableEditor(table);
editor.grabHorizontal = editor.grabVertical = true;
editor.setEditor(bar, item, 2);
}
column1.pack();
column2.pack();
column3.pack();
column4.pack();
return table;
}
public static Link createMethodLink(final Composite parent, final IMethod method, final EventBus workspaceBus) {
final String text = "<a>" //$NON-NLS-1$
+ JavaElementLabels.getElementLabel(method, JavaElementLabels.M_APP_RETURNTYPE
| JavaElementLabels.M_PARAMETER_TYPES) + "</a>"; //$NON-NLS-1$
final String tooltip = JavaElementLabels.getElementLabel(method, JavaElementLabels.DEFAULT_QUALIFIED);
final Link link = new Link(parent, SWT.NONE);
link.setText(text);
link.setBackground(ApidocsViewUtils.createColor(SWT.COLOR_INFO_BACKGROUND));
link.setToolTipText(tooltip);
link.setFont(JFaceResources.getDialogFont());
link.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
final JavaElementSelectionEvent event = new JavaElementSelectionEvent(method, METHOD_DECLARATION);
workspaceBus.post(event);
}
});
return link;
}
public static Link createMethodLink(final Composite parent, final IMethodName method,
final JavaElementResolver resolver, final EventBus workspaceBus) {
final String text = "<a>" + Names.vm2srcSimpleMethod(method) + "</a>"; //$NON-NLS$ //$NON-NLS-1$ //$NON-NLS-2$
final String tooltip = Names.vm2srcQualifiedMethod(method);
final Link link = new Link(parent, SWT.NONE);
link.setText(text);
link.setBackground(ApidocsViewUtils.createColor(SWT.COLOR_INFO_BACKGROUND));
link.setFont(JFaceResources.getDialogFont());
link.setToolTipText(tooltip);
link.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
final Optional<IMethod> opt = resolver.toJdtMethod(method);
if (opt.isPresent()) {
final JavaElementSelectionEvent event = new JavaElementSelectionEvent(opt.get(), METHOD_DECLARATION);
workspaceBus.post(event);
} else {
link.setEnabled(false);
}
}
});
return link;
}
/**
* @param parent
* The composite to which the label shall be appended.
* @param text
* The label's text.
* @param wrap
* True, if the label should set GridData in order to be wrapped when it exceeds the parent's width.
* @return The label created with the specified parameters.
*/
public static Label createLabel(final Composite parent, final String text, final boolean wrap) {
return createLabel(parent, text, false, false, SWT.COLOR_INFO_FOREGROUND, wrap);
}
public static Label createLabel(final Composite parent, final String text, final boolean bold, final boolean code,
final int color, final boolean wrap) {
final Label label = new Label(parent, SWT.WRAP);
label.setText(text);
setInfoBackgroundColor(label);
if (code) {
label.setFont(CODEFONT);
} else if (bold) {
label.setFont(BOLDFONT);
}
label.setForeground(createColor(color));
if (wrap) {
label.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
}
return label;
}
public static CLabel createCLabel(final Composite parent, final String text, final boolean bold, final Image image) {
final CLabel label = new CLabel(parent, SWT.NONE);
setInfoBackgroundColor(label);
label.setText(text);
if (bold) {
label.setFont(BOLDFONT);
}
label.setImage(image);
return label;
}
/**
* @param parent
* The composite to which the text shall be appended.
* @param text
* The default text of the text widget.
* @param width
* The width of the text widget.
* @return The text widget created with the specified parameters.
*/
public static Text createText(final Composite parent, final String text, final int width) {
final Text textComponent = new Text(parent, SWT.BORDER | SWT.SINGLE);
textComponent.setText(text);
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false);
gridData.widthHint = width;
textComponent.setLayoutData(gridData);
return textComponent;
}
public static Text createTextArea(final Composite parent, final String text, final int height, final int width) {
final Text textComponent = new Text(parent, SWT.BORDER | SWT.WRAP | SWT.MULTI | SWT.V_SCROLL);
textComponent.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).hint(width, height).create());
textComponent.setText(text);
return textComponent;
}
public static StyledText createStyledText(final Composite parent, final String text, final int color,
final boolean grabExcessHorizontalSpace) {
final StyledText styledText = new StyledText(parent, SWT.WRAP);
styledText.setEnabled(false);
styledText.setDoubleClickEnabled(false);
styledText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, grabExcessHorizontalSpace, false));
styledText.setEditable(false);
styledText.setText(text);
styledText.setForeground(createColor(color));
return styledText;
}
public static void createStyleRange(final StyledText styledText, final int start, final int length,
final int fontStyle, final boolean makeBlue, final boolean makeCodeFont) {
final StyleRange styleRange = new StyleRange();
styleRange.start = start;
styleRange.length = length;
styleRange.fontStyle = fontStyle;
if (makeBlue) {
styleRange.foreground = createColor(SWT.COLOR_BLUE);
}
if (makeCodeFont) {
styleRange.font = CODEFONT;
}
styledText.setStyleRange(styleRange);
}
public static StyleRange createStyleRange(final int start, final int length, final int fontStyle,
final boolean makeBlue, final boolean makeCodeFont) {
final StyleRange range = new StyleRange();
range.start = start;
range.length = length;
range.fontStyle = fontStyle;
if (makeBlue) {
range.foreground = createColor(SWT.COLOR_BLUE);
}
if (makeCodeFont) {
range.font = CODEFONT;
}
return range;
}
public static Font bold(Font src, Display d) {
FontData[] fD = src.getFontData();
fD[0].setStyle(SWT.BOLD);
return new Font(d, fD[0]);
}
public static void bold(TableItem item, int index) {
item.setFont(index, bold(item.getFont(), item.getDisplay()));
}
public static void bold(Control item) {
item.setFont(bold(item.getFont(), item.getDisplay()));
}
// TODO: Use link and put together with a image into a grid.
public static CLabel createLink(final Composite parent, final String text, final String tooltip, final Image image,
final boolean blueColor, final MouseListener listener) {
final CLabel link = new CLabel(parent, SWT.NONE);
link.setText(text);
if (tooltip != null) {
link.setToolTipText(tooltip);
}
if (blueColor) {
link.setForeground(createColor(SWT.COLOR_BLUE));
}
link.setImage(image);
link.addMouseListener(listener);
link.setCursor(new Cursor(parent.getDisplay(), SWT.CURSOR_HAND));
if (blueColor) {
link.addMouseTrackListener(new MouseTrackAdapter() {
@Override
public void mouseExit(final MouseEvent event) {
link.setForeground(createColor(SWT.COLOR_BLUE));
}
@Override
public void mouseEnter(final MouseEvent event) {
link.setForeground(createColor(SWT.COLOR_DARK_BLUE));
}
});
}
return link;
}
public static String percentageToRecommendationPhrase(final int percentage) {
if (percentage >= 95) {
return Messages.TABLE_CELL_FREQUENCY_ALWAYS;
} else if (percentage >= 65) {
return Messages.TABLE_CELL_FREQUENCY_USUALLY;
} else if (percentage >= 25) {
return Messages.TABLE_CELL_FREQUENCY_SOMETIMES;
} else if (percentage >= 10) {
return Messages.TABLE_CELL_FREQUENCY_OCCASIONALLY;
} else {
return Messages.TABLE_CELL_FREQUENCY_RARELY;
}
}
public static SourceCodeArea createSourceCodeArea(final Composite parent, final String snippet) {
final SourceCodeArea area = new SourceCodeArea(parent);
area.setCode(snippet);
return area;
}
public static Button createButton(final Composite parent, final String text,
final SelectionListener selectionListener) {
final Button button = new Button(parent, SWT.NONE);
button.setText(text);
button.addSelectionListener(selectionListener);
return button;
}
public static Color createColor(final int swtColor) {
final Integer color = Integer.valueOf(swtColor);
if (!COLORCACHE.containsKey(color)) {
COLORCACHE.put(color, Display.getCurrent().getSystemColor(swtColor));
}
return COLORCACHE.get(color);
}
public static Composite createComposite(final Composite parent, final int numColumns) {
final Composite container = new Composite(parent, SWT.NONE);
setInfoBackgroundColor(container);
container.setLayout(GridLayoutFactory.fillDefaults().margins(10, 0).spacing(0, 0).numColumns(numColumns)
.create());
container.setLayoutData(GridDataFactory.fillDefaults().create());
return container;
}
public static Optional<IType> findType(ILocalVariable var) {
String signature = var.getTypeSignature();
return findTypeFromSignature(signature, var);
}
public static Optional<IType> findType(IField var) {
try {
String signature = var.getTypeSignature();
return findTypeFromSignature(signature, var);
} catch (JavaModelException e) {
return Optional.absent();
}
}
}