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

org.jsimpledb.vaadin.JObjectChooser Maven / Gradle / Ivy

The newest version!

/*
 * Copyright (C) 2015 Archie L. Cobbs. All rights reserved.
 */

package org.jsimpledb.vaadin;

import com.google.common.base.Preconditions;
import com.vaadin.data.Property;
import com.vaadin.server.Sizeable;
import com.vaadin.shared.ui.combobox.FilteringMode;
import com.vaadin.ui.AbstractSelect;
import com.vaadin.ui.Button;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.TextArea;

import java.util.Collections;
import java.util.HashSet;

import org.jsimpledb.JClass;
import org.jsimpledb.JObject;
import org.jsimpledb.JSimpleDB;
import org.jsimpledb.core.ObjId;
import org.jsimpledb.parse.ParseSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Contains widgets that allow choosing an object reference. Supports searching via Java expression and filtering.
 */
@SuppressWarnings({ "serial", "deprecation" })
public class JObjectChooser implements Property.ValueChangeNotifier {

    protected final Logger log = LoggerFactory.getLogger(this.getClass());

    private final Button showButton = new Button("Show", e -> this.showButtonClicked());
    private final CheckBox reverseCheckBox = new CheckBox("Reverse sort");

    private final JSimpleDB jdb;
    private final ParseSession session;
    private final boolean showFields;
    private final TypeContainer typeContainer;
    private final ExprQueryJObjectContainer objectContainer;
    private final HashSet listeners = new HashSet<>();

    private final HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
    private final FormLayout showForm = new FormLayout();
    private final TypeTable typeTable;
    private final TextArea exprField = new TextArea();
    private final ComboBox sortComboBox = new ComboBox();

    private JObjectTable objectTable;
    private SortKeyContainer sortKeyContainer;

    /**
     * Constructor.
     *
     * @param session session for evaluating expressions
     * @param type type restriction, or null for none
     * @param showFields true to show all object fields, false for just reference label
     */
    public JObjectChooser(ParseSession session, Class type, boolean showFields) {
        Preconditions.checkArgument(session != null, "null session");
        this.jdb = session.getJSimpleDB();
        this.session = session;
        this.showFields = showFields;
        this.typeContainer = new TypeContainer(this.jdb, type);
        this.typeTable = new TypeTable(this.typeContainer);
        this.objectContainer = new ExprQueryJObjectContainer(this.session, this.typeContainer.getRootType());

        // Build object panel
        this.splitPanel.setWidth("100%");
        this.splitPanel.setHeight(300, Sizeable.Unit.PIXELS);
        this.splitPanel.setFirstComponent(this.typeTable);
        this.splitPanel.setSecondComponent(new SizedLabel(" "));
        this.splitPanel.setSplitPosition(20);

        // Build show form
        this.showForm.setMargin(false);
        this.showForm.setWidth("100%");

        // Add "Sort by" combo box and "Reverse sort" check box
        final HorizontalLayout sortLayout = new HorizontalLayout();
        sortLayout.setCaption("Sort by:");
        sortLayout.setSpacing(true);
        sortLayout.setMargin(false);
        this.sortComboBox.setNullSelectionAllowed(false);
        this.sortComboBox.setNewItemsAllowed(false);
        this.sortComboBox.setTextInputAllowed(false);
        this.sortComboBox.setFilteringMode(FilteringMode.OFF);
        this.sortComboBox.setItemCaptionMode(AbstractSelect.ItemCaptionMode.PROPERTY);
        this.sortComboBox.setItemCaptionPropertyId(SortKeyContainer.DESCRIPTION_PROPERTY);
        this.sortComboBox.setImmediate(true);
        this.reverseCheckBox.setImmediate(true);
        sortLayout.addComponent(this.sortComboBox);
        sortLayout.addComponent(this.reverseCheckBox);
        this.showForm.addComponent(sortLayout);

        // Add show/expression field
        this.exprField.setCaption("Expression:");
        this.exprField.setRows(6);
        this.exprField.setWidth("100%");
        this.exprField.addStyleName("jsdb-fixed-width");
        this.showForm.addComponent(this.exprField);
        this.showForm.addComponent(this.showButton);

        // Listen to type selections
        this.typeTable.addValueChangeListener(e -> this.selectType((Class)e.getProperty().getValue(), false));

        // Listen to "Sort by" and "Reverse sort" selections
        final Property.ValueChangeListener sortListener = e -> this.selectSort();
        this.sortComboBox.addValueChangeListener(sortListener);
        this.reverseCheckBox.addValueChangeListener(sortListener);

        // Populate table
        this.selectType(type != null ? type : this.typeContainer.getRootType(), true);
    }

    /**
     * Get the {@link ParseSession} used by this instance.
     *
     * @return associated {@link ParseSession}
     */
    public ParseSession getParseSession() {
        return this.session;
    }

    /**
     * Get the object container for this instance.
     *
     * @return associated object container
     */
    public ExprQueryJObjectContainer getJObjectContainer() {
        return this.objectContainer;
    }

