Archive

Archive for the ‘OutlineView’ Category

Recipe 11: Why my OutlineView is not refreshed?

March 2, 2014 Leave a comment

Problem

Your outline view needs to be updated from data that are received from the network or when you edit a cell and press ENTER, nothing happens. Or when you add/remove a row the outline view is not updated.

Solution

For the cells to be updated/refreshed, one needs to add a property change listener to the underlying bean that when a property is changed, the node is refreshed, e.g.

public class MyNode extends BeanNode<MyBean> {

   private final transient PropertyChangeListener pcl = new PropertyChangeListener() {

     @Override
     public void propertyChange(final PropertyChangeEvent evt) {
       firePropertySetsChange(null, getPropertySets());
     }
   };

   public MyNode(MyBean bean) throws IntrospectionException {
     super(bean, Children.LEAF, Lookups.singleton(bean));
     bean.addPropertyChangeListener(pcl);
   }
}

and you need to fire a property change in your bean when a property changed.
This will refresh your outline view each time a cell value is changed.
To refresh your outline view when a row is added/removed, you need to modify your ChildFactory accordingly, e.g.

public class MyChildFactory extends ChildFactory<MyBean> {

   private final MyProvider provider;
   private final transient PropertyChangeListener pcl = new PropertyChangeListener() {

     @Override
     public void propertyChange(final PropertyChangeEvent evt) {
       refresh(true);
     }
   };

   public MyChildFactory() {
     provider = Lookup.getDefault().lookup(MyProvider.class);
     provider.addPropertyChangeListener(pcl);
   }

   @Override
   protected boolean createKeys(final List<MyBean> toPopulate) {
     toPopulate.addAll(provider.list());
     return true;
   }
}

where MyProvider is a service provider that popuplates your ChildFactory. Again, you need to fire a property change in your provider when an instance of MyBean is added/removed from it.

Categories: OutlineView

Recipe 10: How to remove a filter that returned no rows from an OutlineView?

March 2, 2014 Leave a comment

Problem

By right-clicking inside an outline view, a popup menu is displayed where you can select the action Show only rows where you can define your criteria depending under which column you clicked. However, if the filter resulted in no rows, how can you display all rows again since the action is displayed only when there are visible rows in the outline view?

Solution

An easy solution is to add a toolbar next to your outline view inside the top component and add the following button:

public class RemoveFilterAction extends AbstractAction {
  /** The outline view to sort. */
  private final OutlineView outlineView;
  /** PropertyChangeListener to set the enabled state. */
  private final PropertyChangeListener pcl = new PropertyChangeListener() {
     @Override
     public void propertyChange(PropertyChangeEvent evt) {
       setEnabled(RemoveFilterAction.this.outlineView.getOutline().getQuickFilterColumn() != -1);
     }
  };

  /**
    *
    * @param view the outline view to remove filter from.
    */
  public RemoveFilterAction(OutlineView view) {
     super(NbBundle.getMessage(RemoveFilterAction.class, "HINT_RemoveFilter"),
           ImageUtilities.loadImageIcon("deleteFilter.png", false));
     this.outlineView = view;
     view.getOutline().addPropertyChangeListener(pcl);
     pcl.propertyChange(null);
     putValue(SHORT_DESCRIPTION, org.openide.util.NbBundle.getMessage(RemoveFilterAction.class, "HINT_RemoveFilter"));
  }

  @Override
  public void actionPerformed(ActionEvent e) {
     outlineView.getOutline().unsetQuickFilter();
     pcl.propertyChange(null);
  }
}

where

HINT_RemoveFilter=Remove the applied filter from view

Whenever a filter is applied to the outline view, the button becomes enabled, and by clicking on it the filter is removed.

Categories: Filter, OutlineView

Recipe 9: How to filter an OutlineView?

February 26, 2014 1 comment

Problem

How can I filter an OutlineView programmatically?

Solution

By right-clicking inside an outline view, a popup menu is displayed where you can select the action Show only rows where you can define your criteria depending under which column you clicked.

To do filtering programmatically, ETable defines two methods:

outlineView.getOutline().setQuickFilter(column, filter);
outlineView.getOutline().unsetQuickFilter();

where column is 1 for first column, 2 for second etc. and filter is of type Object and can be one of two types:

  • a value that is matched directly to the values of the column, e.g.
