@Override
  public void updateEnableState() {
    boolean enabled = false;
    final VizMapperMainPanel vizMapperMainPanel = getVizMapperMainPanel();
    VisualPropertySheet vpSheet = null;

    if (vizMapperMainPanel != null) vpSheet = vizMapperMainPanel.getSelectedVisualPropertySheet();

    if (vpSheet != null) {
      for (final VisualPropertySheetItem<?> vpSheetItem : vpSheet.getSelectedItems()) {
        final VisualPropertySheetItemModel<?> model = vpSheetItem.getModel();
        final PropertySheetTable table = vpSheetItem.getPropSheetPnl().getTable();
        final int[] selected = table.getSelectedRows();

        if (selected != null && model.getVisualMappingFunction() instanceof DiscreteMapping) {
          // Make sure the selected rows have at least one Discrete Mapping entry
          for (int i = 0; i < selected.length; i++) {
            final Item item = (Item) table.getValueAt(selected[i], 0);

            if (item != null && item.getProperty() instanceof VizMapperProperty) {
              final VizMapperProperty<?, ?, ?> prop =
                  (VizMapperProperty<?, ?, ?>) item.getProperty();

              if (prop.getCellType() == CellType.DISCRETE) {
                enabled = true;
                break;
              }
            }
          }
        }
      }
    }

    setEnabled(enabled);
  }
  /**
   * Gets the CellEditor for the given row and column. It uses the editor registry to find a
   * suitable editor for the property.
   *
   * @see javax.swing.JTable#getCellEditor(int, int)
   */
  public TableCellEditor getCellEditor(int row, int column) {
    if (column == 0) {
      return null;
    }

    Item item = getSheetModel().getPropertySheetElement(row);
    if (!item.isProperty()) return null;

    TableCellEditor result = null;
    Property propery = item.getProperty();
    PropertyEditor editor = getEditorFactory().createPropertyEditor(propery);
    if (editor != null) result = new CellEditorAdapter(editor);

    return result;
  }
  /** Edit all selected cells at once. This is for Discrete Mapping only. */
  @Override
  @SuppressWarnings({"rawtypes", "unchecked"})
  public void actionPerformed(final ActionEvent e) {
    final VizMapperMainPanel vizMapperMainPanel = getVizMapperMainPanel();

    if (vizMapperMainPanel == null) return;

    final VisualPropertySheet vpSheet = vizMapperMainPanel.getSelectedVisualPropertySheet();

    if (vpSheet == null) return;

    for (final VisualPropertySheetItem<?> vpSheetItem : vpSheet.getSelectedItems()) {
      final VisualPropertySheetItemModel<?> model = vpSheetItem.getModel();
      final PropertySheetTable table = vpSheetItem.getPropSheetPnl().getTable();
      final int[] selected = table.getSelectedRows();

      if (selected == null
          || selected.length == 0
          || !(model.getVisualMappingFunction() instanceof DiscreteMapping)) continue;

      // Test with the first selected item
      final DiscreteMapping dm = (DiscreteMapping) model.getVisualMappingFunction();
      final VisualProperty vp = dm.getVisualProperty();

      Object newValue = null;

      try {
        // Get new value
        newValue =
            editorManager.showVisualPropertyValueEditor(vizMapperMainPanel, vp, vp.getDefault());
      } catch (Exception ex) {
        logger.error("Could not edit value.", ex);
      }

      if (newValue == null) continue;

      final Map<Object, Object> newValues = new HashMap<Object, Object>();
      final Map<Object, Object> previousValues = new HashMap<Object, Object>();

      for (int i = 0; i < selected.length; i++) {
        final Item item = ((Item) table.getValueAt(selected[i], 0));

        if (item != null && item.getProperty() instanceof VizMapperProperty) {
          final VizMapperProperty<?, ?, ?> prop = (VizMapperProperty<?, ?, ?>) item.getProperty();

          if (prop.getCellType() == CellType.DISCRETE) {
            // Save the current value for undo
            previousValues.put(prop.getKey(), prop.getValue());

            // New value
            newValues.put(prop.getKey(), newValue);
          }
        }
      }

      // Save the mapping->old_values for undo
      if (!previousValues.isEmpty()) previousMappingValues.put(dm, previousValues);

      // Save the mapping->new_values for redo
      if (!newValues.isEmpty()) newMappingValues.put(dm, newValues);

      // Update the visual mapping
      dm.putAll(newValues);
    }

    // Undo support
    if (!previousMappingValues.isEmpty()) {
      final UndoSupport undo = servicesUtil.get(UndoSupport.class);
      undo.postEdit(new EditSelectedDiscreteValuesEdit());
    }
  }