Package org.freeplane.features.styles

Source Code of org.freeplane.features.styles.MapStyle$XmlWriter

/*
*  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.File;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URL;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Vector;

import org.freeplane.core.extension.IExtension;
import org.freeplane.core.io.IElementContentHandler;
import org.freeplane.core.io.IElementDOMHandler;
import org.freeplane.core.io.IElementHandler;
import org.freeplane.core.io.IExtensionElementWriter;
import org.freeplane.core.io.ITreeWriter;
import org.freeplane.core.resources.NamedObject;
import org.freeplane.core.resources.ResourceController;
import org.freeplane.core.ui.components.UITools;
import org.freeplane.core.undo.IActor;
import org.freeplane.core.undo.IUndoHandler;
import org.freeplane.core.util.ColorUtils;
import org.freeplane.core.util.Compat;
import org.freeplane.core.util.LogUtils;
import org.freeplane.core.util.TextUtils;
import org.freeplane.features.filter.FilterController;
import org.freeplane.features.filter.condition.ASelectableCondition;
import org.freeplane.features.filter.condition.ConditionFactory;
import org.freeplane.features.map.IMapLifeCycleListener;
import org.freeplane.features.map.MapChangeEvent;
import org.freeplane.features.map.MapController;
import org.freeplane.features.map.MapModel;
import org.freeplane.features.map.MapWriter;
import org.freeplane.features.map.MapWriter.Mode;
import org.freeplane.features.map.NodeModel;
import org.freeplane.features.mode.Controller;
import org.freeplane.features.mode.ModeController;
import org.freeplane.features.mode.NodeHookDescriptor;
import org.freeplane.features.mode.PersistentNodeHook;
import org.freeplane.features.styles.ConditionalStyleModel.Item;
import org.freeplane.features.url.UrlManager;
import org.freeplane.n3.nanoxml.XMLElement;

/**
* @author Dimitry Polivaev
* Mar 9, 2009
*/
@NodeHookDescriptor(hookName = "MapStyle")
public class MapStyle extends PersistentNodeHook implements IExtension, IMapLifeCycleListener {
  private static final String NODE_CONDITIONAL_STYLES = "NodeConditionalStyles";
  public static final String RESOURCES_BACKGROUND_COLOR = "standardbackgroundcolor";
  public static final String RESOURCES_BACKGROUND_IMAGE = "backgroundImageURI";
  public static final String MAP_STYLES = "MAP_STYLES";
  public static final String FIT_TO_VIEWPORT = "fit_to_viewport";
 
  public static void install(boolean persistent){
    new MapStyle(persistent);
  }
 
