Package org.locationtech.udig.legend.ui

Source Code of org.locationtech.udig.legend.ui.LegendGraphic

/* uDig - User Friendly Desktop Internet GIS client
* http://udig.refractions.net
* (C) 2005, Refractions Research Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
* License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
*/
package org.locationtech.udig.legend.ui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.locationtech.udig.mapgraphic.MapGraphic;
import org.locationtech.udig.mapgraphic.MapGraphicContext;
import org.locationtech.udig.mapgraphic.internal.MapGraphicResource;
import org.locationtech.udig.mapgraphic.style.FontStyle;
import org.locationtech.udig.mapgraphic.style.FontStyleContent;
import org.locationtech.udig.mapgraphic.style.LocationStyleContent;
import org.locationtech.udig.project.IBlackboard;
import org.locationtech.udig.project.ILayer;
import org.locationtech.udig.project.internal.Layer;
import org.locationtech.udig.project.internal.StyleBlackboard;
import org.locationtech.udig.project.ui.internal.LayerGeneratedGlyphDecorator;
import org.locationtech.udig.ui.PlatformGIS;
import org.locationtech.udig.ui.graphics.AWTSWTImageUtils;
import org.locationtech.udig.ui.graphics.SLDs;
import org.locationtech.udig.ui.graphics.ViewportGraphics;

import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Rule;
import org.geotools.styling.Style;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.feature.type.Name;

/**
* Draw a legend based on looking at the current list layer list.
*
* @author Amr
* @since 1.0.0
*/
public class LegendGraphic implements MapGraphic {

  private int verticalMargin; // distance between border and icons/text
  private int horizontalMargin; // distance between border and icons/text
  private int verticalSpacing; // distance between layers
  private int horizontalSpacing; // space between image and text
  private Color foregroundColour;
  private Color backgroundColour;
  private int indentSize;

  private int imageWidth;
  private int imageHeight; // size of glyph image

