All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.datacleaner.widgets.properties.AbstractMultipleCheckboxesPropertyWidget Maven / Gradle / Ivy

/**
 * DataCleaner (community edition)
 * Copyright (C) 2014 Free Software Foundation, Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.datacleaner.widgets.properties;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JCheckBox;

import org.apache.commons.lang.ArrayUtils;
import org.datacleaner.descriptors.ConfiguredPropertyDescriptor;
import org.datacleaner.job.builder.ComponentBuilder;
import org.datacleaner.panels.DCPanel;
import org.datacleaner.util.WidgetFactory;
import org.datacleaner.widgets.DCCheckBox;
import org.datacleaner.widgets.DCCheckBox.Listener;
import org.jdesktop.swingx.HorizontalLayout;
import org.jdesktop.swingx.VerticalLayout;

/**
 * Abstract implementation of the {@link PropertyWidget} interface, for array
 * properties that are represented using a list of checkboxes.
 *
 * @param 
 */
public abstract class AbstractMultipleCheckboxesPropertyWidget extends AbstractPropertyWidget {

    private final Listener _changeListener = (item, selected) -> fireValueChanged();
    private final Map> _checkBoxes;
    private final ActionListener _selectAllListener = new ActionListener() {
        @Override
        public void actionPerformed(final ActionEvent e) {
            for (final JCheckBox cb : _checkBoxes.values()) {
                if (cb.isEnabled()) {
                    cb.setSelected(true);
                }
            }
            fireValueChanged();
        }
    };
    private final ActionListener _selectNoneListener = new ActionListener() {
        @Override
        public void actionPerformed(final ActionEvent e) {
            for (final JCheckBox cb : _checkBoxes.values()) {
                cb.setSelected(false);
            }
            fireValueChanged();
        }
    };
    private final Class _itemClass;
    private final DCPanel _buttonPanel;
    private final DCCheckBox _notAvailableCheckBox;

    public AbstractMultipleCheckboxesPropertyWidget(final ComponentBuilder componentBuilder,
            final ConfiguredPropertyDescriptor propertyDescriptor, final Class itemClass) {
        super(componentBuilder, propertyDescriptor);
        _itemClass = itemClass;
        _checkBoxes = new LinkedHashMap<>();
        setLayout(new VerticalLayout(2));

        _notAvailableCheckBox = new DCCheckBox<>(getNotAvailableText(), false);
        _notAvailableCheckBox.setOpaque(false);
        _notAvailableCheckBox.setEnabled(false);

        _buttonPanel = createButtonPanel();

        add(_buttonPanel);
    }

    private void updateVisibility() {
        _buttonPanel.setVisible(_checkBoxes.size() > 3);
        if (_checkBoxes.isEmpty()) {
            add(_notAvailableCheckBox);
        } else {
            remove(_notAvailableCheckBox);
        }
    }

    protected DCPanel createButtonPanel() {
        final DCPanel buttonPanel = new DCPanel();
        buttonPanel.setLayout(new HorizontalLayout(2));

        final JButton selectAllButton = WidgetFactory.createDefaultButton("Select all");
        selectAllButton.addActionListener(_selectAllListener);
        buttonPanel.add(selectAllButton);

        final JButton selectNoneButton = WidgetFactory.createDefaultButton("Select none");
        selectNoneButton.addActionListener(_selectNoneListener);
        buttonPanel.add(selectNoneButton);
        return buttonPanel;
    }

    public void initialize(final E[] values) {
        if (values != null) {
            // add all registered values
            for (final E item : values) {
                addCheckBox(item, true);
            }
        }

        // add all available checkboxes
        final E[] availableValues = getAvailableValues();
        for (final E item : availableValues) {
            addCheckBox(item, isEnabled(item, values));
        }

        updateVisibility();
    }

    protected JCheckBox[] getCheckBoxes() {
        return _checkBoxes.values().toArray(new JCheckBox[_checkBoxes.size()]);
    }

    protected abstract E[] getAvailableValues();

    /**
     * Gets the text for an optional disabled checkbox in case no items are
     * available.
     *
     * @return
     */
    protected abstract String getNotAvailableText();

    protected JCheckBox addCheckBox(final E item, final boolean checked) {
        final String name = getName(item);
        DCCheckBox checkBox = _checkBoxes.get(name);
        if (checkBox != null) {
            checkBox.setSelected(checked);
            return checkBox;
        }
        checkBox = new DCCheckBox<>(name, checked);
        checkBox.setValue(item);
        checkBox.setOpaque(false);
        checkBox.addListener(_changeListener);
        _checkBoxes.put(name, checkBox);
        add(checkBox);

        updateVisibility();
        updateUI();

        return checkBox;
    }

    protected void editCheckBox(final E oldvalue, final E newValue) {
        final String name = getName(oldvalue);
        final DCCheckBox checkBox = _checkBoxes.get(name);
        if (checkBox != null) {
            _checkBoxes.remove(name);
            checkBox.addListener(_changeListener);
            final boolean isSelected = checkBox.isSelected();
            checkBox.setValue(newValue);
            checkBox.setSelected(isSelected, true);
            _checkBoxes.put(name, checkBox);
            add(checkBox);
            // 'fireValueChanged' changes the value in the component builder. Otherwise the listener 
            // is activated at the later point(when the window is opened again) *
            fireValueChanged();
        } else {
            addCheckBox(newValue, true);
        }
        updateVisibility();
        updateUI();
    }

    protected void removeCheckBox(final E item) {
        final DCCheckBox checkBox = _checkBoxes.remove(getName(item));
        if (checkBox != null) {
            remove(checkBox);
        }

        updateVisibility();
    }

    private boolean isEnabled(final E value, final E[] enabledValues) {
        if (enabledValues == null || enabledValues.length == 0) {
            return false;
        }
        for (final E currentValue : enabledValues) {
            if (currentValue.equals(value)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean isSet() {
        for (final JCheckBox checkBox : getCheckBoxes()) {
            if (checkBox.isSelected()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public E[] getValue() {
        final List result = new ArrayList<>();
        final Collection> checkBoxes = _checkBoxes.values();
        for (final DCCheckBox cb : checkBoxes) {
            if (cb.isSelected()) {
                result.add(cb.getValue());
            }
        }
        @SuppressWarnings("unchecked") final E[] array = (E[]) Array.newInstance(_itemClass, result.size());
        return result.toArray(array);
    }

    @Override
    protected void setValue(final E[] values) {
        // if checkBoxes is empty it means that the value is being set before
        // initializing the widget. This can occur in subclasses and automatic
        // creating of checkboxes should be done.
        if (_checkBoxes.isEmpty() && values != null) {
            for (final E value : values) {
                addCheckBox(value, true);
            }
        }

        // update selections in checkboxes
        for (final DCCheckBox cb : _checkBoxes.values()) {
            if (ArrayUtils.contains(values, cb.getValue())) {
                cb.setSelected(true);
            } else {
                cb.setSelected(false);
            }
        }

        updateVisibility();
    }

    protected abstract String getName(E item);
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy