/******************************************************************************* * Copyright (c) 2012, 2014 Wind River Systems, Inc. and others. 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: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.tcf.te.launch.ui.model; import java.util.ArrayList; import java.util.Arrays; import java.util.EventObject; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.Assert; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationListener; import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.tcf.te.launch.core.bindings.LaunchConfigTypeBindingsManager; import org.eclipse.tcf.te.launch.core.interfaces.IReferencedProjectItem; import org.eclipse.tcf.te.launch.core.lm.interfaces.ICommonLaunchAttributes; import org.eclipse.tcf.te.launch.core.persistence.DefaultPersistenceDelegate; import org.eclipse.tcf.te.launch.core.persistence.launchcontext.LaunchContextsPersistenceDelegate; import org.eclipse.tcf.te.launch.core.persistence.projects.ReferencedProjectItem; import org.eclipse.tcf.te.launch.core.persistence.projects.ReferencedProjectsPersistenceDelegate; import org.eclipse.tcf.te.launch.core.selection.LaunchSelection; import org.eclipse.tcf.te.launch.core.selection.ProjectSelectionContext; import org.eclipse.tcf.te.launch.core.selection.RemoteSelectionContext; import org.eclipse.tcf.te.runtime.events.ChangeEvent; import org.eclipse.tcf.te.runtime.events.EventManager; import org.eclipse.tcf.te.runtime.interfaces.events.IEventListener; import org.eclipse.tcf.te.runtime.model.interfaces.IContainerModelNode; import org.eclipse.tcf.te.runtime.model.interfaces.IModelNode; import org.eclipse.tcf.te.ui.views.Managers; import org.eclipse.tcf.te.ui.views.interfaces.ICategory; /** * LaunchModel */ public final class LaunchModel implements IEventListener, ILaunchConfigurationListener { private static final Map<Object,LaunchModel> models = new HashMap<Object, LaunchModel>(); private static final Map<String,String> nameToUUID = new HashMap<String, String>(); /** * Get the launch model of the rootNode. * If it does not exist yet, create a new instance and store it. * * @param rootNode The rootNode of the model. * @return The launch model. */ public static LaunchModel getLaunchModel(final Object modelRoot) { if (modelRoot instanceof ICategory || modelRoot instanceof IModelNode || modelRoot instanceof IProject) { LaunchModel model = models.get(modelRoot); if (model == null) { model = new LaunchModel(modelRoot); models.put(modelRoot, model); } return model; } return null; } private final LaunchNode rootNode; private final Object modelRoot; private String lastAddedUUID = null; /** * Constructor. */ private LaunchModel(Object modelRoot) { Assert.isNotNull(modelRoot); this.modelRoot = modelRoot; rootNode = new LaunchNode(this); refresh(); DebugPlugin.getDefault().getLaunchManager().addLaunchConfigurationListener(this); if (modelRoot instanceof ICategory) { EventManager.getInstance().addEventListener(this, ChangeEvent.class); } } /* (non-Javadoc) * @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationRemoved(org.eclipse.debug.core.ILaunchConfiguration) */ @Override public void launchConfigurationRemoved(ILaunchConfiguration configuration) { if (!configuration.isWorkingCopy()) { if (getModelRoot() instanceof ICategory) { if (!getCategoryId(configuration).equals(lastAddedUUID)) { Managers.getCategoryManager().remove(((ICategory)getModelRoot()).getId(), getCategoryId(configuration)); } nameToUUID.remove(configuration.getName()); lastAddedUUID = null; } if (refresh()) { EventManager.getInstance().fireEvent(new ChangeEvent(this, ChangeEvent.ID_REMOVED, null, null)); } } } /* (non-Javadoc) * @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationChanged(org.eclipse.debug.core.ILaunchConfiguration) */ @Override public void launchConfigurationChanged(ILaunchConfiguration configuration) { if (!configuration.isWorkingCopy()) { refresh(); EventManager.getInstance().fireEvent(new ChangeEvent(this, ChangeEvent.ID_CHANGED, null, null)); } } /* (non-Javadoc) * @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationAdded(org.eclipse.debug.core.ILaunchConfiguration) */ @Override public void launchConfigurationAdded(ILaunchConfiguration configuration) { if (!configuration.isWorkingCopy()) { if (getModelRoot() instanceof ICategory) { if (Managers.getCategoryManager().belongsTo(((ICategory)getModelRoot()).getId(), getCategoryId(configuration))) { lastAddedUUID = getCategoryId(configuration); } } if (refresh()) { EventManager.getInstance().fireEvent(new ChangeEvent(this, ChangeEvent.ID_ADDED, null, null)); } } } /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.interfaces.events.IEventListener#eventFired(java.util.EventObject) */ @Override public void eventFired(EventObject event) { if (event instanceof ChangeEvent) { ChangeEvent e = (ChangeEvent)event; if (e.getSource() instanceof ICategory && ((e.getNewValue() instanceof String && ((String)e.getNewValue()).startsWith(LaunchNode.class.getName())) || (e.getOldValue() instanceof String && ((String)e.getOldValue()).startsWith(LaunchNode.class.getName())))) { if (refresh()) { EventManager.getInstance().fireEvent(new ChangeEvent(this, ((ChangeEvent)event).getEventId(), null, null)); } } } } /** * Return the root node of the model tree. */ public LaunchNode getRootNode() { return rootNode; } /** * Return the model root (IModelNode, IProject, ICategory). */ public Object getModelRoot() { return modelRoot; } /** * Refresh the model. * @return <code>true</code> if the model has changed. */ public boolean refresh() { boolean changed = false; Object parent = rootNode.getModel().getModelRoot(); String[] typeIds = new String[0]; if (parent instanceof ICategory) { List<String> ids = new ArrayList<String>(); for (ILaunchConfigurationType type : DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationTypes()) { ids.add(type.getIdentifier()); } typeIds = ids.toArray(new String[ids.size()]); } if (parent instanceof IProject) { typeIds = LaunchConfigTypeBindingsManager.getInstance().getValidLaunchConfigTypes( new LaunchSelection(null, new ProjectSelectionContext((IProject)parent, true))); } else if (parent instanceof IModelNode) { typeIds = LaunchConfigTypeBindingsManager.getInstance().getValidLaunchConfigTypes( new LaunchSelection(null, new RemoteSelectionContext((IModelNode)parent, true))); } List<IModelNode> typeNodes = new ArrayList<IModelNode>(Arrays.asList(rootNode.getChildren())); for (String typeId : typeIds) { ILaunchConfigurationType type = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationType(typeId); if (type.isPublic()) { IModelNode typeNode = find(type, typeNodes); if (typeNode != null) { typeNodes.remove(typeNode); } else { typeNode = new LaunchNode(type); rootNode.add(typeNode); changed = true; } ILaunchConfiguration[] configs; try { configs = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(type); } catch (Exception e) { configs = new ILaunchConfiguration[0]; } List<IModelNode> configNodes = new ArrayList<IModelNode>(Arrays.asList(((IContainerModelNode)typeNode).getChildren())); for (ILaunchConfiguration config : configs) { if (parent instanceof ICategory) { if (Managers.getCategoryManager().belongsTo(((ICategory)parent).getId(), getCategoryId(config))) { changed |= checkAndAdd(config, (IContainerModelNode)typeNode, configNodes); } } else if (parent instanceof IModelNode) { IModelNode[] contexts = LaunchContextsPersistenceDelegate.getLaunchContexts(config); if (contexts != null && Arrays.asList(contexts).contains(parent)) { changed |= checkAndAdd(config, (IContainerModelNode)typeNode, configNodes); } } else if (parent instanceof IProject) { IReferencedProjectItem[] projects = ReferencedProjectsPersistenceDelegate.getReferencedProjects(config); IReferencedProjectItem project = new ReferencedProjectItem(); project.setProperty(IReferencedProjectItem.PROPERTY_PROJECT_NAME, ((IProject)parent).getName()); if (projects != null && Arrays.asList(projects).contains(project)) { changed |= checkAndAdd(config, (IContainerModelNode)typeNode, configNodes); } } } for (IModelNode configToDelete : configNodes) { ((IContainerModelNode)typeNode).remove(configToDelete, true); changed = true; } if (parent instanceof ICategory && typeNode.isEmpty()) { typeNodes.add(typeNode); } } } for (IModelNode typeToDelete : typeNodes) { rootNode.remove(typeToDelete, true); changed = true; } return changed; } private boolean checkAndAdd(ILaunchConfiguration config, IContainerModelNode typeNode, List<IModelNode> configNodes) { IModelNode configNode = find(config, configNodes); if (configNode != null) { configNodes.remove(configNode); } else { configNode = new LaunchNode(config); typeNode.add(configNode); return true; } return false; } private IModelNode find(ILaunchConfiguration config, List<IModelNode> list) { for (IModelNode candidate : list) { if (candidate instanceof LaunchNode) { LaunchNode node = new LaunchNode(config); node.setProperty(LaunchNode.PROPERTY_MODEL, this); if (((LaunchNode)candidate).equals(node)) { return candidate; } } } return null; } private IModelNode find(ILaunchConfigurationType type, List<IModelNode> list) { for (IModelNode candidate : list) { if (candidate instanceof LaunchNode) { LaunchNode node = new LaunchNode(type); node.setProperty(LaunchNode.PROPERTY_MODEL, this); if (((LaunchNode)candidate).equals(node)) { return candidate; } } } return null; } /** * Get the unique category id for this launch config. * @param config The launch configuration. * @return The unique category id. */ public static String getCategoryId(ILaunchConfiguration config) { String uuid = DefaultPersistenceDelegate.getAttribute(config, ICommonLaunchAttributes.ATTR_UUID, (String)null); if (uuid == null) { uuid = nameToUUID.get(config.getName()); } if (uuid != null && !nameToUUID.containsKey(config.getName())) { nameToUUID.put(config.getName(), uuid); } return LaunchNode.class.getName() + "." + (uuid != null ? uuid : config.getName()); //$NON-NLS-1$ } }