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

org.jsimpledb.vaadin.app.MainPanel Maven / Gradle / Ivy


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

package org.jsimpledb.vaadin.app;

import com.vaadin.data.Property;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Notification;
import com.vaadin.ui.VerticalLayout;

import org.dellroad.stuff.spring.RetryTransaction;
import org.jsimpledb.CopyState;
import org.jsimpledb.JClass;
import org.jsimpledb.JObject;
import org.jsimpledb.JSimpleDB;
import org.jsimpledb.JTransaction;
import org.jsimpledb.UntypedJObject;
import org.jsimpledb.core.DeletedObjectException;
import org.jsimpledb.core.ObjId;
import org.jsimpledb.core.ReferencedObjectException;
import org.jsimpledb.parse.ParseSession;
import org.jsimpledb.vaadin.JObjectChooser;
import org.jsimpledb.vaadin.JObjectContainer;
import org.jsimpledb.vaadin.SizedLabel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;

/**
 * Main GUI panel containing the object chooser, object table, buttons, and expresssion text area.
 */
@SuppressWarnings("serial")
public class MainPanel extends VerticalLayout {

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

    // Buttons
    private final Button editButton = new Button("Edit", new Button.ClickListener() {
        @Override
        public void buttonClick(Button.ClickEvent event) {
            final ObjId id = MainPanel.this.objectChooser.getObjId();
            if (id != null)
                MainPanel.this.editButtonClicked(id);
        }
    });
    private final Button newButton = new Button("New", new Button.ClickListener() {
        @Override
        public void buttonClick(Button.ClickEvent event) {
            MainPanel.this.newButtonClicked();
        }
    });
    private final Button deleteButton = new Button("Delete", new Button.ClickListener() {
        @Override
        public void buttonClick(Button.ClickEvent event) {
            final ObjId id = MainPanel.this.objectChooser.getObjId();
            if (id != null)
                MainPanel.this.deleteButtonClicked(id);
        }
    });
    private final Button upgradeButton = new Button("Upgrade", new Button.ClickListener() {
        @Override
        public void buttonClick(Button.ClickEvent event) {
            final ObjId id = MainPanel.this.objectChooser.getObjId();
            if (id != null)
                MainPanel.this.upgradeButtonClicked(id);
        }
    });
    private final Button refreshButton = new Button("Refresh", new Button.ClickListener() {
        @Override
        public void buttonClick(Button.ClickEvent event) {
            MainPanel.this.refreshButtonClicked();
        }
    });

    private final GUIConfig guiConfig;
    private final JSimpleDB jdb;
    private final ParseSession session;
    private final JObjectChooser objectChooser;

    public MainPanel(GUIConfig guiConfig) {
        this.guiConfig = guiConfig;
        this.jdb = this.guiConfig.getJSimpleDB();

        // Setup parse session
        this.session = new ParseSession(this.jdb) {
            @Override
            protected void reportException(Exception e) {
                Notification.show("Error: " + e.getMessage(), null, Notification.Type.ERROR_MESSAGE);
                if (MainPanel.this.guiConfig.isVerbose())
                    MainPanel.this.log.info("exception in parse session", e);
            }
        };
        this.session.setReadOnly(this.guiConfig.isReadOnly());
        this.session.setSchemaModel(this.jdb.getSchemaModel());
        this.session.setSchemaVersion(this.guiConfig.getSchemaVersion());
        this.session.setAllowNewSchema(this.guiConfig.isAllowNewSchema());

        // Register built-in functions
        this.session.registerStandardFunctions();

        // Register custom functions
        final Iterable> customFunctionClasses = this.guiConfig.getFunctionClasses();
        if (customFunctionClasses != null) {
            for (Class cl : customFunctionClasses) {
                try {
                    this.session.registerFunction(cl);
                } catch (IllegalArgumentException e) {
                    this.log.warn("failed to register function " + cl + ": " + e.getMessage());
                }
            }
        }

        // Setup object chooser
        this.objectChooser = new JObjectChooser(this.session, null, true);

        // Listen to object selections
        this.objectChooser.addValueChangeListener(new Property.ValueChangeListener() {
            @Override
            public void valueChange(Property.ValueChangeEvent event) {
                MainPanel.this.selectObject(MainPanel.this.objectChooser.getObjId());
            }
        });
    }

    @Override
    public void attach() {
        super.attach();
        this.setMargin(false);
        this.setSpacing(true);
        this.setHeight("100%");

        // Layout top split panel
        this.addComponent(this.objectChooser.getObjectPanel());

        // Add row with schema version and buttons
        final HorizontalLayout buttonRow = new HorizontalLayout();
        buttonRow.setSpacing(true);
        buttonRow.setWidth("100%");
        final SizedLabel versionLabel = new SizedLabel("Schema Version " + this.jdb.getActualVersion());
        buttonRow.addComponent(versionLabel);
        buttonRow.setComponentAlignment(versionLabel, Alignment.MIDDLE_LEFT);
        final Label spacer1 = new Label();
        buttonRow.addComponent(spacer1);
        buttonRow.setExpandRatio(spacer1, 1.0f);
        buttonRow.addComponent(this.editButton);
        buttonRow.addComponent(this.newButton);
        buttonRow.addComponent(this.deleteButton);
        buttonRow.addComponent(this.upgradeButton);
        buttonRow.addComponent(this.refreshButton);
        this.addComponent(buttonRow);
        this.setComponentAlignment(buttonRow, Alignment.TOP_RIGHT);

        // Add show form
        this.addComponent(this.objectChooser.getShowForm());

        // Add space filler
        final Label spacer2 = new Label();
        this.addComponent(spacer2);
        this.setExpandRatio(spacer2, 1.0f);

        // Populate table
        //this.selectType(Object.class, true);
    }

// GUI Updates