outlineView.getOutline().setQuickFilter(3, Boolean.TRUE);
  • a QuickFilter e.g.
private final QuickFilter filter = new QuickFilter() {
   @Override
   public boolean accept(Object aValue) {
      if (aValue instanceof TaskNode) {
         TaskNode taskNode = (TaskNode) aValue;
         Task task = taskNode.getLookup().lookup(Task.class);
         return task.isCompleted();
      }
     return true;
   }
};
outlineView.getOutline().setQuickFilter(0, filter);

In the previous example we pass the filter to column 0. This is the node column which gives us access to all fields of the node, i.e. the bean that is wrapped, which allows to filter the outline view even for fields that are not displayed in the outline view. E.g. you have a class :

public class Task implements Serializable {
  private int id;
  private String description;
  private int priority;
  private Date dueDate;
  private boolean alert = false;
  private int daysBefore;
  private String obs;
  private boolean completed = false;

but the outline view displays only: priority, description, alert and due date and you want to filter the tasks that are completed, then the above filter will do the job.

Categories: Filter, OutlineView

Recipe 8: Hide node column in OutlineView

April 14, 2013 Leave a comment

Problem

The OutlineView is a combined tree/table structure. As a consequence, when using it to display tabular data, the node column is displayed as the first column of the table in addition to the data columns. How can I remove it?

Solution

In older (< 7.0) versions of NetBeans, it was recommended to use this trick:

outlineView.getOutline().setRootVisible(false);
outlineView.getOutline().getColumnModel().removeColumn(outlineView.getOutline().getColumnModel().getColumn(0));

However, it is not a good idea to remove this column because NetBeans is using it. The recommended way, that works in 7.0 (there seems to be a bug in previous versions), is:

Outline outline = outlineView.getOutline();
outline.setRootVisible(false);
TableColumnModel columnModel = outline.getColumnModel();
ETableColumn column = (ETableColumn) columnModel.getColumn(0);
((ETableColumnModel) columnModel).setColumnHidden(column, true);
Categories: OutlineView

Recipe 7: Decorate an OutlineView

November 28, 2011 1 comment

Problem

When an OutlineView is not editable, its cells appear grey and the property editor button is shown. How do I decorate a read-only OutlineView?

Solution

Use the following custom cell renderer in NetBeans 7.0 and above:

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import org.netbeans.swing.outline.DefaultOutlineCellRenderer;
import org.openide.awt.HtmlRenderer;
import org.openide.nodes.Node.Property;
import org.openide.util.Exceptions;
/**
 * Renderer used to remove the property editor button and the grey appearance of the cells of an outline view.
 * It uses the &lt;@link PropertyTextRenderer/&gt; of the property if any was set.
 */
public class CustomOutlineCellRenderer extends DefaultOutlineCellRenderer {

 /** Gray Color for the odd lines in the view. */
 private static final Color VERY_LIGHT_GRAY = new Color(236, 236, 236);
 /** Center the content of the cells displaying text. */
 protected boolean centered = System.getProperty(&quot;os.name&quot;).toLowerCase().indexOf(&quot;windows&quot;) &lt; 0;
 /** Highlight the non editable cells making the foreground lighter.*/
 protected boolean lighterEditableFields = false;
 @Override
 @SuppressWarnings(&quot;unchecked&quot;)
 public Component getTableCellRendererComponent(final JTable table,
                                                final Object value,
                                                final boolean isSelected,
                                                final boolean hasFocus,
                                                final int row,
                                                final int column) {
  Component cell = null;
  Object valueToDisplay = value;
  if (value instanceof Property) {
     try {
        valueToDisplay = ((Property) value).getValue();
     } catch (IllegalAccessException ex) {
        Exceptions.printStackTrace(ex);
     } catch (InvocationTargetException ex) {
        Exceptions.printStackTrace(ex);
     }
  }
  if (valueToDisplay != null) {
    TableCellRenderer renderer = table.getDefaultRenderer(valueToDisplay.getClass());
    if (renderer != null) {
       cell = renderer.getTableCellRendererComponent(table, valueToDisplay, isSelected,
                                                     hasFocus, row, column);
    }
  } else {
       cell = super.getTableCellRendererComponent(table, valueToDisplay, isSelected, hasFocus, row, column);
  }
  if (cell != null) {
     if (centered) {
        if (cell instanceof HtmlRenderer.Renderer) {
           ((HtmlRenderer.Renderer) cell).setCentered(centered);
        } else if (cell instanceof DefaultTableCellRenderer.UIResource) {
           ((DefaultTableCellRenderer.UIResource) cell).setHorizontalAlignment(JLabel.CENTER);
        }
     }
     Color foregroundColor = table.getForeground();
     int modelRow = table.convertRowIndexToModel(row);
     int modelColumn = table.convertColumnIndexToModel(column);
     final boolean cellEditable = table.getModel().isCellEditable(modelRow, modelColumn);
     if (lighterEditableFields &amp;&amp; cellEditable) {
        foregroundColor = Color.BLUE;
     }
     cell.setForeground(foregroundColor);
     cell.setBackground(row % 2 == 0 ? Color.WHITE : VERY_LIGHT_GRAY);
     if (isSelected) {
        if (lighterEditableFields &amp;&amp; cellEditable) {
           cell.setFont(cell.getFont().deriveFont(Font.BOLD));
        }
        cell.setBackground(table.getSelectionBackground());
     }
  }
  return cell;
 }
 /**
   * @return true if the text rendered in labels is centered.
   */
 public boolean isCentered() {
    return centered;
 }

