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

nl.cloudfarming.client.fleet.machine.windows.MachineOverviewController Maven / Gradle / Ivy

/**
 * Copyright (C) 2008-2012 AgroSense Foundation.
 *
 * AgroSense is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * There are special exceptions to the terms and conditions of the GPLv3 as it is applied to
 * this software, see the FLOSS License Exception
 * .
 *
 * AgroSense 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with AgroSense.  If not, see .
 */
package nl.cloudfarming.client.fleet.machine.windows;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import nl.cloudfarming.client.fleet.machine.MachineDataService;
import nl.cloudfarming.client.fleet.machine.MachineDataService.Model;
import nl.cloudfarming.client.fleet.model.Machine;
import nl.cloudfarming.client.fleet.model.MachineProvider;
import nl.cloudfarming.client.util.swing.beanbinding.NonEmptyStringValidator;
import nl.cloudfarming.client.util.swing.beanbinding.ToStringNotEmptyValidator;
import org.jdesktop.beansbinding.*;
import org.netbeans.api.project.Project;
import org.openide.util.NbBundle;

/**
 *
 * @author Merijn Zengers 
 */
@NbBundle.Messages({"MachineOverviewController custom value combox text=Custom",
    "MachineOverviewController empty name error message=Name can not be empty",
    "MachineOverviewController name exists error message=Name already exists",
    "MachineOverviewController empty type error message=No type selected",
    "MachineOverviewController empty brand error message=No brand selected",
    "MachineOverviewController empty model error message=No model selected"})
public abstract class MachineOverviewController {

    private CustomItemString customValue = new CustomItemString();
    private Machine machine;
    private E machineOverviewPanel;
    private Collection dataServices;

    public MachineOverviewController(E machineOverviewPanel, Machine machine, Collection dataServices) {
        this.machine = machine;
        this.machineOverviewPanel = machineOverviewPanel;
        this.dataServices = dataServices;
        initComboxValues();
        bind();
        addListeners();
    }

    /**
     * fills the type combobox
     */
    private void initComboxValues() {
        //Deactivate custom rows
        machineOverviewPanel.deactivateCustomBrandInput();
        machineOverviewPanel.deactivateCustomModelNumberInput();

        //fill the type combo box
        Set types = new TreeSet<>();
        ModelIterator modelIterator = new ModelIterator();
        while (modelIterator.hasNext()) {
            MachineDataService.Model model = modelIterator.next();
            types.add(model.getType());
        }
        if (types.size() > 1) {
            types.add("");
        }
        machineOverviewPanel.setTypes(types.toArray());

        //Fill the brand combo box or custom value or leave it empty for new machines
        String brand = machine.getBrand();
        if (brand != null) {
            updateBrands();
            if (isCustomBrandValue(brand)) {
                machineOverviewPanel.getBrandCombobox().setSelectedItem(customValue);
                machineOverviewPanel.activateCustomBrandInput();
            } else {
                machineOverviewPanel.getBrandCombobox().setSelectedItem(brand);
            }
        }
        //Fill the model number combo box or custom value. Or leave it empty for new machines
        String modelNumber = machine.getModelNumber();
        if (modelNumber != null) {
            updateModelNumbers();
            if (isCustomModelNumberValue(modelNumber)) {
                machineOverviewPanel.getModelNumberCombobox().setSelectedItem(customValue);
                machineOverviewPanel.activateCustomModelNumberInput();
            } else {
                machineOverviewPanel.getModelNumberCombobox().setSelectedItem(modelNumber);
            }
        }
    }

    /**
     * Checks if the value in that is saved as brand is a custom value or a
     * predefined one
     */
    boolean isCustomBrandValue(String brand) {
        ModelIterator modelIterator = new ModelIterator();
        while (modelIterator.hasNext()) {
            MachineDataService.Model model = modelIterator.next();
            if (model.getBrand().equals(brand)) {
                return false;
            }
        }
        return true;
    }

