/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.ui;

import com.intellij.ui.components.JBList;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Enumeration;

/**
 * @author Eugene Belyaev
 */
public class TreeList extends JBList implements TreeModelListener {
  private final TreeModel myTreeModel;
  private boolean myRootVisible = false;
  private final DefaultListModel myListModel = new DefaultListModel();

  /**
   * Constructs a <code>JList</code> with an empty model.
   */
  public TreeList(TreeModel treeModel) {
    super.setModel(myListModel);
    myTreeModel = treeModel;
    myTreeModel.addTreeModelListener(this);
    Object root = myTreeModel.getRoot();
    if (root instanceof TreeNode) {
      TreeNode node = (TreeNode) root;
      myListModel.addElement(node);
      if (myTreeModel instanceof DefaultTreeModel && ((DefaultTreeModel)myTreeModel).asksAllowsChildren() && node.getAllowsChildren()) {
        Enumeration enumeration = node.children();
        while (enumeration.hasMoreElements()) {
          Object object = enumeration.nextElement();
          myListModel.addElement(object);
        }
      }
    }
  }

  public boolean isRootVisible() {
    return myRootVisible;
  }

  public void setRootVisible(boolean rootVisible) {
    myRootVisible = rootVisible;
  }

  /**
   * Sets the model that represents the contents or "value" of the
   * list and clears the list selection after notifying
   * <code>PropertyChangeListeners</code>.
   * <p>
   * This is a JavaBeans bound property.
   *
   * @param model  the <code>ListModel</code> that provides the
   *						list of items for display
   * @exception IllegalArgumentException  if <code>model</code> is
   *						<code>null</code>
   * @see #getModel
   * @beaninfo
   *       bound: true
   *   attribute: visualUpdate true
   * description: The object that contains the data to be drawn by this JList.
   */
  public void setModel(@NotNull ListModel model) {
    throw new UnsupportedOperationException("TreeList accepts only TreeModel as a model");
  }

  /**
   * <p>Invoked after a node (or a set of siblings) has changed in some
   * way. The node(s) have not changed locations in the tree or
   * altered their children arrays, but other attributes have
   * changed and may affect presentation. Example: the name of a
   * file has changed, but it is in the same location in the file
   * system.</p>
   * <p>To indicate the root has changed, childIndices and children
   * will be null. </p>
   *
   * <p>Use <code>e.getPath()</code>
   * to get the parent of the changed node(s).
   * <code>e.getChildIndices()</code>
   * returns the index(es) of the changed node(s).</p>
   */
  public void treeNodesChanged(TreeModelEvent e) {
    //To change body of implemented methods use Options | File Templates.
  }

  /**
   * <p>Invoked after nodes have been inserted into the tree.</p>
   *
   * <p>Use <code>e.getPath()</code>
   * to get the parent of the new node(s).
   * <code>e.getChildIndices()</code>
   * returns the index(es) of the new node(s)
   * in ascending order.</p>
   */
  public void treeNodesInserted(TreeModelEvent e) {
    //To change body of implemented methods use Options | File Templates.
  }

  /**
   * <p>Invoked after nodes have been removed from the tree.  Note that
   * if a subtree is removed from the tree, this method may only be
   * invoked once for the root of the removed subtree, not once for
   * each individual set of siblings removed.</p>
   *
   * <p>Use <code>e.getPath()</code>
   * to get the former parent of the deleted node(s).
   * <code>e.getChildIndices()</code>
   * returns, in ascending order, the index(es)
   * the node(s) had before being deleted.</p>
   */
  public void treeNodesRemoved(TreeModelEvent e) {
    //To change body of implemented methods use Options | File Templates.
  }

  /**
   * <p>Invoked after the tree has drastically changed structure from a
   * given node down.  If the path returned by e.getPath() is of length
   * one and the first element does not identify the current root node
   * the first element should become the new root of the tree.<p>
   *
   * <p>Use <code>e.getPath()</code>
   * to get the path to the node.
   * <code>e.getChildIndices()</code>
   * returns null.</p>
   */
  public void treeStructureChanged(TreeModelEvent e) {
    //To change body of implemented methods use Options | File Templates.
  }



  @SuppressWarnings({"HardCodedStringLiteral"})
  public static void main(String[] args) {
    JFrame frame = new JFrame("TreeList Showcase");
    frame.setLocation(0, 0);
    frame.setSize(800, 600);
    frame.addWindowListener(
        new WindowAdapter() {
          /**
           * Invoked when a window is in the process of being closed.
           * The close operation can be overridden at this point.
           */
          public void windowClosing(WindowEvent e) {
            System.exit(0);
          }
        }
    );
    Container contentPane = frame.getContentPane();
    contentPane.setLayout(new BorderLayout());
    DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Sample root node");
    for (int i = 0; i < 5; i++) {
      DefaultMutableTreeNode node = new DefaultMutableTreeNode("Node #" + (i + 1));
      rootNode.add(node);
    }
    DefaultTreeModel treeModel = new DefaultTreeModel(rootNode, true);
    TreeList treeList = new TreeList(treeModel);
    contentPane.add(treeList);
    frame.setVisible(true);
  }
}
