/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.gui.datamanagement.browser;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.exec.OS;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareEditorInput;
import org.eclipse.compare.CompareUI;
import org.eclipse.compare.IModificationDate;
import org.eclipse.compare.IStreamContentAccessor;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.structuremergeviewer.DiffNode;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.core.runtime.CoreException;
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.IJobChangeListener;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
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.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.SelectionProviderAction;
import org.eclipse.ui.part.DrillDownAdapter;
import org.eclipse.ui.part.ViewPart;
import de.rcenvironment.core.authentication.AuthenticationException;
import de.rcenvironment.core.authorization.AuthorizationException;
import de.rcenvironment.core.communication.common.CommunicationException;
import de.rcenvironment.core.communication.common.InstanceNodeSessionId;
import de.rcenvironment.core.communication.common.ResolvableNodeId;
import de.rcenvironment.core.communication.management.WorkflowHostService;
import de.rcenvironment.core.datamanagement.DataManagementService;
import de.rcenvironment.core.datamanagement.FileDataService;
import de.rcenvironment.core.datamanagement.commons.MetaData;
import de.rcenvironment.core.datamanagement.commons.MetaDataKeys;
import de.rcenvironment.core.gui.datamanagement.browser.spi.DMBrowserNode;
import de.rcenvironment.core.gui.datamanagement.browser.spi.DMBrowserNodeType;
import de.rcenvironment.core.gui.datamanagement.browser.spi.DMBrowserNodeUtils;
import de.rcenvironment.core.gui.datamanagement.commons.DataManagementWorkbenchUtils;
import de.rcenvironment.core.gui.resources.api.ImageManager;
import de.rcenvironment.core.gui.resources.api.StandardImages;
import de.rcenvironment.core.gui.utils.common.ClipboardHelper;
import de.rcenvironment.core.gui.workflow.view.timeline.TimelineView;
import de.rcenvironment.core.utils.common.StringUtils;
import de.rcenvironment.core.utils.common.TempFileServiceAccess;
import de.rcenvironment.core.utils.incubator.ServiceRegistry;
import de.rcenvironment.core.utils.incubator.ServiceRegistryAccess;
/**
* A visual tree-based navigator for data represented in the RCE data management.
*
* @author Markus Litz
* @author Robert Mischke
* @author Jan Flink
* @author Doreen Seider
*/
public class DataManagementBrowser extends ViewPart implements DMBrowserNodeContentAvailabilityHandler {
/**
* The ID of the view as specified by the extension.
*/
public static final String ID = "de.rcenvironment.rce.gui.datamanagement.browser.DataManagementBrowser";
private static final String ROOT_NODE_TITLE = "<root>";
private static final String NODE_TEXT_FORMAT_TITLE_PLUS_HOSTNAME = "%s %s";
private static final String BRACKET_OPEN = "[";
private static final String BRACKET_CLOSE = "]";
private static final String LOCAL = "local";
private static final MetaData META_DATA_WORKFLOW_FINAL_STATE = new MetaData(MetaDataKeys.WORKFLOW_FINAL_STATE, true, true);
private static final MetaData METADATA_WORKFLOW_FILES_DELETED = new MetaData(
MetaDataKeys.WORKFLOW_FILES_DELETED, true, true);
private static final MetaData METADATA_WORKFLOW_IS_MARKED_FOR_DELETION = new MetaData(
MetaDataKeys.WORKFLOW_MARKED_FOR_DELETION, true, true);
protected final Log log = LogFactory.getLog(getClass());
protected DMTreeSorter treeSorter;
private Object[] expandedNodes = null;
private TreeViewer viewer;
private DrillDownAdapter drillDownAdapter;
private DMContentProvider contentProvider;
private Action sortAscendingName;
private Action actionRefreshAll;
private Action openInEditorAction;
private Action openTiglAction;
private Action doubleClickAction;
private Action deleteNodeAction;
private Action deleteFilesAction;
private Action exportNodeAction;
private RefreshNodeAction refreshNodeAction;
private CollapseAllNodesAction collapseAllNodesAction;
/**
* FileDataService for storing/loading resources to the data management.
*/
private FileDataService fileDataService;
private IAction sortDescendingName;
private IAction sortTimestampAsc;
private Action compareAction;
private Action timelineAction;
private Action copyAction;
private Action sortTimestampDesc;
private ServiceRegistryAccess serviceRegistryAccess;
/**
* An {@link Action} to export data management entries to local files.
*
* @author Christian Weiss
*
*/
private final class CustomExportAction extends SelectionProviderAction {
private final List<DMBrowserNode> selectedNodes = new LinkedList<DMBrowserNode>();
private Display display;
private final List<DMBrowserNodeType> savableNodeTypes = new ArrayList<DMBrowserNodeType>();
private final List<DMBrowserNodeType> savableNodeAsFolder = new ArrayList<DMBrowserNodeType>();
/*
* Set all savable DMBrowserNodeTypes.
*/
{
// Set all DMBrowserNodeTypes which are to save as folder.
savableNodeAsFolder.add(DMBrowserNodeType.Timeline);
savableNodeAsFolder.add(DMBrowserNodeType.Components);
savableNodeAsFolder.add(DMBrowserNodeType.Component);
savableNodeAsFolder.add(DMBrowserNodeType.HistoryObject);
savableNodeAsFolder.add(DMBrowserNodeType.Input);
savableNodeAsFolder.add(DMBrowserNodeType.Output);
savableNodeAsFolder.add(DMBrowserNodeType.IntermediateInputsFolder);
savableNodeAsFolder.add(DMBrowserNodeType.LogFolder);
savableNodeAsFolder.add(DMBrowserNodeType.ToolInputOutputFolder);
savableNodeAsFolder.add(DMBrowserNodeType.DMDirectoryReference);
// Set all savable DMBrowserNodeTypes.
savableNodeTypes.add(DMBrowserNodeType.HistoryRoot);
savableNodeTypes.add(DMBrowserNodeType.DMFileResource);
savableNodeTypes.add(DMBrowserNodeType.Resource);
savableNodeTypes.add(DMBrowserNodeType.Float);
savableNodeTypes.add(DMBrowserNodeType.Vector);
savableNodeTypes.add(DMBrowserNodeType.ShortText);
savableNodeTypes.add(DMBrowserNodeType.Boolean);
savableNodeTypes.add(DMBrowserNodeType.Integer);
savableNodeTypes.add(DMBrowserNodeType.SmallTable);
savableNodeTypes.add(DMBrowserNodeType.Indefinite);
savableNodeTypes.add(DMBrowserNodeType.File);
savableNodeTypes.add(DMBrowserNodeType.CommonText);
}
private CustomExportAction(ISelectionProvider provider, String text) {
super(provider, text);
}
@Override
public void selectionChanged(final IStructuredSelection selection) {
// clear the old selection
selectedNodes.clear();
// the 'save' action is only enabled, if a DataService is
// connected to delegate the deletion request to and the
// selected is not empty
boolean enabled = fileDataService != null && !selection.isEmpty();
if (enabled) {
@SuppressWarnings("unchecked") final Iterator<DMBrowserNode> iter = selection.iterator();
while (iter.hasNext()) {
DMBrowserNode selectedNode = iter.next();
DMBrowserNodeType nodeType = selectedNode.getType();
if (selectedNode.isEnabled() && !selectedNode.areAllChildrenDisabled()
&& (savableNodeTypes.contains(nodeType) || savableNodeAsFolder.contains(nodeType))) {
selectedNodes.add(selectedNode);
}
}
// action is only enabled, if at least one node is deletable
// according to the deletable DMBrowserNodeTypes list
enabled &= !selectedNodes.isEmpty();
// action is only enabled if a potential content node is
// selected
enabled = mightHaveContent(selectedNodes);
// store the Display to show the DirectoryDialog in 'run'
display = Display.getCurrent();
}
setEnabled(enabled);
}
@Override
public void run() {
final List<DMBrowserNode> browserNodesToSave = new LinkedList<DMBrowserNode>(selectedNodes);
FileDialog fileDialog = new FileDialog(display.getActiveShell(), SWT.SAVE);
fileDialog.setText("Export");
fileDialog.setFileName(browserNodesToSave.get(0).getTitle().replace(":", "_"));
final String directoryPath = fileDialog.open();
if (directoryPath == null) {
return;
}
final File targetDirectory = new File(directoryPath);
final ExportJob job = new ExportJob("Exporting", browserNodesToSave, targetDirectory);
job.addJobChangeListener(new IJobChangeListener() {
@Override
public void done(IJobChangeEvent event) {
if (event.getResult() == Status.OK_STATUS) {
display.syncExec(new Runnable() {
@Override
public void run() {
String location;
if (job.getTargetFile() != null) {
location = StringUtils.format(Messages.exportSuccessText, browserNodesToSave.toString(),
job.getTargetFile().getAbsolutePath()).replace(BRACKET_OPEN, "").replace(BRACKET_CLOSE, "");
} else {
location = StringUtils.format(Messages.exportSuccessText,
browserNodesToSave.toString(), targetDirectory.getAbsolutePath()).replace(BRACKET_OPEN, "")
.replace(BRACKET_CLOSE, "");
}
MessageDialog.openInformation(display.getActiveShell(), "Export", location);
}
});
} else if (event.getResult() == Status.CANCEL_STATUS) {
display.syncExec(new Runnable() {
@Override
public void run() {
MessageDialog.openError(display.getActiveShell(), "Error",
Messages.exportErrorText);
}
});
}
}
@Override
public void awake(IJobChangeEvent arg0) {}
@Override
public void aboutToRun(IJobChangeEvent arg0) {}
@Override
public void sleeping(IJobChangeEvent arg0) {}
@Override
public void scheduled(IJobChangeEvent arg0) {}
@Override
public void running(IJobChangeEvent arg0) {}
});
job.setUser(true);
job.schedule();
}
/**
* A {@link Job} to handle the exporting of data management entries to local files.
*/
private final class ExportJob extends Job {
private static final String DOT = ".";
private List<DMBrowserNode> browserNodesToSave;
private File targetDirectory;
private File targetFile;
protected ExportJob(String title, List<DMBrowserNode> browserNodesToSave, File ordnerPath) {
super(title);
this.browserNodesToSave = browserNodesToSave;
this.targetDirectory = ordnerPath;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
// delete the nodes recursively
monitor.beginTask(StringUtils.format("Exporting %d node(s): %s",
browserNodesToSave.size(),
browserNodesToSave.toString()).replace(BRACKET_OPEN, "").replace(BRACKET_CLOSE, ""), 2);
monitor.worked(1);
for (final DMBrowserNode browserNodeToSave : browserNodesToSave) {
DMBrowserNode workflowNode = browserNodeToSave.getNodeWithTypeWorkflow();
if (workflowNode.getWorkflowHostName().equals(LOCAL)
|| isWorkflowHostReachable(workflowNode.getNodeIdentifier())) {
saveNode(browserNodeToSave);
} else {
return Status.CANCEL_STATUS;
}
}
monitor.worked(1);
return Status.OK_STATUS;
}
protected File getTargetFile() {
return targetFile;
}
private void saveNode(final DMBrowserNode browserNode) {
if (savableNodeAsFolder.contains(browserNode.getType())) {
if (!targetDirectory.exists()) {
targetDirectory.mkdir();
}
if (!browserNode.areChildrenKnown()) {
contentProvider.fetchChildren(browserNode);
}
for (final DMBrowserNode child : contentProvider.getChildren(browserNode)) {
if (child.isEnabled()) {
save(child, targetDirectory);
}
}
} else {
String fileName = targetDirectory.getName();
targetDirectory = new File(targetDirectory.getAbsolutePath().replace(File.separator + fileName, ""));
if (!fileName.contains(DOT)) {
final String[] fileEnding = browserNode.getAssociatedFilename().split(Pattern.quote(DOT));
if (fileEnding.length == 2) {
fileName = fileName + DOT + fileEnding[1];
}
}
targetFile = findUniqueFilename(targetDirectory, fileName);
if (browserNode.isEnabled()) {
save(browserNode.getDataReferenceId(), browserNode.getFileReferencePath(), targetFile.getName(), targetDirectory,
browserNode.getNodeWithTypeWorkflow().getNodeIdentifier());
}
}
}
private void save(final DMBrowserNode browserNode, final File directory) {
// get the current DataReference and delete it, if it is
// not null (null DataReferences are used for
// aggregating tree items)
final String dataReferenceId = browserNode
.getDataReferenceId();
final String fileReferencePath = browserNode.getFileReferencePath();
String filename = browserNode.getAssociatedFilename();
if (filename == null) {
filename = browserNode.getTitle();
}
filename = filename.replaceAll(
"[^-\\s\\(\\)._a-zA-Z0-9]", "_");
final File nodeFile = findUniqueFilename(directory,
filename);
if (!browserNode.areChildrenKnown()) {
contentProvider.fetchChildren(browserNode);
}
if (browserNode.getNumChildren() > 0) {
nodeFile.mkdir();
// save children
for (final DMBrowserNode child : contentProvider.getChildren(browserNode)) {
// recur
if (child.isEnabled()) {
save(child, nodeFile);
}
}
} else {
if (browserNode.isEnabled() && dataReferenceId != null || fileReferencePath != null) {
save(dataReferenceId, fileReferencePath, nodeFile.getName(), directory,
browserNode.getNodeWithTypeWorkflow().getNodeIdentifier());
}
}
}
private File findUniqueFilename(final File directory,
final String filename) {
File result = new File(directory, filename);
if (!result.exists()) {
return result;
}
String prefix = filename;
String postfix = "";
final Pattern pattern = Pattern
.compile("^(.*)\\.([a-zA-Z0-9]+)$");
final Matcher matcher = pattern.matcher(filename);
if (matcher.matches()) {
prefix = matcher.group(1);
postfix = DOT + matcher.group(2);
}
int i = 0;
do {
++i;
result = new File(directory, StringUtils.format(
"%s (%d)%s", prefix, i, postfix));
} while (result.exists());
return result;
}
private void save(final String dataReferenceId, final String fileReferencePath, final String filename,
final File directory, ResolvableNodeId rceNodeIdentifier) {
try {
DataManagementWorkbenchUtils.getInstance().saveReferenceToFile(dataReferenceId, fileReferencePath,
new File(directory, filename).getAbsolutePath(), rceNodeIdentifier);
} catch (NullPointerException e) {
log.error("");
// FIXME: log and warn
e = null;
} catch (AuthorizationException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
/**
* An {@link Action} that opens the data associated with the selected node with the TiGL Viewer.
*/
private final class OpenInTiglAction extends SelectionProviderAction {
private final String[] supportedFileExtensions = new String[] { "xml", "brep", "step", "stp", "iges", "igs", "stl", "mesh" };
private OpenInTiglAction(ISelectionProvider provider, String text) {
super(provider, text);
}
@Override
public void selectionChanged(IStructuredSelection selection) {
Object obj = selection.getFirstElement();
if (obj instanceof DMBrowserNode) {
DMBrowserNode node = (DMBrowserNode) obj;
if (node.isEnabled() && node.getType() == DMBrowserNodeType.DMFileResource
&& Arrays.asList(supportedFileExtensions)
.contains(FilenameUtils.getExtension(node.getAssociatedFilename()))) {
setEnabled(true);
return;
}
}
setEnabled(false);
}
@Override
public void run() {
if (!isEnabled()) {
return;
}
ISelection selection = viewer.getSelection();
Object object = ((IStructuredSelection) selection).getFirstElement();
if (object instanceof DMBrowserNode) {
DMBrowserNode node = (DMBrowserNode) object;
// if node type is workflow or directory prevent opening in viewer
if (node.getType() != DMBrowserNodeType.Workflow && node.getType() != DMBrowserNodeType.DMDirectoryReference) {
String dataReferenceId = node.getDataReferenceId();
String associatedFilename = node.getAssociatedFilename();
String fileReferencePath = node.getFileReferencePath();
if (associatedFilename == null) {
associatedFilename = "default";
}
// try to open in Viewer
DataManagementWorkbenchUtils.getInstance().tryOpenDataReferenceInReadonlyEditor(dataReferenceId, fileReferencePath,
associatedFilename, node.getNodeWithTypeWorkflow().getNodeIdentifier(), true);
// ok -> return
return;
}
}
}
}
/**
* An {@link Action} to delete data management entries.
*
* @author Christian Weiss
*
*/
private final class CustomDeleteAction extends SelectionProviderAction {
private final List<DMBrowserNode> selectedNodes = new LinkedList<DMBrowserNode>();
private Display display;
private final List<DMBrowserNodeType> deletableNodeTypes = new ArrayList<DMBrowserNodeType>();
private boolean hasNotFinishedWorkflows;
private boolean isFileAction;
/*
* Set all deletable DMBrowserNodeTypes.
*/
{
deletableNodeTypes.add(DMBrowserNodeType.Workflow);
}
private CustomDeleteAction(ISelectionProvider provider, String text, boolean isFileAction) {
super(provider, text);
this.isFileAction = isFileAction;
}
@Override
public void selectionChanged(final IStructuredSelection selection) {
// clear the old selection
selectedNodes.clear();
boolean enabled = fileDataService != null && !selection.isEmpty();
hasNotFinishedWorkflows = false;
if (enabled) {
@SuppressWarnings("unchecked") final Iterator<DMBrowserNode> iter = selection.iterator();
while (iter.hasNext()) {
DMBrowserNode selectedNode = iter.next();
if (deletableNodeTypes.contains(selectedNode.getType())) {
boolean hasfinalState =
selectedNode.getMetaData() != null
&& selectedNode.getMetaData().getValue(META_DATA_WORKFLOW_FINAL_STATE) != null;
boolean hasDataReferences =
!Boolean.valueOf(selectedNode.getMetaData().getValue(METADATA_WORKFLOW_FILES_DELETED));
boolean isMarkedForDeletion =
Boolean.valueOf(selectedNode.getMetaData().getValue(METADATA_WORKFLOW_IS_MARKED_FOR_DELETION));
if (hasfinalState && !isMarkedForDeletion && (hasDataReferences || !isFileAction)) {
selectedNodes.add(selectedNode);
}
hasNotFinishedWorkflows |= !hasfinalState;
} else {
enabled = false;
}
}
enabled &= !selectedNodes.isEmpty();
// store the Display to refresh the tree viewer in 'run'
display = Display.getCurrent();
}
setEnabled(enabled);
}
@Override
public void run() {
final List<DMBrowserNode> browserNodesToDelete = new LinkedList<DMBrowserNode>(
selectedNodes);
String jobTitle;
if (isFileAction) {
jobTitle = StringUtils.format(Messages.jobTitleDeleteFiles,
browserNodesToDelete.size(),
browserNodesToDelete.toString());
} else {
jobTitle = StringUtils.format(Messages.jobTitleDelete,
browserNodesToDelete.size(),
browserNodesToDelete.toString());
}
final Job job = new Job(jobTitle) {
@Override
protected IStatus run(IProgressMonitor monitor) {
for (final DMBrowserNode browserNodeToDelete : browserNodesToDelete) {
// get the parent node of the node to update the tree
// and remove the deleted child node
final DMBrowserNode parentNode = browserNodeToDelete
.getParent();
if (!isFileAction) {
boolean deleted = deleteWorkflowRun(browserNodeToDelete);
if (deleted) {
parentNode.removeChild(browserNodeToDelete);
}
} else {
deleteFiles(browserNodeToDelete);
setEnabled(false);
display.syncExec(new Runnable() {
@Override
public void run() {
refresh(browserNodeToDelete);
}
});
}
}
if (!isFileAction) {
// update the tree
display.syncExec(new Runnable() {
@Override
public void run() {
refresh();
}
});
}
// return OK as status
return Status.OK_STATUS;
}
private void deleteFiles(DMBrowserNode browserNode) {
contentProvider.deleteWorkflowRunFiles(browserNode);
}
private boolean deleteWorkflowRun(final DMBrowserNode browserNode) {
return contentProvider.deleteWorkflowRun(browserNode);
}
};
// job is a UI task
job.setUser(true);
boolean schedule = true;
final Shell shell = Display.getCurrent().getActiveShell();
String dialogMessage;
String dialogTitle;
if (!isFileAction) {
dialogTitle = Messages.dialogTitleDelete;
if (hasNotFinishedWorkflows) {
dialogMessage = Messages.dialogMessageDeleteWithNotDeletableNodes;
} else {
dialogMessage = Messages.dialogMessageDelete;
}
} else {
dialogTitle = Messages.dialogTitleDeleteFiles;
if (hasNotFinishedWorkflows) {
dialogMessage = Messages.dialogMessageDeleteFilesWithNotDeletableNodes;
} else {
dialogMessage = Messages.dialogMessageDeleteFiles;
}
}
if (!MessageDialog.openConfirm(shell, dialogTitle, dialogMessage)) {
schedule = false;
}
if (schedule) {
job.schedule();
}
}
}
/**
* An {@link Action} that opens the data associated with the selected node in a read-only editor.
*/
private final class OpenInEditorAction extends SelectionProviderAction {
private OpenInEditorAction(ISelectionProvider provider, String text) {
super(provider, text);
}
@Override
public void selectionChanged(IStructuredSelection selection) {
Object obj = selection.getFirstElement();
if (obj instanceof DMBrowserNode) {
DMBrowserNode node = (DMBrowserNode) obj;
if (node.isEnabled()
&& (node.getType() == DMBrowserNodeType.Boolean
|| node.getType() == DMBrowserNodeType.CommonText
|| node.getType() == DMBrowserNodeType.DMFileResource
|| node.getType() == DMBrowserNodeType.File
|| node.getType() == DMBrowserNodeType.Float
|| node.getType() == DMBrowserNodeType.Integer
|| node.getType() == DMBrowserNodeType.ShortText
|| node.getType() == DMBrowserNodeType.SmallTable
|| node.getType() == DMBrowserNodeType.Matrix
|| node.getType() == DMBrowserNodeType.Vector)) {
setEnabled(true);
return;
}
}
setEnabled(false);
}
@Override
public void run() {
if (!isEnabled()) {
return;
}
ISelection selection = viewer.getSelection();
Object object = ((IStructuredSelection) selection).getFirstElement();
if (object instanceof DMBrowserNode) {
DMBrowserNode node = (DMBrowserNode) object;
// if node type is workflow or directory prevent opening in text editor
if (node.getType() != DMBrowserNodeType.Workflow && node.getType() != DMBrowserNodeType.DMDirectoryReference) {
String dataReferenceId = node.getDataReferenceId();
String associatedFilename = node.getAssociatedFilename();
String fileReferencePath = node.getFileReferencePath();
if (associatedFilename == null) {
associatedFilename = "default";
}
// try to open in editor
DataManagementWorkbenchUtils.getInstance().tryOpenDataReferenceInReadonlyEditor(dataReferenceId, fileReferencePath,
associatedFilename, node.getNodeWithTypeWorkflow().getNodeIdentifier(), false);
// ok -> return
return;
}
}
}
}
/**
* An {@link Action} that triggers a refresh of the selected node.
*
*/
private final class RefreshNodeAction extends SelectionProviderAction {
private final List<DMBrowserNode> selectedNodes = new LinkedList<DMBrowserNode>();
private final List<DMBrowserNodeType> refreshableNodes = new ArrayList<DMBrowserNodeType>();
/*
* Whitelist: Nodes which can be refreshed.
*/
{
refreshableNodes.add(DMBrowserNodeType.Workflow);
refreshableNodes.add(DMBrowserNodeType.Timeline);
refreshableNodes.add(DMBrowserNodeType.Components);
refreshableNodes.add(DMBrowserNodeType.WorkflowRunInformation);
}
private RefreshNodeAction(ISelectionProvider provider, String text) {
super(provider, text);
}
@Override
public void selectionChanged(final IStructuredSelection selection) {
boolean enabled = !selection.isEmpty();
selectedNodes.clear();
// refresh node, if only one is selected
if (enabled) {
// clear the old selection
@SuppressWarnings("unchecked") final Iterator<DMBrowserNode> iter = selection.iterator();
while (iter.hasNext()) {
DMBrowserNode selectedNode = iter.next();
if (refreshableNodes.contains(selectedNode.getType())) {
selectedNodes.add(selectedNode);
} else {
enabled = false;
}
}
enabled &= !selectedNodes.isEmpty();
}
setEnabled(enabled);
}
@Override
public void run() {
for (final DMBrowserNode node : selectedNodes) {
refresh(node);
}
}
}
/**
* An {@link Action} that opens the timeline view for a workflow.
*
*/
private final class OpenTimelineViewAction extends SelectionProviderAction {
private DMBrowserNode nodeSelected;
private OpenTimelineViewAction(ISelectionProvider provider, String text) {
super(provider, text);
}
@Override
public void selectionChanged(IStructuredSelection selection) {
Object obj = selection.getFirstElement();
if (selection.size() == 1 && obj instanceof DMBrowserNode) {
nodeSelected = (DMBrowserNode) obj;
if (nodeSelected.getType() == DMBrowserNodeType.Workflow
|| nodeSelected.getType() == DMBrowserNodeType.WorkflowRunInformation
|| nodeSelected.getType() == DMBrowserNodeType.Timeline
|| nodeSelected.getType() == DMBrowserNodeType.Components) {
setEnabled(true);
return;
}
}
setEnabled(false);
}
@Override
public void run() {
try {
final IViewPart view = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().
showView("de.rcenvironment.gui.Timeline", nodeSelected.getNodeWithTypeWorkflow().getWorkflowID(),
IWorkbenchPage.VIEW_ACTIVATE);
((TimelineView) view).initialize(Long.parseLong(nodeSelected.getNodeWithTypeWorkflow().getWorkflowID()),
nodeSelected.getNodeWithTypeWorkflow().getWorkflowControllerNode());
} catch (PartInitException e) {
log.error("Failed to open timeline view for workflow: " + nodeSelected.getName(), e);
}
}
}
/**
* An {@link Action} that copies the title of the workflow node if it is of type DMBrowserNodeType.InformationText.
*
*/
private final class CopyNodeTitleAction extends SelectionProviderAction {
private DMBrowserNode nodeSelected;
private CopyNodeTitleAction(ISelectionProvider provider, String text) {
super(provider, text);
}
@Override
public void selectionChanged(IStructuredSelection selection) {
Object obj = selection.getFirstElement();
if (selection.size() == 1 && obj instanceof DMBrowserNode) {
nodeSelected = (DMBrowserNode) obj;
if (nodeSelected.getType() == DMBrowserNodeType.InformationText) {
setEnabled(true);
return;
}
}
setEnabled(false);
}
@Override
public void run() {
String nodeTitle = nodeSelected.getTitle();
if (nodeTitle.matches(".*: .*")) {
nodeTitle = nodeTitle.split(": ")[1];
}
ClipboardHelper.setContent(nodeTitle);
}
}
/**
* An {@link Action} that collapses all nodes.
*
* @author Christian Weiss
*/
private final class CollapseAllNodesAction extends Action {
CollapseAllNodesAction(String text) {
super(text);
}
@Override
public void run() {
viewer.collapseAll();
expandedNodes = new Object[] {};
}
}
/**
* An {@link Action} that triggers the different sort actions.
*
*/
private final class CustomSortAction extends SelectionProviderAction {
private final List<DMBrowserNode> selectedNodes = new LinkedList<DMBrowserNode>();
private final int sortingType;
private CustomSortAction(ISelectionProvider provider, String text, int sortingType) {
super(provider, text);
this.sortingType = sortingType;
setChecked(treeSorter.getSortingType() == sortingType);
}
@Override
public void selectionChanged(final IStructuredSelection selection) {
// clear the old selection
selectedNodes.clear();
boolean enabled = true;
Object obj = selection.getFirstElement();
if (obj instanceof DMBrowserNode) {
DMBrowserNode node = (DMBrowserNode) obj;
enabled = treeSorter.isSortable(node, sortingType);
if (enabled) {
@SuppressWarnings("unchecked") final Iterator<DMBrowserNode> iter = selection.iterator();
while (iter.hasNext()) {
DMBrowserNode selectedNode = iter.next();
selectedNodes.add(selectedNode);
}
enabled &= !selectedNodes.isEmpty();
}
}
setEnabled(enabled);
setChecked((selectedNodes.isEmpty() || containsNodeTypeWorkflow(selectedNodes))
&& treeSorter.getSortingType() == sortingType);
}
@Override
public void run() {
if (selectedNodes.isEmpty() || containsNodeTypeWorkflow(selectedNodes)) {
treeSorter.setSortingType(sortingType);
treeSorter.enableSorting(true);
viewer.refresh();
setSortActionsChecked();
} else {
for (DMBrowserNode node : selectedNodes) {
if (treeSorter.isSortable(node, sortingType) && node.areChildrenKnown()) {
treeSorter.enableSorting(false);
setComparator(node);
setChecked(false);
viewer.refresh(node);
}
}
}
}
private boolean containsNodeTypeWorkflow(List<DMBrowserNode> nodes) {
for (DMBrowserNode node : nodes) {
if (node.getType().equals(DMBrowserNodeType.Workflow)) {
return true;
}
}
return false;
}
private void setSortActionsChecked() {
sortAscendingName.setChecked(treeSorter.getSortingType() == DMTreeSorter.SORT_BY_NAME_ASC);
sortDescendingName.setChecked(treeSorter.getSortingType() == DMTreeSorter.SORT_BY_NAME_DESC);
sortTimestampAsc.setChecked(treeSorter.getSortingType() == DMTreeSorter.SORT_BY_TIMESTAMP);
sortTimestampDesc.setChecked(treeSorter.getSortingType() == DMTreeSorter.SORT_BY_TIMESTAMP_DESC);
}
private void setComparator(DMBrowserNode node) {
switch (sortingType) {
case DMTreeSorter.SORT_BY_TIMESTAMP:
node.sortChildren(DMBrowserNodeUtils.COMPARATOR_BY_HISTORY_TIMESTAMP);
break;
case DMTreeSorter.SORT_BY_NAME_ASC:
node.sortChildren(DMBrowserNodeUtils.COMPARATOR_BY_NODE_TITLE);
break;
case DMTreeSorter.SORT_BY_NAME_DESC:
node.sortChildren(DMBrowserNodeUtils.COMPARATOR_BY_NODE_TITLE_DESC);
break;
case DMTreeSorter.SORT_BY_TIMESTAMP_DESC:
node.sortChildren(DMBrowserNodeUtils.COMPARATOR_BY_HISTORY_TIMESTAMP_DESC);
break;
default:
break;
}
}
}
/**
* An {@link Action} to compare same data typs with each other.
*
* @author Christian Weiss
*
*/
private final class CustomCompareAction extends SelectionProviderAction {
private final List<DMBrowserNodeType> comparableNodeTypes = new ArrayList<DMBrowserNodeType>();
private DMBrowserNode node;
private DMBrowserNode node2;
/*
* Set all comparable DMBrowserNodeTypes.
*/
{
comparableNodeTypes.add(DMBrowserNodeType.DMFileResource);
// add comparable node typs like double, float...
}
protected CustomCompareAction(ISelectionProvider provider, String text) {
super(provider, text);
}
@Override
public void selectionChanged(final IStructuredSelection selection) {
if (selection.size() == 2) {
@SuppressWarnings("unchecked") final Iterator<DMBrowserNode> iter = selection.iterator();
Object obj = iter.next();
Object obj2 = iter.next();
if (obj instanceof DMBrowserNode && obj2 instanceof DMBrowserNode) {
node = (DMBrowserNode) obj;
node2 = (DMBrowserNode) obj2;
boolean compareEnabled = false;
if (comparableNodeTypes.contains(node.getType()) && comparableNodeTypes.contains(node2.getType())
&& node.getType() == node2.getType()) {
compareEnabled = true;
}
compareAction.setEnabled(compareEnabled);
}
} else {
compareAction.setEnabled(false);
}
}
@Override
public void run() {
if (node != null && node2 != null) {
String dataReferenceId = node.getDataReferenceId();
String associatedFilename = node.getAssociatedFilename();
String dataReferenceId2 = node2.getDataReferenceId();
String associatedFilename2 = node2.getAssociatedFilename();
if (dataReferenceId == null || dataReferenceId2 == null) {
return;
} else {
try {
final File left = TempFileServiceAccess.getInstance().createTempFileWithFixedFilename(associatedFilename);
final File right = TempFileServiceAccess.getInstance().createTempFileWithFixedFilename(associatedFilename2);
DataManagementService dataManagementService =
DataManagementWorkbenchUtils.getInstance().getDataManagementService();
dataManagementService.copyReferenceToLocalFile(
dataReferenceId, left,
node.getNodeWithTypeWorkflow().getNodeIdentifier());
dataManagementService.copyReferenceToLocalFile(
dataReferenceId2, right,
node.getNodeWithTypeWorkflow().getNodeIdentifier());
final CompareConfiguration cc = new CompareConfiguration();
cc.setLeftLabel(left.getName());
cc.setRightLabel(right.getName());
CompareUI.openCompareEditor(new FileCompareInput(cc, left, right));
} catch (IOException e) {
throw new RuntimeException(e.getCause());
} catch (CommunicationException e) {
throw new RuntimeException(StringUtils.format(
"Failed to copy data reference from remote node @%s to local file: ",
node.getNodeWithTypeWorkflow().getNodeIdentifier())
+ e.getMessage(), e);
}
}
}
}
}
/** A {@link KeyListener} to react on pressedkey's. */
private final class DataManagementKeyListener implements KeyListener {
@Override
public void keyPressed(KeyEvent event) {
if (event.stateMask == SWT.CTRL) {
if (event.keyCode == 'a') {
// add shortcut for select all action
viewer.getTree().selectAll();
getSite().getSelectionProvider().setSelection(viewer.getSelection());
} else if (event.keyCode == 'c' && copyAction.isEnabled()) {
// add shortcut for copy action
copyAction.run();
} else if (event.keyCode == 't' && timelineAction.isEnabled()) {
// add shortcut for open timeline action
timelineAction.run();
} else if (event.keyCode == SWT.F5 && refreshNodeAction.isEnabled()) {
// add shortcut for refresh selected action
refreshNodeAction.run();
}
} else if (event.keyCode == SWT.DEL) {
// add shortcut for delete action
if (deleteNodeAction.isEnabled()) {
deleteNodeAction.run();
}
} else if (event.keyCode == SWT.F5) {
// add shortcut for refresh all action
actionRefreshAll.run();
}
}
@Override
public void keyReleased(KeyEvent arg0) {}
}
/**
* The constructor.
*/
public DataManagementBrowser() {
serviceRegistryAccess = ServiceRegistry.createAccessFor(this);
}
/**
* Registers an event listener for network changes as an OSGi service (whiteboard pattern).
*
* @param display
*/
private void refresh(final DMBrowserNode node) {
// clear children of selected node
DMBrowserNode toRefresh = node.getNodeWithTypeWorkflow();
toRefresh.clearChildren();
contentProvider.clear(toRefresh);
if (viewer.getExpandedState(toRefresh)) {
expandedNodes = viewer.getVisibleExpandedElements();
viewer.refresh(toRefresh);
} else {
// Called in order to update the workflow node's title (update "not terminated yet") even if node is not expanded.
// viewer.refresh(toRefresh) doesn't do that. Actually, the children don't need to be fetched here, but I didn't find a proper
// way to just update the node title by using the RetrieverTask of DMContentProvider. I liked to use the RetrieverTask to make
// sure the "in progress" and error handling are performed as well so that nothing gets broken here. As a user usually expand
// the node after refresh, fetching the children is not for nothing
contentProvider.getChildren(toRefresh);
}
}
@Override
public void createPartControl(Composite parent) {
viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(DoubleClickEvent event) {
// TreeViewer viewer = (TreeViewer) event.getViewer();
IStructuredSelection thisSelection = (IStructuredSelection) event.getSelection();
Object selectedNode = thisSelection.getFirstElement();
viewer.setExpandedState(selectedNode, !viewer.getExpandedState(selectedNode));
}
});
viewer.getControl().addKeyListener(new DataManagementKeyListener());
drillDownAdapter = new DrillDownAdapter(viewer);
try {
contentProvider = new DMContentProvider();
contentProvider.addContentAvailabilityHandler(this);
viewer.setContentProvider(contentProvider);
} catch (AuthenticationException e) {
// FIXME
log.error(e);
}
ColumnViewerToolTipSupport.enableFor(viewer);
viewer.setLabelProvider(new DMLabelProvider());
treeSorter = new DMTreeSorter(DMTreeSorter.SORT_BY_TIMESTAMP_DESC);
viewer.setSorter(treeSorter);
getSite().setSelectionProvider(viewer);
// FIXME: re-enable?
// Create the help context id for the viewer's control
// PlatformUI.getWorkbench().getHelpSystem().setHelp(viewer.getControl(),"FIXME");
makeActions();
hookContextMenu();
hookDoubleClickAction();
contributeToActionBars();
initialize();
}
private void initialize() {
fileDataService = serviceRegistryAccess.getService(FileDataService.class);
refresh();
}
private DMBrowserNode createRootNode() {
DMBrowserNode rootNode = new DMBrowserNode(ROOT_NODE_TITLE);
rootNode.setType(DMBrowserNodeType.HistoryRoot);
return rootNode;
}
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu");
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager manager) {
DataManagementBrowser.this.fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
private void fillLocalPullDown(IMenuManager manager) {
manager.add(actionRefreshAll);
manager.add(new Separator());
manager.add(openInEditorAction);
}
private void fillContextMenu(IMenuManager manager) {
// submenu for sorting
MenuManager subMenuManager = new MenuManager(Messages.sorting);
subMenuManager.add(sortAscendingName);
subMenuManager.add(sortDescendingName);
subMenuManager.add(sortTimestampAsc);
subMenuManager.add(sortTimestampDesc);
manager.add(new Separator());
manager.add(openInEditorAction);
if (OS.isFamilyWindows()) {
manager.add(openTiglAction);
}
manager.add(refreshNodeAction);
manager.add(actionRefreshAll);
manager.add(new Separator());
// manager.add(autoRefreshAction);
manager.add(new Separator());
drillDownAdapter.addNavigationActions(manager);
manager.add(new Separator());
manager.add(subMenuManager);
manager.add(new Separator());
manager.add(copyAction);
manager.add(exportNodeAction);
manager.add(new Separator());
manager.add(deleteFilesAction);
manager.add(deleteNodeAction);
manager.add(new Separator());
manager.add(timelineAction);
manager.add(new Separator());
manager.add(compareAction);
manager.add(new Separator());
// Other plug-ins can contribute there actions here
// manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void fillLocalToolBar(IToolBarManager manager) {
manager.add(sortAscendingName);
manager.add(sortDescendingName);
manager.add(sortTimestampAsc);
manager.add(sortTimestampDesc);
manager.add(new Separator());
manager.add(refreshNodeAction);
manager.add(actionRefreshAll);
// manager.add(autoRefreshAction);
manager.add(collapseAllNodesAction);
manager.add(deleteNodeAction);
manager.add(new Separator());
drillDownAdapter.addNavigationActions(manager);
}
private void makeActions() {
final ISelectionProvider selectionProvider = getSite().getSelectionProvider();
// sort Actions: Ascending Name/Timestamp, Descending Name/Timestamp
sortAscendingName = new CustomSortAction(selectionProvider, Messages.sortUp, DMTreeSorter.SORT_BY_NAME_ASC);
sortAscendingName.setImageDescriptor(DMBrowserImages.IMG_SORT_ALPHABETICAL_ASC);
sortDescendingName = new CustomSortAction(selectionProvider, Messages.sortDown, DMTreeSorter.SORT_BY_NAME_DESC);
sortDescendingName.setImageDescriptor(DMBrowserImages.IMG_SORT_ALPHABETICAL_DESC);
sortTimestampAsc = new CustomSortAction(selectionProvider, Messages.sortTime, DMTreeSorter.SORT_BY_TIMESTAMP);
sortTimestampAsc.setImageDescriptor(DMBrowserImages.IMG_SORT_TIMESTAMP_ASC);
sortTimestampDesc = new CustomSortAction(selectionProvider, Messages.sortTimeDesc, DMTreeSorter.SORT_BY_TIMESTAMP_DESC);
sortTimestampDesc.setImageDescriptor(DMBrowserImages.IMG_SORT_TIMESTAMP_DESC);
compareAction = new CustomCompareAction(selectionProvider, Messages.compareMsg);
compareAction.setEnabled(false);
// refresh Actions: refresh a node or refresh all
makeRefreshActions(selectionProvider);
// an action to open a selected entry in a read-only editor
openInEditorAction = new OpenInEditorAction(selectionProvider, "Open in editor (read-only)");
openInEditorAction.setImageDescriptor(ImageManager.getInstance().getImageDescriptor(StandardImages.OPEN_READ_ONLY_16));
openTiglAction = new OpenInTiglAction(selectionProvider, "Open in TiGL Viewer");
openTiglAction.setImageDescriptor(ImageManager.getInstance().getImageDescriptor(StandardImages.TIGL_ICON));
doubleClickAction = openInEditorAction;
deleteNodeAction =
new CustomDeleteAction(selectionProvider, Messages.deleteNodeActionContextMenuLabel + Messages.shortcutDelete, false);
deleteNodeAction.setImageDescriptor(ImageManager.getInstance().getImageDescriptor(StandardImages.DELETE_16));
deleteNodeAction.setEnabled(false);
deleteFilesAction = new CustomDeleteAction(selectionProvider, Messages.deleteFilesActionContextMenuLabel, true);
deleteFilesAction.setImageDescriptor(DMBrowserImages.IMG_DESC_DELETE_FILES);
deleteFilesAction.setEnabled(false);
exportNodeAction = new CustomExportAction(selectionProvider, Messages.saveNodeActionContextMenuLabel);
exportNodeAction.setImageDescriptor(ImageManager.getInstance().getImageDescriptor(StandardImages.EXPORT_16));
collapseAllNodesAction = new CollapseAllNodesAction(Messages.collapseAllNodesActionContextMenuLabel);
collapseAllNodesAction.setImageDescriptor(DMBrowserImages.IMG_DESC_COLLAPSE_ALL);
timelineAction = new OpenTimelineViewAction(selectionProvider, "Show Timeline");
timelineAction.setImageDescriptor(ImageDescriptor.createFromImage(DMBrowserImages.IMG_TIMELINE));
timelineAction.setEnabled(false);
copyAction = new CopyNodeTitleAction(selectionProvider, "Copy");
copyAction.setImageDescriptor(ImageDescriptor.createFromImage(ImageManager.getInstance().getSharedImage(StandardImages.COPY_16)));
copyAction.setEnabled(false);
}
private void makeRefreshActions(final ISelectionProvider selectionProvider) {
actionRefreshAll = new Action(Messages.refreshAllNodesActionContextMenuLabel + Messages.shortcutRefreshAll) {
@Override
public void run() {
refresh();
}
};
actionRefreshAll.setImageDescriptor(ImageManager.getInstance().getImageDescriptor(StandardImages.REFRESH_16));
refreshNodeAction =
new RefreshNodeAction(selectionProvider, Messages.refreshNodeActionContextMenuLabel + Messages.shortcutRefreshSelected);
refreshNodeAction.setImageDescriptor(DMBrowserImages.IMG_DESC_REFRESH_NODE);
refreshNodeAction.setEnabled(false);
}
private void refresh() {
contentProvider.clear();
// disable the widget
viewer.getTree().setEnabled(false);
// disable the action
// FIXME: ensure re-enabling upon errors
actionRefreshAll.setEnabled(false);
DMBrowserNode rootNode = (DMBrowserNode) viewer.getInput();
if (rootNode == null) {
rootNode = createRootNode();
viewer.setInput(rootNode);
} else {
rootNode.clearChildren();
}
expandedNodes = viewer.getVisibleExpandedElements();
viewer.getTree().setEnabled(true);
viewer.getTree().setFocus();
viewer.refresh();
}
private boolean mightHaveContent(final DMBrowserNode node) {
if (node.getDataReference() != null
|| node.getDataReferenceId() != null || node.getFileReferencePath() != null) {
return true;
}
if (node.areChildrenKnown()) {
return mightHaveContent(node.getChildren());
} else {
// if the child nodes are unknown, the current node *might* have
// content
return true;
}
}
private boolean mightHaveContent(final Collection<DMBrowserNode> nodes) {
boolean result = false;
for (final DMBrowserNode node : nodes) {
if (mightHaveContent(node)) {
result = true;
break;
}
}
return result;
}
private void hookDoubleClickAction() {
viewer.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(DoubleClickEvent event) {
if (event.getSelection() instanceof TreeSelection) {
TreeSelection sel = (TreeSelection) event.getSelection();
if (sel.getFirstElement() instanceof DMBrowserNode) {
DMBrowserNode node = (DMBrowserNode) sel.getFirstElement();
if (node.isLeafNode()) {
doubleClickAction.run();
}
}
}
}
});
}
/**
* Passing the focus request to the viewer's control.
*/
@Override
public void setFocus() {
viewer.getControl().setFocus();
}
/**
* @return list with the reachable host's
*/
private Set<InstanceNodeSessionId> registerWorkflowHostService() {
WorkflowHostService workflowHostService = serviceRegistryAccess.getService(WorkflowHostService.class);
return workflowHostService.getWorkflowHostNodes();
}
private boolean isWorkflowHostReachable(ResolvableNodeId nodeID) {
Set<InstanceNodeSessionId> registeredNodeID = registerWorkflowHostService();
for (InstanceNodeSessionId nodeIdentifier : registeredNodeID) {
if (nodeID.isSameInstanceNodeAs(nodeIdentifier)) {
return true;
}
}
return false;
}
private void disableUnreachableNode(final ResolvableNodeId unreachableID) {
for (TreeItem item : viewer.getTree().getItems()) {
DMBrowserNode node = (DMBrowserNode) item.getData();
ResolvableNodeId nodeID = node.getNodeIdentifier();
if (node.isEnabled() && nodeID.isSameInstanceNodeAs(unreachableID)) {
node.setTitle(StringUtils.format(NODE_TEXT_FORMAT_TITLE_PLUS_HOSTNAME, node.getTitle(),
"[offline]"));
disableNode(node);
}
}
}
private void disableNode(DMBrowserNode node) {
refreshNodeAction.setEnabled(false);
disableNodeWithoutRefresh(node);
if (viewer != null && !viewer.getControl().isDisposed()) {
viewer.refresh(node);
}
}
private void disableNodeWithoutRefresh(DMBrowserNode node) {
node.setType(DMBrowserNodeType.Workflow_Disabled);
node.markAsLeaf();
node.setEnabled(false);
}
@Override
public void handleContentAvailable(final DMBrowserNode node) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
if (viewer.getTree().isDisposed()) {
return;
}
viewer.refresh(node);
if (node == viewer.getInput()) {
viewer.getTree().setEnabled(true);
actionRefreshAll.setEnabled(true);
}
if (node.getType() != DMBrowserNodeType.HistoryRoot) {
DMBrowserNode workflowNode = node.getNodeWithTypeWorkflow();
if (workflowNode != null && !workflowNode.getWorkflowHostName().equals(LOCAL)
&& !isWorkflowHostReachable(workflowNode.getNodeIdentifier())) {
disableUnreachableNode(workflowNode.getNodeIdentifier());
}
}
for (final Object expNode : expandedNodes) {
if (node.getChildren().contains(expNode)) {
viewer.expandToLevel(expNode, 1);
}
}
if (node.getChildren().isEmpty()) {
viewer.setExpandedState(node, false);
}
}
});
}
@Override
public void handleContentRetrievalError(final DMBrowserNode node, final Exception cause) {
if (cause instanceof CommunicationException) {
// Since this type of exception can occur often during normal operation (e.g. remote node is offline) and is not an error, we do
// not print the whole stack trace.
log.warn("Retrieving data from data management failed: " + cause.getMessage());
} else {
log.error("Retrieving data from data management failed", cause);
}
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
/*
* No refresh of the node as a refresh would trigger another fetch which might result in the very same error.
*/
if (node == viewer.getInput()) {
viewer.getTree().setEnabled(true);
actionRefreshAll.setEnabled(true);
}
// disable workflow without showing error
findAndDisableRootnode(node);
}
});
};
// recursively browse parent nodes until history root is found
private void findAndDisableRootnode(DMBrowserNode node) {
if (node.getParent().getType() == DMBrowserNodeType.HistoryRoot) {
disableUnreachableNode(node.getNodeIdentifier());
} else {
findAndDisableRootnode(node.getParent());
}
}
/**
*
* An Item to compare.
*
* @author Sascha Zur
*/
private class FileCompareInput extends CompareEditorInput {
private File left;
private File right;
FileCompareInput(CompareConfiguration cc, File left, File right) {
super(cc);
this.left = left;
this.right = right;
}
@Override
protected Object prepareInput(IProgressMonitor arg0) throws InvocationTargetException, InterruptedException {
DiffNode result = new DiffNode(Differencer.CONFLICTING);
result.setAncestor(new CompareItem(left));
result.setLeft(new CompareItem(left));
result.setRight(new CompareItem(right));
return result;
}
}
/**
*
* One item for the comparison.
*
* @author Sascha Zur
*/
class CompareItem implements IStreamContentAccessor, ITypedElement, IModificationDate {
private File contents;
CompareItem(File f) {
this.contents = f;
}
@Override
public InputStream getContents() throws CoreException {
try {
return new ByteArrayInputStream(FileUtils.readFileToString(contents).getBytes());
} catch (IOException e) {
return null;
}
}
@Override
public long getModificationDate() {
return 0;
}
@Override
public Image getImage() {
return null;
}
@Override
public String getName() {
return null;
}
@Override
public String getType() {
return null;
}
}
}