    // Invoked when an object is clicked on
    protected void selectObject(ObjId id) {

        // New button
        this.newButton.setEnabled(this.objectChooser.getJClass() != null);

        // Update buttons
        if (id == null) {
            this.editButton.setEnabled(false);
            this.deleteButton.setEnabled(false);
            this.upgradeButton.setEnabled(false);
        } else {
            this.editButton.setEnabled(true);
            this.deleteButton.setEnabled(true);
            this.upgradeButton.setEnabled(this.canUpgrade(id));
        }
    }

// Refresh

    private void refreshButtonClicked() {
        this.objectChooser.getJObjectContainer().reload();
    }

// Edit

    private void editButtonClicked(ObjId id) {
        this.log.info("editing object " + id);

        // Copy object
        final JObject jobj = this.doCopyForEdit(id);
        if (jobj == null) {
            Notification.show("Object " + id + " no longer exists", null, Notification.Type.WARNING_MESSAGE);
            return;
        }

        // Ensure object type is known
        if (jobj instanceof UntypedJObject) {
            Notification.show("Can't edit object " + id + " having unknown object type",
              "Storage ID " + id.getStorageId() + " not defined in the current schema version",
              Notification.Type.WARNING_MESSAGE);
            return;
        }

        // Build title component from reference label
        Object refLabel = MainPanel.this.objectChooser.getJObjectContainer().getContainerProperty(
          id, JObjectContainer.REFERENCE_LABEL_PROPERTY).getValue();
        final Component titleComponent = refLabel instanceof Component ? (Component)refLabel : new Label("" + refLabel);

        // Open window
        final JObjectEditorWindow editor = new JObjectEditorWindow(this.getUI(),
          this.session, this.jdb.getJClass(id), jobj, titleComponent);
        editor.setReloadContainerAfterCommit(this.objectChooser.getJObjectContainer());
        editor.show();
    }

    @RetryTransaction
    @Transactional("jsimpledbGuiTransactionManager")
    private JObject doCopyForEdit(ObjId id) {

        // Find object
        final JTransaction jtx = JTransaction.getCurrent();
        final JObject jobj = jtx.get(id);
        if (!jobj.exists())
            return null;

        // Copy out object and its dependencies
        return this.objectChooser.getJObjectContainer().copyWithRelated(jobj, jtx.getSnapshotTransaction(), new CopyState());
    }

// New

    private void newButtonClicked() {
        final JClass jclass = this.objectChooser.getJClass();
        if (jclass == null) {
            Notification.show("Can't create object having unknown type",
              "Please select an object type first", Notification.Type.WARNING_MESSAGE);
            return;
        }
        this.log.info("creating new object of type " + jclass.getType().getName());
        new JObjectEditorWindow(this.getUI(), this.session, jclass).show();
    }

// Delete

    private void deleteButtonClicked(ObjId id) {
        this.log.info("deleting object " + id);
        final boolean deleted;
        try {
            deleted = this.doDelete(id);
        } catch (DeletedObjectException e) {
            Notification.show("Object " + e.getId() + " no longer exists", null, Notification.Type.WARNING_MESSAGE);
            return;
        } catch (ReferencedObjectException e) {
            Notification.show("Object " + id + " is referenced by " + e.getReferrer(),
              e.getMessage(), Notification.Type.ERROR_MESSAGE);
            return;
        }
        if (deleted)
            Notification.show("Removed object " + id);
        else
            Notification.show("Could not delete object " + id, null, Notification.Type.WARNING_MESSAGE);
        this.selectObject(null);
    }

    @RetryTransaction
    @Transactional("jsimpledbGuiTransactionManager")
    private boolean doDelete(ObjId id) {
        final boolean deleted = JTransaction.getCurrent().get(id).delete();
        if (deleted)
            this.objectChooser.getJObjectContainer().reloadAfterCommit();
        return deleted;
    }

// Upgrade

    private void upgradeButtonClicked(ObjId id) {
        final int newVersion = this.jdb.getActualVersion();
        this.log.info("upgrading object " + id + " to schema version " + newVersion);
        final int oldVersion = this.doUpgrade(id);
        switch (oldVersion) {
        case -1:
            Notification.show("Object " + id + " no longer exists", null, Notification.Type.WARNING_MESSAGE);
            break;
        case 0:
            Notification.show("Object " + id + " was already upgraded", null, Notification.Type.WARNING_MESSAGE);
            break;
        default:
            Notification.show("Upgraded object " + id + " version from " + oldVersion + " to " + newVersion);
            break;
        }
    }

    @RetryTransaction
    @Transactional("jsimpledbGuiTransactionManager")
    private int doUpgrade(ObjId id) {
        final JObject jobj = JTransaction.getCurrent().get(id);
        final int oldVersion;
        try {
            oldVersion = jobj.getSchemaVersion();
        } catch (DeletedObjectException e) {
            return -1;
        }
        final boolean upgraded = jobj.upgrade();
        if (upgraded)
            this.objectChooser.getJObjectContainer().reloadAfterCommit();
        return upgraded ? oldVersion : 0;
    }

    @RetryTransaction
    @Transactional("jsimpledbGuiTransactionManager")
    private boolean canUpgrade(ObjId id) {
        final JObject jobj = JTransaction.getCurrent().get(id);
        return jobj.exists() && jobj.getSchemaVersion() != this.jdb.getActualVersion();
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy