org.eclipse.osee.ats.editor.SMAMembersTab.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.osee.ats.editor.SMAMembersTab.java

Source

/*******************************************************************************
 * Copyright (c) 2004, 2007 Boeing.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Boeing - initial API and implementation
 *******************************************************************************/

package org.eclipse.osee.ats.editor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.nebula.widgets.xviewer.customize.CustomizeData;
import org.eclipse.nebula.widgets.xviewer.customize.FilterData;
import org.eclipse.nebula.widgets.xviewer.customize.SortingData;
import org.eclipse.osee.ats.actions.OpenNewAtsWorldEditorSelectedAction;
import org.eclipse.osee.ats.api.data.AtsArtifactTypes;
import org.eclipse.osee.ats.core.client.actions.ISelectedAtsArtifacts;
import org.eclipse.osee.ats.core.client.artifact.CollectorArtifact;
import org.eclipse.osee.ats.core.client.artifact.GoalArtifact;
import org.eclipse.osee.ats.core.client.artifact.SprintArtifact;
import org.eclipse.osee.ats.core.client.config.AtsBulkLoad;
import org.eclipse.osee.ats.core.client.task.TaskArtifact;
import org.eclipse.osee.ats.core.client.workflow.AbstractWorkflowArtifact;
import org.eclipse.osee.ats.goal.RemoveFromCollectorAction;
import org.eclipse.osee.ats.goal.RemoveFromCollectorAction.RemovedFromCollectorHandler;
import org.eclipse.osee.ats.goal.SetCollectorOrderAction;
import org.eclipse.osee.ats.internal.Activator;
import org.eclipse.osee.ats.world.IMenuActionProvider;
import org.eclipse.osee.ats.world.IWorldViewerEventHandler;
import org.eclipse.osee.ats.world.WorldComposite;
import org.eclipse.osee.ats.world.WorldLabelProvider;
import org.eclipse.osee.ats.world.WorldViewDragAndDrop;
import org.eclipse.osee.ats.world.WorldXViewer;
import org.eclipse.osee.ats.world.WorldXViewerEventManager;
import org.eclipse.osee.framework.core.operation.IOperation;
import org.eclipse.osee.framework.core.operation.Operations;
import org.eclipse.osee.framework.core.util.Result;
import org.eclipse.osee.framework.jdk.core.type.OseeCoreException;
import org.eclipse.osee.framework.jdk.core.util.Conditions;
import org.eclipse.osee.framework.jdk.core.util.Lib;
import org.eclipse.osee.framework.jdk.core.util.Strings;
import org.eclipse.osee.framework.logging.OseeLog;
import org.eclipse.osee.framework.plugin.core.util.Jobs;
import org.eclipse.osee.framework.skynet.core.artifact.Artifact;
import org.eclipse.osee.framework.skynet.core.artifact.ArtifactData;
import org.eclipse.osee.framework.skynet.core.event.model.EventBasicGuidArtifact;
import org.eclipse.osee.framework.skynet.core.event.model.EventModType;
import org.eclipse.osee.framework.ui.plugin.util.AWorkbench;
import org.eclipse.osee.framework.ui.plugin.xnavigate.XNavigateComposite.TableLoadOption;
import org.eclipse.osee.framework.ui.skynet.action.CollapseAllAction;
import org.eclipse.osee.framework.ui.skynet.action.ExpandAllAction;
import org.eclipse.osee.framework.ui.skynet.action.RefreshAction;
import org.eclipse.osee.framework.ui.skynet.artifact.ArtifactTransfer;
import org.eclipse.osee.framework.ui.skynet.util.FormsUtil;
import org.eclipse.osee.framework.ui.skynet.util.LoadingComposite;
import org.eclipse.osee.framework.ui.swt.Displays;
import org.eclipse.osee.framework.ui.swt.ExceptionComposite;
import org.eclipse.osee.framework.ui.swt.ImageManager;
import org.eclipse.osee.framework.ui.swt.KeyedImage;
import org.eclipse.osee.framework.ui.swt.Widgets;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.editor.FormPage;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.progress.UIJob;

/**
 * @author Donald G. Dunne
 */