  protected MapStyle( final boolean persistent) {
    super();
    ModeController modeController = Controller.getCurrentModeController();
    if (persistent) {
      final MapController mapController = modeController.getMapController();
      mapController.getWriteManager().addExtensionElementWriter(getExtensionClass(),
        new XmlWriter());
      mapController.getReadManager().addElementHandler("conditional_styles", new IElementDOMHandler() {
        public Object createElement(Object parent, String tag, XMLElement attributes) {
          return parent;
        }

        public void endElement(Object parent, String tag, Object element, XMLElement dom) {
          final NodeModel node = (NodeModel) parent;
          final MapStyleModel mapStyleModel = MapStyleModel.getExtension(node);
          if(mapStyleModel != null)
            loadConditionalStyles(mapStyleModel.getConditionalStyleModel(), dom);
        }
        });

        mapController.getWriteManager().addExtensionElementWriter(ConditionalStyleModel.class,
          new IExtensionElementWriter() {
          public void writeContent(ITreeWriter writer, Object element, IExtension extension) throws IOException {
            final ConditionalStyleModel conditionalStyleModel = (ConditionalStyleModel) extension;
            if (conditionalStyleModel.getStyleCount() == 0)
              return;
            final XMLElement hook = new XMLElement("hook");
            hook.setAttribute("NAME", NODE_CONDITIONAL_STYLES);
            saveConditionalStyles(conditionalStyleModel, hook, false);
            writer.addElement(null, hook);
          }
        });
       
        mapController.getReadManager().addElementHandler("hook", new IElementDOMHandler() {
          public Object createElement(Object parent, String tag, XMLElement attributes) {
            if (attributes == null
                || !NODE_CONDITIONAL_STYLES.equals(attributes.getAttribute("NAME", null))) {
              return null;
          }
          final ConditionalStyleModel conditionalStyleModel = new ConditionalStyleModel();
          ((NodeModel)parent).addExtension(conditionalStyleModel);
          return conditionalStyleModel;
        }
       
        public void endElement(Object parent, String tag, Object element, XMLElement dom) {
          loadConditionalStyles((ConditionalStyleModel) element, dom);
        }
      });
      mapController.getReadManager().addElementHandler("map_styles"new IElementContentHandler() {
        public Object createElement(Object parent, String tag, XMLElement attributes) {
                  return parent;
                }
        public void endElement(final Object parent, final String tag, final Object userObject,
                               final XMLElement attributes, final String content) {
          // bugfix
          if(isContentEmpty(content))
            return;
          final NodeModel node = (NodeModel) userObject;
          final MapStyleModel mapStyleModel = MapStyleModel.getExtension(node);
          if (mapStyleModel == null) {
            return;
          }
          final MapModel map = node.getMap();
          mapStyleModel.createStyleMap(map, mapStyleModel, content);
          map.getIconRegistry().addIcons(mapStyleModel.getStyleMap());
        }
        private boolean isContentEmpty(final String content) {
          return content.indexOf('<') == -1;
        }

      }
      );

    }
    modeController.getMapController().addMapLifeCycleListener(this);
    final MapController mapController = modeController.getMapController();
    mapController.addMapLifeCycleListener(this);
  }

  protected class XmlWriter implements IExtensionElementWriter {
    public void writeContent(final ITreeWriter writer, final Object object, final IExtension extension)
            throws IOException {
      final MapStyleModel mapStyleModel = (MapStyleModel) extension;
      final MapModel styleMap = mapStyleModel.getStyleMap();
      final String el = System.getProperty("line.separator");
      if (styleMap == null) {
        return;
      }
      final MapWriter mapWriter = Controller.getCurrentModeController().getMapController().getMapWriter();
      final StringWriter sw = new StringWriter();
      sw.append(el);
      sw.append("<map_styles>");
      sw.append(el);
      final NodeModel rootNode = styleMap.getRootNode();
      final boolean forceFormatting = Boolean.TRUE.equals(writer.getHint(MapWriter.WriterHint.FORCE_FORMATTING));
      try {
        mapWriter.writeNodeAsXml(sw, rootNode, Mode.STYLE, true, true, forceFormatting);
      }
      catch (final IOException e) {
        e.printStackTrace();
      }
      sw.append("</map_styles>");
      sw.append(el);
      final XMLElement element = new XMLElement("hook");
      saveExtension(extension, element);
      writer.addElement(sw.toString(), element);
    }
  }

  @Override
  protected XmlWriter createXmlWriter() {
    return null;
  }

  protected class MyXmlReader extends XmlReader{
    public Object createElement(final Object parent, final String tag, final XMLElement attributes) {
      if (null == super.createElement(parent, tag, attributes)){
        return null;
      }
      super.endElement(parent, tag, parent, attributes);
      return parent;
    }

    @Override
        public void endElement(Object parent, String tag, Object userObject, XMLElement xml) {
      // do nothing for not root nodes
      final XMLElement parentNodeElement = xml.getParent().getParent();
      if (parentNodeElement == null || !parentNodeElement.getName().equals("map")) {
        return;
      }
      NodeModel node = (NodeModel) userObject;
      loadMapStyleProperties(MapStyleModel.getExtension(node), xml);
       }

    private void loadMapStyleProperties(MapStyleModel model, XMLElement xml) {
      final Vector<XMLElement> propertyXml = xml.getChildrenNamed("properties");
      if(propertyXml != null && propertyXml.size() >= 1){
        final Map<String, String> properties = model.getProperties();
        final Properties attributes = propertyXml.get(0).getAttributes();
        for(Entry<Object, Object> attribute:attributes.entrySet()){
          properties.put(attribute.getKey().toString(), attribute.getValue().toString());
        }
      }
        }
   
  }

