/* * GeoTools - The Open Source Java GIS Tookit * http://geotools.org * * (C) 2006-2008, Open Source Geospatial Foundation (OSGeo) * * This file is hereby placed into the Public Domain. This means anyone is * free to do whatever they wish with this file. Use it well and enjoy! */ package org.geotools.demo.widgets; import java.awt.BorderLayout; import java.awt.Component; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.TreePath; import org.apache.commons.collections.map.SingletonMap; import org.geotools.data.DataStore; import org.geotools.data.DataStoreFinder; import org.geotools.data.FeatureSource; import org.geotools.gui.swing.contexttree.ContextTreeNode; import org.geotools.gui.swing.contexttree.JContextTree; import org.geotools.gui.swing.contexttree.JContextTreePopup; import org.geotools.gui.swing.contexttree.LightContextTreeModel; import org.geotools.gui.swing.contexttree.TreeContextEvent; import org.geotools.gui.swing.contexttree.TreeContextListener; import org.geotools.gui.swing.contexttree.column.TreeTableColumn; import org.geotools.gui.swing.contexttree.node.SubNodeGroup; import org.geotools.gui.swing.contexttree.popup.TreePopupItem; import org.geotools.gui.swing.contexttree.renderer.DefaultCellEditor; import org.geotools.gui.swing.contexttree.renderer.DefaultCellRenderer; import org.geotools.gui.swing.contexttree.renderer.RenderAndEditComponent; import org.geotools.gui.swing.icon.IconBundle; import org.geotools.gui.swing.misc.Render.RandomStyleFactory; import org.geotools.map.DefaultMapContext; import org.geotools.map.DefaultMapLayer; import org.geotools.map.MapContext; import org.geotools.map.MapLayer; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.styling.Style; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; /** * * @author johann sorel * * @source $URL$ */ public class Demo_ContextTree extends JPanel { public Demo_ContextTree() { JContextTree tree = new JContextTree(); setLayout(new BorderLayout()); add(BorderLayout.CENTER, tree); //manipulating contexts------------------------------------------------- MapContext context = buildContext(); tree.addContext(context); // tree.removeContext(context); // MapContext aContext = tree.getContext(0); // int nbContexts = tree.getContextCount(); // int aContextIndex = tree.getContextIndex(context); // MapContext[] contexts = tree.getContexts(); // MapContext activeContext = tree.getActiveContext(); // tree.setActiveContext(context); TreeContextListener treeContextListener = new TreeContextListener() { public void contextAdded(TreeContextEvent event) { System.out.println("Context added :" + event.getContext().getTitle() + " at position :" + event.getToIndex()); } public void contextRemoved(TreeContextEvent event) { System.out.println("Context removed :" + event.getContext().getTitle() + " at position :" + event.getFromIndex()); } public void contextActivated(TreeContextEvent event) { System.out.println("Context activated :" + event.getContext().getTitle() + " at position :" + event.getFromIndex()); } public void contextMoved(TreeContextEvent event) { System.out.println("Context moved :" + event.getContext().getTitle() + " from : " + event.getFromIndex() + " to : " + event.getToIndex()); } }; tree.addTreeContextListener(treeContextListener); // tree.removeTreeContextListener(treeContextListener); // TreeContextListener[] treeContextListeners = tree.getTreeContextListeners(); //manipulating selections listener-------------------------------------- TreeSelectionListener treeSelectionListener = new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent e) { System.out.println("Selection Paths : " + e.getPaths()); if (e.getPath() != null) { ContextTreeNode node = (ContextTreeNode) e.getPath().getLastPathComponent(); Object obj = node.getUserObject(); if (obj instanceof MapLayer) { System.out.println("It's a layer node"); } else if (obj instanceof MapContext) { System.out.println("It's a context node"); } else { System.out.println("It's something else node"); } } } }; tree.getTreeSelectionModel().addTreeSelectionListener(treeSelectionListener); //tree.getTreeSelectionModel().removeTreeSelectionListener(treeSelectionListener); //Copy/Cut/Paste/Delete/Duplicate functions----------------------------- String prefix = tree.getPrefixString(); tree.setPrefixString("It is a copy element - "); //see if he can do the action boolean canCopy = tree.canCopySelection(); boolean canCut = tree.canCutSelection(); boolean canDelete = tree.canDeleteSelection(); boolean canDuplicate = tree.canDuplicateSelection(); boolean canPaste = tree.canPasteBuffer(); //do the action, return true if succeed boolean copySucceed = tree.copySelectionInBuffer(); boolean cutSucceed = tree.cutSelectionInBuffer(); boolean deleteSucceed = tree.deleteSelection(); boolean duplicateSucceed = tree.duplicateSelection(); boolean pasteSucceed = tree.pasteBuffer(); //and other stuff boolean selection = tree.hasSelection(); boolean empty = tree.isBufferEmpty(); Object[] datas = tree.getBuffer(); tree.clearBuffer(); //Manipulating columns-------------------------------------------------- TreeTableColumn mycolumn = buildColumn(); tree.addColumn(mycolumn); // tree.removeColumn(mycolumn); // tree.removeColumn(0); // int nbcolumns = tree.getColumnCount() // int index = tree.getColumnIndex(mycolumn); // TreeTableColumn[] cols = tree.getColumns(); //Manipulating popup menu----------------------------------------------- JContextTreePopup popup = tree.getPopupMenu(); TreePopupItem myTreePopupItem = buildPopupItem(); popup.addItem(myTreePopupItem); // popup.addItem( index, myTreePopupItem); // popup.addAllItem( index, Collection <? extends TreePopupItem>); // popup.addAllItem(Collection <? extends TreePopupItem>); // popup.removeItem( myTreePopupItem ); // popup.removeItem( index ); // TreePopupItem[] tpi = popup.getControls(); //Manipulating sub nodes------------------------------------------------ SubNodeGroup myGroup = buildSubNodeGroup(); tree.addSubNodeGroup(myGroup); // tree.removeSubNodeGroup(myGroup); // tree.removeSubNodeGroup(0); // int nbgroups = tree.getSubNodeGroupCount(); // int index = tree.getSubNodeGroupIndex(myGroup); // SubNodeGroup[] groups = tree.getSubNodeGroups(); } public MapContext buildContext() { RandomStyleFactory RANDOM_STYLE_FACTORY = new RandomStyleFactory(); MapContext context = null; MapLayer layer; try { context = new DefaultMapContext(DefaultGeographicCRS.WGS84); DataStore store = DataStoreFinder.getDataStore(new SingletonMap("url", Demo_ContextTree.class.getResource("/org/geotools/gui/swing/demo/shape/test_polygon.shp"))); FeatureSource<SimpleFeatureType, SimpleFeature> fs = store.getFeatureSource(store.getTypeNames()[0]); Style style = RANDOM_STYLE_FACTORY.createRandomVectorStyle(fs); layer = new DefaultMapLayer(fs, style); layer.setTitle("demo_polygon.shp"); context.addLayer(layer); store = DataStoreFinder.getDataStore(new SingletonMap("url", Demo_ContextTree.class.getResource("/org/geotools/gui/swing/demo/shape/test_ligne.shp"))); fs = store.getFeatureSource(store.getTypeNames()[0]); style = RANDOM_STYLE_FACTORY.createRandomVectorStyle(fs); layer = new DefaultMapLayer(fs, style); layer.setTitle("demo_line.shp"); context.addLayer(layer); store = DataStoreFinder.getDataStore(new SingletonMap("url", Demo_ContextTree.class.getResource("/org/geotools/gui/swing/demo/shape/test_point.shp"))); fs = store.getFeatureSource(store.getTypeNames()[0]); style = RANDOM_STYLE_FACTORY.createRandomVectorStyle(fs); layer = new DefaultMapLayer(fs, style); layer.setTitle("demo_point.shp"); context.addLayer(layer); context.setTitle("DemoContext"); } catch (Exception ex) { ex.printStackTrace(); } return context; } public TreeTableColumn buildColumn() { class MyCellComponent extends RenderAndEditComponent { private MapLayer layer = null; private JButton button = new JButton("map"); private boolean edited = false; MyCellComponent() { setLayout(new GridLayout(1, 1)); add(button); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (layer != null) { edited = true; JOptionPane.showMessageDialog(null, "hello layer : " + layer.getTitle()); } } }); } // we edit our component depending on what is been passed // This component is used for all cell so be sure to // put back value to default if needed @Override public void parse(Object obj) { removeAll(); edited = false; if (obj instanceof MapLayer) { layer = (MapLayer) obj; add(button); } else { layer = null; } } // the returned value when edition stop @Override public Object getValue() { return edited; } } class FlyingColumn extends TreeTableColumn { public FlyingColumn() { //properties of our column setWidth(70); setPreferredWidth(70); setMaxWidth(70); setResizable(false); // This is interesting, if you set it to true the cell will switch // to edit mode on mouseOver. It makes the column much more dynamic // but also need a bit more performance setEditableOnMouseOver(true); //... and many others available... //THE RENDERER AND EDITOR COMPONANTS // // If you are used to CellRenderer and CellEditor you can use : // - setCellEditor( myCellEditor ); // - setCellRenderer( myCellRenderer ); // // If you are not used to, I prepare a simplified solution used below // setCellEditor(new DefaultCellEditor(new MyCellComponent())); setCellRenderer(new DefaultCellRenderer(new MyCellComponent())); // // The same component type is used for rendering and editing // //THE HEADER setHeaderValue("FreeMap"); // If you want an icon in the header use : // setHeaderValue( new HeaderInfo( "FreeMap_id", "FreeMap", myIcon ) ); // - "FreeMap_id" will be visible in the topleft control menu of the JContextTree // - "FreeMap" is the title seen in the header, you can use null // - myIcon is your Icon, you can use null // // If you're not satisfied yet you can rewrite the header renderer // setHeaderRenderer( myRenderer ); } @Override public void setValue(Object target, Object value) { // here the Editor component returns a Value // We made it return a Boolean. // We'll just set visible or unvisible the boolean edited = (Boolean) value; if (edited) { //do some stuff } } @Override public Object getValue(Object target) { // we return the MapLayer, but we can return anything // just be sure the Renderer and Editor Component will // handle it the same way if (target instanceof MapLayer) { return target; } else { return null; } } @Override public Class getColumnClass() { // the class of the object returned return MapLayer.class; } @Override public boolean isCellEditable(Object target) { // We choose on what kind of Object (MapContext or MapLayer) // the component will be visible. // Here we choose only MapLayers if (target instanceof MapLayer) { return isEditable(); } else { return false; } } } return new FlyingColumn(); } public TreePopupItem buildPopupItem() { class ActionItem implements TreePopupItem { private JMenu menu = new JMenu("Grid Menu"); public ActionItem() { menu.add(new JMenuItem("Action1")); menu.add(new JMenuItem("Action2")); menu.add(new JCheckBoxMenuItem("check this")); } public boolean isValid(TreePath[] selection) { //We said it could be visible only with rasters // and only if there is one selected if (selection.length == 1) { ContextTreeNode node = (ContextTreeNode) selection[0].getLastPathComponent(); if (node.getUserObject() instanceof MapLayer) { return true; } } return false; } public Component getComponent(TreePath[] selection) { // We can return whatever we want, a classic JMenuItem // or much more complicate components. we could imagine // a JTable or an animated component. there's no limit. return menu; } } return new ActionItem(); } public SubNodeGroup buildSubNodeGroup() { class TitleNode extends ContextTreeNode{ String title = ""; TitleNode(String title,LightContextTreeModel model){ super(model); this.title = title; } @Override public Object getValue() { return title; } @Override public void setValue(Object obj) { } @Override public Icon getIcon() { return IconBundle.EMPTY_ICON; } @Override public boolean isEditable() { return false; } } class TitleNodeGroup implements SubNodeGroup{ public boolean isValid(Object target) { return (target instanceof MapLayer); } public void installInNode(LightContextTreeModel model, ContextTreeNode node) { MapLayer layer = (MapLayer) node.getUserObject(); TitleNode mynode = new TitleNode(layer.getTitle(),model); model.insetNodeInto(mynode, node, 0); } public void removeForNode(LightContextTreeModel model, ContextTreeNode node) { int max = node.getChildCount(); for(int i=0; i<max; i++){ ContextTreeNode aNode = (ContextTreeNode) node.getChildAt(i); if( aNode instanceof TitleNode){ model.removeNodeFromParent(aNode); } } } }; return new TitleNodeGroup(); } public static void main(String[] args) { JFrame frm = new JFrame("Demo : JContextTree"); frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frm.setContentPane(new Demo_ContextTree()); frm.pack(); frm.setLocationRelativeTo(null); frm.setVisible(true); } }