blob: 22f815e0f50d773e58fc22b2144cbbc2fcaa65bf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 BSI Business Systems Integration AG.
* 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:
* BSI Business Systems Integration AG - initial API and implementation
******************************************************************************/
package org.eclipse.scout.sdk.ui.internal.extensions.technology;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.scout.commons.CollectionUtility;
import org.eclipse.scout.commons.EventListenerList;
import org.eclipse.scout.commons.TriState;
import org.eclipse.scout.sdk.Texts;
import org.eclipse.scout.sdk.jobs.OperationJob;
import org.eclipse.scout.sdk.operation.IOperation;
import org.eclipse.scout.sdk.ui.dialog.CheckableTreeSelectionDialog;
import org.eclipse.scout.sdk.ui.extensions.technology.IScoutTechnologyHandler;
import org.eclipse.scout.sdk.ui.extensions.technology.IScoutTechnologyResource;
import org.eclipse.scout.sdk.ui.fields.bundletree.CheckableTree;
import org.eclipse.scout.sdk.ui.fields.bundletree.ITreeNode;
import org.eclipse.scout.sdk.ui.fields.bundletree.TreeNode;
import org.eclipse.scout.sdk.ui.fields.bundletree.TreeUtility;
import org.eclipse.scout.sdk.ui.internal.ScoutSdkUi;
import org.eclipse.scout.sdk.util.typecache.IWorkingCopyManager;
import org.eclipse.scout.sdk.workspace.IScoutBundle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.model.IWorkbenchAdapter;
public class Technology implements Comparable<Technology> {
private static final String TREE_TYPE_BUNDLE = "bundle";
private static final String TREE_TYPE_RESOURCE = "resource";
private final String m_id, m_name, m_category;
private final ArrayList<IScoutTechnologyHandler> m_handlers;
private final EventListenerList m_eventListeners;
public Technology(String id, String name, String category) {
m_handlers = new ArrayList<IScoutTechnologyHandler>();
m_eventListeners = new EventListenerList();
m_id = id;
m_name = name;
m_category = category;
}
public void addSelectionChangedListener(ITechnologyListener listener) {
m_eventListeners.add(ITechnologyListener.class, listener);
}
public void removeSelectionChangedListener(ITechnologyListener listener) {
m_eventListeners.remove(ITechnologyListener.class, listener);
}
private void fireSelectionChanged(boolean newSelection) {
for (ITechnologyListener l : m_eventListeners.getListeners(ITechnologyListener.class)) {
try {
l.selectionChangeCompleted(newSelection);
}
catch (Exception e) {
ScoutSdkUi.logError("error during listener notification.", e);
}
}
}
public boolean setSelection(IScoutBundle project, boolean selected) throws CoreException {
// collect all resources from all handlers
HashSet<IScoutTechnologyResource> allResources = new HashSet<IScoutTechnologyResource>();
for (IScoutTechnologyHandler handler : getHandlers(project)) {
List<IScoutTechnologyResource> resources = handler.getModifactionResourceCandidates(project);
if (resources.size() > 0) {
for (IScoutTechnologyResource res : resources) {
res.setHandler(handler);
allResources.add(res);
}
}
}
// build resources tree
ITreeNode changesTree = getModificationResourcesTree(allResources.toArray(new IScoutTechnologyResource[allResources.size()]));
// create selection dialog
final CheckableTreeSelectionDialog dialog = new CheckableTreeSelectionDialog(Display.getDefault().getActiveShell(), changesTree,
Texts.get("ChangeTechnology"), Texts.get("TechnologyResourcesToModifyDesc"));
dialog.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (CheckableTreeSelectionDialog.PROP_CHECKED_NODES.equals(evt.getPropertyName())) {
boolean complete = false;
if (evt.getNewValue() instanceof ITreeNode[]) {
ITreeNode[] checkedNodes = (ITreeNode[]) evt.getNewValue();
complete = checkedNodes != null && checkedNodes.length > 0;
}
dialog.setComplete(complete);
}
}
});
dialog.setCheckedNodes(getDefaultSelectedNodes(changesTree));
if (dialog.open() == Dialog.OK) {
ITreeNode[] selectedNodes = dialog.getCheckedNodes();
if (selectedNodes != null && selectedNodes.length > 0) {
OperationJob job = new OperationJob(new P_ChangeSelectionOperation(selectedNodes, selected));
job.schedule();
}
return true;
}
return false;
}
private ITreeNode[] getDefaultSelectedNodes(ITreeNode root) {
HashSet<ITreeNode> ret = new HashSet<ITreeNode>();
collectDefaultSelection(root, ret);
return ret.toArray(new ITreeNode[ret.size()]);
}
private void collectDefaultSelection(ITreeNode node, Set<ITreeNode> collector) {
if (node.isVisible() && node.isCheckable()) {
if (node.getData() instanceof IScoutTechnologyResource) {
IScoutTechnologyResource res = (IScoutTechnologyResource) node.getData();
if (res.getDefaultSelection()) {
collector.add(node);
}
}
}
for (ITreeNode child : node.getChildren()) {
collectDefaultSelection(child, collector);
}
}
private ITreeNode getModificationResourcesTree(IScoutTechnologyResource[] resources) {
HashMap<String, ArrayList<IScoutTechnologyResource>> mapping = new HashMap<String, ArrayList<IScoutTechnologyResource>>();
for (IScoutTechnologyResource res : resources) {
ArrayList<IScoutTechnologyResource> list = mapping.get(res.getResource().getProject().getName());
if (list == null) {
list = new ArrayList<IScoutTechnologyResource>();
mapping.put(res.getResource().getProject().getName(), list);
}
list.add(res);
}
ITreeNode rootNode = new TreeNode(CheckableTree.TYPE_ROOT, "root");
rootNode.setVisible(false);
for (Entry<String, ArrayList<IScoutTechnologyResource>> bundle : mapping.entrySet()) {
if (bundle.getValue().size() > 0) {
ImageDescriptor bundleImage = bundle.getValue().get(0).getBundleImage();
ITreeNode bundleNode = TreeUtility.createNode(rootNode, TREE_TYPE_BUNDLE, bundle.getKey(), bundleImage, 0, null, true, false);
for (IScoutTechnologyResource res : bundle.getValue()) {
if (res.getResource().exists()) {
IWorkbenchAdapter wbAdapter = (IWorkbenchAdapter) res.getResource().getAdapter(IWorkbenchAdapter.class);
ImageDescriptor imageDescriptor = null;
if (wbAdapter != null) {
imageDescriptor = wbAdapter.getImageDescriptor(res.getResource());
}
TreeUtility.createNode(bundleNode, TREE_TYPE_RESOURCE, res.getResource().getName(), imageDescriptor, 0, res, false, true);
}
}
}
}
return rootNode;
}
private List<IScoutTechnologyHandler> getHandlers(IScoutBundle project) {
ArrayList<IScoutTechnologyHandler> ret = new ArrayList<IScoutTechnologyHandler>(m_handlers.size());
for (IScoutTechnologyHandler h : m_handlers) {
if (h.isActive(project)) {
ret.add(h);
}
}
return ret;
}
public boolean isActive(IScoutBundle project) {
return getHandlers(project).size() > 0;
}
public TriState getSelection(IScoutBundle project) throws CoreException {
List<IScoutTechnologyHandler> handlers = getHandlers(project);
if (handlers.size() == 0) {
throw new InvalidParameterException("At least one handler must be defined for a technology");
}
TriState ret = handlers.get(0).getSelection(project);
for (int i = 1; i < handlers.size(); i++) {
TriState selection = handlers.get(i).getSelection(project);
if (selection != null) {
if (ret == null) {
ret = selection;
}
else if (ret != selection) {
return TriState.UNDEFINED;
}
}
}
if (ret == null) {
return TriState.UNDEFINED;
}
return ret;
}
public String getName() {
return m_name;
}
public String getId() {
return m_id;
}
public String getCategory() {
return m_category;
}
public void addAllHandlers(Collection<IScoutTechnologyHandler> c) {
if (c == null || c.size() == 0) {
return;
}
m_handlers.addAll(c);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Technology)) {
return false;
}
Technology other = (Technology) obj;
return m_id.equals(other.m_id) && m_category.equals(other.m_category) && m_name.equals(other.m_name);
}
@Override
public int hashCode() {
int hash = m_id.hashCode();
hash ^= m_category.hashCode();
hash ^= m_name.hashCode();
return hash;
}
@Override
public int compareTo(Technology o) {
int ret = m_category.compareTo(o.m_category);
if (ret == 0) {
ret = m_name.compareTo(o.m_name);
if (ret == 0) {
return m_id.compareTo(o.m_id);
}
else {
return ret;
}
}
else {
return ret;
}
}
private final class P_ChangeSelectionOperation implements IOperation {
private final ITreeNode[] m_selectedNodes;
private final boolean m_newSelection;
private boolean m_success;
private P_ChangeSelectionOperation(ITreeNode[] selectedNodes, boolean newSelection) {
m_selectedNodes = selectedNodes;
m_newSelection = newSelection;
m_success = false; // nothing done yet
}
@Override
public void run(IProgressMonitor monitor, IWorkingCopyManager workingCopyManager) throws CoreException {
try {
// map the checked resources to the contributing handler
HashMap<IScoutTechnologyHandler, HashSet<IScoutTechnologyResource>> resourcesToModify = new HashMap<IScoutTechnologyHandler, HashSet<IScoutTechnologyResource>>();
for (ITreeNode selectedNode : m_selectedNodes) {
if (selectedNode.isVisible() && selectedNode.getData() instanceof IScoutTechnologyResource) {
IScoutTechnologyResource res = (IScoutTechnologyResource) selectedNode.getData();
HashSet<IScoutTechnologyResource> set = resourcesToModify.get(res.getHandler());
if (set == null) {
set = new HashSet<IScoutTechnologyResource>();
resourcesToModify.put(res.getHandler(), set);
}
set.add(res);
}
}
monitor.beginTask(getOperationName(), resourcesToModify.size() * 3);
// fire pre-selection changed for all checked resources (each handler only gets the resources that were contributed by itself)
for (Entry<IScoutTechnologyHandler, HashSet<IScoutTechnologyResource>> entry : resourcesToModify.entrySet()) {
try {
if (!entry.getKey().preSelectionChanged(CollectionUtility.hashSet(entry.getValue()), m_newSelection, new SubProgressMonitor(monitor, 1))) {
return; // cancel the execution if a handler requests an abort
}
}
catch (CoreException e) {
ScoutSdkUi.logError("Error while preparing technology changes.", e);
return; // cancel further processing
}
monitor.worked(1);
}
// fire selection changed for all checked resources (each handler only gets the resources that were contributed by itself)
for (Entry<IScoutTechnologyHandler, HashSet<IScoutTechnologyResource>> entry : resourcesToModify.entrySet()) {
try {
entry.getKey().selectionChanged(CollectionUtility.hashSet(entry.getValue()), m_newSelection, new SubProgressMonitor(monitor, 1), workingCopyManager);
}
catch (CoreException e) {
ScoutSdkUi.logError("Error while applying technology changes.", e);
return; // cancel further processing
}
monitor.worked(1);
}
// fire post-selection changed for all checked resources (each handler only gets the resources that were contributed by itself)
for (Entry<IScoutTechnologyHandler, HashSet<IScoutTechnologyResource>> entry : resourcesToModify.entrySet()) {
try {
entry.getKey().postSelectionChanged(m_newSelection, new SubProgressMonitor(monitor, 1));
}
catch (CoreException e) {
ScoutSdkUi.logError("Error while finishing technology changes.", e);
return; // cancel further processing
}
monitor.worked(1);
}
m_success = true;
}
finally {
final boolean wasSuccessful = m_success;
ScoutSdkUi.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
// only change the selection if it was successful. otherwise the selection keeps the old value
fireSelectionChanged(wasSuccessful == m_newSelection);
}
});
monitor.done();
}
}
@Override
public String getOperationName() {
return "Changing Technology Selection '" + getName() + "'...";
}
@Override
public void validate() {
}
}
}