Re: [xml-dev] tree editor syntax completion and more... ready for checkin

Petr Kuzel <[email protected]> Mon, 02 Dec 2002 16:18:18 +0100
Newsgroups gmane.comp.java.netbeans.modules.xml.devel
Organization Sun Microsystems
Message-ID <[email protected]>
> * Included a propertysheet customizer for the above framework which is
> a workalike of the org.openide.explorer.propertysheet package, but
> edits attributes of an xml element instead of java bean properties.
> It uses simple String property editors for each element, or a
> drop-down list if the DTD/schema specifies an enumerated list of
> allowable values.   Also, this propertysheet customizer can co-exist
> with other customizers in a JTabbedPane.

I looked at impl and I would like to eliminate openide.explorer.propertysheet
copy&paste. I'd prefer openide developers removing hardcoded behaviour
if it exists. I scanned diff -u xml/propertysheet openide/propertysheet
and found:

PropertyPanel.java: 1) your code does not share painting settings
   (using PropertySheetSettingsInvoker). Is it intention?
   What is problem with shared painting settings?

PropertySheetTab.java: 2) class made public with a contructor
   taking Customizer that is not used, why?
   3) Node.PropertySet replaced by AttributeSet (a class emulating
   properties over XML element attributes).
   4) setObject() is reimplemented  attaching PropertyChangeListeners
   to different sources.

I think that only 4) may needs openide/propertysheet implementation
change.

   Cc.

-- 
<address>
<a href="mailto:[email protected]">Petr Kuzel</a> at Sun Microsystems :
<a href="http://performance.netbeans.org/">IDE performance</a></address>

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
x2o.diff (text/plain, 15.5 KB)
--- PropertyPanel.java	2002-11-28 20:06:14.000000000 +0100
+++ /data/cvs/nb40/nb_all/openide/src/org/openide/explorer/propertysheet/PropertyPanel.java	2002-11-08 11:08:01.000000000 +0100
@@ -12,7 +12,7 @@
  */
 
 
-package org.netbeans.modules.xml.tree.nodes.propertysheet;
+package org.openide.explorer.propertysheet;
 
 
 import java.awt.BorderLayout;
@@ -121,6 +121,9 @@
     /** Descriptor for the property. */
     private FeatureDescriptor descriptor = new FeatureDescriptor();
     
+    /** Holds painting style. */
+    private int paintingStyle;
+    
     /** Foreground color of values. */
     private Color foregroundColor;
     /** Foreground color of disabled values. */
@@ -263,12 +266,23 @@
         setLayout (new BorderLayout ());
         
         boolean problem = false;
-
-        current.set(this);
-        // set defaults without PropertySheetSettings
-        plastic = false;
-        disabledColor = UIManager.getColor("textInactiveText");
-        foregroundColor = new Color (0, 0, 128);
+        try {
+            Class c = Class.forName("org.openide.explorer.propertysheet.PropertyPanel$PropertySheetSettingsInvoker"); // NOI18N
+            Runnable r = (Runnable)c.newInstance();
+            current.set(this);
+            r.run();
+        } catch (Exception e) {
+            problem = true;
+        } catch (LinkageError e) {
+            problem = true;
+        }
+        if (problem) {
+            // set defaults without P ropertySheetSettings
+            paintingStyle = PropertySheet.PAINTING_PREFERRED;
+            plastic = false;
+            disabledColor = UIManager.getColor("textInactiveText");
+            foregroundColor = new Color (0, 0, 128);
+        }
         
         model.addPropertyChangeListener (getModelListener());
         updateEditor ();
@@ -281,6 +295,22 @@
     }
     
     
