se.streamsource.streamflow.client.ui.workspace.cases.general.CaseGeneralView.java Source code

Java tutorial

Introduction

Here is the source code for se.streamsource.streamflow.client.ui.workspace.cases.general.CaseGeneralView.java

Source

/**
 *
 * Copyright 2009-2014 Jayway Products AB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package se.streamsource.streamflow.client.ui.workspace.cases.general;

import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.swing.EventComboBoxModel;
import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.factories.Borders;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.Sizes;
import org.jdesktop.application.Action;
import org.jdesktop.application.ApplicationContext;
import org.jdesktop.application.Task;
import org.jdesktop.swingx.JXDatePicker;
import org.jdesktop.swingx.calendar.DatePickerFormatter;
import org.jdesktop.swingx.color.ColorUtil;
import org.qi4j.api.constraint.ConstraintViolationException;
import org.qi4j.api.injection.scope.Service;
import org.qi4j.api.injection.scope.Structure;
import org.qi4j.api.injection.scope.Uses;
import org.qi4j.api.object.ObjectBuilderFactory;
import org.qi4j.api.property.Property;
import org.qi4j.api.structure.Module;
import org.qi4j.library.constraints.annotation.MaxLength;
import se.streamsource.dci.value.link.LinkValue;
import se.streamsource.streamflow.api.administration.priority.PriorityValue;
import se.streamsource.streamflow.client.MacOsUIWrapper;
import se.streamsource.streamflow.client.StreamflowResources;
import se.streamsource.streamflow.client.ui.workspace.WorkspaceResources;
import se.streamsource.streamflow.client.ui.workspace.cases.caselog.CaseLogView;
import se.streamsource.streamflow.client.ui.workspace.cases.general.forms.PossibleFormsView;
import se.streamsource.streamflow.client.ui.workspace.cases.note.CaseNoteView;
import se.streamsource.streamflow.client.util.ActionBinder;
import se.streamsource.streamflow.client.util.CommandTask;
import se.streamsource.streamflow.client.util.RefreshComponents;
import se.streamsource.streamflow.client.util.RefreshWhenShowing;
import se.streamsource.streamflow.client.util.Refreshable;
import se.streamsource.streamflow.client.util.StreamflowButton;
import se.streamsource.streamflow.client.util.UncaughtExceptionHandler;
import se.streamsource.streamflow.client.util.ValueBinder;
import se.streamsource.streamflow.client.util.dialog.DialogService;
import se.streamsource.streamflow.client.util.dialog.SelectLinkDialog;
import se.streamsource.streamflow.client.util.i18n;
import se.streamsource.streamflow.infrastructure.event.domain.TransactionDomainEvents;
import se.streamsource.streamflow.infrastructure.event.domain.source.TransactionListener;
import se.streamsource.streamflow.util.Strings;

import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.LayoutFocusTraversalPolicy;
import javax.swing.SwingConstants;
import javax.swing.text.DefaultFormatterFactory;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.geom.Ellipse2D;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

import static java.awt.RenderingHints.*;
import static java.lang.Integer.*;
import static se.streamsource.streamflow.client.util.BindingFormBuilder.Fields.*;
import static se.streamsource.streamflow.client.util.i18n.*;
import static se.streamsource.streamflow.infrastructure.event.domain.source.helper.Events.*;

/**
 * JAVADOC
 */
public class CaseGeneralView extends JScrollPane implements TransactionListener, Refreshable {
    @Service
    private DialogService dialogs;

    @Service
    private UncaughtExceptionHandler exception;

    @Structure
    Module module;

    private ActionBinder actionBinder;
    private ValueBinder valueBinder;

    private CaseGeneralModel model;

    private JTextField descriptionField;
    private JXDatePicker dueOnField;
    private JPanel leftPane;
    private CaseLabelsView labels;
    private PossibleFormsView forms;
    private RemovableLabel selectedCaseType = new RemovableLabel();
    private StreamflowButton caseTypeButton;
    private StreamflowButton labelButton;
    private final ApplicationContext appContext;
    private CaseNoteView caseNotes;
    private JComboBox casePriority;

