org.polymap.wbv.ui.WaldbesitzerPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.polymap.wbv.ui.WaldbesitzerPanel.java

Source

/*
 * Copyright (C) 2014-2016, Polymap GmbH. All rights reserved.
 * 
 * This is free software; you can redistribute it and/or modify it under the terms of
 * the GNU Lesser General Public License as published by the Free Software
 * Foundation; either version 3.0 of the License, or (at your option) any later
 * version.
 * 
 * This software 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.
 */
package org.polymap.wbv.ui;

import static org.eclipse.ui.forms.widgets.ExpandableComposite.TREE_NODE;
import static org.polymap.core.ui.FormDataFactory.on;
import static org.polymap.rhei.batik.app.SvgImageRegistryHelper.WHITE24;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import java.beans.PropertyChangeEvent;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;

import org.eclipse.ui.forms.widgets.ColumnLayoutData;
import org.eclipse.ui.forms.widgets.Section;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;

import org.polymap.model2.runtime.UnitOfWork;
import org.polymap.model2.runtime.ValueInitializer;
import org.polymap.model2.runtime.ConcurrentEntityModificationException;
import org.polymap.model2.runtime.EntityRuntimeContext.EntityStatus;

import org.polymap.core.security.SecurityContext;
import org.polymap.core.ui.ColumnLayoutFactory;
import org.polymap.core.ui.FormDataFactory;
import org.polymap.core.ui.FormLayoutFactory;
import org.polymap.core.ui.StatusDispatcher;

import org.polymap.rhei.batik.BatikPlugin;
import org.polymap.rhei.batik.Context;
import org.polymap.rhei.batik.PanelChangeEvent.EventType;
import org.polymap.rhei.batik.PanelIdentifier;
import org.polymap.rhei.batik.app.MultiStatusManager;
import org.polymap.rhei.batik.toolkit.ActionItem;
import org.polymap.rhei.batik.toolkit.IPanelSection;
import org.polymap.rhei.batik.toolkit.PriorityConstraint;
import org.polymap.rhei.batik.toolkit.Snackbar.Appearance;
import org.polymap.rhei.field.FormFieldEvent;
import org.polymap.rhei.field.IFormFieldListener;
import org.polymap.rhei.field.PicklistFormField;
import org.polymap.rhei.field.TextFormField;
import org.polymap.rhei.form.DefaultFormPage;
import org.polymap.rhei.form.IFormPageSite;
import org.polymap.rhei.form.batik.BatikFormContainer;

import org.polymap.wbv.WbvPlugin;
import org.polymap.wbv.model.Ereignis;
import org.polymap.wbv.model.Flurstueck;
import org.polymap.wbv.model.Kontakt;
import org.polymap.wbv.model.Waldbesitzer;
import org.polymap.wbv.model.Waldbesitzer.Waldeigentumsart;
import org.polymap.wbv.model.WbvRepository;
import org.polymap.wbv.ui.reports.EntityReport;

/**
 * Dieses Panel zeigt einen {@link Waldbesitzer} und erlaubt es dessen Properties zu
 * verndern. Die Entity wird als {@link Context} bergeben. Ist dieses bei
 * {@link EventType#ACTIVATED Aktivierung} null, dann wird eine neue Entity erzeugt.
 * 
 * @author <a href="http://www.polymap.de">Falko Brutigam</a>
 */
public class WaldbesitzerPanel extends WbvPanel {

    private static Log log = LogFactory.getLog(WaldbesitzerPanel.class);

    public static final PanelIdentifier ID = new PanelIdentifier("wbv", "waldbesitzer");

    /** Der aktuell selektierte {@link Waldbesitzer}. */
    private Context<Waldbesitzer> selected;

    private Context<UnitOfWork> uow;

    private Waldbesitzer wb;

    private BatikFormContainer wbFormContainer;

    private IFormFieldListener wbFormListener;

    private Map<BatikFormContainer, IFormFieldListener> kForms = new HashMap();

    private Map<BatikFormContainer, IFormFieldListener> eForms = new HashMap();

    private List<IFormFieldListener> eFormListeners = new ArrayList();

    private WbvMapViewer map;

    private Button submitBtn;

    private MultiStatusManager statusAdapter;

    private boolean ignoreDirty;

    private FlurstueckTableViewer fstViewer;