    /**
     * Get the current type restriction, if any.
     *
     * @return current type restriction
     */
    public Class getType() {
        return this.objectContainer.getType();
    }

    /**
     * Get the type table.
     *
     * @return type selection table
     */
    public TypeTable getTypeTable() {
        return this.typeTable;
    }

    /**
     * Get the component containing the type chooser and object panel.
     *
     * @return object panel
     */
    public HorizontalSplitPanel getObjectPanel() {
        return this.splitPanel;
    }

    /**
     * Get the currently selected object, if any.
     *
     * @return selected object ID, or null if none
     */
    public ObjId getObjId() {
        return this.objectTable != null ? (ObjId)this.objectTable.getValue() : null;
    }

    /**
     * Get the form with the sort chooser and expression text area.
     *
     * @return expression form
     */
    public FormLayout getShowForm() {
        return this.showForm;
    }

    /**
     * Get the {@link JClass} corresponding to the currently selected type, if any.
     *
     * @return selected type object type
     */
    public JClass getJClass() {
        final Class type = this.objectContainer.getType();
        if (type == null)
            return null;
        try {
            return this.jdb.getJClass(type);
        } catch (IllegalArgumentException e) {
            return null;
        }
    }

// Property.ValueChangeNotifier

    @Override
    public void addValueChangeListener(Property.ValueChangeListener listener) {
        Preconditions.checkArgument(listener != null, "null listener");
        this.listeners.add(listener);
        if (this.objectTable != null)
            this.objectTable.addValueChangeListener(listener);
    }

    @Override
    public void removeValueChangeListener(Property.ValueChangeListener listener) {
        if (listener == null)
            return;
        this.listeners.remove(listener);
        if (this.objectTable != null)
            this.objectTable.removeValueChangeListener(listener);
    }

    @Override
    public void addListener(Property.ValueChangeListener listener) {
        this.addValueChangeListener(listener);
    }

    @Override
    public void removeListener(Property.ValueChangeListener listener) {
        this.removeValueChangeListener(listener);
    }

// GUI Updates

    // Invoked when a type is clicked on
    private void selectType(Class type, boolean force) {

        // Anything to do?
        if (type == null)
            return;
        if (!this.setNewType(!type.equals(Object.class) ? type : null, force))
            return;

        // Get previous sort key
        final SortKeyContainer.SortKey previousSort = (SortKeyContainer.SortKey)this.sortComboBox.getValue();

        // Rebuild the sort combobox
        final JClass jclass = this.getJClass();
        this.sortKeyContainer = jclass != null ?
          new SortKeyContainer(this.jdb, jclass) : new SortKeyContainer(this.jdb, this.objectContainer.getType());
        this.sortComboBox.setContainerDataSource(this.sortKeyContainer);

        // Try to restore previous sort, otherwise default to sorting by object ID
        SortKeyContainer.SortKey newSort = this.sortKeyContainer.getJavaObject(previousSort);
        if (newSort == null)
            newSort = this.sortKeyContainer.new ObjectIdSortKey();
        this.sortComboBox.setValue(newSort);
        this.selectSort();
        this.showObjects();
    }

    // Update sort based on current selection
    private void selectSort() {
        this.selectSort((SortKeyContainer.SortKey)this.sortComboBox.getValue(), this.reverseCheckBox.getValue());
    }

    // Invoked when a sort choice is made
    private void selectSort(SortKeyContainer.SortKey sortKey, boolean reverse) {
        if (sortKey == null)
            return;
        this.exprField.setValue(sortKey.getExpression(this.session, null, reverse));          // TODO: starting point
        this.showObjects();
    }

    // Invoked when "Show" button is clicked
    private void showButtonClicked() {
        this.setNewType(null, false);
        this.typeTable.setValue(null);
        this.showObjects();
    }

    private void showObjects() {
        this.objectContainer.setContentExpression(this.exprField.getValue());
    }

    private boolean setNewType(Class type, boolean force) {
        final Class currentType = this.objectContainer.getType();
        if (!force && (currentType != null ? currentType.equals(type) : type == null))
            return false;
        if (this.objectTable != null) {
            for (Property.ValueChangeListener listener : this.listeners)
                this.objectTable.removeValueChangeListener(listener);
            this.splitPanel.removeComponent(this.objectTable);
        }
        this.objectContainer.setType(type);
        this.objectContainer.load(Collections.emptySet());
        this.objectTable = new JObjectTable(this.jdb, this.objectContainer, this.session, this.showFields);
        for (Property.ValueChangeListener listener : this.listeners)
            this.objectTable.addValueChangeListener(listener);
        this.splitPanel.setSecondComponent(this.objectTable);
        this.objectTable.setValue(null);
        final Property.ValueChangeEvent event = new Property.ValueChangeEvent() {
            @Override
            public Property getProperty() {
                return JObjectChooser.this.objectTable;
            }
        };
        for (Property.ValueChangeListener listener : new HashSet(this.listeners)) {
            try {
                listener.valueChange(event);
            } catch (Exception e) {
                this.log.error("exception thrown by value change listener", e);
            }
        }
        return true;
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy