blob: e2b18b8b68d1dc7e7bc48754e4b078c5a8d951c7 [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2004, 2007 Boeing
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Boeing - initial API and implementation
**********************************************************************/
package org.eclipse.osee.ats.ide.editor.tab.workflow;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.osee.ats.api.data.AtsArtifactTypes;
import org.eclipse.osee.ats.help.ui.AtsHelpContext;
import org.eclipse.osee.ats.ide.config.AtsBulkLoad;
import org.eclipse.osee.ats.ide.editor.WorkflowEditor;
import org.eclipse.osee.ats.ide.editor.tab.WfeAbstractTab;
import org.eclipse.osee.ats.ide.editor.tab.workflow.header.WfeHeaderComposite;
import org.eclipse.osee.ats.ide.editor.tab.workflow.section.WfeDetailsSection;
import org.eclipse.osee.ats.ide.editor.tab.workflow.section.WfeHistorySection;
import org.eclipse.osee.ats.ide.editor.tab.workflow.section.WfeOperationsSection;
import org.eclipse.osee.ats.ide.editor.tab.workflow.section.WfeRelationsSection;
import org.eclipse.osee.ats.ide.editor.tab.workflow.section.WfeUndefinedStateSection;
import org.eclipse.osee.ats.ide.editor.tab.workflow.section.WfeWorkflowSection;
import org.eclipse.osee.ats.ide.internal.Activator;
import org.eclipse.osee.ats.ide.workdef.StateXWidgetPage;
import org.eclipse.osee.ats.ide.workflow.AbstractWorkflowArtifact;
import org.eclipse.osee.ats.ide.workflow.WorkflowManager;
import org.eclipse.osee.ats.ide.world.IWorldViewerEventHandler;
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.result.XResultData;
import org.eclipse.osee.framework.jdk.core.type.OseeCoreException;
import org.eclipse.osee.framework.jdk.core.type.Pair;
import org.eclipse.osee.framework.logging.OseeLevel;
import org.eclipse.osee.framework.logging.OseeLog;
import org.eclipse.osee.framework.skynet.core.artifact.Artifact;
import org.eclipse.osee.framework.ui.plugin.util.HelpUtil;
import org.eclipse.osee.framework.ui.skynet.artifact.editor.parts.MessageSummaryNote;
import org.eclipse.osee.framework.ui.skynet.util.FormsUtil;
import org.eclipse.osee.framework.ui.skynet.util.LoadingComposite;
import org.eclipse.osee.framework.ui.skynet.widgets.ArtifactStoredWidget;
import org.eclipse.osee.framework.ui.skynet.widgets.EditorWidget;
import org.eclipse.osee.framework.ui.skynet.widgets.XWidget;
import org.eclipse.osee.framework.ui.swt.ALayout;
import org.eclipse.osee.framework.ui.swt.Displays;
import org.eclipse.osee.framework.ui.swt.ExceptionComposite;
import org.eclipse.osee.framework.ui.swt.Widgets;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
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.IMessage;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.progress.UIJob;
/**
* @author Donald G. Dunne
*/
public class WfeWorkFlowTab extends WfeAbstractTab implements IWorldViewerEventHandler {
private final AbstractWorkflowArtifact awa;
private final List<WfeWorkflowSection> stateSections = new ArrayList<>();
private final List<StateXWidgetPage> statePages = new ArrayList<>();
private IManagedForm managedForm;
private Composite bodyComp;
private Composite atsBody;
private LoadingComposite loadingComposite;
public final static String ID = "ats.workflow.tab";
private final WorkflowEditor editor;
private final List<WfeUndefinedStateSection> undefinedStateSections = new ArrayList<>();
private WfeDetailsSection detailsSection;
private WfeRelationsSection relationsSection;
private WfeHistorySection historySection;
public WfeWorkFlowTab(WorkflowEditor editor, AbstractWorkflowArtifact awa) {
super(editor, ID, awa, "Workflow");
this.editor = editor;
this.awa = awa;
}
@Override
protected void createFormContent(IManagedForm managedForm) {
super.createFormContent(managedForm);
this.managedForm = managedForm;
try {
updateTitleBar(managedForm);
bodyComp = managedForm.getForm().getBody();
GridLayout gridLayout = new GridLayout(1, false);
bodyComp.setLayout(gridLayout);
GridData gd = new GridData(SWT.LEFT, SWT.LEFT, true, false);
gd.widthHint = 300;
bodyComp.setLayoutData(gd);
setLoading(true);
if (awa.isTypeEqual(AtsArtifactTypes.DecisionReview)) {
HelpUtil.setHelp(managedForm.getForm(), AtsHelpContext.DECISION_REVIEW);
} else if (awa.isTypeEqual(AtsArtifactTypes.PeerToPeerReview)) {
HelpUtil.setHelp(managedForm.getForm(), AtsHelpContext.PEER_TO_PEER_REVIEW);
} else {
HelpUtil.setHelp(managedForm.getForm(), AtsHelpContext.WORKFLOW_EDITOR__WORKFLOW_TAB);
}
List<IOperation> ops = new ArrayList<>();
ops.addAll(AtsBulkLoad.getConfigLoadingOperations());
IOperation operation = Operations.createBuilder("Load Workflow Tab").addAll(ops).build();
Operations.executeAsJob(operation, false, Job.LONG, new ReloadJobChangeAdapter(editor));
} catch (Exception ex) {
handleException(ex);
}
}
@Override
public void showBusy(boolean busy) {
super.showBusy(busy);
IManagedForm managedForm = getManagedForm();
if (managedForm != null && Widgets.isAccessible(getManagedForm().getForm())) {
getManagedForm().getForm().getForm().setBusy(busy);
}
}
private final class ReloadJobChangeAdapter extends JobChangeAdapter {
private final WorkflowEditor editor;
private ReloadJobChangeAdapter(WorkflowEditor editor) {
this.editor = editor;
showBusy(true);
}
@Override
public void done(IJobChangeEvent event) {
super.done(event);
Job job = new UIJob("Draw Workflow Tab") {
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
try {
if (managedForm != null && Widgets.isAccessible(managedForm.getForm())) {
updateTitleBar(managedForm);
createToolbar(managedForm);
setLoading(false);
createAtsBody();
addMessageDecoration(managedForm.getForm());
FormsUtil.addHeadingGradient(editor.getToolkit(), managedForm.getForm(), true);
editor.onDirtied();
}
} catch (OseeCoreException ex) {
handleException(ex);
} finally {
showBusy(false);
}
return Status.OK_STATUS;
}
};
Operations.scheduleJob(job, false, Job.SHORT, null);
}
}
@Override
public void handleException(Exception ex) {
setLoading(false);
if (Widgets.isAccessible(atsBody)) {
atsBody.dispose();
}
OseeLog.log(Activator.class, Level.SEVERE, ex);
new ExceptionComposite(bodyComp, ex);
bodyComp.layout();
}
@Override
public void setLoading(boolean set) {
Displays.ensureInDisplayThread(new Runnable() {
@Override
public void run() {
if (set) {
loadingComposite = new LoadingComposite(bodyComp);
bodyComp.layout();
} else {
if (Widgets.isAccessible(loadingComposite)) {
loadingComposite.dispose();
}
}
showBusy(set);
}
});
}
private void createAtsBody() {
if (Widgets.isAccessible(atsBody)) {
if (getManagedForm() != null && getManagedForm().getMessageManager() != null) {
getManagedForm().getMessageManager().removeAllMessages();
}
atsBody.dispose();
}
atsBody = editor.getToolkit().createComposite(bodyComp);
atsBody.setLayoutData(new GridData(GridData.FILL_BOTH));
atsBody.setLayout(new GridLayout(1, false));
StateXWidgetPage page = WorkflowManager.getCurrentAtsWorkPage(awa);
if (page == null) {
OseeLog.logf(Activator.class, OseeLevel.SEVERE_POPUP,
"Can't retrieve current page from current state [%s] of work definition [%s]", awa.getCurrentStateName(),
awa.getWorkDefinition().getName());
}
headerComp =
new WfeHeaderComposite(atsBody, SWT.NONE, editor, WorkflowManager.getCurrentAtsWorkPage(awa), managedForm);
headerComp.create();
createPageSections();
createUndefinedStateSections();
createHistorySection();
createRelationsSection();
createOperationsSection();
createDetailsSection();
setEditorWidgets();
atsBody.layout();
atsBody.setFocus();
}
private void setEditorWidgets() {
if (Widgets.isAccessible(headerComp)) {
Collection<XWidget> headerWidgets = headerComp.getXWidgets(new ArrayList<XWidget>());
for (XWidget widget : headerWidgets) {
if (widget instanceof EditorWidget) {
((EditorWidget) widget).setEditorData(editor);
}
}
}
List<StateXWidgetPage> statePages = getStatePages();
for (StateXWidgetPage currStatePage : statePages) {
Collection<XWidget> updateWidgets = currStatePage.getDynamicXWidgetLayout().getXWidgets();
for (XWidget widget : updateWidgets) {
if (widget instanceof EditorWidget) {
((EditorWidget) widget).setEditorData(editor);
}
}
}
}
private void createDetailsSection() {
try {
detailsSection = new WfeDetailsSection(editor, atsBody, editor.getToolkit(), SWT.NONE);
managedForm.addPart(detailsSection);
} catch (Exception ex) {
OseeLog.log(Activator.class, Level.SEVERE, ex);
}
}
private void createOperationsSection() {
try {
WfeOperationsSection smaOperationsSection =
new WfeOperationsSection(editor, atsBody, editor.getToolkit(), SWT.NONE);
managedForm.addPart(smaOperationsSection);
} catch (Exception ex) {
OseeLog.log(Activator.class, Level.SEVERE, ex);
}
}
private void createRelationsSection() {
try {
relationsSection = new WfeRelationsSection(editor, atsBody, editor.getToolkit(), SWT.NONE);
managedForm.addPart(relationsSection);
} catch (Exception ex) {
OseeLog.log(Activator.class, Level.SEVERE, ex);
}
}
private void createUndefinedStateSections() {
try {
if (WfeUndefinedStateSection.hasUndefinedStates(editor.getWorkItem())) {
for (String stateName : WfeUndefinedStateSection.getUndefinedStateNames(awa)) {
WfeUndefinedStateSection section =
new WfeUndefinedStateSection(stateName, editor, atsBody, editor.getToolkit(), SWT.NONE);
managedForm.addPart(section);
undefinedStateSections.add(section);
}
}
} catch (Exception ex) {
OseeLog.log(Activator.class, Level.SEVERE, ex);
}
}
private void createHistorySection() {
try {
historySection = new WfeHistorySection(editor, atsBody, editor.getToolkit(), SWT.NONE);
managedForm.addPart(historySection);
} catch (Exception ex) {
OseeLog.log(Activator.class, Level.SEVERE, ex);
}
}
private final Map<String, Pair<StateXWidgetPage, Composite>> stateNameToPageAndComposite = new HashMap<>();
private void createPageSections() {
try {
Composite sectionsComp = editor.getToolkit().createComposite(atsBody);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
gd.widthHint = 100;
sectionsComp.setLayoutData(gd);
sectionsComp.setLayout(ALayout.getZeroMarginLayout(1, false));
for (StateXWidgetPage statePage : WorkflowManager.getStatePagesOrderedByOrdinal(awa)) {
try {
// Only display current or past states
if (awa.isInState(statePage) || awa.getStateMgr().isStateVisited(statePage)) {
createStateSection(sectionsComp, statePage);
}
// Else make placeholder for state transition
else {
Composite placeHolderComp = editor.getToolkit().createComposite(sectionsComp);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.widthHint = 100;
placeHolderComp.setLayoutData(gd);
placeHolderComp.setLayout(ALayout.getZeroMarginLayout(1, false));
stateNameToPageAndComposite.put(statePage.getName(),
new Pair<StateXWidgetPage, Composite>(statePage, placeHolderComp));
}
} catch (Exception ex) {
OseeLog.log(Activator.class, Level.SEVERE, ex);
}
}
} catch (Exception ex) {
OseeLog.log(Activator.class, Level.SEVERE, ex);
}
}
private void createStateSection(Composite sectionsComp, StateXWidgetPage statePage) {
WfeWorkflowSection section = new WfeWorkflowSection(sectionsComp, SWT.NONE, statePage, awa, editor);
managedForm.addPart(section);
stateSections.add(section);
statePages.add(statePage);
}
private void addMessageDecoration(ScrolledForm form) {
form.getForm().addMessageHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
String title = e.getLabel();
Object href = e.getHref();
if (href instanceof IMessage[]) {
Point noteLocation = ((Control) e.widget).toDisplay(0, 0);
noteLocation.x += 10;
noteLocation.y += 10;
MessageSummaryNote note = new MessageSummaryNote(getManagedForm(), title, (IMessage[]) href);
note.setLocation(noteLocation);
note.open();
}
}
});
}
public XResultData isXWidgetDirty(XResultData rd) {
if (Widgets.isAccessible(headerComp)) {
rd.log("======> WFE - Header\n");
headerComp.isXWidgetDirty(rd);
}
for (WfeWorkflowSection section : stateSections) {
rd.logf("======> WFE Section - %s\n", section.getStatePage().getName());
section.isXWidgetDirty(rd);
}
return rd;
}
public Result isXWidgetSavable() {
Result result = null;
if (Widgets.isAccessible(headerComp)) {
result = headerComp.isXWidgetSavable();
}
for (WfeWorkflowSection section : stateSections) {
result = section.isXWidgetSavable();
if (result.isFalse()) {
return result;
}
}
return Result.TrueResult;
}
public void saveXWidgetToArtifact() {
List<ArtifactStoredWidget> artWidgets = new ArrayList<>();
headerComp.getDirtyIArtifactWidgets(artWidgets);
// Collect all dirty widgets first (so same attribute shown on different sections don't colide
for (WfeWorkflowSection section : stateSections) {
section.getDirtyIArtifactWidgets(artWidgets);
}
for (ArtifactStoredWidget widget : artWidgets) {
widget.saveToArtifact();
}
}
@Override
public void dispose() {
if (Widgets.isAccessible(headerComp)) {
headerComp.dispose();
}
if (detailsSection != null) {
detailsSection.dispose();
}
for (WfeUndefinedStateSection section : undefinedStateSections) {
section.dispose();
}
if (historySection != null) {
historySection.dispose();
}
if (relationsSection != null) {
relationsSection.dispose();
}
for (WfeWorkflowSection section : stateSections) {
section.dispose();
}
}
private WfeHeaderComposite headerComp;
public WfeWorkflowSection getCurrentStateSection() {
for (WfeWorkflowSection section : stateSections) {
if (section.getPage().getName().equals(editor.getWorkItem().getCurrentStateName())) {
return section;
}
}
return null;
}
public void refresh() {
if (editor != null && Widgets.isAccessible(headerComp)) {
Displays.ensureInDisplayThread(new Runnable() {
@Override
public void run() {
String stateName = awa.getCurrentStateName();
// Determine if state already exists
boolean found = false;
for (WfeWorkflowSection section : stateSections) {
if (section.getPage().getName().equals(stateName)) {
found = true;
}
}
headerComp.refresh();
// Create state if not exist
if (!found) {
Pair<StateXWidgetPage, Composite> pageAndComp = stateNameToPageAndComposite.get(stateName);
if (pageAndComp != null) {
StateXWidgetPage statePage = pageAndComp.getFirst();
createStateSection(pageAndComp.getSecond(), statePage);
}
}
for (WfeWorkflowSection section : stateSections) {
section.refresh();
}
refreshExpandStates();
relationsSection.refresh();
historySection.refresh();
detailsSection.refresh();
}
});
}
}
public void refreshExpandStates() {
for (WfeWorkflowSection wfeSection : stateSections) {
if (!Widgets.isAccessible(wfeSection.getMainComp())) {
continue;
}
boolean isCurrentState = wfeSection.isCurrentState();
if (isCurrentState) {
wfeSection.expand();
} else {
if (Widgets.isAccessible(wfeSection.getSection())) {
wfeSection.getSection().setExpanded(false);
}
}
}
if (Widgets.isAccessible(bodyComp)) {
bodyComp.layout(true, true);
bodyComp.getParent().layout(true, true);
}
}
@Override
public void relationsModifed(Collection<Artifact> relModifiedArts, Collection<Artifact> goalMemberReordered, Collection<Artifact> sprintMemberReordered) {
if (relModifiedArts.contains(awa)) {
refresh();
}
}
@Override
public boolean isDisposed() {
return editor.isDisposed();
}
public WfeHeaderComposite getHeader() {
return headerComp;
}
public List<StateXWidgetPage> getStatePages() {
return statePages;
}
public void computeSizeAndReflow() {
for (WfeWorkflowSection section : stateSections) {
section.computeTextSizesAndReflow();
}
}
}