/* ****************************************************************************** * 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.internal.editpolicies; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import org.xmind.core.IFileEntry; import org.xmind.core.IWorkbook; import org.xmind.core.IWorkbookComponent; import org.xmind.core.style.IStyle; import org.xmind.core.style.IStyleSheet; import org.xmind.core.style.IStyled; import org.xmind.core.util.HyperlinkUtils; import org.xmind.core.util.Property; import org.xmind.gef.IViewer; import org.xmind.gef.Request; import org.xmind.gef.command.ICommandStack; import org.xmind.ui.commands.CommandBuilder; import org.xmind.ui.commands.ModifyStyleCommand; import org.xmind.ui.mindmap.MindMapUI; import org.xmind.ui.style.Styles; public class ModifyStyleCommandBuilder extends CommandBuilder { private static final String NULL = "$NULL$"; //$NON-NLS-1$ private Request request; private IStyle sourceStyle; private Map<String, String> idCache = null; private Map<String, Properties> propertiesCache = new HashMap<String, Properties>(); private List<IStyled> sources = new ArrayList<IStyled>(); public ModifyStyleCommandBuilder(Request request) { this(request.getTargetViewer(), request.getTargetDomain() .getCommandStack(), request); } public ModifyStyleCommandBuilder(IViewer viewer, CommandBuilder delegate, Request request) { super(viewer, delegate); init(request); } public ModifyStyleCommandBuilder(IViewer viewer, ICommandStack commandStack, Request request) { super(viewer, commandStack); init(request); } private void init(Request request) { this.request = request; Object resource = request.getParameter(MindMapUI.PARAM_RESOURCE); this.sourceStyle = (resource instanceof IStyle) ? (IStyle) resource : null; } public List<IStyled> getModifiedSources() { return sources; } public boolean isSourceModified(IStyled source) { return sources.contains(source); } public void modify(IStyled source) { if (isSourceModified(source)) return; String sourceType = getStyleType(source); if (sourceType == null) return; String sourceStyleId = source.getStyleId(); String oldStyleId = sourceStyleId; if (oldStyleId == null) oldStyleId = NULL + sourceType; String newStyleId = getCachedId(oldStyleId); if (newStyleId == null) { newStyleId = getNewStyleId(source, sourceStyleId, sourceType); if (newStyleId == null) newStyleId = NULL + sourceType; cacheId(oldStyleId, newStyleId); } if (oldStyleId.equals(newStyleId)) return; modifyStyle(source, newStyleId); sources.add(source); } public void removeStyle(IStyled source) { if (isSourceModified(source)) return; modifyStyle(source, null); sources.add(source); } private void modifyStyle(IStyled source, String newStyleId) { if (NULL.equals(newStyleId)) newStyleId = null; add(new ModifyStyleCommand(source, newStyleId), true); } private void cacheId(String oldId, String newId) { if (idCache == null) idCache = new HashMap<String, String>(); idCache.put(oldId, newId); } private String getCachedId(String oldId) { if (idCache != null) return idCache.get(oldId); return null; } private String getNewStyleId(IStyled source, String sourceStyleId, String sourceType) { IStyleSheet styleSheet = getStyleSheet(source); if (styleSheet == null) return null; IStyle oldStyle = sourceStyleId == null ? null : styleSheet .findStyle(sourceStyleId); Properties oldProperties = getProperties(oldStyle); if (oldProperties == null) { oldProperties = new Properties(); } else { Properties p = new Properties(); p.putAll(oldProperties); oldProperties = p; } putValues(source, oldProperties, sourceType); if (oldProperties.isEmpty()) return null; IStyle similarStyle = findSimilarStyle(oldProperties, styleSheet); if (similarStyle != null) return similarStyle.getId(); IStyle newStyle = createStyle(styleSheet, source, oldProperties, sourceType); if (newStyle != null) return newStyle.getId(); return null; } private void putValues(IStyled source, Properties oldProperties, String sourceType) { if (sourceStyle != null && sourceStyle.getType().equals(sourceType)) { Iterator<Property> sourceProperties = sourceStyle.properties(); while (sourceProperties.hasNext()) { Property prop = sourceProperties.next(); if (prop.value == null) { oldProperties.remove(prop.key); } else { oldProperties.put(prop.key, prop.value); } } } for (String name : request.getParameterNames()) { if (name.startsWith(MindMapUI.PARAM_STYLE_PREFIX)) { String key = name.substring(MindMapUI.PARAM_STYLE_PREFIX .length()); String value = (String) request.getParameter(name); value = evaluate(source, key, value); if (value == null) { oldProperties.remove(key); } else { oldProperties.put(key, value); } } } } private IStyle findSimilarStyle(Properties sourceProperties, IStyleSheet styleSheet) { Set<IStyle> styles = styleSheet.getStyles(IStyleSheet.NORMAL_STYLES); for (IStyle style : styles) { Properties contents = getProperties(style); if (contents.equals(sourceProperties)) return style; } return null; } private IStyle createStyle(IStyleSheet styleSheet, IStyled source, Properties properties, String sourceType) { if (sourceType == null) return null; IStyle newStyle = styleSheet.createStyle(sourceType); for (Entry<Object, Object> en : properties.entrySet()) { newStyle.setProperty((String) en.getKey(), (String) en.getValue()); } styleSheet.addStyle(newStyle, IStyleSheet.NORMAL_STYLES); return newStyle; } private String getStyleType(IStyled source) { return source == null ? null : source.getStyleType(); // if (source instanceof ITopic) // return IStyle.TOPIC; // if (source instanceof IBoundary) // return IStyle.BOUNDARY; // if (source instanceof IRelationship) // return IStyle.RELATIONSHIP; // if (source instanceof ISheet) // return IStyle.MAP; // if (source instanceof ISummary) // return IStyle.SUMMARY; // return null; } private String evaluate(IStyled source, String key, String value) { if (value != null) { if (Styles.Background.equals(key)) { String attachmentURL = getCachedId(value); if (attachmentURL == null) { attachmentURL = createAttachmentURL(source, value); if (attachmentURL != null) { cacheId(value, attachmentURL); } } if (attachmentURL != null) value = attachmentURL; } } return value; } private String createAttachmentURL(IStyled source, String value) { File file = new File(value); if (!file.exists() || !file.canRead()) return null; IWorkbook workbook = getWorkbook(source); if (workbook == null) return null; IFileEntry entry; try { entry = workbook.getManifest().createAttachmentFromFilePath(value); } catch (IOException e) { return null; } if (entry == null) return null; return HyperlinkUtils.toAttachmentURL(entry.getPath()); } private Properties getProperties(IStyle style) { if (style == null) return null; String id = style.getId(); if (propertiesCache == null) propertiesCache = new HashMap<String, Properties>(); Properties properties = propertiesCache.get(id); if (properties != null) return properties; properties = new Properties(); propertiesCache.put(id, properties); Iterator<Property> it = style.properties(); while (it.hasNext()) { Property p = it.next(); properties.put(p.key, p.value); } return properties; } private IWorkbook getWorkbook(IStyled styled) { if (styled instanceof IWorkbookComponent) { return ((IWorkbookComponent) styled).getOwnedWorkbook(); } return null; } private IStyleSheet getStyleSheet(IStyled styled) { if (styled instanceof IWorkbookComponent) return ((IWorkbookComponent) styled).getOwnedWorkbook() .getStyleSheet(); return null; } }