+    /** Reference to PropertySheetSettings are separated here.*/
+    static class PropertySheetSettingsInvoker implements Runnable {
+        public void run() {
+            PropertyPanel instance = (PropertyPanel)current.get();
+            current.set(null);
+            if (instance == null) {
+                throw new IllegalStateException();
+            }
+            PropertySheetSettings pss = PropertySheetSettings.getDefault();
+            instance.paintingStyle = pss.getPropertyPaintingStyle();
+            instance.plastic = pss.getPlastic();
+            instance.disabledColor = pss.getDisabledPropertyColor();
+            instance.foregroundColor = pss.getValueColor();
+        }
+    }
+
     // public methods -------------------------------------------------------
     
     /** Getter for property preferences.
@@ -540,6 +570,12 @@
         reset();
     }
 
+    /** Sets painting style. */
+    void setPaintingStyle(int style) {
+        paintingStyle = style;
+        reset();
+    }
+    
     /** Adds sheet button listener to the <code>readComponent</code>. */
     void addSheetButtonListener(SheetButtonListener list) {
         this.sheetButtonListener = list;
@@ -816,7 +852,11 @@
             }
           
             if ( editor.isPaintable () &&
-                (stringValue == null)
+                ( (paintingStyle == PropertySheet.PAINTING_PREFERRED) ||
+                ( (paintingStyle == PropertySheet.STRING_PREFERRED) &&
+                    (stringValue == null)
+                  )
+                )
                ) {
                    if (differentValues)
                        c = getTextView (NbBundle.getMessage (PropertyPanel.class, "CTL_Different_Values")); //NOI18N
@@ -1169,7 +1209,8 @@
     private JComponent getInput(Component leftComponent, boolean existsCustomEditor) {
         JPanel panel;
         if ( (leftComponent == null) &&
-                (editor != null) && (editor.isPaintable ())
+                (editor != null) && (editor.isPaintable ()) &&
+                (paintingStyle != PropertySheet.ALWAYS_AS_STRING)
            ) {
             panel = new PropertyShow(editor);
         } else {
--- PropertySheetTab.java	2002-11-28 20:06:15.000000000 +0100
+++ /data/cvs/nb40/nb_all/openide/src/org/openide/explorer/propertysheet/PropertySheetTab.java	2002-08-08 11:53:12.000000000 +0200
@@ -11,15 +11,13 @@
  * Microsystems, Inc. All Rights Reserved.
  */
 
-package org.netbeans.modules.xml.tree.nodes.propertysheet;
+package org.openide.explorer.propertysheet;
 
 import java.awt.*;
 import java.awt.event.*;
 import java.beans.*;
 import java.util.*;
 import javax.swing.*;
-import java.beans.FeatureDescriptor;
-import java.lang.reflect.InvocationTargetException;
 
 import org.openide.awt.JPopupMenuPlus;
 import org.openide.awt.MouseUtils;
@@ -38,16 +36,12 @@
 import org.openide.util.WeakListener;
 import org.openide.util.Mutex;
 
-import org.netbeans.modules.xml.tree.nodes.ElementCustomizer;
-import org.netbeans.modules.xml.tree.nodes.ElementNode;
-import org.netbeans.tax.*;
-
 /**
  * A JPanel in property sheet showing a set of properties. The set
- * is represented by an AttributeSet instance.
+ * is represented by a Node.PropertySet instance.
  * @author  David Strupl
  */
-public class PropertySheetTab extends JPanel implements PropertyChangeListener {
+class PropertySheetTab extends JPanel implements PropertyChangeListener {
 
     /** Panel with SheetButtons with names of properties. */
     private NamesPanel namesPanel;
@@ -56,12 +50,10 @@
     private NamesPanel valuesPanel;
     
     /** Set of properties in this tab. */
-    private AttributeSet properties;
+    private Node.PropertySet properties;
     
     /** */
     private Node node;
-
-    private ElementCustomizer m_parent;
     
     /**
      * Maps property name (String) --> model from property panel 
@@ -74,6 +66,22 @@
      */
     private boolean changeInProgress;
     
+    /** Listens on changes in the global settings for sorter and
+     * displayWritableOnly.
+     */
+    private SettingsListener settingsListener;
+    
+    /** Comparator for instances of Node.Property */
+    private Comparator sorter;
+    
+    /** Value of this can be one of the constants defined in PropertySheet
+     * (UNSORTED, SORTED_BY_NAMES, SORTED_BY_TYPES).
+     */
+    private int sortingMode;
+    
+    /** When it's true only writable properties are shown. */
+    private PropertySheet mySheet;
+    
     /** The propertyChangeListener */
     private PropertyChangeListener propertyChangeListener;
     
@@ -120,27 +128,32 @@
     private JPopupMenu popupMenu;
 
     /** Creates new PropertySheetTab */
-    public PropertySheetTab(ElementCustomizer parent) {
-        m_parent = parent;
+    public PropertySheetTab(Node.PropertySet properties, Node node, PropertySheet mySheet) {
+        this.properties = properties;
+        this.node = node;
         modelCache = new HashMap();
+        this.mySheet = mySheet;
 
         setLayout (new BorderLayout ());
-        add (new EmptyPanel ("Attributes"), BorderLayout.CENTER);
+        add (new EmptyPanel (properties.getDisplayName()), BorderLayout.CENTER);
         
-    }
-
-    /** Customizer interface */
-    public void setObject( Object obj )
-    {
-        ElementNode elementNode = (ElementNode)obj;
-        this.node = elementNode;
-        this.properties = new AttributeSet( elementNode );
+        try {
+            setSortingMode(mySheet.getSortingMode());
+        } catch (PropertyVetoException x) {
+            ErrorManager.getDefault ().notify (x);
+        }
 
+        settingsListener = new SettingsListener();
+        mySheet.addPropertyChangeListener(
+            WeakListener.propertyChange(
+                settingsListener, 
+                mySheet
+            )
+        );
+        
         propertyChangeListener = WeakListener.propertyChange(this, node);
+        
         node.addPropertyChangeListener( propertyChangeListener );
-        elementNode.getElement().addPropertyChangeListener( propertyChangeListener );
-
-        createPane();
     }
 
     void detachPropertyChangeListener() {
@@ -194,7 +207,7 @@
                 return;
             }
             removeAll ();
-            add (new EmptyPanel ("Attributes"), BorderLayout.CENTER);
+            add (new EmptyPanel (properties.getDisplayName()), BorderLayout.CENTER);
             invalidate();
             validate();
             repaint();
@@ -225,7 +238,7 @@
     }
     
     /**
-     * Creates a SheetButtons and
+     * Sorts the properties with a sorter. Creates a SheetButtons and
      * PropertyPanels for the display and adds them to namesPanel and
      * valuesPanel.
      */
@@ -234,8 +247,14 @@
         
         ArrayList a = new ArrayList(p.length);
         for (int i = 0; i < p.length; i++) {
+            if (mySheet.getDisplayWritableOnly() && !p[i].canWrite()) {
+                continue;
+            }
             a.add(p[i]);
         }
+        if (sorter != null) {
+            Collections.sort(a, sorter);
+        }
         
         Object [] beans = new Object[] { node };
         if (node instanceof ProxyNode) {
@@ -248,19 +267,22 @@
             class LazyToolTipSheetButton extends SheetButton {
                 /** cache it, and do not compute it until requested */
                 private String toolTipText = null;
-                public LazyToolTipSheetButton() {
-                    super(prop.getDisplayName(), false, true);
+                Node.Property pr;
+                
+                public LazyToolTipSheetButton(Node.Property pr) {
+                    super(pr.getDisplayName(), false, true);
                     // Cause it to be registered with manager:
                     this.setToolTipText("dummy"); // NOI18N
+                    this.pr = pr;
                 }
                 public String getToolTipText(MouseEvent event) {
                     if (toolTipText == null) {
-                        toolTipText = getToolTipTextForProperty(prop);
+                        toolTipText = getToolTipTextForProperty(pr);
                     }
                     return toolTipText;
                 }
             }
-            final SheetButton leftButton = new LazyToolTipSheetButton();
+            final SheetButton leftButton = new LazyToolTipSheetButton(prop);
             leftButton.setFocusTraversable(false);
             
             namesPanel.add(leftButton);
@@ -271,15 +293,18 @@
             rightPanel.addSheetButtonListener(listener);
             leftButton.addSheetButtonListener(listener);
             leftButton.setPlastic(rightPanel.getPlastic());
+            if (prop.canWrite()) {
+                leftButton.setActiveForeground(mySheet.getValueColor());
+            } else {
+                leftButton.setActiveForeground(mySheet.getDisabledPropertyColor());
+            }
 
             leftButton.addMouseListener (
                 new MouseUtils.PopupMouseAdapter () {
                     public void showPopup (MouseEvent ev) {
-                        if (MouseUtils.isRightMouseButton (ev)) {
-                            setActions(prop);
-                            createPopup();
-                            popupMenu.show (leftButton, ev.getX(), ev.getY ());
-                        }
+                        setActions(prop);
+                        createPopup();
+                        popupMenu.show (leftButton, ev.getX(), ev.getY ());
                     }
                 }
             );
@@ -348,6 +373,61 @@
         }
     }
 
+    void setPaintingStyle(int style) {
+        int count = valuesPanel.getComponentCount();
+        for (int i = 0; i < count; i++) {
+            if (valuesPanel.getComponent(i) instanceof PropertyPanel) {
+                ((PropertyPanel)valuesPanel.getComponent(i)).setPaintingStyle(style);
+            }
+        }
+    }
+    
+    /**
+     * Set the sorting mode.
+     *
+     * @param sortingMode one of {@link #UNSORTED}, {@link #SORTED_BY_NAMES}, {@link #SORTED_BY_TYPES}
+     */
+    public void setSortingMode (int sortingMode) throws PropertyVetoException {
+        switch (sortingMode) {
+        case PropertySheet.UNSORTED:
+            sorter = null;
+            break;
+        case PropertySheet.SORTED_BY_NAMES:
+            sorter = SORTER_NAME;
+            break;
+        case PropertySheet.SORTED_BY_TYPES:
+            sorter = SORTER_TYPE;
+            break;
+        default:
+            throw new PropertyVetoException (
+                getString ("EXC_Unknown_sorting_mode"),
+                new PropertyChangeEvent (this, PropertySheet.PROPERTY_SORTING_MODE,
+                new Integer (this.sortingMode),
+                new Integer (sortingMode))
+            );
+        }
+        
+        int oldSortingMode = this.sortingMode;
+        this.sortingMode = sortingMode;
+        firePropertyChange(PropertySheet.PROPERTY_SORTING_MODE, oldSortingMode, this.sortingMode);
+    }
+
+    /**
+     * Get the sorting mode.
+     *
+     * @return the mode
+     * @see #setSortingMode
+     */
+    public int getSortingMode () {
+        return sortingMode;
+    }
+
+    /** Gets help ID for this property sheet tab.
+     * @see PropertySheet.HelpAwareJTabbedPane#getHelpCtx */
+    String getHelpID() {
+        return (String)properties.getValue("helpID"); // NOI18N
+    }
+    
     private static String getString(String key) {
         return NbBundle.getBundle(PropertySheetTab.class).getString(key);
     }
@@ -379,11 +459,6 @@
             // should not end up in infinite loop
             return;
         }
-        if( ElementNode.PROP_CUSTOMIZER.equals(propertyName) )
-        {
-            // do nothing
-            return;
-        }
         PropertyModel m = (PropertyModel)modelCache.get (propertyName);
         if (m == null) {
             // the model is not in our cache, probably we are not displaying
@@ -560,6 +635,36 @@
         }
     }
     
+    // Settings listener
+    final class SettingsListener implements PropertyChangeListener {
+        public void propertyChange (PropertyChangeEvent e) {
+            String name = e.getPropertyName ();
+
+            if (name == null) return;
+
+            if (name.equals (PropertySheet.PROPERTY_SORTING_MODE)) {
+                try {
+                    setSortingMode (((Integer)e.getNewValue ()).intValue ());
+                    if (paneCreated)
+                        createPane();
+                } catch (PropertyVetoException ee) {
+                    PropertyDialogManager.notify(ee);
+                }
+            } else if (name.equals (PropertySheet.PROPERTY_DISPLAY_WRITABLE_ONLY)) {
+                if (paneCreated)
+                    createPane();
+            } else if (name.equals (PropertySheet.PROPERTY_VALUE_COLOR)) {
+                setForegroundColor ((Color)e.getNewValue ());
+            } else if (name.equals (PropertySheet.PROPERTY_DISABLED_PROPERTY_COLOR)) {
+                setDisabledColor ((Color)e.getNewValue ());
+            } else if (name.equals (PropertySheet.PROPERTY_PLASTIC)) {
+                setPlastic (((Boolean)e.getNewValue ()).booleanValue ());
+            } else if (name.equals (PropertySheet.PROPERTY_PROPERTY_PAINTING_STYLE)) {
+                setPaintingStyle (((Integer)e.getNewValue ()).intValue ());
+            }
+        }
+    }
+
     /**
      * Scrollable enhancement of SplittedPanel.
      */
@@ -570,6 +675,7 @@
         ScrollableSplittedPanel (Component scroll, Container element) {
             this.scroll = scroll;
             this.element = element;
+            setSplitPosition (mySheet.getSavedPosition ());
         }
 
         /**
@@ -632,6 +738,7 @@
          */
         public void setSplitPosition(int value) {
             super.setSplitPosition(value);
+            mySheet.setSavedPosition (value);
         }
     } // End of class ScrollableSplittedPanel.