/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.ui.style;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.TextStyle;
import org.eclipse.swt.widgets.Display;
import org.xmind.core.Core;
import org.xmind.core.ISheet;
import org.xmind.core.IWorkbook;
import org.xmind.core.io.ByteArrayStorage;
import org.xmind.core.style.IStyle;
import org.xmind.core.style.IStyleSheet;
import org.xmind.gef.GEF;
import org.xmind.gef.IViewer;
import org.xmind.gef.draw2d.decoration.IDecoration;
import org.xmind.gef.graphicalpolicy.IStyleSelector;
import org.xmind.gef.graphicalpolicy.IStyleValueProvider;
import org.xmind.gef.part.IGraphicalPart;
import org.xmind.ui.decorations.IArrowDecoration;
import org.xmind.ui.decorations.IBoundaryDecoration;
import org.xmind.ui.decorations.IBranchConnectionDecoration;
import org.xmind.ui.decorations.IDecorationDescriptor;
import org.xmind.ui.decorations.IRelationshipDecoration;
import org.xmind.ui.decorations.ISummaryDecoration;
import org.xmind.ui.decorations.ITopicDecoration;
import org.xmind.ui.internal.decorations.ArrowDecorationAdapter;
import org.xmind.ui.internal.decorations.BoundaryDecorationAdapter;
import org.xmind.ui.internal.decorations.BranchConnectionDecorationAdapter;
import org.xmind.ui.internal.decorations.CurlySummaryDecoration;
import org.xmind.ui.internal.decorations.CurvedRelationshipDecoration;
import org.xmind.ui.internal.decorations.DefaultBranchDecoration;
import org.xmind.ui.internal.decorations.RelationshipDecorationAdapter;
import org.xmind.ui.internal.decorations.RoundedRectBoundaryDecoration;
import org.xmind.ui.internal.decorations.RoundedRectTopicDecoration;
import org.xmind.ui.internal.decorations.StraightBranchConnection;
import org.xmind.ui.internal.decorations.SummaryDecorationAdapter;
import org.xmind.ui.internal.decorations.TopicDecorationAdapter;
import org.xmind.ui.mindmap.IBranchPart;
import org.xmind.ui.mindmap.ISheetPart;
import org.xmind.ui.mindmap.MindMapUI;
import org.xmind.ui.resources.ColorUtils;
import org.xmind.ui.resources.FontUtils;
import org.xmind.ui.util.MindMapUtils;
public class StyleUtils {
private StyleUtils() {
}
public static IStyleSelector getStyleSelector(IGraphicalPart part) {
if (part == null)
return null;
return (IStyleSelector) part.getAdapter(IStyleSelector.class);
}
public static RGB getRGB(IGraphicalPart part, IStyleSelector ss, String key,
String decorationId) {
if (part != null && ss != null) {
String value = ss.getStyleValue(part, key);
return convertRGB(key, value);
}
return null;
}
public static RGB convertRGB(String key, String value) {
if (Styles.NONE.equals(value))
return null;
if (Styles.SYSTEM.equals(value)) {
return getSystemRGB(key, null);
}
return ColorUtils.toRGB(value);
}
public static Color getColor(IGraphicalPart part, IStyleSelector ss,
String key, String decorationId, String defaultColor) {
if (part != null && ss != null) {
String value = ss.getStyleValue(part, key,
getDecorationDefaultValueProvider(decorationId, key));
if (value != null)
return convertColor(key, value);
}
return convertColor(key, defaultColor);
}
public static Color convertColor(String key, String value) {
if (Styles.NONE.equals(value)) {
return null;
} else if (Styles.SYSTEM.equals(value)) {
return getSystemColor(key, null);
}
return ColorUtils.getColor(value);
}
private static RGB getSystemRGB(String key, RGB defaultValue) {
if (Styles.FillColor.equals(key)) {
return Display.getCurrent()
.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND).getRGB();
} else if (Styles.LineColor.equals(key)) {
return Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BORDER)
.getRGB();
} else if (Styles.TextColor.equals(key)) {
return Display.getCurrent()
.getSystemColor(SWT.COLOR_WIDGET_FOREGROUND).getRGB();
}
return defaultValue;
}
public static Color getSystemColor(String key, Color defaultValue) {
if (Styles.FillColor.equals(key)) {
return Display.getCurrent()
.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
} else if (Styles.LineColor.equals(key)) {
return Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BORDER);
} else if (Styles.TextColor.equals(key)) {
return Display.getCurrent()
.getSystemColor(SWT.COLOR_WIDGET_FOREGROUND);
}
return defaultValue;
}
public static int getInteger(IGraphicalPart part, IStyleSelector ss,
String key, int defaultValue) {
return getInteger(part, ss, key, null, defaultValue);
}
public static int getInteger(IGraphicalPart part, IStyleSelector ss,
String key, String decorationId, int defaultValue) {
if (part != null && ss != null) {
String value = ss.getStyleValue(part, key,
getDecorationDefaultValueProvider(decorationId, key));
if (value != null) {
value = trimNumber(value);
try {
return Integer.parseInt(value);
} catch (Exception e) {
}
}
}
return defaultValue;
}
public static double getDouble(IGraphicalPart part, IStyleSelector ss,
String key, double defaultValue) {
if (part != null && ss != null) {
String value = ss.getStyleValue(part, key);
if (value != null) {
value = trimNumber(value);
try {
return Double.parseDouble(value);
} catch (Exception e) {
}
}
}
return defaultValue;
}
public static Font getFont(IGraphicalPart part, IStyleSelector ss,
String key) {
if (part != null && ss != null) {
String value = ss.getStyleValue(part, key);
if (value != null) {
Font f = FontUtils.getFont(value);
if (f != null)
return f;
}
}
return null;
}
public static Font getFont(IGraphicalPart part, IStyleSelector ss,
String key, Font defaultValue) {
Font f = getFont(part, ss, key);
if (f != null)
return f;
return defaultValue;
}
public static String getString(IGraphicalPart part, IStyleSelector ss,
String key, String defaultValue) {
if (part != null && ss != null) {
String value = ss.getStyleValue(part, key);
if (value != null)
return value;
}
return defaultValue;
}
public static TextStyleData getTextStyleData(IGraphicalPart part,
IStyleSelector ss, TextStyleData defaultData) {
Object cache = MindMapUtils.getCache(part, MindMapUI.CACHE_TEXT_STYLE);
if (cache instanceof TextStyleData)
return (TextStyleData) cache;
TextStyleData data;
if (defaultData == null) {
data = new TextStyleData();
defaultData = data;
} else {
data = new TextStyleData(defaultData);
}
String name = getString(part, ss, Styles.FontFamily, defaultData.name);
String availableFontName = FontUtils.getAAvailableFontNameFor(name);
name = availableFontName != null ? availableFontName : name;
if (Styles.SYSTEM.equals(name)) {
name = JFaceResources.getDefaultFont().getFontData()[0].getName();
}
data.name = name;
data.height = getInteger(part, ss, Styles.FontSize, defaultData.height);
String weight = getString(part, ss, Styles.FontWeight, null);
if (weight != null) {
data.bold = weight.contains(Styles.FONT_WEIGHT_BOLD);
}
String style = getString(part, ss, Styles.FontStyle, null);
if (style != null) {
data.italic = style.contains(Styles.FONT_STYLE_ITALIC);
}
RGB c = getRGB(part, ss, Styles.TextColor, null);
if (c != null) {
data.color = c;
}
String decoration = getString(part, ss, Styles.TextDecoration, null);
if (decoration != null) {
data.underline = decoration
.contains(Styles.TEXT_DECORATION_UNDERLINE);
data.strikeout = decoration
.contains(Styles.TEXT_DECORATION_LINE_THROUGH);
}
int align = getAlignValue(part, ss, Styles.TextAlign);
data.align = align;
int textCase = getCaseValue(part, ss, Styles.TextCase);
data.textCase = textCase;
return data;
}
public static int getAlign(IGraphicalPart part, IStyleSelector ss,
String key) {
return getAlignValue(part, ss, Styles.TextAlign);
}
private static int getAlignValue(IGraphicalPart part, IStyleSelector ss,
String key) {
// TODO Auto-generated method stub
if (part != null && ss != null) {
String value = ss.getStyleValue(part, key);
if (Styles.ALIGN_CENTER.equals(value))
return PositionConstants.CENTER;
else if (Styles.ALIGN_RIGHT.equals(value))
return PositionConstants.RIGHT;
else
return PositionConstants.LEFT;
}
return PositionConstants.LEFT;
}
public static int getCaseValue(IGraphicalPart part, IStyleSelector ss,
String key) {
if (part != null && ss != null) {
String value = ss.getStyleValue(part, key);
if (Styles.MANUAL.equals(value))
return GEF.MANUAL;
else if (Styles.UPPERCASE.equals(value))
return GEF.UPPERCASE;
else if (Styles.LOWERCASE.equals(value))
return GEF.LOWERCASE;
else if (Styles.CAPITALIZE.equals(value))
return GEF.CAPITALIZE;
}
return GEF.MANUAL;
}
public static FontData getCompositeFontData(IGraphicalPart part,
IStyleSelector ss, FontData defaultFontData) {
if (defaultFontData == null)
defaultFontData = JFaceResources.getDefaultFont().getFontData()[0];
TextStyleData data = getTextStyleData(part, ss,
new TextStyleData(defaultFontData));
return data.createFontData();
}
public static Font getCompositeFont(IGraphicalPart part, IStyleSelector ss,
Font defaultFont) {
if (defaultFont == null)
defaultFont = JFaceResources.getDefaultFont();
TextStyleData data = getTextStyleData(part, ss,
new TextStyleData(defaultFont.getFontData()[0]));
return data.createFont();
}
public static TextStyle getTextStyle(IGraphicalPart part,
IStyleSelector ss) {
Object cache = MindMapUtils.getCache(part, MindMapUI.CACHE_TEXT_STYLE);
if (cache instanceof TextStyle)
return (TextStyle) cache;
TextStyleData data = getTextStyleData(part, ss, null);
return data.createTextStyle();
}
public static int getMajorSpacing(IGraphicalPart part, int defaultValue) {
IStyleSelector ss = getStyleSelector(part);
String connectionId = getString(part, ss, Styles.LineClass, null);
return getInteger(part, ss, Styles.MajorSpacing, connectionId,
defaultValue);
}
public static int getLineStyle(IGraphicalPart part, IStyleSelector ss,
String decorationId, int defaultValue) {
return getLineStyle(part, ss, Styles.LinePattern, decorationId,
defaultValue);
}
public static int getLineStyle(IGraphicalPart part, IStyleSelector ss,
String key, String decorationId, int defaultValue) {
if (part != null && ss != null) {
String value = ss.getStyleValue(part, key,
getDecorationDefaultValueProvider(decorationId, key));
if (value != null) {
return toSWTLineStyle(value, defaultValue);
}
}
return defaultValue;
}
public static int toSWTLineStyle(String value, int defaultValue) {
if (Styles.LINE_PATTERN_SOLID.equals(value))
return SWT.LINE_SOLID;
if (Styles.LINE_PATTERN_DASH.equals(value))
return SWT.LINE_DASH;
if (Styles.LINE_PATTERN_DASH_DOT.equals(value))
return SWT.LINE_DASHDOT;
if (Styles.LINE_PATTERN_DASH_DOT_DOT.equals(value))
return SWT.LINE_DASHDOTDOT;
if (Styles.LINE_PATTERN_DOT.equals(value))
return SWT.LINE_DOT;
return defaultValue;
}
public static int getAlpha(IGraphicalPart part, IStyleSelector ss,
int defaultValue) {
return getAlpha(part, ss, Styles.Opacity, defaultValue);
}
public static int getAlpha(IGraphicalPart part, IStyleSelector ss,
String key, int defaultValue) {
if (part != null && ss != null) {
double opacity = getDouble(part, ss, key, -1);
if (opacity >= 0) {
return (int) (opacity * 255.0d);
}
}
return defaultValue;
}
private static Pattern trimNumber = null;
public static String trimNumber(String value) {
if (value != null) {
value = value.trim();
if (trimNumber == null) {
// extract digits from the head to the first non-digit charater
trimNumber = Pattern.compile("^([\\d\\.]+)([^\\d\\.]*)"); //$NON-NLS-1$
}
Matcher m = trimNumber.matcher(value);
if (m.find()) {
value = m.group(1);
}
}
return value;
}
public static boolean isSameDecoration(IDecoration oldDecoration,
String newId) {
if (newId != null) {
if (oldDecoration == null)
return false;
String oldId = oldDecoration.getId();
return newId.equals(oldId);
}
return oldDecoration == null;
}
public static IDecoration createDecoration(IGraphicalPart part, String id) {
IDecoration decoration = MindMapUI.getMindMapDecorationFactory()
.createDecoration(id, part);
if (decoration != null)
decoration.setId(id);
return decoration;
}
public static IArrowDecoration createArrowDecoration(IGraphicalPart part,
String id) {
IDecoration decoration = id == null ? null : createDecoration(part, id);
if (decoration instanceof IArrowDecoration)
return (IArrowDecoration) decoration;
if (decoration != null)
return new ArrowDecorationAdapter(decoration);
return null;
}
public static IBoundaryDecoration createBoundaryDecoration(
IGraphicalPart part, String id) {
IDecoration decoration = id == null ? null : createDecoration(part, id);
if (decoration instanceof IBoundaryDecoration)
return (IBoundaryDecoration) decoration;
if (decoration != null)
return new BoundaryDecorationAdapter(decoration);
return new RoundedRectBoundaryDecoration(id);
}
public static IBranchConnectionDecoration createBranchConnection(
IGraphicalPart part, String id) {
IDecoration decoration = id == null ? null : createDecoration(part, id);
if (decoration instanceof IBranchConnectionDecoration)
return (IBranchConnectionDecoration) decoration;
if (decoration != null)
return new BranchConnectionDecorationAdapter(decoration);
return new StraightBranchConnection(id);
}
public static IDecoration createBranchDecoration(IGraphicalPart part,
String id) {
IDecoration decoration = id == null ? null : createDecoration(part, id);
if (decoration != null)
return decoration;
if (part instanceof IBranchPart)
return new DefaultBranchDecoration((IBranchPart) part, id);
return null;
}
public static IRelationshipDecoration createRelationshipDecoration(
IGraphicalPart part, String id) {
IDecoration decoration = id == null ? null : createDecoration(part, id);
if (decoration instanceof IRelationshipDecoration)
return (IRelationshipDecoration) decoration;
if (decoration != null)
return new RelationshipDecorationAdapter(decoration);
return new CurvedRelationshipDecoration(id);
}
public static ISummaryDecoration createSummaryDecoration(
IGraphicalPart part, String id) {
IDecoration decoration = id == null ? null : createDecoration(part, id);
if (decoration instanceof ISummaryDecoration)
return (ISummaryDecoration) decoration;
if (decoration != null)
return new SummaryDecorationAdapter(decoration);
return new CurlySummaryDecoration(id);
}
public static ITopicDecoration createTopicDecoration(IGraphicalPart part,
String id) {
IDecoration decoration = id == null ? null : createDecoration(part, id);
if (decoration instanceof ITopicDecoration)
return (ITopicDecoration) decoration;
if (decoration != null)
return new TopicDecorationAdapter(decoration);
return new RoundedRectTopicDecoration(id);
}
public static boolean isBranchLineTapered(IBranchPart branch,
IStyleSelector ss) {
if (branch != null && ss != null && branch.isCentral()) {
String value = ss.getUserValue(branch, Styles.LineTapered);
if (value == null) {
// compatible with former versions:
IViewer viewer = branch.getSite().getViewer();
if (viewer != null) {
ISheetPart sheet = (ISheetPart) viewer
.getAdapter(ISheetPart.class);
if (sheet != null) {
value = getStyleSelector(sheet).getStyleValue(sheet,
Styles.LineTapered);
}
}
}
if (value == null) {
value = ss.getStyleValue(branch, Styles.LineTapered);
}
return value != null && value.contains(Styles.TAPERED);
}
return false;
}
private static String[] getAncestorMultiLineColor(IBranchPart branch) {
if (branch == null)
return null;
IBranchPart parentBranch = branch.getParentBranch();
if (parentBranch == null)
return null;
IStyleSelector ss = getStyleSelector(parentBranch);
if (ss == null)
return null;
String value = ss.getStyleValue(parentBranch, Styles.MultiLineColors);
if (value != null && !Styles.NONE.equals(value)) {
int index = parentBranch.getSubBranches().indexOf(branch);
return new String[] { String.valueOf(index), value };
}
return getAncestorMultiLineColor(parentBranch);
}
private static int getMultiColorsIndex(IBranchPart branch) {
IBranchPart parentBranch = branch.getParentBranch();
if (parentBranch == null)
return -1;
if (MindMapUI.BRANCH_CENTRAL.equals(parentBranch.getBranchType())) {
return parentBranch.getSubBranches().indexOf(branch);
} else {
return getMultiColorsIndex(parentBranch);
}
}
public static String getIndexedBranchLineColor(IBranchPart branch) {
IBranchPart parent = branch.getParentBranch();
if (parent != null) {
int index = parent.getSubBranches().indexOf(branch);
if (index >= 0) {
String value = null;
String[] indexAndValue = getAncestorMultiLineColor(branch);
if (indexAndValue != null && indexAndValue.length == 2) {
index = Integer.parseInt(indexAndValue[0]);
value = indexAndValue[1];
}
ISheetPart sheet = null;
if (value == null || Styles.NONE.equals(value)) {
// compatible with former versions:
IViewer viewer = parent.getSite().getViewer();
if (viewer != null) {
sheet = (ISheetPart) viewer
.getAdapter(ISheetPart.class);
if (sheet != null) {
value = StyleUtils.getStyleSelector(sheet)
.getStyleValue(sheet,
Styles.MultiLineColors);
if (value != null) {
index = getMultiColorsIndex(branch);
}
}
}
}
if (index >= 0 && value != null) {
if (!Styles.NONE.equals(value)) {
value = value.trim();
// split by whitespaces
String[] colors = value.split("[\\s]+"); //$NON-NLS-1$
if (colors.length > 0) {
index %= colors.length;
String color = colors[index].trim();
return color;
}
}
}
return null;
}
}
return null;
}
public static Color getBranchConnectionColor(final IBranchPart branch,
final IStyleSelector ss, final IBranchPart child,
final int childIndex, Color defaultColor) {
if (child != null) {
IStyleSelector childSS = getStyleSelector(child);
String shapeId = getString(child, childSS, Styles.LineClass, null);
String defaultValue = defaultColor == null ? null
: ColorUtils.toString(defaultColor);
return getColor(child, childSS, Styles.LineColor, shapeId,
defaultValue);
}
return defaultColor;
}
public static String addUnitPixel(int number) {
return String.valueOf(number) + "px"; //$NON-NLS-1$
}
public static String addUnitPoint(int number) {
return String.valueOf(number) + "pt"; //$NON-NLS-1$
}
// public static String addUnit(double number) {
// return Double.toString(number) + "px"; //$NON-NLS-1$
// }
public static IStyleValueProvider getDecorationDefaultValueProvider(
String decorationId, String key) {
if (decorationId != null) {
IDecorationDescriptor descriptor = MindMapUI.getDecorationManager()
.getDecorationDescriptor(decorationId);
if (descriptor != null) {
return descriptor.getDefaultValueProvider(key);
}
}
return null;
}
public static String toTextDecoration(boolean underline,
boolean strikeout) {
if (underline || strikeout) {
if (!underline)
return Styles.TEXT_DECORATION_LINE_THROUGH;
if (!strikeout)
return Styles.TEXT_DECORATION_UNDERLINE;
return Styles.TEXT_UNDERLINE_AND_LINE_THROUGH;
}
return Styles.NORMAL;
}
public static boolean isBold(IStyle style) {
if (style != null) {
String weight = style.getProperty(Styles.FontWeight);
return weight != null && weight.contains(Styles.FONT_WEIGHT_BOLD);
}
return false;
}
public static boolean isItalic(IStyle style) {
if (style != null) {
String weight = style.getProperty(Styles.FontStyle);
return weight != null && weight.contains(Styles.FONT_STYLE_ITALIC);
}
return false;
}
public static boolean isUnderline(IStyle style) {
if (style != null) {
String weight = style.getProperty(Styles.TextDecoration);
return weight != null
&& weight.contains(Styles.TEXT_DECORATION_UNDERLINE);
}
return false;
}
public static boolean isStrikeout(IStyle style) {
if (style != null) {
String weight = style.getProperty(Styles.TextDecoration);
return weight != null
&& weight.contains(Styles.TEXT_DECORATION_LINE_THROUGH);
}
return false;
}
public static void setTheme(ISheet sheet, IStyle theme) {
if (sheet == null)
return;
if (theme == null || theme.isEmpty()) {
sheet.setThemeId(null);
} else {
IWorkbook workbook = sheet.getOwnedWorkbook();
IStyleSheet styleSheet = workbook.getStyleSheet();
theme = styleSheet.importStyle(theme);
if (theme == null || theme.isEmpty()) {
sheet.setThemeId(null);
} else {
sheet.setThemeId(theme.getId());
setThemeStyles(workbook, styleSheet, sheet, theme,
Styles.MultiLineColors, Styles.LineTapered);
}
}
}
private static void setThemeStyles(IWorkbook workbook,
IStyleSheet styleSheet, ISheet sheet, IStyle theme,
String... sheetStyleNames) {
IStyle sheetTheme = theme.getDefaultStyle(Styles.FAMILY_MAP);
if (sheetTheme == null)
return;
IStyle sourceStyle = styleSheet.findStyle(sheet.getStyleId());
IWorkbook tempWorkbook = Core.getWorkbookBuilder()
.createWorkbook(new ByteArrayStorage());
IStyle tempStyle = sourceStyle == null
? tempWorkbook.getStyleSheet().createStyle(sheet.getStyleType())
: tempWorkbook.getStyleSheet().importStyle(sourceStyle);
for (String styleName : sheetStyleNames) {
String value = sheetTheme.getProperty(styleName);
tempStyle.setProperty(styleName, value);
}
if (tempStyle.isEmpty()) {
sheet.setStyleId(null);
} else {
IStyle targetStyle = workbook.getStyleSheet()
.importStyle(tempStyle);
if (targetStyle != null) {
sheet.setStyleId(targetStyle.getId());
}
}
}
}