public ProductTree() {
		super();
		
		// Create the model.
		root = new NodeItem(Product.class);
		model = new DefaultTreeModel(root);
		map = new HashMap<String, NodeItem>();
		
		// Set model and settings.
		setModel(model);
		getSelectionModel().setSelectionMode
			(TreeSelectionModel.SINGLE_TREE_SELECTION);
		setShowsRootHandles(false);
		setToggleClickCount(1); // One click expand.
		
		CustomIconRenderer renderer = new CustomIconRenderer();
		setCellRenderer(renderer);
		
		addTreeSelectionListener(new TreeSelectionListener() {
			 /**
			  * The valueChanged listener is called all the time.
			  * The most crucial part is that it accurately distinguishes between class and product selection.
			  * If it's a class selection, it fires a classSelectionEvent which is either handled as a DB
			  * or cache query. A product selection results in a productSelection event firing which ends up
			  * filling in the form in the GUI.
			  */
			@Override
			public void valueChanged(TreeSelectionEvent event) {
				if(event.isAddedPath()){
					if (productEditedListener != null && lastSelectedNode != null && (!lastSelectedNode.isClassNode())) {
						ActionEvent edited = new ActionEvent((Product)lastSelectedNode.getStoredObject(), 0, "");
						productEditedListener.actionPerformed(edited);
					}
					
					TreePath path = event.getNewLeadSelectionPath();
					NodeItem selectedNode = (NodeItem) path.getLastPathComponent();
					
					if (selectedNode.isClassNode()) {
						String s = selectedNode.getStoredObject().toString();
						ActionEvent i = new ActionEvent(model, 0, s);
						classSelectListener.actionPerformed(i);
					}
					else {	
						//The user has selected a product. So we'll update the form.
						ActionEvent s = new ActionEvent((Product)selectedNode.getStoredObject(), 0, "");
						productSelectedListener.actionPerformed(s);
						lastSelectedNode = selectedNode;
					}

				}
			}
		});
		
		addTreeExpansionListener(new TreeExpansionListener() {
			
			@Override
			public void treeCollapsed(TreeExpansionEvent event) {
			}
			/**
			 * The treeExpanded method is similar to valueChanged - it fires the same classSelected event
			 * but seeing as products can't have children it doesn't need to worry about updating the form.
			 * The main purpose in this existing is for when products are added and automatically scrolled to.
			 * This doesn't could as a valueChanged event, but a treeExpanded event, and it needs to react accordingly.
			 */
			@Override
			public void treeExpanded(TreeExpansionEvent event) {
				
				TreePath path = (TreePath) event.getPath();
				if (!(path == null)){
					NodeItem selectedNode = (NodeItem) event.getPath().getLastPathComponent();				
					Object o = selectedNode.getStoredObject();
					if (o.getClass().equals(Class.class)){
						String s = o.toString();
						ActionEvent i = new ActionEvent(model, 0, s);
						classSelectListener.actionPerformed(i);
					}
				}
			}
		});
		
		
	}