  @Override
  protected IElementHandler createXmlReader() {
    return new MyXmlReader();
  }

  @Override
  protected IExtension createExtension(final NodeModel node, final XMLElement element) {
    final MapStyleModel model = new MapStyleModel();
    final String colorString = element.getAttribute("background", null);
    final Color bgColor;
    if (colorString != null) {
      bgColor = ColorUtils.stringToColor(colorString);
    }
    else {
      bgColor = null;
    }
    model.setBackgroundColor(bgColor);
    final String zoomString = element.getAttribute("zoom", null);
    if (zoomString != null) {
      final float zoom = Float.valueOf(zoomString);
      model.setZoom(zoom);
    }
    final String layoutString = element.getAttribute("layout", null);
    try {
      if (layoutString != null) {
        final MapViewLayout layout = MapViewLayout.valueOf(layoutString);
        model.setMapViewLayout(layout);
      }
    }
    catch (final Exception e) {
    }
    final String maxNodeWidthString = element.getAttribute("max_node_width", null);
    final String minNodeWidthString = element.getAttribute("min_node_width",null);
    try {
      if (maxNodeWidthString != null) {
        final int maxNodeWidth = Integer.valueOf(maxNodeWidthString);
        model.setMaxNodeWidth(maxNodeWidth);
      }
      if (minNodeWidthString != null) {
        final int minNodeWidth = Integer.valueOf(minNodeWidthString);
        model.setMinNodeWidth(minNodeWidth);
      }
    }
    catch (final Exception e) {
    }
    return model;
  }

  private void loadConditionalStyles(ConditionalStyleModel conditionalStyleModel, XMLElement conditionalStylesRoot) {
    final ConditionFactory conditionFactory = FilterController.getCurrentFilterController().getConditionFactory();
    final Vector<XMLElement> styleElements = conditionalStylesRoot.getChildrenNamed("conditional_style");
    for(XMLElement styleElement : styleElements){
      final boolean isActive = Boolean.valueOf(styleElement.getAttribute("ACTIVE", "false"));
      final boolean isLast = Boolean.valueOf(styleElement.getAttribute("LAST", "false"));
      String styleText = styleElement.getAttribute("LOCALIZED_STYLE_REF", null);
      final IStyle style;
      if(styleText != null){
        style = StyleFactory.create(NamedObject.format((String) styleText));
      }
      else {
        style = StyleFactory.create(styleElement.getAttribute("STYLE_REF", null));
      }
      final ASelectableCondition condition;
      if(styleElement.getChildrenCount() == 1){
        final XMLElement conditionElement = styleElement.getChildAtIndex(0);
        try {
                  condition = conditionFactory.loadCondition(conditionElement);
                }
                catch (Exception e) {
                  e.printStackTrace();
                  continue;
                }
      }
      else{
        condition = null;
      }
      conditionalStyleModel.addCondition(isActive, condition, style, isLast);
    }
    }
  private void saveConditionalStyles(ConditionalStyleModel conditionalStyleModel, XMLElement parent, boolean createRoot) {
    final int styleCount = conditionalStyleModel.getStyleCount();
    if(styleCount == 0){
      return;
    }
    final XMLElement conditionalStylesRoot;
    if(createRoot){
      conditionalStylesRoot = parent.createElement("conditional_styles");
    parent.addChild(conditionalStylesRoot);
    }
    else
      conditionalStylesRoot = parent;
    for(final Item item : conditionalStyleModel){
      item.toXml(conditionalStylesRoot);
    }
     
    }

  public Color getBackground(final MapModel map) {
    final IExtension extension = map.getRootNode().getExtension(MapStyleModel.class);
    final Color backgroundColor = extension != null ? ((MapStyleModel) extension).getBackgroundColor() : null;
    if (backgroundColor != null) {
      return backgroundColor;
    }
    final String stdcolor = ResourceController.getResourceController().getProperty(
        MapStyle.RESOURCES_BACKGROUND_COLOR);
    final Color standardMapBackgroundColor = ColorUtils.stringToColor(stdcolor);
    return standardMapBackgroundColor;
  }