  public void draw(MapGraphicContext context) {

    IBlackboard blackboard = context.getLayer().getStyleBlackboard();
    LegendStyle legendStyle = (LegendStyle) blackboard
        .get(LegendStyleContent.ID);
    if (legendStyle == null) {
      legendStyle = LegendStyleContent.createDefault();
      blackboard.put(LegendStyleContent.ID, legendStyle);
    }

    Rectangle locationStyle = (Rectangle) blackboard
        .get(LocationStyleContent.ID);
    if (locationStyle == null) {
      locationStyle = new Rectangle(-1, -1, -1, -1);
      blackboard.put(LocationStyleContent.ID, locationStyle);
    }

    FontStyle fontStyle = (FontStyle) blackboard.get(FontStyleContent.ID);
    if (fontStyle == null) {
      fontStyle = new FontStyle();
      blackboard.put(FontStyleContent.ID, fontStyle);
    }

    this.backgroundColour = legendStyle.backgroundColour;
    this.foregroundColour = legendStyle.foregroundColour;
    this.horizontalMargin = legendStyle.horizontalMargin;
    this.verticalMargin = legendStyle.verticalMargin;
    this.horizontalSpacing = legendStyle.horizontalSpacing;
    this.verticalSpacing = legendStyle.verticalSpacing;
    this.indentSize = legendStyle.indentSize;
    this.imageHeight = legendStyle.imageHeight;
    this.imageWidth = legendStyle.imageWidth;

    final ViewportGraphics graphics = context.getGraphics();

    if (fontStyle.getFont() != null) {
      graphics.setFont(fontStyle.getFont());
    }

    List<Map<ILayer, LegendEntry[]>> layers = new ArrayList<Map<ILayer, LegendEntry[]>>();

    int longestRow = 0; // used to calculate the width of the graphic
    final int[] numberOfEntries = new int[1]; // total number of entries to
                          // draw
    numberOfEntries[0] = 0;

    /*
     * Set up the layers that we want to draw so we can operate just on
     * those ones. Layers at index 0 are on the bottom of the map, so we
     * must iterate in reverse.
     *
     * While we are doing this, determine the longest row so we can properly
     * draw the graphic's border.
     */
    Dimension imageSize = new Dimension(imageWidth,imageHeight);
    Dimension textSize = new Dimension(0, graphics.getFontHeight());
   
    for (int i = context.getMapLayers().size() - 1; i >= 0; i--) {
      ILayer layer = context.getMapLayers().get(i);

      if (!(layer.getGeoResource() instanceof MapGraphicResource)
          && layer.isVisible()) {

        if (layer.hasResource(MapGraphic.class)) {
          // don't include mapgraphics
          continue;
        }
        String layerName = layer.getName();
        if (layerName == null) {
          layerName = null;
        }
        LegendEntry layerEntry = new LegendEntry(layerName);

        FeatureTypeStyle[] styles = locateStyle(layer);
        LegendEntry[] entries = null;
        if (styles == null) {
          // we should have a label but no style
          entries = new LegendEntry[] { layerEntry };
        } else {
          List<Rule> rules = rules(styles);
          int ruleCount = rules.size();

          if (ruleCount == 1
              && layer.getGeoResource().canResolve(
                  GridCoverage.class)) {
            // grid coverage with single rule; lets see if it is a
            // theming style
            List<LegendEntry> cmEntries = ColorMapLegendCreator
                .findEntries(styles, imageSize, textSize);
            if (cmEntries != null) {
              cmEntries.add(0, layerEntry); // add layer legend
                              // entry
              entries = cmEntries
                  .toArray(new LegendEntry[cmEntries.size()]);
            }
          }
          if (entries == null) {
            List<LegendEntry> localEntries = new ArrayList<LegendEntry>();
            if (ruleCount == 1) {
              // only one rule so apply this to the layer legend
              // entry
              layerEntry.setRule(rules.get(0));
            }
            localEntries.add(layerEntry); // add layer legend entry

            if (ruleCount > 1) {
              // we have more than one rule so there is likely
              // some
              // themeing going on; add each of these rules
              for (Rule rule : rules) {
                LegendEntry rentry = new LegendEntry(rule);
                localEntries.add(rentry);
              }
            }
            entries = localEntries
                .toArray(new LegendEntry[localEntries.size()]);
          }
        }
        layers.add(Collections.singletonMap(layer, entries));

        // compute maximum length for each entry
        for (int j = 0; j < entries.length; j++) {
          StringBuilder sb = new StringBuilder();
          for (int k = 0; k < entries[j].getText().length; k++){
            sb.append(entries[j].getText()[k]);
          }
          Rectangle2D bounds = graphics.getStringBounds(sb.toString());
          int length = indentSize + imageWidth + horizontalSpacing
              + (int) bounds.getWidth();

          if (length > longestRow) {
            longestRow = length;
          }
          numberOfEntries[0]++;
        }
      }
    }

    if (numberOfEntries[0] == 0) {
      // nothing to draw!
      return;
    }

    final int rowHeight = Math.max(imageHeight, graphics.getFontHeight()); // space
                                        // allocated
                                        // to
                                        // each
                                        // layer

    if (locationStyle.width == 0 || locationStyle.height == 0) {
      // we want to change the location style as needed
      // but not change the saved one so we create a copy here
      locationStyle = new Rectangle(locationStyle);
      if (locationStyle.width == 0) {
        // we want to grow to whatever size we need
        int width = longestRow + horizontalMargin * 2;
        locationStyle.width = width;
      }
      if (locationStyle.height == 0) {
        // we want to grow to whatever size we need
        int height = rowHeight * numberOfEntries[0] + verticalMargin * 2;
        for (int i = 0; i < layers.size(); i++) {
          Map<ILayer, LegendEntry[]> map = layers.get(i);
          final LegendEntry[] entries = map.values().iterator().next();
          for (int j = 0; j < entries.length; j ++){
            if (entries[j].getSpacingAfter() == null){
              height += verticalSpacing;
            }else{
              height += entries[j].getSpacingAfter();
            }
          }
        }
        locationStyle.height = height- verticalSpacing;
      }
    }

    // ensure box within the display
    Dimension displaySize = context.getMapDisplay().getDisplaySize();
    if (locationStyle.x < 0) {
      locationStyle.x = displaySize.width - locationStyle.width
          + locationStyle.x;
    }
    if ((locationStyle.x + locationStyle.width + 6) > displaySize.width) {
      locationStyle.x = displaySize.width - locationStyle.width - 5;
    }

    if (locationStyle.y < 0) {
      locationStyle.y = displaySize.height - locationStyle.height - 5
          + locationStyle.y;
    }
    if ((locationStyle.y + locationStyle.height + 6) > displaySize.height) {
      locationStyle.y = displaySize.height - locationStyle.height - 5;
    }

    graphics.setClip(new Rectangle(locationStyle.x, locationStyle.y,
        locationStyle.width + 1, locationStyle.height + 1));

    /*
     * Draw the box containing the layers/icons
     */
    drawOutline(graphics, context, locationStyle);

    /*
     * Draw the layer names/icons
     */
    final int[] rowsDrawn = new int[1];
    rowsDrawn[0] = 0;
    final int[] x = new int[1];
    x[0] = locationStyle.x + horizontalMargin;
    final int[] y = new int[1];
    y[0] = locationStyle.y + verticalMargin;

    if (fontStyle.getFont() != null) {
      graphics.setFont(fontStyle.getFont());
    }

    for (int i = 0; i < layers.size(); i++) {
      Map<ILayer, LegendEntry[]> map = layers.get(i);
      final ILayer layer = map.keySet().iterator().next();
      final LegendEntry[] entries = map.values().iterator().next();

      try {
        layer.getGeoResources().get(0).getInfo(null);
      } catch (Exception ex) {
      }

      PlatformGIS.syncInDisplayThread(new Runnable() {
        public void run() {
          for (int i = 0; i < entries.length; i++) {
            BufferedImage awtIcon = null;
            if (entries[i].getRule() != null) {
              // generate icon from use
              ImageDescriptor descriptor = LayerGeneratedGlyphDecorator
                  .generateStyledIcon(layer,
                      entries[i].getRule());
              if (descriptor == null) {
                descriptor = LayerGeneratedGlyphDecorator
                    .generateIcon((Layer) layer);
              }
              if (descriptor != null) {
                awtIcon = AWTSWTImageUtils
                    .convertToAWT(descriptor.getImageData());
              }
            } else if (entries[i].getIcon() != null) {
              // use set icon
              awtIcon = AWTSWTImageUtils.convertToAWT(entries[i]
                    .getIcon().getImageData());
            } else {
              // no rule, no icon, try default for layer
              ImageDescriptor descriptor = LayerGeneratedGlyphDecorator
                  .generateIcon((Layer) layer);
              if (descriptor != null) {
                awtIcon = AWTSWTImageUtils
                    .convertToAWT(descriptor.getImageData());
              }
            }
            drawRow(graphics, x[0], y[0], awtIcon,
                entries[i].getText(), i != 0, entries[i].getTextPosition());

            y[0] += rowHeight;
            if ((rowsDrawn[0] + 1) < numberOfEntries[0]) {
              if (entries[i].getSpacingAfter() != null){
                y[0] += entries[i].getSpacingAfter();
              }else{
                y[0] += verticalSpacing;
              }
            }
            rowsDrawn[0]++;
          }

        }
      });
    }
    // clear the clip so we don't affect other rendering processes
    graphics.setClip(null);
  }

