/* * Freeplane - mind map editor * Copyright (C) 2009 Dimitry Polivaev * * This file author is Dimitry Polivaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.freeplane.features.styles; import java.awt.Color; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.event.ListDataListener; import org.freeplane.core.extension.IExtension; import org.freeplane.core.undo.IUndoHandler; import org.freeplane.features.cloud.CloudModel; import org.freeplane.features.cloud.CloudModel.Shape; import org.freeplane.features.edge.EdgeModel; import org.freeplane.features.edge.EdgeStyle; import org.freeplane.features.map.MapModel; import org.freeplane.features.map.MapReader; import org.freeplane.features.map.NodeBuilder; import org.freeplane.features.map.NodeModel; import org.freeplane.features.map.MapWriter.Hint; import org.freeplane.features.map.MapWriter.Mode; import org.freeplane.features.mode.Controller; import org.freeplane.features.mode.ModeController; import org.freeplane.features.nodestyle.NodeSizeModel; /** * @author Dimitry Polivaev * Mar 12, 2009 */ public class MapStyleModel implements IExtension { public static final String STYLES_PREDEFINED = "styles.predefined"; public static final IStyle DEFAULT_STYLE = new StyleNamedObject("default"); public static final IStyle DETAILS_STYLE = new StyleNamedObject("defaultstyle.details"); public static final IStyle NOTE_STYLE = new StyleNamedObject("defaultstyle.note"); public static final IStyle FLOATING_STYLE = new StyleNamedObject("defaultstyle.floating"); private Map<IStyle, NodeModel> styleNodes; private MapModel styleMap; private ConditionalStyleModel conditionalStyleModel; final private DefaultComboBoxModel stylesComboBoxModel; final private Map<String, String> properties; Map<String, String> getProperties() { return properties; } public static MapStyleModel getExtension(final MapModel map) { return MapStyleModel.getExtension(map.getRootNode()); } public MapModel getStyleMap() { return styleMap; } public static MapStyleModel getExtension(final NodeModel node) { return (MapStyleModel) node.getExtension(MapStyleModel.class); } private Color backgroundColor; public MapStyleModel() { conditionalStyleModel = new ConditionalStyleModel(); styleNodes = new LinkedHashMap<IStyle, NodeModel>(); properties = new LinkedHashMap<String, String>(); stylesComboBoxModel = new DefaultComboBoxModel(); } public ConditionalStyleModel getConditionalStyleModel() { return conditionalStyleModel; } private void insertStyleMap(MapModel map, MapModel styleMap) { this.styleMap = styleMap; final NodeModel rootNode = styleMap.getRootNode(); createNodeStyleMap(rootNode); styleMap.putExtension(IUndoHandler.class, map.getExtension(IUndoHandler.class)); final MapStyleModel defaultStyleModel = new MapStyleModel(); defaultStyleModel.styleNodes = styleNodes; initStylesComboBoxModel(); rootNode.putExtension(defaultStyleModel); } public void refreshStyles() { final NodeModel rootNode = styleMap.getRootNode(); styleNodes.clear(); stylesComboBoxModel.removeAllElements(); createNodeStyleMap(rootNode); } void createStyleMap(final MapModel parentMap, MapStyleModel mapStyleModel, final String styleMapStr) { final ModeController modeController = Controller.getCurrentModeController(); MapModel styleMap = new StyleMapModel(); styleMap.createNewRoot(); final MapReader mapReader = modeController.getMapController().getMapReader(); final Reader styleReader = new StringReader(styleMapStr); NodeModel root; try { Map<Object, Object> hints = new HashMap<Object, Object>(); hints.put(Hint.MODE, Mode.FILE); hints.put(NodeBuilder.FOLDING_LOADED, Boolean.TRUE); root = mapReader.createNodeTreeFromXml(styleMap, styleReader, hints); styleMap.setRoot(root); insertStyleMap(parentMap, styleMap); NodeModel predefinedStyleParentNode = getStyleNodeGroup(styleMap, STYLES_PREDEFINED); if(predefinedStyleParentNode == null){ predefinedStyleParentNode = new NodeModel(styleMap); predefinedStyleParentNode.setUserObject(new StyleNamedObject(MapStyleModel.STYLES_PREDEFINED)); root.insert(predefinedStyleParentNode); } if(styleNodes.get(DEFAULT_STYLE) == null){ final NodeModel newNode = new NodeModel(DEFAULT_STYLE, styleMap); predefinedStyleParentNode.insert(newNode, 0); addStyleNode(newNode); } NodeModel defaultStyleModel = styleNodes.get(DEFAULT_STYLE); if(maxNodeWidth != NodeSizeModel.NOT_SET && NodeSizeModel.NOT_SET == NodeSizeModel.getNodeMaxNodeWidth(defaultStyleModel)) NodeSizeModel.setNodeMaxNodeWidth(defaultStyleModel, maxNodeWidth); if(minNodeWidth != NodeSizeModel.NOT_SET && NodeSizeModel.NOT_SET == NodeSizeModel.getMinNodeWidth(defaultStyleModel)) NodeSizeModel.setNodeMinWidth(defaultStyleModel, minNodeWidth); if(styleNodes.get(DETAILS_STYLE) == null){ final NodeModel newNode = new NodeModel(DETAILS_STYLE, styleMap); predefinedStyleParentNode.insert(newNode, 1); addStyleNode(newNode); } if(styleNodes.get(NOTE_STYLE) == null){ final NodeModel newNode = new NodeModel(NOTE_STYLE, styleMap); predefinedStyleParentNode.insert(newNode, 2); addStyleNode(newNode); } if(styleNodes.get(FLOATING_STYLE) == null){ final NodeModel newNode = new NodeModel(FLOATING_STYLE, styleMap); EdgeModel.createEdgeModel(newNode).setStyle(EdgeStyle.EDGESTYLE_HIDDEN); CloudModel.createModel(newNode).setShape(Shape.ROUND_RECT); predefinedStyleParentNode.insert(newNode, 3); addStyleNode(newNode); } } catch (Exception e) { e.printStackTrace(); } } private void createNodeStyleMap(final NodeModel node) { if (node.hasChildren()) { final Enumeration<NodeModel> children = node.children(); while (children.hasMoreElements()) { createNodeStyleMap(children.nextElement()); } return; } if (node.depth() >= 2) { addStyleNode(node); } } public void addStyleNode(final NodeModel node) { final IStyle userObject = (IStyle) node.getUserObject(); if(null == styleNodes.put(userObject, node)) stylesComboBoxModel.addElement(userObject); } private void initStylesComboBoxModel() { stylesComboBoxModel.removeAllElements(); for(IStyle s : getStyles()) stylesComboBoxModel.addElement(s); } public void removeStyleNode(final NodeModel node) { final Object userObject = node.getUserObject(); if(null != styleNodes.remove(userObject)) stylesComboBoxModel.removeElement(userObject); } public NodeModel getStyleNodeSafe(final IStyle style) { final NodeModel node = getStyleNode(style); if(node != null) return node; return getStyleNode(DEFAULT_STYLE); } public NodeModel getStyleNode(final IStyle style) { if(style instanceof StyleNode){ return ((StyleNode)style).getNode(); } final NodeModel node = styleNodes.get(style); return node; } public Color getBackgroundColor() { return backgroundColor; } public void setBackgroundColor(final Color backgroundColor) { this.backgroundColor = backgroundColor; } public Set<IStyle> getStyles() { return styleNodes.keySet(); } private float zoom = 1f; public float getZoom() { return zoom; } public MapViewLayout getMapViewLayout() { return mapViewLayout; } void setMapViewLayout(final MapViewLayout mapViewLayout) { this.mapViewLayout = mapViewLayout; } void setZoom(final float zoom) { this.zoom = zoom; } private MapViewLayout mapViewLayout = MapViewLayout.MAP; private int maxNodeWidth = NodeSizeModel.NOT_SET; private int minNodeWidth = NodeSizeModel.NOT_SET; public void setMaxNodeWidth(final int maxNodeWidth) { this.maxNodeWidth = maxNodeWidth; } public void setMinNodeWidth(final int minNodeWidth) { this.minNodeWidth = minNodeWidth; } void copyFrom(MapStyleModel source, boolean overwrite) { if(overwrite && source.styleMap != null || styleMap == null){ styleMap = source.styleMap; styleNodes = source.styleNodes; initStylesComboBoxModel(); conditionalStyleModel = source.conditionalStyleModel; } if(overwrite && source.backgroundColor != null|| backgroundColor == null){ backgroundColor = source.backgroundColor; } } public void setProperty(String key, String value){ if (value != null){ properties.put(key, value); } else{ properties.remove(key); } } public String getProperty(String key){ return properties.get(key); } public NodeModel getStyleNodeGroup(NodeModel styleNode){ final int depth = styleNode.depth(); if(depth < 1) return null; NodeModel node = styleNode; for(int i = depth; i > 1; i--){ node = node.getParentNode(); } return node; } public NodeModel getStyleNodeGroup(final MapModel styleMap, final String group) { final NodeModel rootNode = styleMap.getRootNode(); final int childCount = rootNode.getChildCount(); for(int i = 0; i < childCount; i++){ final NodeModel childNode = (NodeModel) rootNode.getChildAt(i); final StyleNamedObject userObject = (StyleNamedObject) childNode.getUserObject(); if(userObject.getObject().equals(group)){ return childNode; } } return null; } ArrayList<ListDataListener> listeners = new ArrayList<ListDataListener>(); public static final String STYLES_USER_DEFINED = "styles.user-defined"; ComboBoxModel getStylesAsComboBoxModel() { return stylesComboBoxModel; } }