Index: CrsSelectorController.java
===================================================================
--- CrsSelectorController.java	(revision 865)
+++ CrsSelectorController.java	(revision 866)
@@ -5,6 +5,7 @@
 import java.beans.PropertyChangeListener;
 import java.text.ParseException;
 import java.util.ArrayList;
+import java.util.List;
 
 import javax.swing.Action;
 import javax.swing.Icon;
@@ -26,13 +27,15 @@
 import org.gvsig.proj.catalog.exception.UnsupportedCoordinateReferenceSystemException;
 import org.gvsig.proj.catalog.extent.GeographicBoundingBox;
 import org.gvsig.proj.swing.CoordinateReferenceSystemSelectorComponent;
-import org.gvsig.proj.swing.impl.tree.AsyncLoadedGroup;
 import org.gvsig.proj.swing.impl.tree.BranchNode;
 import org.gvsig.proj.swing.impl.tree.CRSSearchFilter;
 import org.gvsig.proj.swing.impl.tree.CrsLoader;
 import org.gvsig.proj.swing.impl.tree.CrsTreeNode;
+import org.gvsig.proj.swing.impl.tree.DirectGroupLoader;
 import org.gvsig.proj.swing.impl.tree.GroupLoader;
+import org.gvsig.proj.swing.impl.tree.AsyncGroupLoader;
 import org.gvsig.proj.swing.impl.tree.LeafNode;
+import org.gvsig.proj.swing.impl.tree.LoadedGroup;
 import org.gvsig.proj.swing.impl.tree.LoadingNode;
 import org.gvsig.proj.swing.impl.tree.TreeContainer;
 import org.gvsig.tools.ToolsLocator;
@@ -47,24 +50,28 @@
 
 public class CrsSelectorController extends CrsSelectorView
 	implements CoordinateReferenceSystemSelectorComponent, 
-												Component, TreeSelectionListener,
+												Component,
 												TreeContainer {
+	private static final long serialVersionUID = -5281166703625751190L;
 	private CoordinateReferenceSystem selectedCrs = null;
 	private ActionListenerSupport listenerSupport = ToolsSwingLocator.getToolsSwingManager().createActionListenerSupport();
 	public static final String CRS_SELECTED_ACTION_COMMAND = "CrsSelected";
 	protected ImageIcon RECENT_ICON;
 	protected ImageIcon FAVOURITE_ICON;
-	public ImageIcon FOLDER_OPEN_ICON;
-	public ImageIcon FOLDER_CLOSED_ICON;
-	public ImageIcon CRS_ICON;
-	public ImageIcon LOADING_ICON;
+	private ImageIcon CRS_ICON;
+	private ImageIcon FOLDER_OPEN_ICON;
+	private ImageIcon FOLDER_CLOSED_ICON;
 	private static Logger logger = LoggerFactory.getLogger(CrsSelectorController.class);
 	protected DefaultTreeModel model;
 	protected BranchNode root;
-	protected RecentCRSs recent;
+	protected LoadedGroup recent;
+	protected LoadedGroup favorite;
+	protected BranchNode customNode; 
 	protected IconTheme iconTheme = null;
 	protected I18nManager i18nManager = null;
 	final protected DefaultCoordinateReferenceSystemSwingManager manager;
+	protected String customLabel = "Layer";
+	protected ArrayList<CRSDefinition> customList = new ArrayList<CRSDefinition>();
 
 	
 	public CrsSelectorController(DefaultCoordinateReferenceSystemSwingManager manager) {
@@ -73,6 +80,7 @@
 		initIcons();
 		initComponents();
 		initTree();
+		initTreeListeners();
 		resetSearchCombo(null);
 		initSearchActions();
 	}
@@ -98,11 +106,26 @@
 	
 	
 	protected void initComponents() {
+		IconTheme theme = getIconTheme();
+
+		this.btnSearch.setIcon(theme.get("crs-crsselector-search"));
+		this.btnSearchRemove.setIcon(theme.get("crs-crsselector-search-remove"));
+		this.lblFilterAlpha.setIcon(theme.get("crs-crsselector-text-filter"));
+		this.lblFilterSpatial.setIcon(theme.get("crs-crsselector-spatial-filter"));
+		this.btnCrsAdd.setIcon(theme.get("crs-crsselector-crs-new"));
+		this.btnRecentCrsRemove.setIcon(theme.get("crs-crsselector-recent-remove"));
+		this.btnFavoritesAdd.setIcon(theme.get("crs-crsselector-favorite-add"));
+		this.btnFavoritesRemove.setIcon(theme.get("crs-crsselector-favorite-remove"));
+		this.btnFilterDropdown.setIcon(theme.get("crs-crsselector-dropdown"));
+		
+		
 		ToolsSwingManager swingManager = ToolsSwingLocator.getToolsSwingManager();
 		// hide spatial filter since it is currently not supported
 		this.btnFilterDropdown.setVisible(false);
 		this.pnl_filterType.setVisible(false);
 		this.cboFilterSpatial.setVisible(false);
+		// hide recent remove since it is currently not supported
+		this.btnRecentCrsRemove.setVisible(false);
 
 		swingManager.translate(this.btnSearch);
 		swingManager.translate(this.btnSearchRemove);
@@ -117,7 +140,8 @@
 		this.txtDescription.setLineWrap(true);
 		this.txtDescription.setWrapStyleWord(true);
 		this.txtCrsWkt.setEditable(false);
-		this.txtCrsWkt.setText("");		
+		this.txtCrsWkt.setText("");
+		
 		/**
 		 * TODO Update strings in CrsPanel and change the name of some components
 		 *
@@ -135,7 +159,45 @@
 		this.txtCrsWkt.setEditable(false);
 		this.txtCrsWkt.setText("");
 		*/
+		
+
+		
 	}
+
+	protected void initTreeListeners() {
+		this.btnFavoritesAdd.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				CoordinateReferenceSystem selectedCrs = CrsSelectorController.this.getCoordinateReferenceSystem();
+				if (selectedCrs != null) {
+					manager.getCoordinateReferenceSystemFavorites().add(selectedCrs.getDefinition());
+					favorite.reloadChildren();
+				}
+			}
+		});
+		
+		this.btnFavoritesRemove.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				CoordinateReferenceSystem selectedCrs = CrsSelectorController.this.getCoordinateReferenceSystem();
+				if (selectedCrs != null) {
+					manager.getCoordinateReferenceSystemFavorites().remove(selectedCrs.getDefinition());
+					favorite.reloadChildren();
+				}
+			}
+		});
+		
+		/*
+		this.btnRecentCrsRemove.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				CoordinateReferenceSystem selectedCrs = CrsSelectorController.this.getCoordinateReferenceSystem();
+				if (selectedCrs != null) {
+					manager.getCoordinateReferenceSystemHistory().remove(selectedCrs.getDefinition());
+				}
+			}
+		});*/
+	}
 	
 	protected void search() {
 		String filter = getAlphanumericFilter();
@@ -150,12 +212,8 @@
 		}
 		resetSearchCombo(filter);
 		model.reload();