  private List<Rule> rules(FeatureTypeStyle[] styles) {
    List<Rule> rules = new ArrayList<Rule>();
    for (FeatureTypeStyle featureTypeStyle : styles) {
      rules.addAll(featureTypeStyle.rules());
    }
    return rules;
  }

  private void drawRow(ViewportGraphics graphics, int x, int y,
      RenderedImage icon, String[] text, boolean indent, int position) {

    if (text.length == 0){
      return;
    }
    Rectangle2D stringBounds = graphics.getStringBounds(text[0]);

    /*
     * Center the smaller item (text or icon) according to the taller one.
     */
    int textVerticalOffset = 0;
    int iconVerticalOffset = 0;

    if ((position | SWT.CENTER) == position) {
      if (imageHeight == (int) stringBounds.getHeight()) {
        // items are the same height; do nothing.
      } else if (imageHeight > (int) stringBounds.getHeight()) {
        int difference = imageHeight - (int) stringBounds.getHeight();
        textVerticalOffset = difference / 2;
      } else if (imageHeight < (int) stringBounds.getHeight()) {
        int difference = (int) stringBounds.getHeight() - imageHeight;
        iconVerticalOffset = difference / 2;
      }
    } else if ((position | SWT.TOP) == position) {
      // do nothing; position everything at top
      textVerticalOffset = (int) (graphics.getFontAscent() * -0.6);
    }

    if (indent) {
      x += indentSize;
    }

    if (icon != null) {
      graphics.drawImage(icon, x, y + iconVerticalOffset);
      x += imageWidth;
    }

    if (text != null && text[0].length() != 0) {
      graphics.drawString(
          text[0],
          x + horizontalMargin,
          y + textVerticalOffset
          - (int) (graphics.getFontHeight() - graphics.getFontAscent()),
          ViewportGraphics.ALIGN_LEFT, ViewportGraphics.ALIGN_TOP);
    }

    if (text != null && text.length > 1) {
      //draw last label at bottom of range
      String end = text[text.length - 1];

      graphics.drawString(end, x + horizontalMargin, y + imageHeight
          + (int) (graphics.getFontAscent() * 0.3),
          ViewportGraphics.ALIGN_LEFT, ViewportGraphics.ALIGN_BOTTOM);
    }

  }

