/**
   * Initialize the LayerTree, using a MapWidget as base reference. It will display the map's
   * layers, as configured in the XML configuration, and select/deselect the layer as the user
   * clicks on them in the tree.
   *
   * @param mapWidget map widget this layer tree is connected to
   * @since 1.6.0
   */
  @Api
  public LayerTree(final MapWidget mapWidget) {
    super();
    setHeight100();
    this.mapModel = mapWidget.getMapModel();
    htmlSelectedLayer.setWidth100();

    // Wait for the MapModel to be loaded
    mapModel.addMapModelChangedHandler(
        new MapModelChangedHandler() {

          public void onMapModelChanged(MapModelChangedEvent event) {
            if (!initialized) {
              buildTree(mapModel);
              toolStrip = buildToolstrip(mapWidget);

              // display the toolbar and the tree
              VLayout vLayout = new VLayout();
              vLayout.setSize("100%", "100%");
              vLayout.addMember(toolStrip);
              htmlSelectedLayer.setBackgroundColor(WidgetLayout.layerTreeBackground);
              htmlSelectedLayer.setAlign(Alignment.CENTER);
              vLayout.addMember(htmlSelectedLayer);
              vLayout.addMember(treeGrid);
              LayerTree.this.addChild(vLayout);
            }
            initialized = true;
            treeGrid.markForRedraw();
            LayerTree.this.markForRedraw();
          }
        });
    mapModel.addLayerSelectionHandler(this);
  }
 /**
  * When the user clicks on a leaf the header text of the tree table is changed to the selected
  * leaf and the toolbar buttons are updated to represent the correct state of the buttons.
  */
 public void onLeafClick(LeafClickEvent event) {
   LayerTreeTreeNode layerTreeNode = (LayerTreeTreeNode) event.getLeaf();
   if (null != selectedLayerTreeNode
       && layerTreeNode.getLayer().getId().equals(selectedLayerTreeNode.getLayer().getId())) {
     mapModel.selectLayer(null);
   } else {
     mapModel.selectLayer(layerTreeNode.getLayer());
   }
 }
  /**
   * Builds up the tree showing the layers
   *
   * @param mapModel The mapModel containing the layerTree
   */
  private void buildTree(MapModel mapModel) {
    treeGrid.setWidth100();
    treeGrid.setHeight100();
    treeGrid.setShowHeader(false);
    tree = new RefreshableTree();
    final TreeNode nodeRoot = new TreeNode("ROOT");
    tree.setRoot(nodeRoot); // invisible ROOT node (ROOT node is required)

    ClientLayerTreeInfo layerTreeInfo = mapModel.getMapInfo().getLayerTree();
    if (layerTreeInfo != null) {
      ClientLayerTreeNodeInfo treeNode = layerTreeInfo.getTreeNode();
      processNode(treeNode, nodeRoot, tree, mapModel, false);
    }

    treeGrid.setData(tree);
    treeGrid.addLeafClickHandler(this);
    treeGrid.addFolderClickHandler(this);

    // -- add event listeners to layers
    for (Layer<?> layer : mapModel.getLayers()) {
      registrations.add(
          layer.addLayerChangedHandler(
              new LayerChangedHandler() {
                public void onLabelChange(LayerLabeledEvent event) {}

                public void onVisibleChange(LayerShownEvent event) {
                  for (TreeNode node : tree.getAllNodes()) {
                    if (node.getName().equals(event.getLayer().getLabel())) {
                      if (node instanceof LayerTreeTreeNode) {
                        ((LayerTreeTreeNode) node).updateIcon();
                      }
                    }
                  }
                }
              }));
    }
  }
  /**
   * Builds the toolbar
   *
   * @param mapWidget The mapWidget containing the layerTree
   * @return {@link com.smartgwt.client.widgets.toolbar.ToolStrip} which was built
   */
  private ToolStrip buildToolstrip(MapWidget mapWidget) {
    toolStrip = new ToolStrip();
    toolStrip.setWidth100();
    toolStrip.setPadding(3);

    ClientLayerTreeInfo layerTreeInfo = mapModel.getMapInfo().getLayerTree();
    if (layerTreeInfo != null) {
      for (ClientToolInfo tool : layerTreeInfo.getTools()) {
        String id = tool.getToolId();
        Canvas button = null;
        ToolbarBaseAction action = LayerTreeRegistry.getToolbarAction(id, mapWidget);
        if (action instanceof ToolbarWidget) {
          toolStrip.addMember(((ToolbarWidget) action).getWidget());
        } else if (action instanceof ToolbarCanvas) {
          button = ((ToolbarCanvas) action).getCanvas();
        } else if (action instanceof LayerTreeAction) {
          button = new LayerTreeButton(this, (LayerTreeAction) action);
        } else if (action instanceof LayerTreeModalAction) {
          button = new LayerTreeModalButton(this, (LayerTreeModalAction) action);
        } else {
          String msg = "LayerTree tool with id " + id + " unknown.";
          Log.logError(msg); // console log
          SC.warn(msg); // in your face
        }
        if (button != null) {
          toolStrip.addMember(button);
          LayoutSpacer spacer = new LayoutSpacer();
          spacer.setWidth(WidgetLayout.layerTreePadding);
          toolStrip.addMember(spacer);
        }
      }
    }
    final Canvas[] toolStripMembers = toolStrip.getMembers();
    // delaying this fixes an image 'undefined' error
    Timer t =
        new Timer() {
          public void run() {
            updateButtonIconsAndStates(toolStripMembers);
          }
        };
    t.schedule(10);
    return toolStrip;
  }
  /**
   * Processes a treeNode (add it to the TreeGrid)
   *
   * @param treeNode The treeNode to process
   * @param nodeRoot The root node to which the treeNode has te be added
   * @param tree The tree to which the node has to be added
   * @param mapModel map model
   * @param refresh True if the tree is refreshed (causing it to keep its expanded state)
   */
  private void processNode(
      final ClientLayerTreeNodeInfo treeNode,
      final TreeNode nodeRoot,
      final Tree tree,
      final MapModel mapModel,
      final boolean refresh) {
    if (null != treeNode) {
      String treeNodeLabel = treeNode.getLabel();
      final TreeNode node = new TreeNode(treeNodeLabel);

      tree.add(node, nodeRoot);

      // (final leafs)
      for (ClientLayerInfo info : treeNode.getLayers()) {
        Layer<?> layer = mapModel.getLayer(info.getId());
        tree.add(new LayerTreeTreeNode(this.tree, layer), node);
      }

      // treeNodes
      List<ClientLayerTreeNodeInfo> children = treeNode.getTreeNodes();
      for (ClientLayerTreeNodeInfo newNode : children) {
        processNode(newNode, node, tree, mapModel, refresh);
      }

      // expand tree nodes
      // when not refreshing expand them like configured
      // when refreshing expand them as before the refresh
      boolean isTreeNodeExpanded = treeNode.isExpanded();
      if (!refresh) {
        if (isTreeNodeExpanded) {
          tree.openFolder(node);
        }
      } else {
        // TODO close previously opened tree nodes, close others
      }
    }
  }
 /** When the user clicks on a folder nothing gets selected. */
 public void onFolderClick(FolderClickEvent event) {
   mapModel.selectLayer(null);
 }