Custom ColumnControlPopup stopped working with 1.0

View: New views
3 Messages — Rating Filter:   Alert me  

Custom ColumnControlPopup stopped working with 1.0

by jdnc-interest :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Back with another compatibility related question:

In our application we customized the ColumnControlPopup for the JXTables because the default one doesn't let us select/deselect multiple columns at once.  The code runs fine under 0.93 (maybe 0.97 - can't remember what we used before 1.0)...but with 1.0, the checkboxes in the ColumnControlPopup stop responding after a few checks/unchecks (well, that's the behavior in the small attached sample below - in our application, it looks like the whole popup becomes blank).

Any suggestions on how to fix this would be much appreciated.  Again, if you take the sample below and run it against 0.9x, you'll see it working properly, but with 1.0, it's hosed.

Thanks,
Tom
[code]
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;

import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.action.AbstractActionExt;
import org.jdesktop.swingx.icon.ColumnControlIcon;
import org.jdesktop.swingx.table.ColumnControlButton;
import org.jdesktop.swingx.table.ColumnControlPopup;

public class JXTableDemo {
     final private JFrame frame = new JFrame("Test JXTable");

   public static void main(String[] args) {
       new JXTableDemo();
   }
     public JXTableDemo() {
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.getContentPane().setLayout(new BorderLayout());
       AbstractTableModel tableModel = new AbstractTableModel() {
           private String[] columnNames = {"Column 1", "Column 2", "Column 3", "Column 4", "Column 5", "Column 6"};
                     public int getColumnCount() { return (columnNames.length); }
           public int getRowCount() { return (10); }
           public Object getValueAt(int rowIndex, int columnIndex) { return ("Cell " + rowIndex + ", " + columnIndex); }
           public String getColumnName(int col) { return columnNames[col]; }
       };
             JXTable table = new JXTable(tableModel) {
           @Override
           protected JComponent createDefaultColumnControl() {
               return (new MyColumnControlButton(this));
           }
       };
       table.setColumnControlVisible(true);
       table.setPreferredScrollableViewportSize(new Dimension(500, 200));
       frame.add(new JScrollPane(table), BorderLayout.CENTER);
             frame.pack();
       SwingUtilities.invokeLater(new Runnable() {
           public void run() {
               frame.setVisible(true);
               frame.setBounds(100, 100, 500, 200);
           }
       });
   }
   private class MyColumnControlButton extends ColumnControlButton {
             public MyColumnControlButton(JXTable table) {
           this(table, new ColumnControlIcon());
       }
       public MyColumnControlButton(JXTable table, Icon icon) {
           super(table, icon);
       }
       @Override
       protected ColumnControlPopup createColumnControlPopup() {
           return (new NFColumnControlPopup());
       }
             public class NFColumnControlPopup extends DefaultColumnControlPopup {
           @Override
           public void addVisibilityActionItems(List<? extends AbstractActionExt> actions) {
               JPanel panel = new JPanel();
               panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
                             for (int i = 0; i < actions.size(); i++) {
                   AbstractActionExt action = actions.get(i);
                   JCheckBox checkBox = new JCheckBox(action);
                      checkBox.setSelected(action.isSelected());
                      checkBox.addItemListener(action);
                   new ToggleActionPropertyChangeListener2(action, checkBox);
                   panel.add(checkBox);
               }
               getPopupMenu().add(panel);
           }
       }
       class ToggleActionPropertyChangeListener2 implements PropertyChangeListener {


           private WeakReference<AbstractButton> buttonRef;
                     public ToggleActionPropertyChangeListener2(Action action, AbstractButton button) {
               if (shouldAddListener(action, button)) {
                   this.buttonRef = new WeakReference<AbstractButton>(button);
                   action.addPropertyChangeListener(this);
               }
           }

                     protected synchronized boolean shouldAddListener(Action action, AbstractButton button) {
               releasePCLs(action);
               // PENDING JW: revisit - we need a configurator to maintain at most a 1:1 from button to
               // action anyway: so a true in isToggling must not happen.
               //
               return !isToggling(action, button);
//                return true;
           }


           protected boolean isToggling(Action action, AbstractButton button) {
               if (!(action instanceof AbstractAction)) return false;
               PropertyChangeListener[] listeners = ((AbstractAction)action).getPropertyChangeListeners();
               for (int i = listeners.length - 1; i >= 0; i--) {
                   if (listeners[i] instanceof ToggleActionPropertyChangeListener2) {
                       if (((ToggleActionPropertyChangeListener2) listeners[i]).isToggling(button)) return true;
                   }
               }
               return false;
           }

           /**
            * Removes all ToggleActionPCLs with unreachable target buttons from the
            * Action's PCL-listeners.
            *
            * @param action to cleanup.
            */
           protected void releasePCLs(Action action) {
               if (!(action instanceof AbstractAction)) return;
               PropertyChangeListener[] listeners = ((AbstractAction)action).getPropertyChangeListeners();
               for (int i = listeners.length - 1; i >= 0; i--) {
                   if (listeners[i] instanceof ToggleActionPropertyChangeListener2) {
                       ((ToggleActionPropertyChangeListener2) listeners[i]).checkReferent(action);
                   }
               }
           }

                     public void propertyChange(PropertyChangeEvent evt) {
               AbstractButton button = checkReferent((Action) evt.getSource());
               if (button == null) return;
               String propertyName = evt.getPropertyName();

               if (propertyName.equals("selected")) {
                   Boolean selected = (Boolean)evt.getNewValue();
                   button.setSelected(selected.booleanValue());
               }
           }

           /**
            * Returns the target button to synchronize from the listener.
            *
            * Side-effects if the target is no longer reachable:
            *  - the internal reference to target is nulled.
            *  - if the given action is != null, this listener removes
            *       itself from the action's listener list.
            *
            * @param action The action this is listening to.
            * @return the target button if it is strongly reachable or null
            *    if it is no longer strongly reachable.
            */
           protected AbstractButton checkReferent(Action action) {
               AbstractButton button = null;
               if (buttonRef != null) {
                   button = buttonRef.get();
               }
               if (button == null) {
                   if (action != null) {
                       action.removePropertyChangeListener(this);
                   }
                  buttonRef = null;
               }
               return button;
           }


           /**
            * Check if this is already synchronizing the given AbstractButton.
            *
            * This may have the side-effect of releasing the weak reference to
            * the target button.
            *
            * @param button must not be null
            * @return true if this target button and the given comp are equal
            *         false otherwise.
            * @throws NullPointerException if the button is null.
            */
           public boolean isToggling(AbstractButton button) {
               // JW: should check identity instead of equality?
               return button.equals(checkReferent(null));
           }

           /**
            * Checks if this is synchronizing to the same target button as the
            * given listener.
            *
            * This may have the side-effect of releasing the weak reference to
            * the target button.
            *
            * @param pcl The listener to test, must not be null.
            * @return true if the target buttons of the given is equal to this target
            *    button and the button is strongly reachable, false otherwise.
            */
//            public boolean isToggling(ToggleActionPropertyChangeListener pcl) {
//                AbstractButton other = pcl.checkReferent(null);
//                if (other != null) {
//                    return isToggling(other);
//                }
//                return false;
//            }
                           }
   }
}
[/code]
[Message sent by forum member 'tjwolf' (twolf@...)]

http://forums.java.net/jive/thread.jspa?messageID=368276

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@...
For additional commands, e-mail: jdnc-help@...


Re: Custom ColumnControlPopup stopped working with 1.0

by jdnc-interest :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Tom,

a bit of digging: working until 0.9.3, not working for 0.9.4-1.0, working again with current. I think the problem is a columnRemoved notification not correctly interpreted as movedToInVisible from DefaultTableColumnModelExt. There had been changes after 093 and a bug report and fix after final. So you might try to use a more recent version of the model.

HTH
Jeanette

as to the site-admin: how about webmaster@... ;-) Plus, somewhere in the java-net project there's a feedback page with several contact options.
[Message sent by forum member 'kleopatra' (fastegal@...)]

http://forums.java.net/jive/thread.jspa?messageID=368305

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@...
For additional commands, e-mail: jdnc-help@...


Re: Custom ColumnControlPopup stopped working with 1.0

by jdnc-interest :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

forgot: the fixed issue is

https://swingx.dev.java.net/issues/show_bug.cgi?id=1123

Cheers
Jeanette
[Message sent by forum member 'kleopatra' (fastegal@...)]

http://forums.java.net/jive/thread.jspa?messageID=368306

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@...
For additional commands, e-mail: jdnc-help@...