  @Override
  protected Class<MapStyleModel> getExtensionClass() {
    return MapStyleModel.class;
  }

  public void onCreate(final MapModel map) {
    final NodeModel rootNode = map.getRootNode();
    final MapStyleModel mapStyleModel = MapStyleModel.getExtension(rootNode);
    if (mapStyleModel != null && mapStyleModel.getStyleMap() != null) {
      return;
    }
    createDefaultStyleMap(map);
  }

  private void createDefaultStyleMap(final MapModel map) {
    UrlManager loader = UrlManager.getController();
    final File file = loader.defaultTemplateFile();
    if (file != null) {
      try {
        MapModel styleMapContainer = new MapModel();
        loader.load(Compat.fileToUrl(file), styleMapContainer);
        if (null != MapStyleModel.getExtension(styleMapContainer)){
          moveStyle(styleMapContainer, map, false);
          return;
        }
      }
      catch (Exception e) {
        LogUtils.warn(e);
        UITools.errorMessage(TextUtils.format("error_in_template", file));
      }
    };
    MapModel styleMapContainer = new MapModel();
    try {
      loader.load(ResourceController.getResourceController().getResource("/styles/viewer_standard.mm"), styleMapContainer);
      moveStyle(styleMapContainer, map, false);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    }


  private void moveStyle(final MapModel sourceMap, final MapModel targetMap, boolean overwrite) {
      final MapStyleModel source = (MapStyleModel) sourceMap.getRootNode().removeExtension(MapStyleModel.class);
      if(source == null)
        return;
    final IExtension undoHandler = targetMap.getExtension(IUndoHandler.class);
    source.getStyleMap().putExtension(IUndoHandler.class, undoHandler);
    final NodeModel targetRoot = targetMap.getRootNode();
    final MapStyleModel target = MapStyleModel.getExtension(targetRoot);
    if(target == null){
      targetRoot.addExtension(source);
    }
    else{
      target.copyFrom(source, overwrite);
    }
    }


  @Override
    protected HookAction createHookAction() {
      return null;
    }
 
  public void copyStyle(final URL source, final MapModel targetMap, boolean undoable) {
      final MapModel styleMapContainer = new MapModel();
    final IExtension oldStyleModel = targetMap.getRootNode().removeExtension(MapStyleModel.class);
    UrlManager.getController().loadCatchExceptions(source, styleMapContainer);
    onCreate(styleMapContainer);
    moveStyle(styleMapContainer, targetMap, true);
    LogicalStyleController.getController().refreshMap(targetMap);
    if(! undoable){
      return;
    }
    final IExtension newStyleModel = targetMap.getRootNode().getExtension(MapStyleModel.class);
    IActor actor = new IActor() {
      public void undo() {
        targetMap.getRootNode().putExtension(oldStyleModel);
      }
     
      public String getDescription() {
        return "moveStyle";
      }
     
      public void act() {
        targetMap.getRootNode().putExtension(newStyleModel);
      }
    };
    Controller.getCurrentModeController().execute(actor, targetMap);
  }
 
  public void onRemove(final MapModel map) {
  }

  @Override
  protected void saveExtension(final IExtension extension, final XMLElement element) {
    final MapStyleModel mapStyleModel = (MapStyleModel) extension;
    super.saveExtension(extension, element);
    final Color backgroundColor = mapStyleModel.getBackgroundColor();
    if (backgroundColor != null) {
      element.setAttribute("background", ColorUtils.colorToString(backgroundColor));
    }
    final float zoom = mapStyleModel.getZoom();
    if (zoom != 1f) {
      element.setAttribute("zoom", Float.toString(zoom));
    }
    final MapViewLayout layout = mapStyleModel.getMapViewLayout();
    if (!layout.equals(MapViewLayout.MAP)) {
      element.setAttribute("layout", layout.toString());
    }
    saveConditionalStyles(mapStyleModel.getConditionalStyleModel(), element, true);
    saveProperties(mapStyleModel.getProperties(), element);
  }
 
  private void saveProperties(Map<String, String> properties, XMLElement element) {
    if(properties.isEmpty()){
      return;
    }
      final XMLElement xmlElement = new XMLElement("properties");
      for (Entry<String, String>  entry: properties.entrySet()){
        xmlElement.setAttribute(entry.getKey(), entry.getValue());
      }
      element.addChild(xmlElement);
    }

  public void setZoom(final MapModel map, final float zoom) {
    final MapStyleModel mapStyleModel = MapStyleModel.getExtension(map);
    if (zoom == mapStyleModel.getZoom()) {
      return;
    }
    mapStyleModel.setZoom(zoom);
    Controller.getCurrentModeController().getMapController().setSaved(map, false);
  }

 
  public void setMapViewLayout(final MapModel map, final MapViewLayout layout) {
    final MapStyleModel mapStyleModel = MapStyleModel.getExtension(map);
    if (layout.equals(mapStyleModel.getMapViewLayout())) {
      return;
    }
    mapStyleModel.setMapViewLayout(layout);
    Controller.getCurrentModeController().getMapController().setSaved(map, false);
  }

  public void setBackgroundColor(final MapStyleModel model, final Color actionColor) {
    final Color oldColor = model.getBackgroundColor();
    if (actionColor == oldColor || actionColor != null && actionColor.equals(oldColor)) {
      return;
    }
    final IActor actor = new IActor() {
      public void act() {
        model.setBackgroundColor(actionColor);
        Controller.getCurrentModeController().getMapController().fireMapChanged(
            new MapChangeEvent(MapStyle.this, Controller.getCurrentController().getMap(), MapStyle.RESOURCES_BACKGROUND_COLOR,
                oldColor, actionColor));
      }

      public String getDescription() {
        return "MapStyle.setBackgroundColor";
      }

      public void undo() {
        model.setBackgroundColor(oldColor);
        Controller.getCurrentModeController().getMapController().fireMapChanged(
            new MapChangeEvent(MapStyle.this, Controller.getCurrentController().getMap(), MapStyle.RESOURCES_BACKGROUND_COLOR,
                actionColor, oldColor));
      }
    };
    Controller.getCurrentModeController().execute(actor, Controller.getCurrentController().getMap());
  }

  public static  MapStyle getController(final ModeController modeController) {
        return (MapStyle) modeController.getExtension(MapStyle.class);
    }

  public static MapStyle getController() {
    return (MapStyle) getController(Controller.getCurrentModeController());
    }

  public void setProperty(final MapModel model, final String key, final String newValue) {
    final MapStyleModel styleModel = MapStyleModel.getExtension(model);
    final String oldValue = styleModel.getProperty(key);
    if(oldValue == newValue || oldValue != null && oldValue.equals(newValue)) {
      return;
    }
    IActor actor = new  IActor() {
      public void undo() {
        setPropertyWithoutUndo(model, key, oldValue);
      }
     
      public String getDescription() {
        return "set map style property";
      }
     
      public void act() {
        setPropertyWithoutUndo(model, key, newValue);
      }

      private void setPropertyWithoutUndo(final MapModel model, final String key, final String newValue) {
        styleModel.setProperty(key, newValue);
          Controller.getCurrentModeController().getMapController().fireMapChanged(
              new MapChangeEvent(MapStyle.this, model, key, oldValue, newValue));
            }
    };
    Controller.getCurrentModeController().execute(actor, model);
  }

  public String getPropertySetDefault(final MapModel model, final String key) {
      final MapStyleModel styleModel = MapStyleModel.getExtension(model);
      final String oldValue = styleModel.getProperty(key);
      if(oldValue != null){
        return oldValue;
      }
      final String value = ResourceController.getResourceController().getProperty(key);
      styleModel.setProperty(key, value);
      return value;
  }
 
  public String getProperty(final MapModel model, final String key) {
      return MapStyleModel.getExtension(model).getProperty(key);
  }
 
    public Map<String, String> getPropertiesReadOnly(final MapModel model) {
        return Collections.unmodifiableMap(MapStyleModel.getExtension(model).getProperties());
    }
}
TOP

Related Classes of org.freeplane.features.styles.MapStyle$XmlWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.