 /**
  * Center the content of the cells displaying text.
  *
  * @param value true to center, false for default alignment.
  */
 public void setCentered(final boolean value) {
    this.centered = value;
 }

 /**
  * @return true if non editable cells have a lighter foreground.
  */
 public boolean isLighterEditableFields() {
    return lighterEditableFields;
 }

 /**
  * Highlight the non editable cells making the foreground lighter.
  *
  * @param value true to activate this feature.
  */
 public void setLighterEditableFields(final boolean value) {
    this.lighterEditableFields = value;
 }
}

Then you can use it in your outline view like so:

outlineView.getOutline().setDefaultRenderer(Node.Property.class,
                                            new CustomOutlineCellRenderer());

If you need more customisation:

outlineView.getOutline().setDefaultRenderer(Node.Property.class,
new CustomOutlineCellRenderer() {

 @Override
 public Component getTableCellRendererComponent(final JTable table, final Object value,
                                               final boolean isSelected,
                                               final boolean hasFocus,
                                               final int row, final int column) {
  JLabel cell = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
  int modelRow = table.convertRowIndexToModel(row);
  Node node = EXPLORER_MANAGER.getRootContext().getChildren().getNodeAt(modelRow);
  if (node != null) {
     if (isSelected) {
        cell.setFont(cell.getFont().deriveFont(Font.BOLD));
     } else {
        cell.setFont(cell.getFont().deriveFont(Font.PLAIN));
     }
     cell.setBackground(Color.black);
     cell.setForeground(Color.white);
  }
  return cell;
 }
});

Recipe 6: Sort an OutlineView programmatically

November 27, 2011 Leave a comment

Problem

How can I sort a column of an OutlineView programmatically?

Solution

You can click on the header of a column in an OutlineView to sort it in ascending/descending order. But how can you do this programmatically? E.g. when you click on a button you wish to have the outline view sorted by one column, and when you click another button to have it sorted based on another column:

/**
 * Sort the outline view {@code ov} on the given {@code field}.
 * @param ov outline view to sort
 * @param field to sort upon
 * @param ascending if {@code true} then the list is sorted in ascending order, if {@code false} in descending order.
 */
public static void sortBy(final OutlineView ov, final String field, final boolean ascending) {
  ETableColumnModel columnModel = (ETableColumnModel) ov.getOutline().getColumnModel();
  int columnCount = columnModel.getColumnCount();
  columnModel.clearSortedColumns();
  for (int i = 0; i < columnCount; i++) {
    ETableColumn column = (ETableColumn)columnModel.getColumn(i);
    if (column.getHeaderValue().equals(field)) {
      columnModel.setColumnSorted(column, ascending, 1);
    }
  }
  TableModel model = ov.getOutline().getModel();
  ov.getOutline().tableChanged(new TableModelEvent(model, 0, model.getRowCount()));
}
Categories: OutlineView Tags: ,