blob: 2dd8d3d37b5454b1268bc7a0cfbc6d4e9c1e1827 [file] [log] [blame]
// GeographicViewer.java
package org.eclipse.stem.ui.views.geographic;
/*******************************************************************************
* Copyright (c) 2007 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.stem.jobs.simulation.ISimulation;
import org.eclipse.stem.jobs.simulation.ISimulationManagerListener;
import org.eclipse.stem.jobs.simulation.SimulationManager;
import org.eclipse.stem.jobs.simulation.SimulationManagerEvent;
import org.eclipse.stem.ui.views.IContextMenuUpdatesListener;
import org.eclipse.stem.ui.views.geographic.map.MapRenderer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
/**
* This class presents "views" of the running simulations.
*/
public class GeographicViewer extends Viewer implements
ISelectionChangedListener, ISimulationManagerListener {
/**
* This is the collection of
* {@link org.eclipse.stem.jobs.simulation.Simulation}s that should be
* displayed.
*/
private final Set<ISimulation> simulationsToDisplay = new LinkedHashSet<ISimulation>();
/**
* This is the {@link SimulationManager} that is the input to the viewer. It
* maintains a collection of active
* {@link org.eclipse.stem.jobs.simulation.Simulation}s in the system.
* This viewer listens to it to discover when new
* {@link org.eclipse.stem.jobs.simulation.Simulation}s are created and
* old ones disappear.
*
* @see #simulationsChanged(SimulationManagerEvent)
*/
private SimulationManager simulationManager;
/**
* The <code>Identifiable</code> that was most recently selected by a user
* clicking on one of the
* {@link org.eclipse.stem.ui.views.geographic.map.MapControl}s, or
* <code>null</code> if none has been selected.
*/
private ISelection selection = null;
/**
* This is the top-level control of the viewer. It contains the
* {@link org.eclipse.stem.ui.views.geographic.map.MapControl}s that
* display the current state of the
* {@link org.eclipse.stem.jobs.simulation.Simulation}s.
*/
private Composite composite;
/**
* This factory is used to create instances of {@link GeographicControl} in
* the method {@link #populateView()}
*/
private GeographicControlFactory gcf;
/**
* This is a list of listeners to get notifications about newly generated
* context menus.
*/
private List<IContextMenuUpdatesListener> contextMenuUpdateListeners = new ArrayList<IContextMenuUpdatesListener>();
/**
* @param parent
* the SWT parent of the control that makes up the viewer
* @param gcf
* the factory that creates instance of {@link GeographicControl}
*/
public GeographicViewer(Composite parent, GeographicControlFactory gcf) {
composite = new Composite(parent, SWT.NONE);
final FillLayout compositeLayout = new FillLayout(SWT.HORIZONTAL);
composite.setLayout(compositeLayout);
// Remember the factory that we'll use to create instances of
// GeographicControl
this.gcf = gcf;
refresh();
composite.pack();
} // GeographicViewer
/**
* @see org.eclipse.jface.viewers.Viewer#getControl()
*/
@Override
public Control getControl() {
return composite;
} // getControl
/**
* @see org.eclipse.jface.viewers.Viewer#getSelection()
*/
@Override
public ISelection getSelection() {
return selection;
}
/**
* @see org.eclipse.jface.viewers.Viewer#refresh()
*/
@Override
public void refresh() {
if (simulationManager != null) {
// Yes
simulationsToDisplay.clear();
simulationsToDisplay.addAll(simulationManager
.getActiveSimulations());
} // if
populateView();
} // refresh
/**
* @see org.eclipse.jface.viewers.Viewer#getInput()
*/
@Override
public Object getInput() {
return simulationManager;
}
/**
* @see org.eclipse.jface.viewers.Viewer#setInput(java.lang.Object)
*/
@Override
public void setInput(Object input) {
final Object oldInput = simulationManager;
simulationManager = (SimulationManager) input;
inputChanged(input, oldInput);
} // setInput
/**
* @see org.eclipse.jface.viewers.Viewer#inputChanged(java.lang.Object,
* java.lang.Object)
*/
@Override
protected void inputChanged(Object input, Object oldInput) {
// Is there already a simulation manager?
if (oldInput != null) {
// Yes
((SimulationManager) oldInput).removeListener(this);
} // if
// Register with the SimulationManager to listen for changes in the set
// of active Simulations.
// Got input?
if (input != null) {
// Yes
((SimulationManager) input).addSimulationManagerListener(this);
} // if
// Update the viewer with the contents of the new input source
refresh();
} // inputChanged
/**
* @see org.eclipse.jface.viewers.Viewer#setSelection(org.eclipse.jface.viewers.ISelection,
* boolean)
*/
@Override
public void setSelection(ISelection selection, @SuppressWarnings("unused")
boolean reveal) {
this.selection = selection;
}
/**
* @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
*/
public void selectionChanged(final SelectionChangedEvent event) {
// Did the event come from a GeographicControl?
if (event.getSelectionProvider() instanceof GeographicControl) {
// Yes
// Just pass it along
selection = event.getSelection();
fireSelectionChanged(event);
} // if
} // selectionChanged
/**
* @see org.eclipse.stem.jobs.simulation.ISimulationManagerListener#simulationsChanged(org.eclipse.stem.jobs.simulation.SimulationManagerEvent)
*/
public void simulationsChanged(final SimulationManagerEvent event) {
addToDisplayedSimulationSet(Arrays.asList(event.getSimulationsAdded()));
removeFromDisplayedSimulationSet(Arrays.asList(event
.getSimulationsRemoved()));
populateView();
} // simulationsChanged
/**
* @param simulations
* the {@link org.eclipse.stem.jobs.simulation.Simulation}s
* to add to the set being displayed.
*/
private void addToDisplayedSimulationSet(final List<ISimulation> simulations) {
// Any simulations to add?
if (!simulations.isEmpty()) {
// Yes
simulationsToDisplay.addAll(simulations);
} // if any simulations
} // addToDisplayedSimulationSet
/**
* @param simulations
* the {@link org.eclipse.stem.jobs.simulation.Simulation}s
* to remove from the set being displayed.
*/
private void removeFromDisplayedSimulationSet(
final List<ISimulation> simulations) {
// Any simulations to remove?
if (!simulations.isEmpty()) {
// Yes
simulationsToDisplay.removeAll(simulations);
} // if
} // removeFromDisplayedSimulationSet
/**
* Create and dispose of MapControls as necessary to display the selected
* Simulations.
*/
private void populateView() {
// Are we done?
if (composite.isDisposed()) {
// Yes
return;
} // if
selection = null;
// Find the Simulations that are not currently being displayed and put
// them into the Set undisplayedSimulations.
final Set<ISimulation> undisplayedSimulations = new HashSet<ISimulation>();
for (final ISimulation simulation : simulationsToDisplay) {
// Is this one associated with a GeographicControl already?
if (!isDisplayed(simulation)) {
// No
undisplayedSimulations.add(simulation);
} // if not displayed
} // for each ISimulation
// Go through the current set of Controls looking for ones that
// we can reassign
final Control[] controls = composite.getChildren();
for (final Control element : controls) {
// Does this GeographicControl have a simulation that is still valid
// to display?
final GeographicControl geoControl = (GeographicControl) element;
if (!simulationsToDisplay.contains(geoControl.getSimulation())
&& !undisplayedSimulations.isEmpty()) {
// No
// Reassign it to one that is valid
final ISimulation simulation = (ISimulation) undisplayedSimulations
.toArray()[0];
geoControl.setSimulation(simulation);
// Notify ViewPart that a new context menu has been generated
notifyContextMenuUpdateListeners(geoControl);
undisplayedSimulations.remove(simulation);
} // if
} // for each MapControl
// At this point we still could have map controls with invalid
// Simulations, let's get rid of them
for (final Control element : controls) {
final GeographicControl geoControl = (GeographicControl) element;
// Does this MapControl have a simulation that is still valid to
// display?
ISimulation simulation = geoControl.getSimulation();
if (simulation != null
&& !simulationsToDisplay.contains(simulation)) {
// No
geoControl.removeSelectionChangedListener(this);
geoControl.dispose();
}
}// for each MapControl
// If there're any Simulations not assigned to a GeographicControl,
// let's take care of that now.
for (final ISimulation simulation2 : undisplayedSimulations) {
final GeographicControl geoControl = gcf.create(composite);
// Notify ViewPart that a new context menu has been generated
notifyContextMenuUpdateListeners(geoControl);
geoControl.addSelectionChangedListener(this);
geoControl.setSimulation(simulation2);
} // for each ISimulation
// If there are no simulations to display, we just put up a "blank"
// GeographicControl
if (composite.getChildren().length == 0) {
// Yes
final GeographicControl geoControl = gcf.create(composite);
geoControl.addSelectionChangedListener(this);
} // if
composite.layout(true, true);
composite.redraw();
} // populateView
/**
* @param simulation
* @return
*/
private boolean isDisplayed(final ISimulation simulation) {
boolean retValue = false;
final Control[] foo = composite.getChildren();
for (final Control element : foo) {
final GeographicControl geoControl = (GeographicControl) element;
final ISimulation testSimulation = geoControl.getSimulation();
if (testSimulation != null && testSimulation.equals(simulation)) {
retValue = true;
break;
} // if
} // for each MapControl
return retValue;
} // isDisplayed
/**
* The method adds the specified listener to the list of listeners
*
* @param newListener
* A listener to be added
*/
public void addContextMenuUpdateListener(
IContextMenuUpdatesListener newListener) {
if (!contextMenuUpdateListeners.contains(newListener)) {
contextMenuUpdateListeners.add(newListener);
} // if
} // addContextMenuUpdateListener
/**
* The method removes the specified listener to the list of listeners
*
* @param newListener
* A listener to be added
*/
public void removeContextMenuUpdateListener(
IContextMenuUpdatesListener newListener) {
contextMenuUpdateListeners.remove(newListener);
} // addContextMenuUpdateListener
/**
* The method will send notification to all listeners about new menu that
* has been created.
*
* @param geoControl
* The <code>GeographicControl</code> that has the new
* <code>MenuManager</code> as a field.
*/
private void notifyContextMenuUpdateListeners(GeographicControl geoControl) {
GeographicRenderer geoRenderer = geoControl.getGeographicRenderer();
if (geoRenderer instanceof MapRenderer) {
MapRenderer mapRenderer = (MapRenderer) geoRenderer;
notifyContextMenuUpdateListeners(mapRenderer.getMenuManager(),
mapRenderer);
} // if
} // notifyContextMenuUpdateListeners
/**
* The method will send notification to all listeners about new menu that
* has been created.
*
* @param menuManager
* The newly added <code>MenuManager</code>
* @param selectionProvider
* A <code>ISelectionProvider</code> for the menu
*/
private void notifyContextMenuUpdateListeners(MenuManager menuManager,
ISelectionProvider selectionProvider) {
for (final IContextMenuUpdatesListener listener : contextMenuUpdateListeners) {
listener.onContextMenuUpdate(menuManager, selectionProvider);
} // for each IContextMenuUpdatesListener
} // notifyContextMenuUpdateListeners
} // GeographicViewer