// Bart 20060831 -> i18n /* * File: Inspector.java * Date: Jul 2001 * Author: Kai Lessmann <klessman@intevation.de> * Copyright 2001 Intevation GmbH, Germany * * This file is Free Software to be included into OpenMap * under its Free Software license. * Permission is granted to use, modify and redistribute. * * Intevation hereby grants BBN a royalty free, worldwide right and license * to use, copy, distribute and make Derivative Works * of this Free Software created by Kai Lessmann * and sublicensing rights of any of the foregoing. * */ package com.bbn.openmap.util.propertyEditor; import java.awt.BorderLayout; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyEditor; import java.util.Collection; import java.util.Hashtable; import java.util.Iterator; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.Vector; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ScrollPaneConstants; import javax.swing.SwingConstants; import com.bbn.openmap.Environment; import com.bbn.openmap.I18n; import com.bbn.openmap.PropertyConsumer; import com.bbn.openmap.gui.WindowSupport; import com.bbn.openmap.util.Debug; import com.bbn.openmap.util.PropUtils; /** * Class to inspect a PropertyConsumer. Used by the LayerAddPanel class to * interactively configure a Layer object before it gets added to the map. This * class should suffice to "inspect" any PropertyConsumer on a very basic level, * handling is more convenient if property editor classes are available. The * behavior of the Inspector is configured through properties; the * propertiesInfo object of a PropertyConsumer may contain a * initPropertiesProperty which determines which properties are to be shown and * in which order, in a space separated list, i.e. * * <code> * initPropertiesProperty=class prettyName shapeFile * * </code> If this property is not defined, then all the properties will be * displayed, in alphabetical order. * * For each property there may be a editorProperty entry giving a PropertyEditor * class to instantiate as an editor for the property, i.e. <code> * shapeFile.editor=com.bbn.openmap.util.propertyEditor.FilePropertyEditor * </code>. */ public class Inspector implements ActionListener { /** A simple TextField as a String editor. */ protected final String defaultEditorClass = "com.bbn.openmap.util.propertyEditor.TextPropertyEditor"; /** * The PropertyConsumer being inspected. Set in inspectPropertyConsumer. */ protected PropertyConsumer propertyConsumer = null; /** Handle to the GUI. Used for setVisible(true/false). */ protected WindowSupport windowSupport = null; /** Action command for the cancelButton. */ // public so it can be referenced from the actionListener public final static String cancelCommand = "cancelCommand"; /** The action command for the doneButton. */ // public so it can be referenced from the actionListener public final static String doneCommand = "doneCommand"; /** * Hashtable containing property names, and their editors. Used to fetch * user inputs for configuring a property consumer. */ protected Hashtable<String, PropertyEditor> editors = null; /** * Handle to call back the object that invokes this Inspector. */ protected ActionListener actionListener = null; /** * Flag to print out the properties. Used when the Inspector is in * stand-alone mode, so that the properties are directed to stdout. */ protected boolean print = false; // I18N mechanism static I18n i18n = Environment.getI18n(); /** * Set an ActionListener for callbacks. Once a Layer object is configured, * i.e. the "Add" button has been clicked, an ActionListener that invoked * this Inspector can register here to be notified. */ public void addActionListener(ActionListener al) { actionListener = al; } /** Does nothing. */ public Inspector() {} /** Sets the actionListener. */ public Inspector(ActionListener al) { actionListener = al; } /** * Inspect and configure a PropertyConsumer object. Main method of this * class. The argument PropertyConsumer is inspected through the * ProperyConsumer interface, the properties are displayed to be edited. */ public void inspectPropertyConsumer(PropertyConsumer propertyConsumer) { String prefix = propertyConsumer.getPropertyPrefix(); // construct GUI if (windowSupport != null) { windowSupport.killWindow(); windowSupport = null; } JComponent comp = createPropertyGUI(propertyConsumer); windowSupport = new WindowSupport(comp, i18n.get(Inspector.class, "Inspector", "Inspector") + " - " + prefix); windowSupport.setMaxSize(-1, 500); windowSupport.displayInWindow(); } @SuppressWarnings("unchecked") public Vector<String> sortKeys(Collection keySet) { Vector<String> vector = new Vector<String>(keySet.size()); // OK, ok, this isn't the most efficient way to do this, but // it's simple. Shouldn't matter for what we are using it // for... Iterator it = keySet.iterator(); while (it.hasNext()) { String key = (String) it.next(); int size = vector.size(); for (int i = 0; i <= size; i++) { if (i == size) { // System.out.println("Adding " + key + " at " + // i); vector.add(key); break; } else { int compare = key.compareTo((String) vector.elementAt(i)); if (compare < 0) { // System.out.println(key + " goes before " + // vector.elementAt(i) + " at " + i); vector.add(i, key); break; } } } } return vector; } /** * Creates a JComponent with the properties to be changed. This component is * suitable for inclusion into a GUI. * * @param pc The property consumer to create a gui for. * @return JComponent, a panel holding the interface to set the properties. */ public JComponent createEmbeddedPropertyGUI(PropertyConsumer pc) { // fill variables this.propertyConsumer = pc; Properties props = new Properties(); props = pc.getProperties(props); Properties info = new Properties(); info = pc.getPropertyInfo(info); String prefix = pc.getPropertyPrefix(); return createEmbeddedPropertyGUI(prefix, props, info); } /** * Creates a JComponent with the properties to be changed. This component is * suitable for inclusion into a GUI. Don't use this method directly! Use * the createPropertyGUI(PropertyConsumer) instead. You will get a * NullPointerException if you use this method without setting the * PropertyConsumer in the Inspector. * * @param prefix the property prefix for the property consumer. Received * from the PropertyConsumer.getPropertyPrefix() method. Properties * that start with this prefix will have the prefix removed from the * display, so the GUI will only show the actual property name. * @param props the properties received from the * PropertyConsumer.getProperties() method. * @param info the properties received from the * PropertyConsumer.getPropertyInfo() method, containing descriptions * and any specific PropertyEditors that should be used for a * particular property named in the PropertyConsumer.getProperties() * properties. * @return JComponent, a panel holding the interface to set the properties. */ public JComponent createEmbeddedPropertyGUI(String prefix, Properties props, Properties info) { if (Debug.debugging("inspectordetail")) { Debug.output("Inspector creating GUI for " + prefix + "\nPROPERTIES " + props + "\nPROP INFO " + info); } // collect the properties that are going to be displayed... // First, check the initPropertiesProperty for the PropertyConsumer // stating which properties it wants included. String propertyList = info.getProperty(PropertyConsumer.initPropertiesProperty); Vector<String> sortedKeys; if (propertyList != null) { Vector<String> propertiesToShow = PropUtils.parseSpacedMarkers(propertyList); for (int i = 0; i < propertiesToShow.size(); i++) { propertiesToShow.set(i, prefix + "." + propertiesToShow.get(i)); } sortedKeys = propertiesToShow; } else { // otherwise, show them all, in alphabetical order sortedKeys = sortKeys(props.keySet()); } editors = new Hashtable<String, PropertyEditor>(sortedKeys.size()); JPanel component = new JPanel(); component.setLayout(new BorderLayout()); JPanel propertyPanel = new JPanel(); GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(2, 10, 2, 10); propertyPanel.setLayout(gridbag); int i = 0; for (String prop : sortedKeys) { // Marker is going to be the scoped version of prop, if needed. String marker = prop; if (prefix != null && prop.startsWith(prefix)) { marker = prop.substring(prefix.length() + 1); } if (marker.startsWith(".")) { marker = marker.substring(1); } String editorMarker = marker + PropertyConsumer.ScopedEditorProperty; String editorClass = info.getProperty(editorMarker); if (editorClass == null) { editorClass = defaultEditorClass; } // instantiate PropertyEditor Class<?> propertyEditorClass = null; PropertyEditor editor = null; try { propertyEditorClass = Class.forName(editorClass); editor = (PropertyEditor) propertyEditorClass.newInstance(); if (editor instanceof PropertyConsumer) { ((PropertyConsumer) editor).setProperties(marker, info); } editors.put(prop, editor); } catch (Exception e) { e.printStackTrace(); editorClass = null; } Component editorFace = null; if (editor != null && editor.supportsCustomEditor()) { editorFace = editor.getCustomEditor(); } else { editorFace = new JLabel(i18n.get(Inspector.class, "Does_not_support_custom_editor", "Does not support custom editor")); } if (editor != null) { Object propVal = props.get(prop); if (Debug.debugging("inspector")) { Debug.output("Inspector loading " + prop + "(" + propVal + ")"); } editor.setValue(propVal); } // Customized labels for each property, instead of the // abbreviated nature of the true property names. String labelMarker = marker + PropertyConsumer.LabelEditorProperty; String labelText = info.getProperty(labelMarker); if (labelText == null) { labelText = marker; } JLabel label = new JLabel(labelText + ":"); label.setHorizontalAlignment(SwingConstants.RIGHT); c.gridx = 0; c.gridy = i++; c.weightx = 0; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.EAST; gridbag.setConstraints(label, c); propertyPanel.add(label); c.gridx = 1; c.anchor = GridBagConstraints.WEST; c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 1f; gridbag.setConstraints(editorFace, c); propertyPanel.add(editorFace); String toolTip = (String) info.get(marker); label.setToolTipText(toolTip == null ? i18n.get(Inspector.class, "No_further_information_available", "No further information available.") : toolTip); } // create the palette's scroll pane JScrollPane scrollPane = new JScrollPane(propertyPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane.setBorder(null); // scrollPane.setAlignmentX(Component.LEFT_ALIGNMENT); scrollPane.setAlignmentY(Component.TOP_ALIGNMENT); component.add(scrollPane, BorderLayout.CENTER); return component; } /** * Creates a JComponent with the properties to be changed. This component is * suitable for inclusion into a GUI. * * @param pc The property consumer to create a gui for. * @return JComponent, a panel holding the interface to set the properties. */ public JComponent createPropertyGUI(PropertyConsumer pc) { // fill variables this.propertyConsumer = pc; Properties props = new Properties(); props = pc.getProperties(props); Properties info = new Properties(); info = pc.getPropertyInfo(info); String prefix = pc.getPropertyPrefix(); return createPropertyGUI(prefix, props, info); } /** * Creates a JComponent with the properties to be changed. This component is * suitable for inclusion into a GUI. Don't use this method directly! Use * the createPropertyGUI(PropertyConsumer) instead. You will get a * NullPointerException if you use this method without setting the * PropertyConsumer in the Inspector. * * @param prefix the property prefix for the property consumer. Received * from the PropertyConsumer.getPropertyPrefix() method. Properties * that start with this prefix will have the prefix removed from the * display, so the GUI will only show the actual property name. * @param props the properties received from the * PropertyConsumer.getProperties() method. * @param info the properties received from the * PropertyConsumer.getPropertyInfo() method, containing descriptions * and any specific PropertyEditors that should be used for a * particular property named in the PropertyConsumer.getProperties() * properties. * @return JComponent, a panel holding the interface to set the properties. */ public JComponent createPropertyGUI(String prefix, Properties props, Properties info) { JComponent component = createEmbeddedPropertyGUI(prefix, props, info); JButton doneButton = null, cancelButton = null; JPanel buttons = new JPanel(); if (print) { doneButton = new JButton(i18n.get(Inspector.class, "Print", "Print")); cancelButton = new JButton(i18n.get(Inspector.class, "Quit", "Quit")); } else { doneButton = new JButton(i18n.get(Inspector.class, "Ok", "Ok")); cancelButton = new JButton(i18n.get(Inspector.class, "Cancel", "Cancel")); } doneButton.addActionListener(this); doneButton.setActionCommand(doneCommand); cancelButton.addActionListener(this); cancelButton.setActionCommand(cancelCommand); buttons.add(doneButton); buttons.add(cancelButton); component.add(buttons, BorderLayout.SOUTH); component.validate(); return component; } /** * Implement the ActionListener interface. The actions registering here * should be generated by the two buttons in the Inspector GUI. */ public void actionPerformed(ActionEvent e) { final String actionCommand = e.getActionCommand(); String prefix = propertyConsumer.getPropertyPrefix(); if (actionCommand == doneCommand) {// confirmed Properties props = collectProperties(); if (!print) { if (windowSupport != null) { windowSupport.killWindow(); } propertyConsumer.setProperties(prefix, props); if (actionListener != null) { actionListener.actionPerformed(e); } } else { Set<Entry<Object, Object>> entrySet = props.entrySet(); Iterator<Entry<Object, Object>> it = entrySet.iterator(); while (it.hasNext()) { Entry<Object, Object> next = it.next(); String val = (String) next.getValue(); System.out.println(next.getKey() + "=" + val); } } } else if (actionCommand == cancelCommand) {// canceled if (actionListener != null && actionListener != this) { actionListener.actionPerformed(e); } propertyConsumer = null; // to be garb. coll'd if (windowSupport != null) { windowSupport.killWindow(); } if (print) { System.exit(0); } } } /** * Tells the Inspector to collect the properties from the editors and set * them on its PropertyConsumer. */ public void collectAndSetProperties() { if (propertyConsumer != null) { String prefix = propertyConsumer.getPropertyPrefix(); Properties props = collectProperties(); propertyConsumer.setProperties(prefix, props); } } /** Extracts properties from textfield[]. */ public Properties collectProperties() { Properties props = new Properties(); for (String key : editors.keySet()) { PropertyEditor editor = editors.get(key); if (editor != null) { String stuff = editor.getAsText(); // If it's not defined with text, don't put it in the // properties. The layer should handle this and use // its default settings. if (stuff != null && stuff.length() > 0) { props.put(key, stuff); } if (editor instanceof PropertyConsumer) { ((PropertyConsumer) editor).getProperties(props); } } } return props; } public void setPrint(boolean p) { print = p; } public boolean getPrint() { return print; } public WindowSupport getWindowSupport() { return windowSupport; } /** test cases. */ public static void main(String[] args) { Debug.init(); String name = (args.length < 1) ? "com.bbn.openmap.layer.shape.ShapeLayer" : args[0]; PropertyConsumer propertyconsumer = null; try { Class<?> c = Class.forName(name); propertyconsumer = (PropertyConsumer) c.newInstance(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } if (propertyconsumer != null) { Properties props = new Properties(), info = new Properties(); System.out.println("Inspecting " + name); String pp = name.substring(name.lastIndexOf(".") + 1); propertyconsumer.setPropertyPrefix(pp.toLowerCase()); props = propertyconsumer.getProperties(props); info = propertyconsumer.getPropertyInfo(info); Inspector inspector = new Inspector(); inspector.setPrint(true); inspector.addActionListener(inspector); inspector.inspectPropertyConsumer(propertyconsumer); } } }