    @Override
    public void init() {
        super.init();
        site().setSize(550, 700, 700);

        assert !uow.isPresent();
        uow.set(WbvRepository.unitOfWork());

        if (!selected.isPresent()) {
            wb = uow.get().createEntity(Waldbesitzer.class, null, Waldbesitzer.defaults);
        } else {
            wb = uow.get().entity(selected.get());
        }
        // make sure that this panel (and subsequent panels) are working with
        // entity of our uow()
        selected.set(wb);

        //        getContext().addListener( this, ev -> 
        //                ev.getPanel() == WaldbesitzerPanel.this && 
        //                ev.getType() == EventType.LIFECYCLE /*&&
        //                ev.getPanel().site().panelStatus() == PanelStatus.FOCUSED*/ );
    }

    @Override
    public boolean beforeDispose() {
        if (statusAdapter != null) {
            if (!ignoreDirty && statusAdapter.highestSeverity() != Status.OK_STATUS) {
                tk().createSnackbar(Appearance.FadeIn, "Es gibt ungespeicherte nderungen",
                        new ActionItem(null).action.put(ev -> {
                            ignoreDirty = true;
                            getContext().closePanel(site().path());
                        }).text.put("Verwerfen"));
                return false;
            }
        }
        return true;
    }

    @Override
    public void dispose() {
        wb = null;

        // rollback uncommitted modifications left over after Exception on submit;
        // if commit was ok then this does not harm
        uow.get().rollback();
        uow.set(null);

        if (wbFormListener != null) {
            wbFormContainer.removeFieldListener(wbFormListener);
        }
        for (Map.Entry<BatikFormContainer, IFormFieldListener> entry : kForms.entrySet()) {
            entry.getKey().removeFieldListener(entry.getValue());
        }
        for (Map.Entry<BatikFormContainer, IFormFieldListener> entry : eForms.entrySet()) {
            entry.getKey().removeFieldListener(entry.getValue());
        }
        super.dispose();
    }

    protected void submit() {
        try {
            fstViewer.submit(new NullProgressMonitor());
            fstViewer.refresh(true);

            wbFormContainer.submit(null);
            for (BatikFormContainer formContainer : kForms.keySet()) {
                formContainer.submit(null);
            }
            for (BatikFormContainer formContainer : eForms.keySet()) {
                formContainer.submit(null);
            }
            uow.get().commit();

            if (wb.status() == EntityStatus.REMOVED) {
                ignoreDirty = true;
                getContext().closePanel(getSite().getPath());
            } else {
                tk().createSnackbar(Appearance.FadeIn, "nderungen wurden gespeichert");
            }
        } catch (ConcurrentEntityModificationException e) {
            // rollback and close panel so that user MUST try again
            uow.get().rollback();

            StatusDispatcher.handleError("Die nderungen knnen nicht korrekt gespeichert werden.",
                    new Exception("Ein anderer Nutzer hat diesen Waldbesitzer ebenfalls gendert."
                            + "<br/>ffnen Sie den Waldbesitzer erneut, um diese nderungen zu sehen."
                            + "<br/>Ihre aktuellen nderungen werden dabei verworfen."));
            getContext().closePanel(site().path());
        } catch (Exception e) {
            StatusDispatcher.handleError("nderungen konnten nicht korrekt gespeichert werden.", e);
        }
    }