    public CaseGeneralView(@Service ApplicationContext appContext, @Uses CaseGeneralModel generalModel,
            @Uses CaseLogView caseLogView, @Structure Module module) {
        this.appContext = appContext;
        this.model = generalModel;
        RefreshComponents refreshComponents = new RefreshComponents();
        model.addObserver(refreshComponents);
        ObjectBuilderFactory obf = module.objectBuilderFactory();
        this.labels = obf.newObjectBuilder(CaseLabelsView.class).use(generalModel.newLabelsModel()).newInstance();
        this.caseNotes = obf.newObjectBuilder(CaseNoteView.class).use(generalModel.newCaseNoteModel())
                .newInstance();

        RefreshComponents refreshLabelComponents = new RefreshComponents();
        labels.getModel().addObserver(refreshLabelComponents);

        this.forms = obf.newObjectBuilder(PossibleFormsView.class).use(generalModel.newPossibleFormsModel())
                .newInstance();
        refreshComponents.visibleOn("changedescription", forms);
        this.setBorder(BorderFactory.createEmptyBorder());
        getVerticalScrollBar().setUnitIncrement(30);

        setActionMap(appContext.getActionMap(this));
        ActionMap am = getActionMap();
        MacOsUIWrapper.convertAccelerators(appContext.getActionMap(CaseGeneralView.class, this));

        actionBinder = obf.newObjectBuilder(ActionBinder.class).use(am).newInstance();
        valueBinder = obf.newObject(ValueBinder.class);
        actionBinder.setResourceMap(appContext.getResourceMap(getClass()));

        // Layout and form for the right panel
        FormLayout leftLayout = new FormLayout("70dlu, 2dlu, 200:grow, 70dlu",
                "pref, pref, pref, pref, 20dlu, pref, pref, pref, pref");

        leftPane = new JPanel(leftLayout);
        leftPane.setFocusable(false);
        DefaultFormBuilder leftBuilder = new DefaultFormBuilder(leftLayout, leftPane);
        leftBuilder.setBorder(Borders.createEmptyBorder(Sizes.DLUY2, Sizes.DLUX2, Sizes.DLUY2, Sizes.DLUX11));

        selectedCaseType.getLabel().setFont(selectedCaseType.getLabel().getFont().deriveFont(Font.BOLD));
        selectedCaseType.getButton().addActionListener(am.get("removeCaseType"));
        valueBinder.bind("caseType", selectedCaseType);

        // Description & DueDate
        leftBuilder.setExtent(3, 1);
        JLabel descriptionLabel = leftBuilder.getComponentFactory()
                .createLabel(i18n.text(WorkspaceResources.description_label));
        leftBuilder.add(descriptionLabel);
        descriptionLabel.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
        leftBuilder.nextColumn(3);
        JLabel dueOnLabel = leftBuilder.append(i18n.text(WorkspaceResources.due_on_label));
        dueOnLabel.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));

        leftBuilder.nextLine();
        leftBuilder.setExtent(3, 1);
        JPanel descPanel = new JPanel(new BorderLayout());
        descPanel.add(valueBinder.bind("description",
                actionBinder.bind("changeDescription", descriptionField = (JTextField) TEXTFIELD.newField())),
                BorderLayout.WEST);
        leftBuilder.add(descPanel);
        descriptionField.setName("txtCaseDescription");
        leftBuilder.add(
                valueBinder.bind("dueOn",
                        actionBinder.bind("changeDueOn", dueOnField = (JXDatePicker) DATEPICKER.newField())),
                new CellConstraints(4, 2, 1, 1, CellConstraints.LEFT, CellConstraints.BOTTOM,
                        new Insets(4, 0, 0, 0)));
        leftBuilder.nextLine();
        descriptionLabel.setLabelFor(descriptionField);
        dueOnLabel.setLabelFor(dueOnField);
        refreshComponents.enabledOn("changedescription", descriptionField);
        refreshComponents.enabledOn("changedueon", dueOnField);

        // Select case type
        javax.swing.Action caseTypeAction = am.get("changeCaseType");
        caseTypeButton = new StreamflowButton(caseTypeAction);
        caseTypeButton.registerKeyboardAction(caseTypeAction,
                (KeyStroke) caseTypeAction.getValue(javax.swing.Action.ACCELERATOR_KEY),
                JComponent.WHEN_IN_FOCUSED_WINDOW);
        caseTypeButton.setHorizontalAlignment(SwingConstants.LEFT);
        refreshComponents.enabledOn("casetype", caseTypeButton, selectedCaseType);

        leftBuilder.add(caseTypeButton,
                new CellConstraints(1, 3, 1, 1, CellConstraints.FILL, CellConstraints.TOP, new Insets(2, 0, 5, 0)));
        leftBuilder.add(selectedCaseType, new CellConstraints(3, 3, 1, 1, CellConstraints.LEFT,
                CellConstraints.BOTTOM, new Insets(5, 5, 0, 0)));

        JLabel priorityLabel = leftBuilder.getComponentFactory()
                .createLabel(i18n.text(WorkspaceResources.priority_label));
        priorityLabel.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));

        leftBuilder.add(priorityLabel, new CellConstraints(4, 3, 1, 1, CellConstraints.FILL, CellConstraints.BOTTOM,
                new Insets(4, 0, 0, 0)));

        leftBuilder.nextLine();

        // Select labels
        javax.swing.Action labelAction = labels.getActionMap().get("addLabel");
        labelButton = new StreamflowButton(labelAction);
        // NotificationGlassPane.registerButton(labelButton);
        labelButton.registerKeyboardAction(labelAction,
                (KeyStroke) labelAction.getValue(javax.swing.Action.ACCELERATOR_KEY),
                JComponent.WHEN_IN_FOCUSED_WINDOW);

        labelButton.setHorizontalAlignment(SwingConstants.LEFT);
        labels.setButtonRelation(labelButton);
        refreshLabelComponents.enabledOn("addlabel", labelButton, labels);

        leftBuilder.add(labelButton,
                new CellConstraints(1, 4, 1, 1, CellConstraints.FILL, CellConstraints.TOP, new Insets(5, 0, 0, 0)));

        labels.setPreferredSize(new Dimension(500, 50));
        leftBuilder.add(labels,
                new CellConstraints(3, 4, 1, 1, CellConstraints.LEFT, CellConstraints.TOP, new Insets(5, 0, 0, 0)));

        JPanel prioPanel = new JPanel(new BorderLayout());
        prioPanel.add(valueBinder.bind("priority",
                actionBinder.bind("changePriority", casePriority = (JComboBox) COMBOBOX.newField())));
        leftBuilder.add(prioPanel, new CellConstraints(4, 4, 1, 1, CellConstraints.FILL, CellConstraints.TOP,

                new Insets(2, 0, 0, 0)));

        priorityLabel.setLabelFor(casePriority);
        refreshComponents.visibleOn("changepriority", casePriority, priorityLabel);
        refreshComponents.enabledOn("changepriority", casePriority, priorityLabel);
        casePriority.setRenderer(new DefaultListCellRenderer() {
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
                    boolean cellHasFocus) {

                final PriorityValue itemValue = (PriorityValue) value;
                String val = itemValue == null ? "" : itemValue.text().get();

                JPanel panel = new JPanel();
                panel.setOpaque(false);
                FormLayout layout = new FormLayout("10dlu, 60dlu:grow", "pref");
                DefaultFormBuilder formBuilder = new DefaultFormBuilder(layout, panel);

                panel.setBorder(BorderFactory.createEmptyBorder(2, 0, 1, 0));
                JLabel label = new JLabel() {
                    @Override
                    protected void paintComponent(Graphics g) {
                        Color color = getBackground();
                        if (itemValue != null) {
                            if (!Strings.empty(itemValue.color().get()))
                                color = new Color(parseInt(itemValue.color().get()));
                            else
                                color = Color.BLACK;
                        }
                        final Color FILL_COLOR = ColorUtil.removeAlpha(color);

                        Graphics2D g2 = (Graphics2D) g.create();

                        try {
                            g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
                            g2.setColor(Color.LIGHT_GRAY);
                            final int DIAM = Math.min(getWidth(), getHeight());
                            final int inset = 3;
                            g2.fill(new Ellipse2D.Float(inset, inset, DIAM - 2 * inset, DIAM - 2 * inset));
                            g2.setColor(FILL_COLOR);
                            final int border = 1;
                            g2.fill(new Ellipse2D.Float(inset + border, inset + border,
                                    DIAM - 2 * inset - 2 * border, DIAM - 2 * inset - 2 * border));
                        } finally {
                            g2.dispose();
                        }
                    }
                };
                label.setPreferredSize(new Dimension(10, 10));
                formBuilder.add((Strings.empty(val) || "-".equals(val)) ? new JLabel() : label, new CellConstraints(
                        1, 1, 1, 1, CellConstraints.FILL, CellConstraints.FILL, new Insets(0, 0, 0, 0)));
                JLabel text = new JLabel(val);
                formBuilder.add(text, new CellConstraints(2, 1, 1, 1, CellConstraints.LEFT, CellConstraints.FILL,
                        new Insets(0, 0, 0, 0)));

                return panel;
            }
        });
        leftBuilder.nextLine();

        leftBuilder.add(caseNotes,
                new CellConstraints(1, 6, 4, 1, CellConstraints.FILL, CellConstraints.TOP, new Insets(0, 2, 5, 0)));

        // Forms
        JLabel formsLabel = new JLabel(i18n.text(WorkspaceResources.forms_label));
        refreshComponents.visibleOn("changedescription", formsLabel);
        leftBuilder.add(formsLabel,
                new CellConstraints(1, 7, 1, 1, CellConstraints.LEFT, CellConstraints.TOP, new Insets(5, 0, 0, 0)));
        leftBuilder.nextLine();

        JPanel formsPanel = new JPanel(new BorderLayout());
        formsPanel.add(forms, BorderLayout.WEST);
        leftBuilder.add(formsPanel, new CellConstraints(1, 8, 3, 1, CellConstraints.FILL, CellConstraints.FILL,
                new Insets(5, 0, 0, 0)));

        // Limit pickable dates to future
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        dueOnField.getMonthView().setLowerBound(calendar.getTime());

        final DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT);
        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
        dueOnField.getEditor().setFormatterFactory(
                new DefaultFormatterFactory(new DatePickerFormatter(new DateFormat[] { dateFormat }) {
                    @Override
                    public Object stringToValue(String text) throws ParseException {
                        Object result;
                        try {
                            result = super.stringToValue(text);
                        } catch (ParseException pe) {
                            dialogs.showMessageDialog(dueOnField,
                                    text(WorkspaceResources.wrong_format_msg) + " "
                                            + ((SimpleDateFormat) dateFormat).toPattern(),
                                    text(WorkspaceResources.wrong_format_title));
                            throw pe;
                        }
                        return result;
                    }
                }));

        // Main panel that contains both left and right pane
        JPanel formsContainer = new JPanel();
        formsContainer.setLayout(new GridLayout(1, 2));
        formsContainer.setBorder(Borders.createEmptyBorder("2dlu, 2dlu, 2dlu, 2dlu"));
        formsContainer.add(leftPane);
        formsContainer.add(caseLogView);

        setViewportView(formsContainer);

        setFocusTraversalPolicy(new LayoutFocusTraversalPolicy());
        setFocusCycleRoot(true);
        setFocusable(true);

        new RefreshWhenShowing(this, this);
    }

    public void refresh() {
        model.refresh();

        valueBinder.update(model.getGeneral());
        selectedCaseType.setClickLink(model.getGeneral().caseType().get());

        if (model.getCommandEnabled("changepriority")) {
            EventComboBoxModel comboBoxModel = model.getCasePriorities();
            casePriority.setModel(comboBoxModel);
            LinkValue selectPriority = model.getGeneral().priority().get();
            if (selectPriority != null) {
                // omit first element since priority is always null in the first element
                for (int i = 0; i < comboBoxModel.getSize(); i++) {
                    PriorityValue priorityValue = ((PriorityValue) comboBoxModel.getElementAt(i));
                    if (priorityValue == null)
                        continue;
                    if (priorityValue.id().get().equals(selectPriority.id().get())) {
                        casePriority.setSelectedItem(comboBoxModel.getElementAt(i));
                        casePriority.setToolTipText(selectPriority.text().get());
                    }
                }
            }
        }
    }

    @Action(block = Task.BlockingScope.COMPONENT)
    public Task changeDescription(final ActionEvent event) {
        Property<String> description = model.getGeneral().description();
        String oldValue = description.get();
        try {
            description.set(descriptionField.getText());
            // set back old value to not mess up model execution
            description.set(oldValue);
        } catch (ConstraintViolationException cve) {
            int maxLength = description.metaInfo(MaxLength.class).value();
            descriptionField.setText(descriptionField.getText().substring(0, maxLength));
            throw new RuntimeException(new MessageFormat(i18n.text(StreamflowResources.max_length))
                    .format(new Object[] { maxLength }).toString());
        }
        return new CommandTask() {
            @Override
            public void command() throws Exception {
                model.changeDescription(descriptionField.getText());
            }
        };
    }

    @Action(block = Task.BlockingScope.COMPONENT)
    public Task changeDueOn(final ActionEvent event) {
        return new CommandTask() {
            @Override
            public void command() throws Exception {

                model.changeDueOn(dueOnField.getDate());
            }
        };
    }

    @Action
    public Task changeCaseType() {
        final SelectLinkDialog dialog = module.objectBuilderFactory().newObjectBuilder(SelectLinkDialog.class)
                .use(model.getPossibleCaseTypes(), new Integer(1)).newInstance();
        dialog.setPreferredSize(new Dimension(400, 200));
        dialogs.showOkCancelHelpDialog(caseTypeButton, dialog, i18n.text(WorkspaceResources.choose_casetype));

        caseTypeButton.requestFocusInWindow();

        if (dialog.getSelectedLink() != null) {
            return new CommandTask() {
                @Override
                protected void command() throws Exception {
                    LinkValue selected = dialog.getSelectedLink();
                    model.changeCaseType(selected);

                    // selectedCaseType.setRemoveLink(selected);

                    String labelQuery = dialog.getFilterField().getText();
                    // if the query string has any match inside label descriptions
                    // we do a search for that labels and add them to the case
                    // automatically
                    if (!"".equals(labelQuery)
                            && selected.classes().get().toLowerCase().indexOf(labelQuery.toLowerCase()) != -1) {
                        EventList<LinkValue> possibleLabels = labels.getModel().getPossibleLabels();
                        for (LinkValue link : possibleLabels) {
                            if (link.text().get().toLowerCase().contains(labelQuery.toLowerCase())) {
                                labels.getModel().addLabel(link);
                            }
                        }
                    }

                }
            };
        } else
            return null;
    }

    @Action
    public Task removeCaseType() {
        return new CommandTask() {
            @Override
            public void command() throws Exception {
                model.removeCaseType();
            }
        };
    }

    @Action
    public Task changePriority() {
        final PriorityValue selected = (PriorityValue) casePriority.getSelectedItem();
        String oldPriority = model.getGeneral().priority().get() != null
                ? model.getGeneral().priority().get().id().get()
                : "-1";
        String newPriority = selected != null ? selected.id().get() : "-1";
        if (!newPriority.equals(oldPriority)) {
            return new CommandTask() {
                @Override
                protected void command() throws Exception {
                    model.changePriority(selected.id().get());
                }
            };
        } else
            return null;
    }

    public void notifyTransactions(Iterable<TransactionDomainEvents> transactions) {
        if (matches(withNames("addedLabel", "removedLabel", "changedOwner", "changedCaseType", "changedStatus",
                "changedPriority", "setUnread"), transactions)) {
            refresh();
        }
    }
}