private void draw(
      Object parentGroup, GeometryIndex parentIndex, Polygon polygon, GraphicsContext graphics) {
    String groupName = baseName;
    if (parentIndex != null) {
      groupName += "." + editingService.getIndexService().format(parentIndex);
    }

    Composite bgGroup = getOrCreateGroup(parentGroup, groupName + ".background");
    Composite geometryGroup = getOrCreateGroup(parentGroup, groupName + ".geometries");

    // Draw the exterior ring:
    GeometryIndex shellIndex =
        editingService
            .getIndexService()
            .addChildren(parentIndex, GeometryIndexType.TYPE_GEOMETRY, 0);
    if (!polygon.isEmpty()) {
      if (styleService.getBackgroundStyle() != null
          && styleService.getBackgroundStyle().getFillOpacity() > 0) {
        graphics.drawPolygon(bgGroup, "background", polygon, findGeometryStyle(shellIndex));
      }
      draw(geometryGroup, shellIndex, polygon.getExteriorRing(), graphics);
    }

    // Draw the interior rings:
    for (int i = 0; i < polygon.getNumInteriorRing(); i++) {
      GeometryIndex holeIndex =
          editingService
              .getIndexService()
              .addChildren(parentIndex, GeometryIndexType.TYPE_GEOMETRY, i + 1);
      draw(geometryGroup, holeIndex, polygon.getInteriorRingN(i), graphics);
    }
  }
 public void setVisible(boolean visible) {
   if (visible) {
     mapWidget.getVectorContext().hide(editingService.getGeometry());
   } else {
     mapWidget.getVectorContext().unhide(editingService.getGeometry());
   }
 }
 private ShapeStyle findGeometryStyle(GeometryIndex index) {
   if (!editingService.getIndexStateService().isEnabled(index)) {
     return styleService.getBackgroundDisabledStyle();
   } else if (editingService.getIndexStateService().isMarkedForDeletion(index)) {
     return styleService.getBackgroundMarkedForDeletionStyle();
   }
   return styleService.getBackgroundStyle();
 }
  /**
   * Start splitting the given geometry.
   *
   * @param geometry to be split
   */
  public void start(Geometry geometry) {
    this.geometry = geometry;

    splitLine = new Geometry(Geometry.LINE_STRING, 0, 0);
    service.start(splitLine);
    service.setInsertIndex(service.getIndexService().create(GeometryIndexType.TYPE_VERTEX, 0));
    service.setEditingState(GeometryEditState.INSERTING);

    started = true;
    eventBus.fireEvent(new GeometrySplitStartEvent(geometry));
  }
  private void updateEdge(Geometry geometry, GeometryIndex index, boolean bringToFront)
      throws GeometryIndexNotFoundException {
    // Some initialization:
    String identifier = baseName + "." + editingService.getIndexService().format(index);
    Object parentGroup =
        groups.get(identifier.substring(0, identifier.lastIndexOf('.')) + ".edges");

    Coordinate[] c = editingService.getIndexService().getEdge(geometry, index);
    LineString temp = mapWidget.getMapModel().getGeometryFactory().createLineString(c);
    LineString edge =
        (LineString)
            mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp);
    mapWidget.getVectorContext().drawLine(parentGroup, identifier, edge, findEdgeStyle(index));
  }
  private void draw(
      Object parentGroup,
      GeometryIndex parentIndex,
      LinearRing linearRing,
      GraphicsContext graphics) {
    String groupName = baseName;
    if (parentIndex != null) {
      groupName += "." + editingService.getIndexService().format(parentIndex);
    }
    Composite edgeGroup = getOrCreateGroup(parentGroup, groupName + ".edges");
    Composite vertexGroup = getOrCreateGroup(parentGroup, groupName + ".vertices");

    Coordinate[] coordinates = linearRing.getCoordinates();
    if (coordinates != null) {
      // Check if we have to draw the background as well (if there are controllers defined for it):
      GraphicsController controller = createGeometryController(parentIndex);
      if (controller != null) {
        Polygon polygon =
            mapWidget.getMapModel().getGeometryFactory().createPolygon(linearRing, null);
        graphics.drawPolygon(parentGroup, groupName + ".background", polygon, new ShapeStyle());
        graphics.setController(parentGroup, groupName + ".background", controller);
      }

      // Draw individual edges:
      int max = coordinates.length;
      if (!styleService.isCloseRingWhileInserting()
          && editingService.getEditingState() == GeometryEditState.INSERTING
          && editingService
              .getIndexService()
              .isChildOf(parentIndex, editingService.getInsertIndex())) {
        max--;
      }
      for (int i = 1; i < max; i++) {
        GeometryIndex edgeIndex =
            editingService
                .getIndexService()
                .addChildren(parentIndex, GeometryIndexType.TYPE_EDGE, i - 1);
        String identifier = baseName + "." + editingService.getIndexService().format(edgeIndex);

        LineString edge =
            linearRing
                .getGeometryFactory()
                .createLineString(new Coordinate[] {coordinates[i - 1], coordinates[i]});
        graphics.drawLine(edgeGroup, identifier, edge, findEdgeStyle(edgeIndex));
        graphics.setController(edgeGroup, identifier, createEdgeController(edgeIndex));
      }

      addInivisibleShapeToGraphicsContext(graphics, vertexGroup);
      for (int i = 0; i < coordinates.length - 1; i++) {
        GeometryIndex vertexIndex =
            editingService
                .getIndexService()
                .addChildren(parentIndex, GeometryIndexType.TYPE_VERTEX, i);
        String identifier = baseName + "." + editingService.getIndexService().format(vertexIndex);
        addShapeToGraphicsContext(
            graphics, vertexGroup, identifier, coordinates[i], findVertexStyle(vertexIndex));
        graphics.setController(vertexGroup, identifier, createVertexController(vertexIndex));
      }
    }
  }
  private void updateVertex(Geometry geometry, GeometryIndex index, boolean moveToBack)
      throws GeometryIndexNotFoundException {
    // Some initialization:
    String identifier = baseName + "." + editingService.getIndexService().format(index);
    Composite parentGroup =
        groups.get(identifier.substring(0, identifier.lastIndexOf('.')) + ".vertices");

    Coordinate temp = editingService.getIndexService().getVertex(geometry, index);
    Coordinate coordinate =
        mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp);
    addShapeToGraphicsContext(
        mapWidget.getVectorContext(), parentGroup, identifier, coordinate, findVertexStyle(index));
    if (moveToBack) {
      mapWidget.getVectorContext().moveToBack(parentGroup, identifier);
    }
  }
  private ShapeStyle findEdgeStyle(GeometryIndex index) {
    if (editingService.getIndexStateService().isMarkedForDeletion(index)) {
      return styleService.getEdgeMarkForDeletionStyle();
    } else if (!editingService.getIndexStateService().isEnabled(index)) {
      return styleService.getEdgeDisabledStyle();
    }

    boolean selected = editingService.getIndexStateService().isSelected(index);
    boolean highlighted = editingService.getIndexStateService().isHightlighted(index);
    if (selected && highlighted) {
      return styleService.getEdgeSelectHoverStyle();
    } else if (selected) {
      return styleService.getEdgeSelectStyle();
    } else if (highlighted) {
      return styleService.getEdgeHoverStyle();
    }
    return styleService.getEdgeStyle();
  }
  public void onCoordinateSnapAttempt(CoordinateSnapEvent event) {
    if (editingService.getEditingState() == GeometryEditState.INSERTING) {
      String identifier =
          baseName + "." + editingService.getIndexService().format(editingService.getInsertIndex());
      Object parentGroup =
          groups.get(identifier.substring(0, identifier.lastIndexOf('.')) + ".vertices");

      Coordinate temp = event.getTo();
      Coordinate coordinate =
          mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp);
      addShapeToGraphicsContext(
          mapWidget.getVectorContext(),
          parentGroup,
          identifier,
          coordinate,
          event.hasSnapped() ? styleService.getVertexSnappedStyle() : new ShapeStyle());
    }
  }
  private void draw(
      Object parentGroup, GeometryIndex parentIndex, MultiPolygon mp, GraphicsContext graphics) {
    String groupName = baseName;
    if (parentIndex != null) {
      groupName += "." + editingService.getIndexService().format(parentIndex);
    }

    Composite geometryGroup = getOrCreateGroup(parentGroup, groupName + ".geometries");

    // Draw all polygons:
    for (int i = 0; i < mp.getNumGeometries(); i++) {
      GeometryIndex polygonIndex =
          editingService
              .getIndexService()
              .addChildren(parentIndex, GeometryIndexType.TYPE_GEOMETRY, i);
      draw(geometryGroup, polygonIndex, (Polygon) mp.getGeometryN(i), graphics);
    }
  }
  private void draw(
      Object parentGroup,
      GeometryIndex parentIndex,
      LineString lineString,
      GraphicsContext graphics) {
    String groupName = baseName;
    if (parentIndex != null) {
      groupName += "." + editingService.getIndexService().format(parentIndex);
    }
    Composite edgeGroup = getOrCreateGroup(parentGroup, groupName + ".edges");
    Composite vertexGroup = getOrCreateGroup(parentGroup, groupName + ".vertices");

    Coordinate[] coordinates = lineString.getCoordinates();
    if (coordinates != null) {
      // Draw individual edges:
      for (int i = 1; i < coordinates.length; i++) {
        GeometryIndex edgeIndex =
            editingService
                .getIndexService()
                .addChildren(parentIndex, GeometryIndexType.TYPE_EDGE, i - 1);
        String identifier = baseName + "." + editingService.getIndexService().format(edgeIndex);

        LineString edge =
            lineString
                .getGeometryFactory()
                .createLineString(new Coordinate[] {coordinates[i - 1], coordinates[i]});
        graphics.drawLine(edgeGroup, identifier, edge, findEdgeStyle(edgeIndex));
        graphics.setController(edgeGroup, identifier, createEdgeController(edgeIndex));
      }

      addInivisibleShapeToGraphicsContext(graphics, vertexGroup);
      for (int i = 0; i < coordinates.length; i++) {
        GeometryIndex vertexIndex =
            editingService
                .getIndexService()
                .addChildren(parentIndex, GeometryIndexType.TYPE_VERTEX, i);
        String identifier = baseName + "." + editingService.getIndexService().format(vertexIndex);

        addShapeToGraphicsContext(
            graphics, vertexGroup, identifier, coordinates[i], findVertexStyle(vertexIndex));
        graphics.setController(vertexGroup, identifier, createVertexController(vertexIndex));
      }
    }
  }
  private void draw(
      Object parentGroup, GeometryIndex parentIndex, Point point, GraphicsContext graphics) {
    String groupName = baseName;
    if (parentIndex != null) {
      groupName += "." + editingService.getIndexService().format(parentIndex);
    }
    Composite vertexGroup = getOrCreateGroup(parentGroup, groupName + ".vertices");

    addInivisibleShapeToGraphicsContext(graphics, vertexGroup);
    if (!point.isEmpty()) {
      GeometryIndex vertexIndex =
          editingService
              .getIndexService()
              .addChildren(parentIndex, GeometryIndexType.TYPE_VERTEX, 0);
      String identifier = baseName + "." + editingService.getIndexService().format(vertexIndex);

      addShapeToGraphicsContext(
          graphics, vertexGroup, identifier, point.getCoordinate(), findVertexStyle(vertexIndex));
      graphics.setController(vertexGroup, identifier, createVertexController(vertexIndex));
    }
  }
  public void onChangeEditingState(GeometryEditChangeStateEvent event) {
    switch (event.getEditingState()) {
      case DRAGGING:
        mapWidget.setCursor(Cursor.MOVE);
        break;
      case IDLE:
      default:
        mapWidget.setCursorString(mapWidget.getDefaultCursorString());
        redraw();

        // Remove the temporary insert move line:
        if (editingService.getInsertIndex() != null) {
          String id =
              baseName
                  + "."
                  + editingService.getIndexService().format(editingService.getInsertIndex());
          Object parentGroup = groups.get(id.substring(0, id.lastIndexOf('.')) + ".edges");
          mapWidget.getVectorContext().deleteElement(parentGroup, insertMoveEdgeId1);
          mapWidget.getVectorContext().deleteElement(parentGroup, insertMoveEdgeId2);
        }
    }
  }
 private GraphicsController createVertexController(GeometryIndex index) {
   CompositeGeometryIndexController controller =
       new CompositeGeometryIndexController(
           mapWidget,
           editingService,
           index,
           editingService.getEditingState() == GeometryEditState.DRAGGING);
   for (AbstractGeometryIndexMapHandler handler : EditingHandlerRegistry.getVertexHandlers()) {
     controller.addMapHandler(handler);
   }
   for (VertexMapHandlerFactory factory : customVertexFactories) {
     controller.addMapHandler(factory.create());
   }
   return controller;
 }
  /**
   * Constructor with a {@link GeometryEditService}, that if stopped, stops this service as well.
   *
   * @param service the {@link GeometryEditService} that needs to be used
   */
  public GeometrySplitService(GeometryEditService service) {
    this.service = service;
    eventBus = new SimpleEventBus();

    service.addGeometryEditStopHandler(
        new GeometryEditStopHandler() {

          @Override
          public void onGeometryEditStop(GeometryEditStopEvent event) {
            if (started) {
              stop(null);
            }
          }
        });
  }
  // TODO make use of the findGeometryStyle method.
  private void updateGeometry(Geometry geometry, GeometryIndex index, boolean bringToFront)
      throws GeometryIndexNotFoundException {
    // Some initialization:
    String identifier = baseName + "." + editingService.getIndexService().format(index);
    boolean marked = editingService.getIndexStateService().isMarkedForDeletion(index);

    // Find current and previous parent groups:
    Composite parentGroup =
        groups.get(identifier.substring(0, identifier.lastIndexOf('.')) + ".geometries");

    // Find the correct style:
    ShapeStyle style = new ShapeStyle();
    if (marked) {
      style = styleService.getBackgroundMarkedForDeletionStyle();
    }

    // Draw the inner ring:
    org.geomajas.gwt.client.spatial.geometry.Geometry transformed =
        mapWidget
            .getMapModel()
            .getMapView()
            .getWorldViewTransformer()
            .worldToPan(
                GeometryConverter.toGwt(
                    editingService.getIndexService().getGeometry(geometry, index)));
    if (transformed instanceof LinearRing) {
      Polygon polygon =
          mapWidget
              .getMapModel()
              .getGeometryFactory()
              .createPolygon((LinearRing) transformed, null);
      mapWidget
          .getVectorContext()
          .drawPolygon(parentGroup, identifier + ".background", polygon, style);
    }
  }
 private void update(Geometry geometry, GeometryIndex index, boolean bringToFront) {
   try {
     switch (editingService.getIndexService().getType(index)) {
       case TYPE_VERTEX:
         updateVertex(geometry, index, bringToFront);
         break;
       case TYPE_EDGE:
         updateEdge(geometry, index, bringToFront);
         break;
       case TYPE_GEOMETRY:
       default:
         updateGeometry(geometry, index, bringToFront);
     }
   } catch (GeometryIndexNotFoundException e) {
   }
 }
  private GraphicsController createGeometryController(GeometryIndex index) {
    List<AbstractGeometryIndexMapHandler> handlers = EditingHandlerRegistry.getGeometryHandlers();
    if (handlers == null || handlers.size() == 0) {
      return null;
    }

    CompositeGeometryIndexController controller =
        new CompositeGeometryIndexController(
            mapWidget,
            editingService,
            index,
            editingService.getEditingState() == GeometryEditState.DRAGGING);
    for (AbstractGeometryIndexMapHandler handler : handlers) {
      controller.addMapHandler(handler);
    }
    return controller;
  }
  /**
   * Stop splitting the geometry.
   *
   * @param callback the {@link GeometryArrayFunction} to be executed after the splitting has
   *     stopped
   */
  public void stop(final GeometryArrayFunction callback) {
    started = false;
    service.stop();
    if (callback != null) {
      calculate(
          new GeometryArrayFunction() {

            public void execute(Geometry[] geometries) {
              callback.execute(geometries);
              splitLine = null;
              eventBus.fireEvent(new GeometrySplitStopEvent(geometry));
            }
          });
    } else {
      eventBus.fireEvent(new GeometrySplitStopEvent(geometry));
      splitLine = null;
    }
  }
  private GraphicsController createEdgeController(GeometryIndex index) {
    CompositeGeometryIndexController controller =
        new CompositeGeometryIndexController(
            mapWidget,
            editingService,
            index,
            editingService.getEditingState() == GeometryEditState.DRAGGING);
    for (AbstractGeometryIndexMapHandler handler : EditingHandlerRegistry.getEdgeHandlers()) {
      controller.addMapHandler(handler);
    }
    for (EdgeMapHandlerFactory factory : customEdgeFactories) {
      controller.addMapHandler(factory.create());
    }

    EdgeMarkerHandler edgeMarkerHandler =
        new EdgeMarkerHandler(mapWidget, editingService, controller);
    controller.addMouseOutHandler(edgeMarkerHandler);
    controller.addMouseMoveHandler(edgeMarkerHandler);
    controller.addMapDownHandler(edgeMarkerHandler);
    return controller;
  }
 public void redraw() {
   groups.clear();
   mapWidget.getVectorContext().deleteGroup(editingService.getGeometry());
   draw(editingService.getGeometry());
 }
  public void onGeometryEditMove(GeometryEditMoveEvent event) {

    // Find the elements that need updating:
    Map<GeometryIndex, Boolean> indicesToUpdate = new HashMap<GeometryIndex, Boolean>();
    for (GeometryIndex index : event.getIndices()) {
      if (!indicesToUpdate.containsKey(index)) {
        indicesToUpdate.put(index, false);
        if (!Geometry.POINT.equals(editingService.getGeometry().getGeometryType())
            && !Geometry.MULTI_POINT.equals(editingService.getGeometry().getGeometryType())) {
          try {
            List<GeometryIndex> neighbors = null;
            switch (editingService.getIndexService().getType(index)) {
              case TYPE_VERTEX:
                // Move current vertex to the back. This helps the delete operation.
                indicesToUpdate.put(index, true);
                neighbors =
                    editingService.getIndexService().getAdjacentEdges(event.getGeometry(), index);
                if (neighbors != null) {
                  for (GeometryIndex neighborIndex : neighbors) {
                    if (!indicesToUpdate.containsKey(neighborIndex)) {
                      indicesToUpdate.put(neighborIndex, false);
                    }
                  }
                }

                neighbors =
                    editingService
                        .getIndexService()
                        .getAdjacentVertices(event.getGeometry(), index);
                if (neighbors != null) {
                  for (GeometryIndex neighborIndex : neighbors) {
                    if (!indicesToUpdate.containsKey(neighborIndex)) {
                      indicesToUpdate.put(neighborIndex, false);
                    }
                  }
                }
                break;
              case TYPE_EDGE:
                neighbors =
                    editingService
                        .getIndexService()
                        .getAdjacentVertices(event.getGeometry(), index);
                if (neighbors != null) {
                  for (GeometryIndex neighborIndex : neighbors) {
                    if (!indicesToUpdate.containsKey(neighborIndex)) {
                      indicesToUpdate.put(neighborIndex, false);
                    }
                  }
                }
                break;
              default:
            }
          } catch (GeometryIndexNotFoundException e) {
            throw new IllegalStateException(e);
          }
        }
      }
    }

    // Check if we need to draw the background (nice, but slows down):
    if (styleService.getBackgroundStyle() != null
        && styleService.getBackgroundStyle().getFillOpacity() > 0) {
      if (event.getGeometry().getGeometryType().equals(Geometry.POLYGON)) {
        org.geomajas.gwt.client.spatial.geometry.Geometry transformed =
            mapWidget
                .getMapModel()
                .getMapView()
                .getWorldViewTransformer()
                .worldToPan(GeometryConverter.toGwt(event.getGeometry()));
        mapWidget
            .getVectorContext()
            .drawPolygon(
                groups.get(baseName + ".background"),
                "background",
                (Polygon) transformed,
                styleService.getBackgroundStyle());
      } else if (event.getGeometry().getGeometryType().equals(Geometry.MULTI_POLYGON)
          && event.getGeometry().getGeometries() != null) {
        for (int i = 0; i < event.getGeometry().getGeometries().length; i++) {
          Geometry polygon = event.getGeometry().getGeometries()[i];

          org.geomajas.gwt.client.spatial.geometry.Geometry transformed =
              mapWidget
                  .getMapModel()
                  .getMapView()
                  .getWorldViewTransformer()
                  .worldToPan(GeometryConverter.toGwt(polygon));
          mapWidget
              .getVectorContext()
              .drawPolygon(
                  groups.get(baseName + ".geometry" + i + ".background"),
                  "background",
                  (Polygon) transformed,
                  styleService.getBackgroundStyle());
        }
      }
    }

    // Next, redraw the list:
    for (GeometryIndex index : indicesToUpdate.keySet()) {
      update(event.getGeometry(), index, indicesToUpdate.get(index));
    }
  }
  public void onTentativeMove(GeometryEditTentativeMoveEvent event) {
    try {
      Coordinate[] vertices =
          editingService
              .getIndexService()
              .getSiblingVertices(editingService.getGeometry(), editingService.getInsertIndex());
      String geometryType =
          editingService
              .getIndexService()
              .getGeometryType(editingService.getGeometry(), editingService.getInsertIndex());

      if (vertices != null && Geometry.LINE_STRING.equals(geometryType)) {
        String identifier =
            baseName
                + "."
                + editingService.getIndexService().format(editingService.getInsertIndex());
        Object parentGroup =
            groups.get(identifier.substring(0, identifier.lastIndexOf('.')) + ".edges");

        Coordinate temp1 = event.getOrigin();
        Coordinate temp2 = event.getCurrentPosition();
        Coordinate c1 =
            mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp1);
        Coordinate c2 =
            mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp2);

        LineString edge =
            mapWidget
                .getMapModel()
                .getGeometryFactory()
                .createLineString(new Coordinate[] {c1, c2});
        mapWidget
            .getVectorContext()
            .drawLine(
                parentGroup, insertMoveEdgeId1, edge, styleService.getEdgeTentativeMoveStyle());
      } else if (vertices != null && Geometry.LINEAR_RING.equals(geometryType)) {
        String identifier =
            baseName
                + "."
                + editingService.getIndexService().format(editingService.getInsertIndex());
        Object parentGroup =
            groups.get(identifier.substring(0, identifier.lastIndexOf('.')) + ".edges");

        // Line 1
        Coordinate temp1 = event.getOrigin();
        Coordinate temp2 = event.getCurrentPosition();
        Coordinate c1 =
            mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp1);
        Coordinate c2 =
            mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp2);
        LineString edge =
            mapWidget
                .getMapModel()
                .getGeometryFactory()
                .createLineString(new Coordinate[] {c1, c2});
        mapWidget
            .getVectorContext()
            .drawLine(
                parentGroup, insertMoveEdgeId1, edge, styleService.getEdgeTentativeMoveStyle());

        // Line 2
        if (styleService.isCloseRingWhileInserting()) {
          temp1 = vertices[vertices.length - 1];
          c1 = mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp1);
          edge =
              mapWidget
                  .getMapModel()
                  .getGeometryFactory()
                  .createLineString(new Coordinate[] {c1, c2});
          mapWidget
              .getVectorContext()
              .drawLine(
                  parentGroup, insertMoveEdgeId2, edge, styleService.getEdgeTentativeMoveStyle());
        }
      }
    } catch (GeometryIndexNotFoundException e) {
      throw new IllegalStateException(e);
    }
  }