public class SMAMembersTab extends FormPage
        implements ISelectedAtsArtifacts, IWorldViewerEventHandler, IMenuActionProvider {
    private IManagedForm managedForm;
    private Composite bodyComp;
    private ScrolledForm scrolledForm;
    private WorldComposite worldComposite;
    private LoadingComposite loadingComposite;
    public final static String ID = "ats.members.tab";
    private final SMAEditor editor;
    private static Map<String, Integer> guidToScrollLocation = new HashMap<String, Integer>();
    private final ReloadJobChangeAdapter reloadAdapter;
    private final IMemberProvider provider;

    public SMAMembersTab(SMAEditor editor, IMemberProvider provider) {
        super(editor, ID, provider.getItemName());
        this.editor = editor;
        this.provider = provider;
        reloadAdapter = new ReloadJobChangeAdapter(editor);
    }

    @Override
    protected void createFormContent(IManagedForm managedForm) {
        super.createFormContent(managedForm);

        this.managedForm = managedForm;
        scrolledForm = managedForm.getForm();
        try {
            scrolledForm.addDisposeListener(new DisposeListener() {
                @Override
                public void widgetDisposed(DisposeEvent e) {
                    storeScrollLocation();
                }
            });
            updateTitleBar();

            bodyComp = scrolledForm.getBody();
            GridLayout gridLayout = new GridLayout(1, true);
            bodyComp.setLayout(gridLayout);
            GridData gd = new GridData(SWT.LEFT, SWT.LEFT, false, false);
            bodyComp.setLayoutData(gd);

            setLoading(true);
            refreshData();
            WorldXViewerEventManager.add(this);
        } catch (Exception ex) {
            handleException(ex);
        }
    }

    private void updateTitleBar() throws OseeCoreException {
        if (Widgets.isAccessible(scrolledForm)) {
            String titleString = editor.getTitleStr();
            String displayableTitle = Strings.escapeAmpersands(titleString);
            if (!scrolledForm.getText().equals(displayableTitle)) {
                scrolledForm.setText(displayableTitle);
            }
            KeyedImage image = provider.getImageKey();
            if (!ImageManager.getImage(image).equals(scrolledForm.getImage())) {
                scrolledForm.setImage(ImageManager.getImage(image));
            }
        }
    }

    @Override
    public void showBusy(boolean busy) {
        super.showBusy(busy);
        if (getManagedForm() != null && Widgets.isAccessible(getManagedForm().getForm())) {
            getManagedForm().getForm().getForm().setBusy(busy);
        }
    }

    public void refreshData() {
        if (Widgets.isAccessible(bodyComp)) {
            List<IOperation> ops = AtsBulkLoad.getConfigLoadingOperations();
            IOperation operation = Operations.createBuilder("Load Members Tab").addAll(ops).build();
            Operations.executeAsJob(operation, false, Job.LONG, reloadAdapter);
        }
    }

    private final class ReloadJobChangeAdapter extends JobChangeAdapter {

        private final SMAEditor editor;
        boolean firstTime = true;

        private ReloadJobChangeAdapter(SMAEditor editor) {
            this.editor = editor;
            showBusy(true);
        }

        @Override
        public void done(IJobChangeEvent event) {
            super.done(event);
            Job job = new UIJob("Draw Members Tab") {

                @Override
                public IStatus runInUIThread(IProgressMonitor monitor) {
                    if (firstTime) {
                        try {
                            if (Widgets.isAccessible(scrolledForm)) {
                                updateTitleBar();
                                setLoading(false);
                                boolean createdAndLoaded = createMembersBody();
                                if (!createdAndLoaded) {
                                    reload();
                                }
                                jumptoScrollLocation();
                                FormsUtil.addHeadingGradient(editor.getToolkit(), scrolledForm, true);
                                refreshToolbar();
                                editor.onDirtied();
                            }
                            firstTime = false;
                        } catch (OseeCoreException ex) {
                            handleException(ex);
                        } finally {
                            showBusy(false);
                        }
                    } else {
                        try {
                            updateTitleBar();
                        } catch (OseeCoreException ex) {
                            handleException(ex);
                        } finally {
                            showBusy(false);
                        }
                        if (managedForm != null && Widgets.isAccessible(managedForm.getForm())) {
                            refresh();
                        }
                    }
                    return Status.OK_STATUS;
                }
            };
            Operations.scheduleJob(job, false, Job.SHORT, null);
        }
    }

    private void handleException(Exception ex) {
        setLoading(false);
        if (Widgets.isAccessible(worldComposite)) {
            worldComposite.dispose();
        }
        OseeLog.log(Activator.class, Level.SEVERE, ex);
        new ExceptionComposite(bodyComp, ex);
        bodyComp.layout();
    }

    private void setLoading(boolean set) {
        if (set) {
            loadingComposite = new LoadingComposite(bodyComp);
            bodyComp.layout();
        } else {
            if (Widgets.isAccessible(loadingComposite)) {
                loadingComposite.dispose();
            }
        }
        showBusy(set);
    }

    /**
     * @return true if created; false if skipped
     */
    private boolean createMembersBody() {
        if (!Widgets.isAccessible(worldComposite)) {
            worldComposite = new WorldComposite("workflow.edtor.members.tab", editor,
                    provider.getXViewerFactory(provider.getArtifact()), bodyComp, SWT.BORDER, false);

            new MembersDragAndDrop(worldComposite, SMAEditor.EDITOR_ID);

            WorldLabelProvider labelProvider = (WorldLabelProvider) worldComposite.getXViewer().getLabelProvider();
            if (editor.getAwa().isOfType(AtsArtifactTypes.Goal)) {
                labelProvider.setParentGoal((GoalArtifact) editor.getAwa());
            } else {
                labelProvider.setParentSprint((SprintArtifact) editor.getAwa());
            }

            worldComposite.getWorldXViewer().addMenuActionProvider(this);
            getSite().setSelectionProvider(worldComposite.getWorldXViewer());
            GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
            gd.widthHint = 100;
            gd.heightHint = 100;
            worldComposite.setLayoutData(gd);

            reload();
            createActions();
            return true;
        }
        return false;
    }

    public void reload() {
        if (isTableDisposed()) {
            return;
        }
        Job job = new Job(String.format("Load %s Members", provider.getItemName())) {

            @Override
            protected IStatus run(IProgressMonitor monitor) {
                if (isTableDisposed()) {
                    return Status.OK_STATUS;
                }
                try {
                    final List<Artifact> artifacts = provider.getMembers();
                    worldComposite.load(provider.getItemName(), artifacts, (CustomizeData) null,
                            TableLoadOption.None);
                } catch (OseeCoreException ex) {
                    OseeLog.log(Activator.class, Level.SEVERE, ex);
                    return new Status(IStatus.ERROR, Activator.PLUGIN_ID,
                            String.format("Exception loading %s", provider.getItemName()), ex);
                }
                return Status.OK_STATUS;
            }
        };
        Jobs.startJob(job, false);
    }

    private boolean isTableDisposed() {
        return worldComposite == null || worldComposite.getXViewer() == null
                || worldComposite.getXViewer().getTree() == null
                || worldComposite.getXViewer().getTree().isDisposed();
    }

    private void jumptoScrollLocation() {
        //       Jump to scroll location if set
        Integer selection = guidToScrollLocation.get(provider.getGuid());
        if (selection != null) {
            JumpScrollbarJob job = new JumpScrollbarJob("");
            job.schedule(500);
        }
    }

    @Override
    public void dispose() {
        if (worldComposite != null) {
            worldComposite.dispose();
        }
        if (editor.getToolkit() != null) {
            editor.getToolkit().dispose();
        }
    }

    private final Control control = null;

    private void storeScrollLocation() {
        if (managedForm != null && managedForm.getForm() != null) {
            Integer selection = managedForm.getForm().getVerticalBar().getSelection();
            guidToScrollLocation.put(provider.getGuid(), selection);
        }
    }

    private class JumpScrollbarJob extends Job {
        public JumpScrollbarJob(String name) {
            super(name);
        }

        @Override
        protected IStatus run(IProgressMonitor monitor) {
            Displays.ensureInDisplayThread(new Runnable() {
                @Override
                public void run() {
                    Integer selection = guidToScrollLocation.get(provider.getGuid());

                    // Find the ScrolledComposite operating on the control.
                    ScrolledComposite sComp = null;
                    if (control == null || control.isDisposed()) {
                        return;
                    }
                    Composite parent = control.getParent();
                    while (parent != null) {
                        if (parent instanceof ScrolledComposite) {
                            sComp = (ScrolledComposite) parent;
                            break;
                        }
                        parent = parent.getParent();
                    }

                    if (sComp != null) {
                        sComp.setOrigin(0, selection);
                    }
                }
            });
            return Status.OK_STATUS;

        }
    }

    public void refresh() {
        Displays.ensureInDisplayThread(new Runnable() {

            @Override
            public void run() {
                if (Widgets.isAccessible(worldComposite)) {
                    updateShown();
                    worldComposite.update();
                    worldComposite.getXViewer().refresh();
                }
            }
        });
    }

    private void updateShown() {
        List<Artifact> members;
        try {
            members = provider.getMembers();
        } catch (OseeCoreException ex) {
            OseeLog.log(Activator.class, Level.SEVERE, ex);
            return;
        }
        List<Artifact> loadedArtifacts = worldComposite.getLoadedArtifacts();
        List<Artifact> toRemoveFromLoaded = new LinkedList<Artifact>(members);
        members.removeAll(loadedArtifacts);
        for (Artifact art : members) {
            worldComposite.insert(art, -1);
        }
        loadedArtifacts.removeAll(toRemoveFromLoaded);
        worldComposite.removeItems(loadedArtifacts);
        worldComposite.getXViewer().remove(loadedArtifacts);
        worldComposite.getXViewer().refresh(provider.getArtifact());
    }

    private void refreshToolbar() {
        IToolBarManager toolBarMgr = scrolledForm.getToolBarManager();
        toolBarMgr.removeAll();
        toolBarMgr.add(new OpenNewAtsWorldEditorSelectedAction(worldComposite));
        toolBarMgr.add(getWorldXViewer().getCustomizeAction());
        toolBarMgr.add(new Separator());
        toolBarMgr.add(new ExpandAllAction(worldComposite.getXViewer()));
        toolBarMgr.add(new CollapseAllAction(worldComposite.getXViewer()));
        toolBarMgr.add(new RefreshAction(worldComposite));
        scrolledForm.updateToolBar();
    }

    public WorldComposite getMembersSection() {
        return worldComposite;
    }

    @Override
    public WorldXViewer getWorldXViewer() {
        if (worldComposite == null) {
            return null;
        }
        return worldComposite.getWorldXViewer();
    }

    @Override
    public void removeItems(Collection<? extends Object> objects) {
        for (Object obj : objects) {
            if (obj instanceof EventBasicGuidArtifact) {
                EventBasicGuidArtifact guidArt = (EventBasicGuidArtifact) obj;
                if (guidArt.getModType() == EventModType.Purged) {
                    refresh();
                    return;
                }
            }
        }
    }

    @Override
    public void relationsModifed(Collection<Artifact> relModifiedArts) {
        if (relModifiedArts.contains(provider.getArtifact())) {
            refresh();
        }
    }

    @Override
    public boolean isDisposed() {
        return editor.isDisposed();
    }

    private class MembersDragAndDrop extends WorldViewDragAndDrop {

        private boolean isFeedbackAfter = false;

        public MembersDragAndDrop(WorldComposite worldComposite, String viewId) {
            super(worldComposite, viewId);
        }

        private Artifact getSelectedArtifact(DropTargetEvent event) {
            if (event.item != null && event.item.getData() instanceof Artifact) {
                return (Artifact) event.item.getData();
            }
            return null;
        }

        private CustomizeData getCustomizeData() throws OseeCoreException {
            CustomizeData customizeData = worldComposite.getCustomizeDataCopy();
            Conditions.checkNotNull(customizeData, "Customized Data");
            return customizeData;
        }

        private FilterData getFilterData() throws OseeCoreException {
            FilterData filterData = getCustomizeData().getFilterData();
            Conditions.checkNotNull(filterData, "Filter Data");
            return filterData;
        }

        private SortingData getSortingData() throws OseeCoreException {
            SortingData sortingData = getCustomizeData().getSortingData();
            Conditions.checkNotNull(sortingData, "Sort Data");
            return sortingData;
        }

        private String getFilterText() throws OseeCoreException {
            String filterText = getFilterData().getFilterText();
            Conditions.checkNotNull(filterText, "Filter Text");
            return filterText;
        }

        private List<String> getSortingIds() throws OseeCoreException {
            return getSortingData().getSortingIds();
        }

        private boolean isSortedByCollectorsOrder() throws OseeCoreException {
            List<String> sortingIds = getSortingIds();
            return (sortingIds.size() == 1 && sortingIds.contains(provider.getColumnName()));
        }

        private boolean isFiltered() throws OseeCoreException {
            String filterText = getFilterText();
            return Strings.isValid(filterText);
        }

        private boolean isDropValid() throws OseeCoreException {
            return !isFiltered() && isSortedByCollectorsOrder();
        }

        @Override
        public void operationChanged(DropTargetEvent event) {
            if (!(event.detail == 1)) {
                isFeedbackAfter = false;
            } else {
                isFeedbackAfter = true;
            }
        }

        @Override
        public void performDragOver(DropTargetEvent event) {
            if (isValidForArtifactDrop(event)) {
                event.detail = DND.DROP_COPY;
                Artifact selectedArtifact = getSelectedArtifact(event);
                if (selectedArtifact != null) {
                    if (isFeedbackAfter) {
                        event.feedback = DND.FEEDBACK_INSERT_AFTER | DND.FEEDBACK_SCROLL;
                    } else {
                        event.feedback = DND.FEEDBACK_INSERT_BEFORE | DND.FEEDBACK_SCROLL;
                    }
                }
            }
        }

        @Override
        public void performDrop(final DropTargetEvent event) {
            final ArtifactData artData = ArtifactTransfer.getInstance().nativeToJava(event.currentDataType);
            final List<Artifact> droppedArtifacts = Arrays.asList(artData.getArtifacts());
            Collections.reverse(droppedArtifacts);
            final Artifact dropTarget = getSelectedArtifact(event);
            try {
                boolean dropValid = isDropValid();
                if (dropValid && ArtifactTransfer.getInstance().isSupportedType(event.currentDataType)) {

                    Collections.reverse(droppedArtifacts);
                    List<Artifact> members = provider.getMembers();
                    Result result = provider.isAddValid(droppedArtifacts);
                    if (result.isFalse()) {
                        if (MessageDialog.openQuestion(Displays.getActiveShell(), "Drop Error", result.getText())) {
                            for (Artifact dropped : droppedArtifacts) {
                                dropped.deleteRelations(provider.getMemberRelationTypeSide().getOpposite());
                            }
                        } else {
                            return;
                        }
                    }
                    for (Artifact dropped : droppedArtifacts) {
                        if (!members.contains(dropped)) {
                            provider.addMember(dropped);
                        }
                        if (dropTarget != null) {
                            provider.getArtifact().setRelationOrder(provider.getMemberRelationTypeSide(),
                                    dropTarget, isFeedbackAfter, dropped);
                        }
                    }
                    provider.getArtifact().persist(SMAMembersTab.class.getSimpleName());
                } else if (!dropValid) {
                    AWorkbench.popup(
                            "Drag/Drop is disabled when table is filtered or sorted.\n\nSwitch to default table customization and try again.");
                }
            } catch (OseeCoreException ex) {
                OseeLog.log(Activator.class, Level.SEVERE, Lib.exceptionToString(ex));
            }
        }

    }

    Action setCollectorOrderAction, removeFromCollectorAction;

    private void createActions() {
        setCollectorOrderAction = new SetCollectorOrderAction(provider, (CollectorArtifact) editor.getAwa(), this);
        RemovedFromCollectorHandler handler = new RemovedFromCollectorHandler() {

            @Override
            public void removedFromCollector(Collection<? extends Artifact> removed) {
                worldComposite.removeItems(removed);
                worldComposite.getXViewer().remove(removed);
                worldComposite.getXViewer().refresh(provider.getArtifact());
            }

        };
        removeFromCollectorAction = new RemoveFromCollectorAction(provider, (CollectorArtifact) editor.getAwa(),
                this, handler);
    }

    @Override
    public void updateMenuActionsForTable() {
        MenuManager mm = worldComposite.getXViewer().getMenuManager();
        mm.insertBefore(WorldXViewer.MENU_GROUP_ATS_WORLD_EDIT, setCollectorOrderAction);
        mm.insertBefore(WorldXViewer.MENU_GROUP_ATS_WORLD_EDIT, removeFromCollectorAction);
        mm.insertBefore(WorldXViewer.MENU_GROUP_ATS_WORLD_EDIT, new Separator());
    }

    @Override
    public Set<? extends Artifact> getSelectedSMAArtifacts() {
        Set<Artifact> artifacts = new HashSet<Artifact>();
        for (Artifact art : worldComposite.getSelectedArtifacts()) {
            if (art instanceof AbstractWorkflowArtifact) {
                artifacts.add(art);
            }
        }
        return artifacts;
    }

    @Override
    public List<Artifact> getSelectedAtsArtifacts() {
        List<Artifact> artifacts = new ArrayList<Artifact>();
        for (Artifact art : worldComposite.getSelectedArtifacts()) {
            if (art.isOfType(AtsArtifactTypes.AtsArtifact)) {
                artifacts.add(art);
            }
        }
        return artifacts;
    }

    @Override
    public List<TaskArtifact> getSelectedTaskArtifacts() {
        List<TaskArtifact> tasks = new ArrayList<TaskArtifact>();
        for (Artifact art : worldComposite.getSelectedArtifacts()) {
            if (art instanceof TaskArtifact) {
                tasks.add((TaskArtifact) art);
            }
        }
        return tasks;
    }

}