/*******************************************************************************
* Copyright (c) 2008, 2010 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.cdt.dsf.debug.ui.viewmodel.launch;
import java.util.Map;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
import org.eclipse.cdt.dsf.ui.viewmodel.update.IElementUpdateTester;
import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicy;
import org.eclipse.cdt.dsf.ui.viewmodel.update.UpdatePolicyDecorator;
import org.eclipse.jface.viewers.TreePath;
/**
* An update strategy decorator specialized for delayed stack frame refresh. The
* strategy flushes only the cached top stack frame in case of an normal {@link ISuspendedDMEvent},
* while in in case of a special {@link FullStackRefreshEvent} everything is invalidated.
*
* <p>
* The underlying base update policy is considered for container contexts only.
* In other cases the cache data is always flushed.
* </p>
*
* @since 1.1
*/
public class DelayedStackRefreshUpdatePolicy extends UpdatePolicyDecorator {
private static final class DelayedStackRefreshUpdateTester implements IElementUpdateTester {
private final IElementUpdateTester fBaseTester;
/** Indicates whether only the top stack frame should be updated */
private final boolean fLazyStackFrameMode;
DelayedStackRefreshUpdateTester(IElementUpdateTester baseTester, boolean lazyStackFrameMode) {
fBaseTester = baseTester;
fLazyStackFrameMode = lazyStackFrameMode;
}
public int getUpdateFlags(Object viewerInput, TreePath path) {
Object element = path.getSegmentCount() != 0 ? path.getLastSegment() : viewerInput;
if (element instanceof IDMVMContext) {
IDMContext dmc = ((IDMVMContext) element).getDMContext();
if (fLazyStackFrameMode) {
if (dmc instanceof IFrameDMContext) {
if (((IFrameDMContext) dmc).getLevel() == 0) {
return FLUSH;
}
} else if (dmc instanceof IExecutionDMContext) {
return fBaseTester.getUpdateFlags(viewerInput, path);
}
return DIRTY;
} else if (dmc instanceof IContainerDMContext) {
return fBaseTester.getUpdateFlags(viewerInput, path);
}
}
return FLUSH;
}
public boolean includes(IElementUpdateTester tester) {
// A non-lazy tester includes a lazy tester, but not vice versa.
// This allows entries that were marked as dirty by a flush with
// the lazy mode to be superseded by a non-lazy update which
// actually clears the entries that were marked as dirty.
if (tester instanceof DelayedStackRefreshUpdateTester) {
DelayedStackRefreshUpdateTester sfTester = (DelayedStackRefreshUpdateTester)tester;
if (fLazyStackFrameMode) {
if (sfTester.fLazyStackFrameMode) {
return fBaseTester.includes(sfTester.fBaseTester);
}
} else {
if (!sfTester.fLazyStackFrameMode) {
return fBaseTester.includes(sfTester.fBaseTester);
}
// non-lazy includes lazy
return true;
}
}
return false;
}
@Override
public String toString() {
return "Delayed stack refresh (lazy = " + fLazyStackFrameMode + ", base = " + fBaseTester + ") update tester"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
private static final class ThreadsUpdateTester implements IElementUpdateTester {
private final IElementUpdateTester fBaseTester;
private final boolean fRefreshAll;
ThreadsUpdateTester(IElementUpdateTester baseTester, boolean refreshAll) {
fBaseTester = baseTester;
fRefreshAll = refreshAll;
}
public int getUpdateFlags(Object viewerInput, TreePath path) {
Object element = path.getSegmentCount() != 0 ? path.getLastSegment() : viewerInput;
if (!fRefreshAll && element instanceof IDMVMContext) {
IDMContext dmc = ((IDMVMContext) element).getDMContext();
if (dmc instanceof IContainerDMContext) {
return fBaseTester.getUpdateFlags(viewerInput, path);
}
}
// If the element is not a container or if the flush all flag is set,
// always flush it.
return FLUSH;
}
public boolean includes(IElementUpdateTester tester) {
// A refresh-all tester includes a non-refresh-all tester, but not
// vice versa. This allows entries that were marked as dirty by
// a flush with
// the non-refresh-all to be superseded by a refresh-all update which
// actually clears the entries that were marked as dirty.
if (tester instanceof ThreadsUpdateTester) {
ThreadsUpdateTester threadsTester = (ThreadsUpdateTester)tester;
if (fRefreshAll) {
if (threadsTester.fRefreshAll) {
return fBaseTester.includes(threadsTester.fBaseTester);
}
// refresh-all includes the non-refresh-all
return true;
} else {
if (!threadsTester.fRefreshAll) {
return fBaseTester.includes(threadsTester.fBaseTester);
}
}
}
return false;
}
@Override
public String toString() {
return "Threads update tester (base = " + fBaseTester + ") update tester"; //$NON-NLS-1$ //$NON-NLS-2$
}
}
public DelayedStackRefreshUpdatePolicy(IVMUpdatePolicy base) {
super(base);
}
@Override
public IElementUpdateTester getElementUpdateTester(Object event) {
if (event instanceof ISuspendedDMEvent) {
return new DelayedStackRefreshUpdateTester(getBaseUpdatePolicy().getElementUpdateTester(event), true);
} else if (event instanceof FullStackRefreshEvent) {
return new DelayedStackRefreshUpdateTester(getBaseUpdatePolicy().getElementUpdateTester(event), false);
} else if (event instanceof IExitedDMEvent &&
((IExitedDMEvent)event).getDMContext() instanceof IContainerDMContext)
{
// container exit should always trigger a refresh
return new ThreadsUpdateTester(super.getElementUpdateTester(event), true);
} else {
return new ThreadsUpdateTester(super.getElementUpdateTester(event), false);
}
}
public Object[] getInitialRootElementChildren(Object rootElement) {
return null;
}
public Map<String, Object> getInitialRootElementProperties(Object rootElement) {
return null;
}
}