blob: 29a937679b6064be7bb19cbd1bf2a03f8b437b72 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 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
*******************************************************************************/
package org.eclipse.debug.internal.ui.views.memory;
import java.math.BigInteger;
import java.util.Enumeration;
import java.util.Hashtable;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.debug.core.IMemoryBlockListener;
import org.eclipse.debug.core.model.IMemoryBlock;
import org.eclipse.debug.ui.memory.IMemoryRendering;
import org.eclipse.debug.ui.memory.IMemoryRenderingSynchronizationService;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.widgets.Display;
/**
* Synchronization service for the memory view.
* @since 3.1
*/
public class MemoryViewSynchronizationService implements
IMemoryRenderingSynchronizationService, IMemoryBlockListener, IPropertyChangeListener {
private static final int ENABLED = 0;
private static final int ENABLING = 1;
private static final int DISABLED = 2;
private Hashtable fSynchronizeInfo;
private int fEnableState = ENABLED;
private Hashtable fPropertyListeners;
private IMemoryRendering fLastChangedRendering;
private IMemoryRendering fSyncServiceProvider;
private static final boolean DEBUG_SYNC_SERVICE = false;
public MemoryViewSynchronizationService()
{
fSynchronizeInfo = new Hashtable();
fPropertyListeners = new Hashtable();
MemoryViewUtil.getMemoryBlockManager().addListener(this);
}
/**
* Wrapper for ISynchronizedMemoryBlockView
* Holds a list of property filters for the view.
*/
class PropertyListener
{
IPropertyChangeListener fListener;
String[] fFilters;
public PropertyListener(IPropertyChangeListener listener, String[] properties)
{
fListener = listener;
if(properties != null)
{
fFilters = properties;
}
}
/**
* If the property matches one of the filters, the property
* is valid and the view should be notified about its change.
* @param property
* @return if the property is specified in the filter
*/
public boolean isValidProperty(String property){
if (fFilters == null)
return true;
for (int i=0; i<fFilters.length; i++)
{
if (fFilters[i].equals(property))
{
return true;
}
}
return false;
}
/**
* Set property filters, indicating what property change events
* the listener is interested in.
* @param filters
*/
public void setPropertyFilters(String[] filters){
fFilters = filters;
}
/**
* @return Returns the fListener.
*/
public IPropertyChangeListener getListener() {
return fListener;
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.IMemoryBlockViewSynchronizer#getSynchronizedProperty(org.eclipse.debug.ui.ISynchronizedMemoryBlockView, java.lang.String)
*/
public Object getSynchronizedProperty(IMemoryBlock memoryBlock, String propertyId)
{
SynchronizeInfo info = (SynchronizeInfo)fSynchronizeInfo.get(memoryBlock);
if (info != null)
{
Object value = info.getProperty(propertyId);
return value;
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.IMemoryBlockListener#MemoryBlockAdded(org.eclipse.debug.core.model.IMemoryBlock)
*/
public void memoryBlocksAdded(IMemoryBlock[] memoryBlocks) {
// do nothing when a memory block is added
// create a synchronize info object when there is a fView
// tab registered to be synchronized.
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.IMemoryBlockListener#MemoryBlockRemoved(org.eclipse.debug.core.model.IMemoryBlock)
*/
public void memoryBlocksRemoved(IMemoryBlock[] memoryBlocks) {
// Sync info can be null if the service is already shut down
if (fSynchronizeInfo == null)
return;
for (int i=0; i<memoryBlocks.length; i++)
{
IMemoryBlock memory = memoryBlocks[i];
if (fLastChangedRendering != null && fLastChangedRendering.getMemoryBlock() == memory)
fLastChangedRendering = null;
if (fSyncServiceProvider != null && fSyncServiceProvider.getMemoryBlock() == memory)
fSyncServiceProvider = null;
// delete the info object and remove it from fSynchronizeInfo
// when the memory block is deleted
SynchronizeInfo info = (SynchronizeInfo)fSynchronizeInfo.get(memory);
if (info != null)
{
info.delete();
fSynchronizeInfo.remove(memory);
}
}
}
/**
* Clean up when the plugin is shutdown
*/
public void shutdown()
{
if (fSynchronizeInfo != null)
{
Enumeration enumeration = fSynchronizeInfo.elements();
// clean up all synchronize info objects
while (enumeration.hasMoreElements()){
SynchronizeInfo info = (SynchronizeInfo)enumeration.nextElement();
info.delete();
}
fSynchronizeInfo.clear();
fSynchronizeInfo = null;
}
MemoryViewUtil.getMemoryBlockManager().removeListener(this);
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.memory.IMemoryRenderingSynchronizationService#addPropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener, java.lang.String[])
*/
public void addPropertyChangeListener(IPropertyChangeListener listener, String[] properties) {
PropertyListener propertylistener = new PropertyListener(listener, properties);
if (!fPropertyListeners.contains(propertylistener))
{
fPropertyListeners.put(listener, propertylistener);
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.memory.IMemoryRenderingSynchronizationService#removePropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
*/
public void removePropertyChangeListener(IPropertyChangeListener listener) {
if (fPropertyListeners.containsKey(listener))
{
fPropertyListeners.remove(listener);
}
}
/**
* Fire property change events
* @param propertyId
*/
public void firePropertyChanged(final PropertyChangeEvent evt)
{
// do not fire property changed event if the synchronization
// service is disabled
if (fEnableState == DISABLED)
return;
// Make sure the synchronizer does not swallow any events
// Values of the properties are updated in the syncrhonizer immediately.
// Change events are queued up on the UI Thread.
Display.getDefault().syncExec(new Runnable()
{
public void run()
{
if (fSynchronizeInfo == null)
return;
IMemoryRendering rendering = (IMemoryRendering)evt.getSource();
String propertyId = evt.getProperty();
SynchronizeInfo info = (SynchronizeInfo)fSynchronizeInfo.get(rendering.getMemoryBlock());
if (info != null)
{
Object value = info.getProperty(propertyId);
if (value != null)
{
Enumeration enumeration = fPropertyListeners.elements();
while(enumeration.hasMoreElements())
{
PropertyListener listener = (PropertyListener)enumeration.nextElement();
IPropertyChangeListener origListener = listener.getListener();
// if it's a valid property - valid means that it's listed in the property filters
if (listener.isValidProperty(propertyId)){
PropertyChangeNotifier notifier = new PropertyChangeNotifier(origListener, evt);
SafeRunner.run(notifier);
}
}
}
}
}
});
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.memory.IMemoryRenderingSynchronizationService#getProperty(org.eclipse.debug.core.model.IMemoryBlock, java.lang.String)
*/
public Object getProperty(IMemoryBlock block, String property) {
// When the synchronization service is disabled
// return null for all queries to properties
// This is to ensure that renderings are not synchronized
// to new synchronization properties when the sync service is
// disabled.
if (!isEnabled())
return null;
SynchronizeInfo info = (SynchronizeInfo)fSynchronizeInfo.get(block);
if (info != null)
return info.getProperty(property);
return null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
if (event == null || !(event.getSource() instanceof IMemoryRendering))
{
return;
}
// Do not handle any property changed event as the
// sync service is being enabled.
// Otheriwse, current sync info provider may overwrite
// sync info unexpectedly. We want to sync with the rendering
// that is last changed.
if (fEnableState == ENABLING)
return;
IMemoryRendering rendering = ((IMemoryRendering)event.getSource());
IMemoryBlock memoryBlock = rendering.getMemoryBlock();
String propertyId = event.getProperty();
Object value = event.getNewValue();
if (DEBUG_SYNC_SERVICE)
{
System.out.println("SYNC SERVICE RECEIVED CHANGED EVENT:"); //$NON-NLS-1$
System.out.println("Source: " + rendering); //$NON-NLS-1$
System.out.println("Property: " + propertyId); //$NON-NLS-1$
System.out.println("Value: " + value); //$NON-NLS-1$
if (value instanceof BigInteger)
{
System.out.println("Value in hex: " + ((BigInteger)value).toString(16)); //$NON-NLS-1$
}
}
if (memoryBlock == null)
return;
if (propertyId == null)
return;
// find the synchronize info object for the memory block
SynchronizeInfo info = (SynchronizeInfo)fSynchronizeInfo.get(memoryBlock);
// if info is not available, need to create one to hold the property
if (info == null)
{
info = new SynchronizeInfo(memoryBlock);
fSynchronizeInfo.put(memoryBlock, info);
}
// get the value of the property
Object oldValue = info.getProperty(propertyId);
if (oldValue == null)
{
// if the value has never been added to the info object
// set the property and fire a change event
info.setProperty(propertyId, value);
fLastChangedRendering = rendering;
firePropertyChanged(event);
return;
}
else if (!oldValue.equals(value))
{
// if the value has changed
// set the property and fire a change event
info.setProperty(propertyId, value);
fLastChangedRendering = rendering;
firePropertyChanged(event);
}
}
public void setEnabled(boolean enabled)
{
if (enabled && fEnableState == ENABLED)
return;
if (!enabled && fEnableState == DISABLED)
return;
try
{
if (enabled)
{
fEnableState = ENABLING;
// get sync info from the sync service provider
if (fLastChangedRendering != null)
{
IMemoryBlock memBlock = fLastChangedRendering.getMemoryBlock();
SynchronizeInfo info = (SynchronizeInfo)fSynchronizeInfo.get(memBlock);
String[] ids = info.getPropertyIds();
// stop handling property changed event while the
// synchronization service is being enabled
// this is to get around problem when the last changed
// rendering is not currently the sync info provider
for (int i=0; i<ids.length; i++)
{
PropertyChangeEvent evt = new PropertyChangeEvent(fLastChangedRendering, ids[i], null, info.getProperty(ids[i]));
firePropertyChanged(evt);
}
}
}
}
finally
{
if (enabled)
fEnableState = ENABLED;
else
fEnableState = DISABLED;
}
}
public boolean isEnabled()
{
return fEnableState == ENABLED;
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.memory.IMemoryRenderingSynchronizationService#setSynchronizationProvider(org.eclipse.debug.ui.memory.IMemoryRendering)
*/
public void setSynchronizationProvider(IMemoryRendering rendering) {
if (DEBUG_SYNC_SERVICE)
System.out.println("SYNCHRONIZATION PROVIDER: " + rendering); //$NON-NLS-1$
if (fSyncServiceProvider != null)
fSyncServiceProvider.removePropertyChangeListener(this);
if (rendering != null)
rendering.addPropertyChangeListener(this);
fSyncServiceProvider = rendering;
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.memory.IMemoryRenderingSynchronizationService#getSynchronizationProvider()
*/
public IMemoryRendering getSynchronizationProvider() {
return fSyncServiceProvider;
}
}