    boolean isCustomModelNumberValue(String modelNumber) {
        ModelIterator modelIterator = new ModelIterator();
        while (modelIterator.hasNext()) {
            MachineDataService.Model model = modelIterator.next();
            if (model.getModelNumber().equals(modelNumber)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Update the brands combobox
     */
    void updateBrands() {
        String selectedModelNumber = machineOverviewPanel.getModelNumberValue();
        Set brands = new TreeSet<>();
        ModelIterator modelIterator = new ModelIterator();
        while (modelIterator.hasNext()) {
            MachineDataService.Model model = modelIterator.next();
            if (brandSelectable(model)) {
                brands.add(model.getBrand());
            }
        }
        if (selectedModelNumber == null || customValue.isCustomValue(selectedModelNumber)) {
            brands.add("");
            brands.add(customValue);
        }
        machineOverviewPanel.setBrands(brands.toArray());
    }

    /**
     * Determines if the brand is selectable The selected type must be null or
     * the type must equal the passed in mode type
     *
     * @param model
     * @return
     */
    boolean brandSelectable(MachineDataService.Model model) {
        String selectedType = machineOverviewPanel.getTypeValue();
        return selectedType == null || selectedType.equals(model.getType());
    }

    void updateModelNumbers() {
        Set modelNumbers = new TreeSet<>();
        ModelIterator modelIterator = new ModelIterator();
        while (modelIterator.hasNext()) {
            MachineDataService.Model model = modelIterator.next();
            if (modelNumberSelectable(model)) {
                modelNumbers.add(model.getModelNumber());
            }
        }
        if (modelNumbers.size() > 1) {
            modelNumbers.add("");
        }
        modelNumbers.add(customValue);
        if (modelNumbers.size() == 1) {
            machineOverviewPanel.activateCustomModelNumberInput();
        } else {
            machineOverviewPanel.deactivateCustomModelNumberInput();
        }
        machineOverviewPanel.setModelNumbers(modelNumbers.toArray());
        validateModelNumber();
    }

    /**
     * Get the selected model
     */
    protected Model getSelectedModel() {
        ModelIterator iterator = new ModelIterator();
        Model selectedModel = new Model(machineOverviewPanel.getTypeValue(), machineOverviewPanel.getBrandField().getText(), machineOverviewPanel.getModelNumberField().getText());
        while (iterator.hasNext()) {
            Model model = iterator.next();
            if (model.equals(selectedModel)) {
                return model;
            }
        }
        return selectedModel;
    }

    boolean modelNumberSelectable(MachineDataService.Model model) {
        String selectedType = machineOverviewPanel.getTypeValue();
        String selectedBrand = machineOverviewPanel.getBrandValue();
        boolean typeValid = selectedType == null || selectedType.equals(model.getType());
        boolean brandValid = selectedBrand == null || selectedBrand.equals(model.getBrand());

        return typeValid && brandValid;
    }

    /**
     * Adds listeners on all the Validated fields and on all the comboboxes to
     * keep them in sync
     */
    private void addListeners() {
        //Add the listeners which keep comboboxes in sync
        ComboboxListener comboboxListener = new ComboboxListener();
        machineOverviewPanel.getTypeComboBox().addItemListener(comboboxListener);
        machineOverviewPanel.getBrandCombobox().addItemListener(comboboxListener);
        machineOverviewPanel.getModelNumberCombobox().addItemListener(comboboxListener);
        //Add the listeners which will inform implementing controllers of a field update in the panel
        PanelChangeListener panelChangeListener = new PanelChangeListener();

        machineOverviewPanel.getNameField().getDocument().addDocumentListener(panelChangeListener);
        machineOverviewPanel.getTypeComboBox().addActionListener(panelChangeListener);
        machineOverviewPanel.getBrandField().getDocument().addDocumentListener(panelChangeListener);
        machineOverviewPanel.getModelNumberField().getDocument().addDocumentListener(panelChangeListener);
    }

    final void bind() {
        BindingGroup machineBindingGroup = new BindingGroup();
        BeanProperty fieldPropName = BeanProperty.create(Machine.PROP_NAME);
        ELProperty formPropName = ELProperty.create("${text_ON_ACTION_OR_FOCUS_LOST}");
        BeanProperty fieldPropType = BeanProperty.create(Machine.PROP_TYPE);
        BeanProperty formPropType = BeanProperty.create("selectedItem");
        BeanProperty fieldPropBrand = BeanProperty.create(Machine.PROP_BRAND);
        BeanProperty formPropBrand = BeanProperty.create("text");
        BeanProperty fieldPropModelNumber = BeanProperty.create(Machine.PROP_MODELNUMBER);
        BeanProperty formPropModelNumber = BeanProperty.create("text");
        BeanProperty fieldPropYear = BeanProperty.create(Machine.PROP_YEAR);
        BeanProperty formPropYear = BeanProperty.create("value");
        BeanProperty fieldPropPurchaseDate = BeanProperty.create(Machine.PROP_PURCHASEDATE);
        BeanProperty formPropPurchaseDate = BeanProperty.create("date");
        BeanProperty fieldPropPurchasePrice = BeanProperty.create(Machine.PROP_PURCHASEPRICE);
        BeanProperty formPropPurchasePrice = BeanProperty.create("value");
        BeanProperty fieldPropMileage = BeanProperty.create(Machine.PROP_MILEAGE);
        BeanProperty formPropmileage = BeanProperty.create("value");

        AutoBinding nameBinding = Bindings.createAutoBinding(AutoBinding.UpdateStrategy.READ_WRITE, machine, fieldPropName, machineOverviewPanel.getNameField(), formPropName);
        nameBinding.setValidator(new NonEmptyStringValidator());
        machineBindingGroup.addBinding(nameBinding);
        AutoBinding typeBinding = Bindings.createAutoBinding(AutoBinding.UpdateStrategy.READ_WRITE, machine, fieldPropType, machineOverviewPanel.getTypeComboBox(), formPropType);
        typeBinding.setValidator(new ToStringNotEmptyValidator());
        machineBindingGroup.addBinding(typeBinding);
        AutoBinding brandBinding = Bindings.createAutoBinding(AutoBinding.UpdateStrategy.READ_WRITE, machine, fieldPropBrand, machineOverviewPanel.getBrandField(), formPropBrand);
        brandBinding.setValidator(new NonEmptyStringValidator());
        machineBindingGroup.addBinding(brandBinding);
        AutoBinding modelNumberBinding = Bindings.createAutoBinding(AutoBinding.UpdateStrategy.READ_WRITE, machine, fieldPropModelNumber, machineOverviewPanel.getModelNumberField(), formPropModelNumber);
        modelNumberBinding.setValidator(new NonEmptyStringValidator());
        machineBindingGroup.addBinding(modelNumberBinding);
        machineBindingGroup.addBinding(Bindings.createAutoBinding(AutoBinding.UpdateStrategy.READ_WRITE, machine, fieldPropYear, machineOverviewPanel.getYearSpinner(), formPropYear));
        machineBindingGroup.addBinding(Bindings.createAutoBinding(AutoBinding.UpdateStrategy.READ_WRITE, machine, fieldPropPurchaseDate, machineOverviewPanel.getPurchaseDataDatePicker(), formPropPurchaseDate));
        machineBindingGroup.addBinding(Bindings.createAutoBinding(AutoBinding.UpdateStrategy.READ_WRITE, machine, fieldPropPurchasePrice, machineOverviewPanel.getPurchasePriceField(), formPropPurchasePrice));
        machineBindingGroup.addBinding(Bindings.createAutoBinding(AutoBinding.UpdateStrategy.READ_WRITE, machine, fieldPropMileage, machineOverviewPanel.getMileageField(), formPropmileage));
        machineBindingGroup.bind();
    }

    /**
     * Get the machine provider from the implementing controller
     *
     * @param
     * @return
     */
    public abstract MachineProvider getMachineProvider();

    /**
     * Get the project
     *
     * @return
     */
    public abstract Project getProject();

    /**
     * Method is called when one of the fields of the {@link MachineOverviewPanel}
     * changes
     */
    public abstract void fieldsUpdated();

    /**
     * Get the MachineOverviewPanel this controller controls
     *
     * @return
     */
    public MachineOverviewPanel getOverviewPanel() {
        return machineOverviewPanel;
    }

    /**
     * Checks if the panel is valid
     *
     * @return
     */
    public boolean isPanelValid() {
        return isTypeValid() && isBrandValid() && isNameValid() && isModelNumberValid() && !machineExists();
    }

    /**
     * 

Validates the panel will set error messages on the form rows if * invalid

will validate if the type row and model number are * filled. Will validate if the name is not empty and if there is no machine * with this name in use

* */ public void validatePanel() { validateType(); validateBrand(); validateModelNumber(); validateName(); } /** * Validates the name field. Will set an error message when invalid */ private void validateName() { machineOverviewPanel.getNameRow().setValid(); if (!isNameValid()) { machineOverviewPanel.getNameRow().setInvalid(Bundle.MachineOverviewController_empty_name_error_message()); } else if (machineExists()) { machineOverviewPanel.getNameRow().setInvalid(Bundle.MachineOverviewController_name_exists_error_message()); } } /** * Validates if the name is not empty * * @return */ private boolean isNameValid() { String name = machineOverviewPanel.getNameField().getText(); if (name.isEmpty()) { return false; } return true; } /** * Validates the type field. Will set error message when invalid. */ private void validateType() { machineOverviewPanel.getTypeRow().setValid(); if (!isTypeValid()) { machineOverviewPanel.getTypeRow().setInvalid(Bundle.MachineOverviewController_empty_type_error_message()); } } /** * Validates if the type is not null and if it is not empty * * @return */ private boolean isTypeValid() { String typeValue = machineOverviewPanel.getTypeValue(); if (typeValue == null || typeValue.isEmpty()) { return false; } return true; } /** * Validates the brand field. Will set error message when invalid */ private void validateBrand() { machineOverviewPanel.getBrandRow().setValid(); machineOverviewPanel.getBrandCustomRow().setValid(); if (!isBrandValid()) { if (!machineOverviewPanel.getBrandCustomRow().isVisible()) { machineOverviewPanel.getBrandRow().setInvalid(Bundle.MachineOverviewController_empty_brand_error_message()); } else { machineOverviewPanel.getBrandCustomRow().setInvalid(Bundle.MachineOverviewController_empty_brand_error_message()); } } } /** * Checks if the brand is not null and it is not empty * * @return */ private boolean isBrandValid() { String brandValue = customValue.isCustomValue(machineOverviewPanel.getBrandValue()) ? machineOverviewPanel.getBrandField().getText() : machineOverviewPanel.getBrandValue(); if (brandValue == null || brandValue.isEmpty()) { return false; } return true; } /** * Validates the model number field. Will set an error message when invalid */ private void validateModelNumber() { machineOverviewPanel.getModelNumberRow().setValid(); machineOverviewPanel.getModelNumberCustomRow().setValid(); if (!isModelNumberValid()) { if (!machineOverviewPanel.getModelNumberCustomRow().isVisible()) { machineOverviewPanel.getModelNumberRow().setInvalid(Bundle.MachineOverviewController_empty_model_error_message()); } else { machineOverviewPanel.getModelNumberCustomRow().setInvalid(Bundle.MachineOverviewController_empty_model_error_message()); } } } /** * Validates if the model number is not null and if it is not empty * * @return */ private boolean isModelNumberValid() { String modelNumberValue = customValue.isCustomValue(machineOverviewPanel.getModelNumberValue()) ? machineOverviewPanel.getModelNumberField().getText() : machineOverviewPanel.getModelNumberValue(); if (modelNumberValue == null || modelNumberValue.isEmpty()) { return false; } return true; } /** * Checks if a machine with the same name does not already exist * * @return */ private boolean machineExists() { String name = machineOverviewPanel.getNameField().getText(); MachineProvider machineProvider = getMachineProvider(); assert machineProvider != null; List machines = machineProvider.findAll(getProject()); for (Machine foundMachine : machines) { if (foundMachine.getName().equalsIgnoreCase(name) && !foundMachine.getURI().equals(machine.getURI())) { return true; } } return false; } private class ModelIterator implements Iterator { private Iterator iterator; public ModelIterator() { List models = new ArrayList<>(); for (MachineDataService service : dataServices) { models.addAll(service.getModels()); } iterator = models.iterator(); } @Override public boolean hasNext() { return iterator.hasNext(); } @Override public MachineDataService.Model next() { return iterator.next(); } @Override public void remove() { throw new UnsupportedOperationException("Not supported."); } } class CustomItemString implements Comparable { @Override public String toString() { return Bundle.MachineOverviewController_custom_value_combox_text(); } public boolean isCustomValue(Object value) { return value != null && value.equals(toString()); } /** * Compare this CustomItemString with the given object. The given object * is in all cases greater, except for when it is an empty String or * null. This way, the CustomItemString is ordered before the "real" * items in a SortedSet. * * @param o The object to compare with * @return 1 if the object is an empty string, -1 otherwise */ @Override public int compareTo(Object o) { if (o == null || o.toString().isEmpty()) { return 1; } return -1; } } private class PanelChangeListener implements DocumentListener, ActionListener { @Override public void insertUpdate(DocumentEvent de) { validateField(de.getDocument()); fieldsUpdated(); } @Override public void removeUpdate(DocumentEvent de) { validateField(de.getDocument()); fieldsUpdated(); } @Override public void changedUpdate(DocumentEvent de) { validateField(de.getDocument()); fieldsUpdated(); } @Override public void actionPerformed(ActionEvent ae) { validateType(); fieldsUpdated(); } private void validateField(Document document) { if (document.equals(getOverviewPanel().getNameField().getDocument())) { validateName(); } else if (document.equals(getOverviewPanel().getBrandField().getDocument())) { validateBrand(); } else if (document.equals(getOverviewPanel().getModelNumberField().getDocument())) { validateModelNumber(); } } } /** * Listens to changes on the combo boxes Will update comboboxes dependent on * state of other comboboxes */ private class ComboboxListener implements ItemListener { @Override public void itemStateChanged(ItemEvent ie) { String selectedBrand = machineOverviewPanel.getBrandValue(); if (ie.getSource().equals(machineOverviewPanel.getTypeComboBox())) { //Type has changed updateBrands(); } else if (ie.getSource().equals(machineOverviewPanel.getBrandCombobox())) { //Brand has changed if (customValue.isCustomValue(selectedBrand)) { machineOverviewPanel.activateCustomBrandInput(); machineOverviewPanel.getBrandField().setText(""); updateModelNumbers(); } else { machineOverviewPanel.deactivateCustomBrandInput(); if (!selectedBrand.isEmpty()) { updateModelNumbers(); //Do not set selection on brand field pospone till model number is valid if (isModelNumberValid()) { machineOverviewPanel.getBrandField().setText(selectedBrand); } } } } else if (ie.getSource().equals(machineOverviewPanel.getModelNumberCombobox())) { //model number has changed String selectedModelNumber = machineOverviewPanel.getModelNumberValue(); if (customValue.isCustomValue(selectedModelNumber)) { machineOverviewPanel.activateCustomModelNumberInput(); machineOverviewPanel.getModelNumberField().setText(""); } else { machineOverviewPanel.deactivateCustomModelNumberInput(); if (selectedModelNumber!= null && !selectedModelNumber.isEmpty()) { machineOverviewPanel.getModelNumberField().setText(selectedModelNumber); machineOverviewPanel.getBrandField().setText(selectedBrand); } } } } } }