    @Override
    public void createContents(Composite parent) {
        while (wb == null) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
            }
        }

        try {
            String title = StringUtils.abbreviate(wb.besitzer().anzeigename(), 20);
            site().title.set(title.length() > 1 ? title : "Neu");
        } catch (Exception e) {
            site().title.set("Kein Besitzer");
        }

        // submit FAB
        submitBtn = tk().createFab(null, BatikPlugin.images().svgImage("check.svg", WHITE24), SWT.TOP | SWT.RIGHT);
        submitBtn.setToolTipText("nderungen in die Datenbank bernehmen");
        submitBtn.setVisible(false);
        submitBtn.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent ev) {
                submit();
            }
        });
        statusAdapter = new MultiStatusManager() {
            private IStatus previousStatus;

            @Override
            protected void doUpdateUI(IStatus highestSeverity) {
                if (!highestSeverity.isOK() && (previousStatus == null || previousStatus.isOK())) {
                    log.info("severity: " + highestSeverity);
                    tk().createSnackbar(Appearance.FadeIn, highestSeverity.getMessage());
                }
                submitBtn.setVisible(highestSeverity.isOK() && highestSeverity != Status.OK_STATUS);
                submitBtn.setEnabled(highestSeverity.isOK() && highestSeverity != Status.OK_STATUS);
                previousStatus = highestSeverity;
            }
        };

        // Basisdaten
        IPanelSection basis = tk().createPanelSection(parent, "Basisdaten", IPanelSection.EXPANDABLE, SWT.BORDER);
        basis.addConstraint(WbvPlugin.MIN_COLUMN_WIDTH, new PriorityConstraint(100));

        wbFormContainer = new BatikFormContainer(new WaldbesitzerForm());
        wbFormContainer.createContents(basis);
        wbFormContainer.addFieldListener(wbFormListener = new EnableSubmitFormFieldListener(wbFormContainer));

        // Kontakte
        final IPanelSection besitzer = tk().createPanelSection(parent, "Besitzer/Kontakte", SWT.NONE);
        besitzer.addConstraint(WbvPlugin.MIN_COLUMN_WIDTH, new PriorityConstraint(1));
        //new NeighborhoodConstraint( basis.getControl(), Neighborhood.BOTTOM, 1 ) );
        besitzer.getBody().setLayout(ColumnLayoutFactory.defaults().spacing(10).columns(1, 1).create());

        int index = 0;
        for (final Kontakt kontakt : wb.kontakte()) {
            createKontaktSection(besitzer.getBody(), kontakt, index++ > 0);
        }

        // Ereignisse
        final IPanelSection ereignisse = tk().createPanelSection(parent, "Ereignisse", SWT.NONE);
        ereignisse.addConstraint(WbvPlugin.MIN_COLUMN_WIDTH, new PriorityConstraint(-10));
        ereignisse.getBody().setLayout(FormLayoutFactory.defaults().spacing(3).create());

        final Composite liste = tk().createComposite(ereignisse.getBody());
        liste.setLayoutData(FormDataFactory.filled().right(100, -30).clearBottom().create());
        liste.setLayout(ColumnLayoutFactory.defaults().spacing(0).columns(1, 1).create());

        // addBtn
        Button addBtn = tk().createButton(ereignisse.getBody(), "+", SWT.PUSH);
        addBtn.setToolTipText("Ein Ereignis hinzufgen");
        addBtn.setLayoutData(FormDataFactory.defaults().left(100, -30).right(100).top(0).create());
        addBtn.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent ev) {
                Ereignis neu = wb.ereignisse.createElement(new ValueInitializer<Ereignis>() {
                    @Override
                    public Ereignis initialize(Ereignis proto) throws Exception {
                        //proto.titel.set( "Neu" );
                        proto.angelegt.set(new Date());
                        proto.angelegtVon.set(SecurityContext.instance().getUser().getName());
                        proto.geaendert.set(new Date());
                        proto.geaendertVon.set(SecurityContext.instance().getUser().getName());
                        return proto;
                    }
                });
                Control child = liste.getChildren()[0];
                if (child instanceof Label) {
                    child.dispose();
                }
                Section newSection = createEreignisSection(liste, neu);
                newSection.setExpanded(true);
                getSite().layout(true);
                liste.layout(new Control[] { newSection }, SWT.ALL | SWT.CHANGED);

                statusAdapter.updateStatusOf(liste,
                        new Status(IStatus.OK, WbvPlugin.ID, "Ein Ereignis hinzugefgt"));
            }
        });
        //
        if (wb.ereignisse.isEmpty()) {
            tk().createLabel(liste, "Noch keine Ereignisse.");
        } else {
            List<Ereignis> reversed = new ArrayList(wb.ereignisse);
            Collections.reverse(reversed);
            for (final Ereignis ereignis : reversed) {
                createEreignisSection(liste, ereignis).setExpanded(false);
            }
        }

        // Flurstcke
        final IPanelSection flurstuecke = tk().createPanelSection(parent,
                "Flurstcke" + (revier.isPresent() ? ", Revier " + revier.get().name : ""));
        flurstuecke.addConstraint(WbvPlugin.MIN_COLUMN_WIDTH, new PriorityConstraint(0));
        createFlurstueckSection(flurstuecke.getBody());
    }

    private double gesamtFlaeche(Collection<Flurstueck> flurstuecke) {
        return flurstuecke.stream().map(f -> f.flaeche.get()).filter(fl -> fl != null).mapToDouble(d -> d).sum();
    }

    private double waldFlaeche(Collection<Flurstueck> flurstuecke) {
        return flurstuecke.stream().map(f -> f.flaecheWald.get()).filter(fl -> fl != null).mapToDouble(d -> d)
                .sum();
    }

    private String summary() {
        Collection<Flurstueck> flurstuecke = wb.flurstuecke(revier.get());
        Collection<Flurstueck> alle = wb.flurstuecke(null);
        return "Flurstcke: " + flurstuecke.size() + ""
                + (flurstuecke.size() != alle.size() ? " (" + alle.size() + ")" : "") + " -- " + "Gesamtflche: "
                + EntityReport.nf.format(gesamtFlaeche(flurstuecke)) + " ha -- " + "davon Wald: "
                + EntityReport.nf.format(waldFlaeche(flurstuecke)) + " ha";
    }

    protected void createFlurstueckSection(Composite parent) {
        parent.setLayout(FormLayoutFactory.defaults().spacing(0).create());

        // summary
        Label summary = tk().createFlowText(parent, summary());
        FormDataFactory.on(summary).fill().height(27).noTop().bottom(100);

        //
        fstViewer = new FlurstueckTableViewer(site(), parent) {
            @Override
            protected void fieldChange(PropertyChangeEvent ev) {
                super.fieldChange(ev);
                IStatus status = null;
                if (!isDirty()) {
                    status = Status.OK_STATUS;
                } else if (!isValid()) {
                    status = new Status(IStatus.ERROR, WbvPlugin.ID, "Eine Eingabe ist nicht korrekt.");
                } else {
                    status = new Status(IStatus.OK, WbvPlugin.ID, "Alle Eingaben sind in Ordnung");
                }
                statusAdapter.updateStatusOf(this, status);

                summary.setText(summary());
            }

            @Override
            public void submit(IProgressMonitor monitor) throws Exception {
                super.submit(monitor);
                statusAdapter.updateStatusOf(this, Status.OK_STATUS);
                summary.setText(summary());
            }
        };
        FormDataFactory.on(fstViewer.getTable()).fill().right(100, -33).bottom(summary, 5).height(250).width(300);

        // addBtn
        final Button addBtn = on(tk().createButton(parent, "+", SWT.PUSH)).left(100, -30).right(100).top(0)
                .control();
        addBtn.setToolTipText("Ein neues Flurstck anlegen");
        addBtn.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent ev) {
                Flurstueck newElm = wb.flurstuecke.createElement(Flurstueck.defaults);
                fstViewer.setInput(wb.flurstuecke(revier.get()));
                //viewer.reveal( new CompositesFeatureContentProvider.FeatureTableElement( newElm ) );
                fstViewer.selectElement(String.valueOf(newElm.hashCode()), true, true);
                //statusAdapter.updateStatusOf( this, new Status( IStatus.OK, WbvPlugin.ID, "Alle Eingaben sind korrekt." ) );
            }
        });
    }

    protected Section createKontaktSection(final Composite parent, final Kontakt kontakt, boolean allowRemove) {
        final Section section = tk().createSection(parent, kontakt.anzeigename(),
                TREE_NODE | Section.SHORT_TITLE_BAR | Section.FOCUS_TITLE);
        //section.setFont( JFaceResources.getFontRegistry().getBold( JFaceResources.DEFAULT_FONT ) );
        ((Composite) section.getClient()).setLayout(FormLayoutFactory.defaults().spacing(3).create());
        section.setExpanded(false);

        // KontaktForm
        KontaktForm form = new KontaktForm(kontakt, getSite());
        BatikFormContainer formContainer = new BatikFormContainer(form);
        formContainer.createContents((Composite) section.getClient());
        formContainer.getContents().setLayoutData(FormDataFactory.filled().right(100, -33).create());

        // FIXME this listener gets soon GCed
        // after porting KontaktForm to page the hackish hard reference is no longer there
        formContainer.addFieldListener(new IFormFieldListener() {
            public void fieldChange(FormFieldEvent ev) {
                if (ev.getEventCode() == VALUE_CHANGE && ev.getFieldName().equals(kontakt.name.info().getName())
                        && !section.isDisposed()) {
                    section.setText((String) ev.getNewFieldValue());
                    section.layout();
                }
            }
        });

        EnableSubmitFormFieldListener listener = new EnableSubmitFormFieldListener(formContainer);
        formContainer.addFieldListener(listener);
        //        form.addAdresseFieldListener( listener );
        kForms.put(formContainer, listener);

        // addBtn
        Button addBtn = tk().createButton((Composite) section.getClient(), "+", SWT.PUSH);
        addBtn.setToolTipText("Einen neuen Kontakt hinzufgen");
        addBtn.setLayoutData(FormDataFactory.defaults().left(100, -30).right(100).top(0).create());
        addBtn.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent ev) {
                Kontakt neu = wb.kontakte.createElement(Kontakt.defaults);
                Section newSection = createKontaktSection(parent, neu, false);
                newSection.setExpanded(true);
                getSite().layout(true);
                parent.layout(new Control[] { newSection }, SWT.ALL | SWT.CHANGED);

                statusAdapter.updateStatusOf(parent,
                        new Status(IStatus.OK, WbvPlugin.ID, "Ein Kontakt hinzugefgt"));
            }
        });

        // removeBtn
        if (allowRemove) {
            Button removeBtn = tk().createButton((Composite) section.getClient(), "-", SWT.PUSH);
            removeBtn.setToolTipText("Diesen Kontakt lschen");
            removeBtn.setLayoutData(FormDataFactory.defaults().left(100, -30).right(100).top(addBtn).create());
            removeBtn.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent ev) {
                    kontakt.geloescht.set(true);
                    section.dispose();
                    kForms.remove(formContainer);
                    getSite().layout(true);

                    statusAdapter.updateStatusOf(parent,
                            new Status(IStatus.OK, WbvPlugin.ID, "Ein Kontakt gelscht"));
                }
            });
        }
        return section;
    }

    protected Section createEreignisSection(final Composite parent, final Ereignis ereignis) {
        String titel = WbvPlugin.df.format(ereignis.geaendert.get()) + " -- " + ereignis.titel.get();
        final Section section = tk().createSection(parent, titel,
                TREE_NODE | Section.SHORT_TITLE_BAR | Section.FOCUS_TITLE);
        section.setToolTipText(ereignis.geaendertVon.get());
        //((Composite)section.getClient()).setLayout( new FillLayout() );

        // form
        final EreignisForm form = new EreignisForm(ereignis, getSite());
        BatikFormContainer formContainer = new BatikFormContainer(form);
        formContainer.createContents((Composite) section.getClient());
        //        form.createContents( tk.createComposite( (Composite)section.getClient() ) );

        IFormFieldListener l = new IFormFieldListener() {
            public void fieldChange(FormFieldEvent ev) {
                if (ev.getEventCode() == VALUE_CHANGE) {
                    if (ev.getFieldName().equals(ereignis.titel.info().getName()) && !section.isDisposed()) {
                        section.setText((String) ev.getNewFieldValue());
                        section.layout();
                    }

                    ereignis.geaendert.set(new Date());
                    ereignis.geaendertVon.set(SecurityContext.instance().getUser().getName());
                }
            }
        };
        formContainer.addFieldListener(l);
        eFormListeners.add(l);

        EnableSubmitFormFieldListener listener = new EnableSubmitFormFieldListener(formContainer);
        formContainer.addFieldListener(listener);
        eForms.put(formContainer, listener);

        return section;
    }

    /**
     * 
     */
    class WaldbesitzerForm extends DefaultFormPage {

        @Override
        public void createFormContents(IFormPageSite site) {
            Composite body = site.getPageBody();
            body.setLayout(ColumnLayoutFactory.defaults().spacing(3).margins(0, 0).columns(1, 1).create());

            assert wb != null;

            site.newFormField(new PropertyAdapter(wb.eigentumsArt)).label.put("Eigentumsart").field
                    .put(new PicklistFormField(Waldeigentumsart.map())).create();

            site.newFormField(new PropertyAdapter(wb.pchter)).create();

            site.newFormField(new PropertyAdapter(wb.bemerkung)).field.put(new TextFormField()).create()
                    .setLayoutData(new ColumnLayoutData(SWT.DEFAULT, 80));
        }
    }

    /**
     * 
     */
    class EnableSubmitFormFieldListener implements IFormFieldListener {

        private BatikFormContainer form;

        public EnableSubmitFormFieldListener(BatikFormContainer form) {
            this.form = form;
        }

        @Override
        public void fieldChange(FormFieldEvent ev) {
            if (ev.getEventCode() == IFormFieldListener.VALUE_CHANGE && wb != null) {
                //submitAction.setEnabled( form.isDirty() && form.isValid() );

                IStatus status = null;
                if (!form.isDirty()) {
                    status = Status.OK_STATUS;
                } else if (!form.isValid()) {
                    status = new Status(IStatus.ERROR, WbvPlugin.ID, "Eingaben sind nicht vollstndig/korrekt.");
                } else {
                    status = new Status(IStatus.OK, WbvPlugin.ID, "Alle Eingaben sind in Ordnung");
                }
                statusAdapter.updateStatusOf(EnableSubmitFormFieldListener.this, status);
                //getSite().setStatus( status );
            }
        }
    }
}