-	    expandBranches();
+	    expandBranches(this.root);
 	}
-	protected void expandBranches() {
-		expandBranches(this.root);
-		
-	}
 	
 	private void expandBranches(TreeNode root) {
 		for (int i=0; i<root.getChildCount(); i++) {
@@ -250,12 +308,11 @@
 	}
 	
 	protected void initIcons() {
-		RECENT_ICON = getIconTheme().get("recent");
-		FAVOURITE_ICON = getIconTheme().get("favourite");
-		FOLDER_OPEN_ICON = getIconTheme().get("folder_open");
-		FOLDER_CLOSED_ICON = getIconTheme().get("folder_closed");
-		CRS_ICON = getIconTheme().get("crs");
-		LOADING_ICON = getIconTheme().get("spinner");
+		RECENT_ICON = getIconTheme().get("crs-crsselector-recent");
+		FAVOURITE_ICON = getIconTheme().get("crs-crsselector-favorite");
+		CRS_ICON = getIconTheme().get("crs-crsselector-crs");
+		FOLDER_OPEN_ICON = getIconTheme().get("crs-branchnode-tree-group-expanded");
+		FOLDER_CLOSED_ICON = getIconTheme().get("crs-branchnode-tree-group-collapsed");
 	}
 	
 	protected void initTree() {
@@ -266,36 +323,71 @@
 		tree.getSelectionModel().setSelectionMode
         	(TreeSelectionModel.SINGLE_TREE_SELECTION);
 		listenerSupport = ToolsSwingLocator.getToolsSwingManager().createActionListenerSupport();
-		tree.addTreeSelectionListener(this);
+		tree.addTreeSelectionListener(new TreeSelectionListener() {
+			@Override
+			public void valueChanged(TreeSelectionEvent e) {
+				CrsSelectorController.this.treeSelectedValueChanged(e);
+			}
+		});
 		tree.setCellRenderer(new CellRenderer());
 		
-		recent = new RecentCRSs(root, getI18nManager().getTranslation("Recent"));
+		recent = new LoadedGroup(root, this, getI18nManager().getTranslation("Recent"), RECENT_ICON);
+		recent.setLoader(new RecentLoader(recent));
 		recent.loadChildren();
-		
 		root.add(recent);
-		BranchNode epsg = new BranchNode(root, this, getI18nManager().getTranslation("EPSG"));
-		root.add(epsg);
-		CRSSearchFilter projectedCRSs = new CRSSearchFilter();
-		projectedCRSs.setAuthority("EPSG");
-		projectedCRSs.setIncludedTypes(new CRSType[]{CRSType.ProjectedCRSType});
-		epsg.add(new AuthorityLoadedGroup(epsg, projectedCRSs, getI18nManager().getTranslation("Projected")));
 		
-		CRSSearchFilter geographicCRSs = new CRSSearchFilter();
-		geographicCRSs.setAuthority("EPSG");
-		geographicCRSs.setIncludedTypes(new CRSType[]{CRSType.GeographicCRSType});
-		epsg.add(new AuthorityLoadedGroup(epsg, geographicCRSs, getI18nManager().getTranslation("Geographic")));
+		favorite = new LoadedGroup(root, this, getI18nManager().getTranslation("Favorites"), FAVOURITE_ICON);
+		favorite.setLoader(new FavoriteLoader(favorite));
+		favorite.loadChildren();
+		root.add(favorite);
+		
+		BranchNode epsg = null;
+		for (String authority: manager.getCatalogManager().getAuthorityNames()) {
+			BranchNode authorityNode = new BranchNode(root, this, getI18nManager().getTranslation(authority));
+			if (authority.equals("EPSG")) {
+				epsg = authorityNode;
+			}
+			root.add(authorityNode);
+			CRSSearchFilter projectedCRSs = new CRSSearchFilter();
+			projectedCRSs.setAuthority(authority);
+			projectedCRSs.setIncludedTypes(new CRSType[]{CRSType.ProjectedCRSType});
+			authorityNode.add(new AuthorityLoadedGroup(authorityNode, projectedCRSs, getI18nManager().getTranslation("Projected")));
+			
+			CRSSearchFilter geographicCRSs = new CRSSearchFilter();
+			geographicCRSs.setAuthority(authority);
+			geographicCRSs.setIncludedTypes(new CRSType[]{CRSType.GeographicCRSType});
+			authorityNode.add(new AuthorityLoadedGroup(authorityNode, geographicCRSs, getI18nManager().getTranslation("Geographic")));
 
-		CRSSearchFilter otherCRSs = new CRSSearchFilter();
-		otherCRSs.setAuthority("EPSG");
-		otherCRSs.setExcludedTypes(new CRSType[]{CRSType.ProjectedCRSType, CRSType.GeographicCRSType});
-		epsg.add(new AuthorityLoadedGroup(epsg, otherCRSs, getI18nManager().getTranslation("Other")));
+			CRSSearchFilter otherCRSs = new CRSSearchFilter();
+			otherCRSs.setAuthority(authority);
+			otherCRSs.setExcludedTypes(new CRSType[]{CRSType.ProjectedCRSType, CRSType.GeographicCRSType});
+			authorityNode.add(new AuthorityLoadedGroup(authorityNode, otherCRSs, getI18nManager().getTranslation("Other")));
+		}
+		
+		initCustomBranch();
+		
 		tree.setModel(model);
-		
-		tree.expandPath(new TreePath(model.getPathToRoot(epsg)));
+		if (epsg!=null) {
+			tree.expandPath(new TreePath(model.getPathToRoot(epsg)));
+		}
 	}
 	
-	@Override
-	public void valueChanged(TreeSelectionEvent e) {
+	protected void initCustomBranch() {
+		if (customList.size()>0) {
+			if (customNode == null) {
+				customNode = new BranchNode(root, this, customLabel);
+				root.add(customNode);
+			}
+			customNode.clear();
+			for (CRSDefinition def: customList) {
+				CrsTreeNode node = new CrsTreeNode(def, customNode);
+				customNode.add(node);
+			}
+			model.reload();
+		}
+	}
+	
+	protected void treeSelectedValueChanged(TreeSelectionEvent e) {
 		TreeNode selection = (TreeNode) this.treeResults.getLastSelectedPathComponent();
 		if (selection==null) {
 			return;
@@ -336,14 +428,13 @@
 
 	@Override
 	public void setCustomGroupLabel(String label) {
-		// TODO Auto-generated method stub
-		
+		this.customLabel = label;
 	}
 
 	@Override
 	public void addCustomCRS(CRSDefinition customCRS) {
-		// TODO Auto-generated method stub
-		
+		this.customList.add(customCRS);
+		initCustomBranch();
 	}
 
 	@Override
@@ -353,7 +444,7 @@
 
 	@Override
 	public void addCRSSelectionListener(ActionListener listener) {
-		// TODO Auto-generated method stub
+		listenerSupport.addActionListener(listener);
 		
 	}
 
@@ -374,18 +465,13 @@
 	}
 	
 	
-	public class RecentCRSs extends BranchNode {
-		public RecentCRSs(TreeNode parent, String message) {
-			super(parent, CrsSelectorController.this, message);
-		}		
-		@Override
-		public Icon getIcon(boolean expanded) {
-			return RECENT_ICON;
+	public class RecentLoader extends DirectGroupLoader {
+		public RecentLoader(LoadedGroup caller) {
+			super(caller);
 		}
+		
 		@Override
-		public void reloadChildren() {
-			super.children.clear();
-			// FIXME: maybe history should also use CRSDefinitions
+		public List<TreeNode> doExecute() {
 			String filter;
 			if (CrsSelectorController.this.getAlphanumericFilter()!=null) {
 				filter = CrsSelectorController.this.getAlphanumericFilter().toLowerCase();
@@ -393,39 +479,59 @@
 			else {
 				filter = null;
 			}
-			for (CoordinateReferenceSystem crs: manager.getCoordinateReferenceSystemHistory()) {
-				if (filter==null || crs.getDefinition().getName().toLowerCase().contains(filter)) {
-					super.children.add(new CrsTreeNode(crs.getDefinition(), this));
+			ArrayList<TreeNode> results = new ArrayList<TreeNode>();
+			for (CRSDefinition crsDef: manager.getCoordinateReferenceSystemHistory()) {
+				if (filter==null || crsDef.toString().toLowerCase().contains(filter)) {
+					results.add(new CrsTreeNode(crsDef, caller));
 				}
 			}
+			return results;
 		}
 	}
 	
-	public class AuthorityLoadedGroup extends AsyncLoadedGroup {
+	public class FavoriteLoader extends DirectGroupLoader {
+	
+		public FavoriteLoader(LoadedGroup caller) {
+			super(caller);
+		}
+		
+		@Override
+		public List<TreeNode> doExecute() {
+			String filter;
+			if (CrsSelectorController.this.getAlphanumericFilter()!=null) {
+				filter = CrsSelectorController.this.getAlphanumericFilter().toLowerCase();
+			}
+			else {
+				filter = null;
+			}
+			ArrayList<TreeNode> results = new ArrayList<TreeNode>();
+			for (CRSDefinition crsDef: manager.getCoordinateReferenceSystemFavorites()) {
+				if (filter==null || crsDef.toString().toLowerCase().contains(filter)) {
+					results.add(new CrsTreeNode(crsDef, caller));
+				}				
+			}
+			return results;
+		}
+	}
+	
+	public class AuthorityLoadedGroup extends LoadedGroup {
 		protected final CRSSearchFilter filter;
+		public AuthorityLoadedGroup(TreeNode parent, CRSSearchFilter filter, String message, Icon icon) {
+			super(parent, CrsSelectorController.this, message, icon);
+			this.filter = filter;
+		}
+		
 		public AuthorityLoadedGroup(TreeNode parent, CRSSearchFilter filter, String message) {
-			super(parent, CrsSelectorController.this, message);
+			super(parent, CrsSelectorController.this, message, null);
 			this.filter = filter;
 		}
 
-		protected GroupLoader doCreateLoader() {
+		protected GroupLoader getLoader() {
 			this.filter.setTextFilter(CrsSelectorController.this.getAlphanumericFilter());
 			// FIXME: set also spatial filter when supported by API and UI
 			this.filter.setSpatialFilter(null);
 			return new CrsLoader(filter, this, CrsSelectorController.this.manager.getCatalogManager());
 		}
-		
-		@Override
-		public void loaded(ArrayList<TreeNode> loadedData) {
-			this.children.clear();
-			this.children.addAll(loadedData);
-			CrsSelectorController.this.model.reload(this);
-		}
-
-		@Override
-		protected void cancelled() {
-			// TODO Auto-generated method stub
-		}
 	}
 
 	public class CellRenderer extends DefaultTreeCellRenderer {
@@ -434,19 +540,31 @@
 				boolean leaf, int row, boolean hasFocus) {
 			java.awt.Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
 			if (value instanceof BranchNode) {
-				this.setIcon(((BranchNode)value).getIcon(expanded));
+				Icon icon = ((BranchNode)value).getIcon(expanded);
+				if (icon!=null) {
+					this.setIcon(icon);
+				}
+				else {
+					if (expanded) {
+						this.setIcon(FOLDER_OPEN_ICON);
+					}
+					else {
+						this.setIcon(FOLDER_CLOSED_ICON);
+					}
+				}
 			}
 			else if (value instanceof CrsTreeNode) {
 				this.setIcon(CRS_ICON);
 			}
 			else if (value instanceof LeafNode) {
-				ImageIcon icon = ((LeafNode)value).getIcon();
+				Icon icon = ((LeafNode)value).getIcon();
 				if (icon != null) {
 					this.setIcon(icon);
 				}
 			}
 			return this;
 		}
+
 		
 	}
 	