  private FeatureTypeStyle[] locateStyle(ILayer layer) {
    StyleBlackboard blackboard = (StyleBlackboard) layer
        .getStyleBlackboard();
    if (blackboard == null) {
      return null;
    }

    Style sld = (Style) blackboard.lookup(Style.class);
    if (sld == null) {
      return null;
    }

    List<FeatureTypeStyle> styles = new ArrayList<FeatureTypeStyle>();
    String layerTypeName = null;
    if (layer.getSchema() != null
        && layer.getSchema().getTypeName() != null) {
      layerTypeName = layer.getSchema().getTypeName();
    }
    for (FeatureTypeStyle style : sld.featureTypeStyles()) {
      Set<Name> names = style.featureTypeNames();
      if (names.size() == 0) {
        styles.add(style);
      } else {
        for (Name name : names) {
          if (name.getLocalPart().equals(
              SLDs.GENERIC_FEATURE_TYPENAME)
              || (layerTypeName != null && layerTypeName
                  .equals(name.getLocalPart()))) {
            styles.add(style);
            break;
          }
        }
      }
    }
    return styles.toArray(new FeatureTypeStyle[0]);
  }

  private void drawOutline(ViewportGraphics graphics,
      MapGraphicContext context, Rectangle locationStyle) {
    Rectangle outline = new Rectangle(locationStyle.x, locationStyle.y,
        locationStyle.width, locationStyle.height);

    // reserve this area free of labels!
    context.getLabelPainter().put(outline);

    graphics.setColor(backgroundColour);
    graphics.fill(outline);

    graphics.setColor(foregroundColour);
    graphics.setBackground(backgroundColour);
    graphics.draw(outline);
  }
}
TOP

Related Classes of org.locationtech.udig.legend.ui.LegendGraphic

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.