/*
	cursus - Race series management program
	Copyright 2011  Simon Arlott

	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 3 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 eu.lp0.cursus.ui.component;

import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

public abstract class AbstractTree<R extends TreeNode, T> extends JTree {
	protected final DatabaseWindow win;
	protected final R root;

	public AbstractTree(DatabaseWindow win, R root) {
		super();
		this.win = win;
		this.root = root;

		setModel(new DefaultTreeModel(root));

		setRootVisible(false);
		getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

		addKeyListener(new KeyAdapter() {
			@Override
			public void keyReleased(KeyEvent ke) {
				if (ke.isConsumed()) {
					return;
				}
				if (ke.getKeyCode() == KeyEvent.VK_CONTEXT_MENU) {
					showMenu(ke);
					ke.consume();
				} else if (ke.getKeyCode() == KeyEvent.VK_INSERT) {
					if (doInsert()) {
						ke.consume();
					}
				} else if (ke.getKeyCode() == KeyEvent.VK_DELETE) {
					if (doDelete()) {
						ke.consume();
					}
				}
			}
		});

		addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent me) {
				if (me.isConsumed()) {
					return;
				}
				ensureSelection(me);
				if (me.isPopupTrigger()) {
					showMenu(me);
					me.consume();
				}
			}

			@Override
			public void mouseReleased(MouseEvent me) {
				if (me.isConsumed()) {
					return;
				}
				ensureSelection(me);
				if (me.isPopupTrigger()) {
					showMenu(me);
					me.consume();
				}
			}
		});
	}

	protected abstract T userObjectFromPathComponent(Object component);

	protected abstract JPopupMenu menuFromUserObject(T item);

	private void ensureSelection(MouseEvent me) {
		TreePath path = getPathForLocation(me.getX(), me.getY());

		if (getSelectionPath() != path) {
			if (path == null || me.isPopupTrigger()) {
				setSelectionPath(path);
			}
		}
	}

	private void showMenu(MouseEvent me) {
		showMenu(me.getX(), me.getY());
	}

	private void showMenu(KeyEvent ke) {
		Point mouse = getMousePosition();
		if (mouse != null) {
			showMenu((int)getMousePosition().getX(), (int)getMousePosition().getY());
		} else {
			showMenu(0, 0);
		}
	}

	private void showMenu(int x, int y) {
		TreePath path = getSelectionPath();
		JPopupMenu menu = null;

		if (path != null) {
			menu = menuFromUserObject(userObjectFromPathComponent(path.getLastPathComponent()));
		} else {
			menu = menuFromUserObject(null);
		}
		menu.show(this, x, y);
	}

	protected abstract void insertFromUserObject(T item);

	protected abstract void deleteFromUserObject(T item);

	private boolean doInsert() {
		TreePath path = getSelectionPath();
		if (path != null) {
			insertFromUserObject(userObjectFromPathComponent(path.getLastPathComponent()));
		} else {
			insertFromUserObject(null);
		}
		return true;
	}

	private boolean doDelete() {
		TreePath path = getSelectionPath();
		if (path != null) {
			deleteFromUserObject(userObjectFromPathComponent(path.getLastPathComponent()));
			return true;
		} else {
			return false;
		}
	}

	public T getSelected() {
		TreePath path = getSelectionPath();

		if (path != null) {
			return userObjectFromPathComponent(path.getLastPathComponent());
		} else {
			return null;
		}
	}
}
@@ -3116,591 +3116,244 @@
 %7B%0A%09%09
-TreePath path = getSelectionPath();%0A%09%09JPopupMenu menu = null;%0A%0A%09%09if (path != null) %7B%0A%09%09%09menu = menuFromUserObject(userObjectFromPathComponent(path.getLastPathComponent()));%0A%09%09%7D else %7B%0A%09%09%09menu = menuFromUserObject(null);%0A%09%09%7D%0A%09%09menu.show(this, x, y);%0A%09%7D%0A%0A%09protected abstract void insertFromUserObject(T item);%0A%0A%09protected abstract void deleteFromUserObject(T item);%0A%0A%09private boolean doInsert() %7B%0A%09%09TreePath path = getSelectionPath();%0A%09%09if (path != null) %7B%0A%09%09%09insertFromUserObject(userObjectFromPathComponent(path.getLastPathComponent()));%0A%09%09%7D else %7B%0A%09%09%09insertFromUserObject(null);%0A%09%09%7D
+menuFromUserObject(getSelected()).show(this, x, y);%0A%09%7D%0A%0A%09protected abstract void insertFromUserObject(T item);%0A%0A%09protected abstract void deleteFromUserObject(T item);%0A%0A%09private boolean doInsert() %7B%0A%09%09insertFromUserObject(getSelected());
 %0A%09%09r
@@ -3486,63 +3486,33 @@
 ect(
-userObjectFromPathComponent(path.getLastPathComponent()
+getSelectionFromPath(path
 ));%0A
@@ -3587,39 +3587,86 @@
 ected() %7B%0A%09%09
-T
 re
-ePath path =
+turn getSelectionFromPath(getSelectionPath());%0A%09%7D%0A%0A%09public T
  getSelectio
@@ -3666,24 +3666,41 @@
 election
+From
 Path(
-);%0A
+TreePath path) %7B
 %0A%09%09if (p

simplify abstract tree