/*******************************************************************************
* Copyright (c) 2004, 2014 QNX Software Systems 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:
* QNX Software Systems - Initial API and implementation
* Wind River Systems - Adapted to TCF
*******************************************************************************/
package org.eclipse.tcf.internal.cdt.ui.breakpoints;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.tcf.internal.cdt.ui.Activator;
import org.eclipse.tcf.internal.cdt.ui.ImageCache;
import org.eclipse.tcf.internal.cdt.ui.preferences.BreakpointPreferencePage;
import org.eclipse.tcf.internal.debug.model.TCFLaunch;
import org.eclipse.tcf.internal.debug.ui.model.TCFChildren;
import org.eclipse.tcf.internal.debug.ui.model.TCFModel;
import org.eclipse.tcf.internal.debug.ui.model.TCFModelManager;
import org.eclipse.tcf.internal.debug.ui.model.TCFNode;
import org.eclipse.tcf.internal.debug.ui.model.TCFNodeExecContext;
import org.eclipse.tcf.protocol.IChannel;
import org.eclipse.tcf.protocol.IToken;
import org.eclipse.tcf.services.IContextQuery;
import org.eclipse.tcf.services.IRunControl;
import org.eclipse.tcf.util.TCFDataCache;
import org.eclipse.tcf.util.TCFTask;
import org.eclipse.ui.dialogs.PreferencesUtil;
public class TCFThreadFilterEditor {
public static final String PLUGIN_ID="org.eclipse.tcf.internal.cdt.ui.breakpoints.TCFThreadFilterEditor"; //$NON-NLS-1$
private static class Context {
private final String fName;
private final String fId;
private final String fParentId;
private final boolean fIsContainer;
private final String fScopeId;
private final String fSessionId;
private final String fBpGroup;
private final Object fAdditionalInfo;
Context(IRunControl.RunControlContext ctx, Context parent) {
this(ctx, parent.fSessionId);
}
Context(IRunControl.RunControlContext ctx, String sessionId) {
fName = ctx.getName();
fSessionId = sessionId;
fScopeId = sessionId != null ? sessionId + '/' + ctx.getID() : ctx.getID();
fId = ctx.getID();
fParentId = ctx.getParentID();
fIsContainer = !ctx.hasState();
fBpGroup = ctx.getBPGroup();
fAdditionalInfo = ctx.getProperties().get("AdditionalInfo"); //$NON-NLS-1$
}
@Override
public boolean equals(Object obj) {
return obj instanceof Context && fScopeId.equals(((Context)obj).fScopeId);
}
@Override
public int hashCode() {
return fScopeId.hashCode();
}
}
public class CheckHandler implements ICheckStateListener {
public void checkStateChanged(CheckStateChangedEvent event) {
Object element = event.getElement();
boolean checked = event.getChecked();
if (checked) {
getThreadViewer().expandToLevel(element, 1);
}
if (element instanceof Context) {
Context ctx = (Context) element;
checkContext(ctx, checked);
updateParentCheckState(ctx);
}
else if (element instanceof ILaunch) {
checkLaunch((ILaunch) element, checked);
}
}
private void checkLaunch(ILaunch launch, boolean checked) {
getThreadViewer().setChecked(launch, checked);
getThreadViewer().setGrayed(launch, false);
Object[] threads = fContentProvider.getChildren(launch);
for (int i = 0; i < threads.length; i++) {
checkContext((Context) threads[i], checked);
}
}
/**
* Check or uncheck a context in the tree viewer. When a container
* is checked, attempt to check all of the containers threads by
* default. When a container is unchecked, uncheck all its threads.
*/
private void checkContext(Context ctx, boolean checked) {
Object[] threads = fContentProvider.getChildren(ctx);
for (int i = 0; i < threads.length; i++) {
checkContext((Context) threads[i], checked);
}
checkThread(ctx, checked);
}
/**
* Check or uncheck a thread.
*/
private void checkThread(Context thread, boolean checked) {
getThreadViewer().setChecked(thread, checked);
getThreadViewer().setGrayed(thread, false);
}
private void updateParentCheckState(Context thread) {
Object[] threads;
Object parent = getContainer(thread);
if (parent == null) {
parent = getLaunch(thread);
if (parent == null) return;
}
threads = fContentProvider.getChildren(parent);
int checkedNumber = 0;
int grayedNumber = 0;
for (int i = 0; i < threads.length; i++) {
if (getThreadViewer().getGrayed(threads[i])) {
++grayedNumber;
}
else if (getThreadViewer().getChecked(threads[i])) {
++checkedNumber;
}
}
if (checkedNumber + grayedNumber == 0) {
getThreadViewer().setChecked(parent, false);
getThreadViewer().setGrayed(parent, false);
}
else if (checkedNumber == threads.length) {
getThreadViewer().setChecked(parent, true);
getThreadViewer().setGrayed(parent, false);
}
else {
getThreadViewer().setGrayChecked(parent, true);
}
if (parent instanceof Context) {
updateParentCheckState((Context) parent);
}
}
}
public class ThreadFilterContentProvider implements ITreeContentProvider {
public Object[] getChildren(Object parent) {
if (parent instanceof Context) {
return filterList(syncGetThreads((Context) parent));
}
if (parent instanceof ILaunch) {
return filterList(syncGetContainers((TCFLaunch) parent));
}
if (parent instanceof ILaunchManager) {
return filterList(getLaunches());
}
return new Object[0];
}
public Object[] filterList(Object[] resultArray) {
ArrayList<Object> filteredList = new ArrayList<Object>();
String filterExpr = null;
if (scopeExprCombo != null) {
filterExpr = scopeExprCombo.getText();
}
for (Object obj : resultArray) {
if (obj instanceof ILaunch || obj instanceof ILaunchManager) {
filteredList.add(obj);
} else if (obj instanceof Context) {
Context context = (Context)obj;
// Add element to list if:
// Check if context in result of query expression (if query expression was specitifed).
// Also check if breakpoint group is valid on context.
// Finally, check if contexts' children are not filtered out.
if ( (filterExpr == null || filterExpr.length() == 0 || fContextList.contains(context.fId))
&& context.fBpGroup != null)
{
filteredList.add(obj);
fFilteredContexts.add(obj);
} else {
Object[] childArray = getChildren(obj);
if (childArray != null && childArray.length != 0) {
filteredList.add(obj);
fFilteredContexts.add(obj);
}
}
}
}
return filteredList.toArray(new Object[filteredList.size()]);
}
public Object getParent(Object element) {
if (element instanceof Context) {
Context ctx = (Context) element;
if (ctx.fParentId == null) {
return DebugPlugin.getDefault().getLaunchManager();
}
else {
return getContainer(ctx);
}
}
return null;
}
public boolean hasChildren(Object element) {
return getChildren(element).length > 0;
}
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
public class ThreadFilterLabelProvider extends LabelProvider {
@Override
public Image getImage(Object element) {
if (element instanceof Context) {
Context ctx = (Context) element;
if (ctx.fIsContainer) {
return DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_DEBUG_TARGET);
}
else {
return DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_THREAD_RUNNING);
}
}
if (element instanceof ILaunch) {
ImageDescriptor desc = DebugUITools.getDefaultImageDescriptor(element);
if (desc != null) return ImageCache.getImage(desc);
}
return null;
}
@Override
public String getText(Object element) {
if (element instanceof Context) {
Context ctx = (Context) element;
String s = ctx.fName;
if (s == null) s = ctx.fId;
if (ctx.fAdditionalInfo != null) s += ctx.fAdditionalInfo.toString();
return s;
}
if (element instanceof ILaunch) {
ILaunchConfiguration config = ((ILaunch) element).getLaunchConfiguration();
if (config != null) return config.getName();
}
return "?"; //$NON-NLS-1$
}
}
private TCFBreakpointThreadFilterPage fPage;
private CheckboxTreeViewer fThreadViewer;
private final ThreadFilterContentProvider fContentProvider;
private final CheckHandler fCheckHandler;
private final List<Context> fContexts = new ArrayList<Context>();
private final Set<Object> fFilteredContexts = new HashSet<Object>();
private final Map<TCFLaunch, Context[]> fContainersPerLaunch = new HashMap<TCFLaunch, Context[]>();
private final Map<Context, Context[]> fContextsPerContainer = new HashMap<Context, Context[]>();
private Combo scopeExprCombo;
private ControlDecoration scopeExpressionDecoration;
private final Set<String> fContextList = new TreeSet<String>();
private Link preferencesLink;
/**
* Returns the dialog settings or <code>null</code> if none
*
* @param create
* whether to create the settings
*/
private IDialogSettings getDialogSettings(boolean create) {
IDialogSettings settings = Activator.getDefault()
.getDialogSettings();
IDialogSettings section = settings.getSection(this.getClass()
.getName());
if (section == null & create) {
section = settings.addNewSection(this.getClass().getName());
}
return section;
}
public TCFThreadFilterEditor(Composite parent, TCFBreakpointThreadFilterPage page) {
fPage = page;
fContentProvider = new ThreadFilterContentProvider();
fCheckHandler = new CheckHandler();
Composite mainComposite = new Composite(parent, SWT.NONE);
mainComposite.setFont(parent.getFont());
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
gd.widthHint = 500;
mainComposite.setLayoutData(gd);
mainComposite.setLayout(new GridLayout(2,false));
createThreadViewer(mainComposite);
}
protected TCFBreakpointThreadFilterPage getPage() {
return fPage;
}
private String getBPFilterExpression() {
return fPage.getFilterExtension().getPropertiesFilter();
}
private String[] getAvailableAttributes() {
String[] result = null;
TCFLaunch launch = (TCFLaunch)getAttributeLaunch();
if (launch == null || launch.isTerminated()) {
return result;
}
final IChannel channel = launch.getChannel();
if (channel == null) {
return result;
}
result = new TCFTask<String[]>(channel) {
public void run() {
IContextQuery service = channel.getRemoteService(IContextQuery.class);
service.getAttrNames(new IContextQuery.DoneGetAttrNames() {
public void doneGetAttrNames(IToken token, Exception error, String[] attributes) {
if (error != null) {
done(null);
}
done(attributes);
}
});
return;
}
}.getE();
return result;
}
/**
* Validate a Context query using the context query service.
* If the query is valid, also get the list of filtered contexts.
*
* @param query The query to validate
* @return Error String if validation has failed, else null.
*/
private String getQueryFilteredContexts (final String query, final Set<String> contextList) {
TCFLaunch launch = (TCFLaunch)getAttributeLaunch();
if (launch == null || launch.isTerminated()) {
return Messages.TCFThreadFilterEditorNoOpenChannel;
}
final IChannel channel = launch.getChannel();
if (channel == null) {
return Messages.TCFThreadFilterEditorNoOpenChannel;
}
String result = new TCFTask<String>() {
public void run() {
IContextQuery service = channel.getRemoteService(IContextQuery.class);
service.query(query, new IContextQuery.DoneQuery() {
public void doneQuery (IToken token, Exception error, String[] contexts) {
if (error != null) {
done(TCFModel.getErrorMessage(error, false));
}
else {
for (String context : contexts) {
contextList.add(context);
}
done(null);
}
}
});
return;
}
}.getE();
return result;
}
String validateBasicSyntax(String expression) {
String result = null;
// Ignore content in double-quotes.
Pattern p = Pattern.compile("\"((?:\\\\\\\\|\\\\\"|[^\"])*)\""); //$NON-NLS-1$
Matcher m = p.matcher(expression);
expression = m.replaceAll("temp"); //$NON-NLS-1$
// No whitespace
if (expression.matches("^(.*?)(\\s)(.*)$")) //$NON-NLS-1$
return Messages.TCFThreadFilterEditorFormatError;
// Check characters around equals.
if (expression.matches("^(.*?)[^a-zA-Z0-9_]=[^a-zA-Z0-9_](.*)$")) //$NON-NLS-1$
return Messages.TCFThreadFilterEditorUnbalancedParameters;
return result;
}
private class ExpressionModifier implements ModifyListener {
public void modifyText(ModifyEvent e) {
String expression = scopeExprCombo.getText();
String error = validateBasicSyntax(expression);
if (error != null) {
scopeExpressionDecoration.show();
fPage.setErrorMessage(error);
fPage.setValid(false);
}
else {
fContextList.clear();
if (expression != null && expression.length() != 0)
error = getQueryFilteredContexts (expression, fContextList);
if (error == null ) {
scopeExpressionDecoration.hide();
fPage.setErrorMessage(null);
fPage.setValid(true);
}
else if (error == Messages.TCFThreadFilterEditorNoOpenChannel) {
// if no open channel, allow to edit expression nonetheless
scopeExpressionDecoration.hide();
fPage.setErrorMessage(NLS.bind(Messages.TCFThreadFilterEditor_cannotValidate, error));
fPage.setValid(true);
}
else {
scopeExpressionDecoration.show();
fPage.setErrorMessage(error);
fPage.setValid(false);
}
scopeExprCombo.getParent().layout();
if (fThreadViewer != null) {
fThreadViewer.refresh();
fFilteredContexts.clear();
setInitialCheckedState();
}
}
}
}
private class ExpressionSelectButton implements Listener {
private Shell parentShell;
public ExpressionSelectButton(Shell shell) {
parentShell = shell;
}
public void handleEvent(Event event) {
String[] attrsList = getAvailableAttributes();
if (attrsList == null) {
fPage.setErrorMessage(NLS.bind(Messages.TCFThreadFilterEditor_cannotRetrieveAttrs, Messages.TCFThreadFilterEditorNoOpenChannel));
}
else if (attrsList.length == 0) {
fPage.setErrorMessage(Messages.TCFThreadFilterEditor_cannotEditExpr);
}
else {
TCFContextQueryExpressionDialog dlg = new TCFContextQueryExpressionDialog(parentShell, attrsList, scopeExprCombo.getText());
if (dlg.open() == Window.OK) {
scopeExprCombo.setText(dlg.getExpression());
}
}
}
}
void setupScopeExpressionCombo() {
if (scopeExprCombo == null) return;
IDialogSettings settings = getDialogSettings(false);
String bpContextQuery = getBPFilterExpression();
String [] expresionList = null;
if ( settings != null ) {
expresionList = settings.getArray(Messages.TCFThreadFilterQueryExpressionStore);
if ( expresionList != null ) {
int index;
// Find if there is a null entry.
for (index = 0; index < expresionList.length; index++) {
String member = expresionList[index];
if (member == null || member.length() == 0) {
break;
}
}
String[] copyList = new String[index];
int found = -1;
for (int loop = 0; loop < index; loop++) {
copyList[loop] = expresionList[loop];
if (bpContextQuery != null && copyList[loop].equals(bpContextQuery)) {
found = loop;
}
}
if (found != -1) {
scopeExprCombo.setItems(copyList);
scopeExprCombo.select(found);
}
else {
int pad = 0;
if (bpContextQuery != null) {
pad = 1;
}
String[] setList = new String[index+pad];
if (bpContextQuery != null) {
setList[0] = bpContextQuery;
}
System.arraycopy(copyList, 0, setList, pad, copyList.length);
scopeExprCombo.setItems(setList);
if (bpContextQuery != null) {
scopeExprCombo.select(0);
}
}
}
else if (bpContextQuery != null) {
scopeExprCombo.setItems(new String[]{bpContextQuery});
scopeExprCombo.select(0);
}
}
else if (bpContextQuery != null) {
scopeExprCombo.setItems(new String[]{bpContextQuery});
scopeExprCombo.select(0);
}
}
public class linkSelectAdapter implements SelectionListener {
private Shell parentShell;
public linkSelectAdapter(Shell shell) {
parentShell = shell;
}
public void widgetSelected(SelectionEvent e) {
PreferencesUtil.createPreferenceDialogOn(parentShell,
BreakpointPreferencePage.PLUGIN_ID,
new String[] { BreakpointPreferencePage.PLUGIN_ID },
null).open();
}
public void widgetDefaultSelected(SelectionEvent e) {
}
}
private void createThreadViewer(Composite parent) {
GridData twoColumnLayout = new GridData(SWT.FILL,0, true, false);
twoColumnLayout.horizontalSpan = 2;
GridData comboGridData = new GridData(SWT.FILL,0, true, false);
comboGridData .horizontalIndent = 5;
FieldDecoration fieldDecoration = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR);
Label epressionLabel = new Label(parent, SWT.NONE);
epressionLabel.setText(Messages.TCFThreadFilterQueryAdvancedLabel);
epressionLabel.setFont(parent.getFont());
epressionLabel.setLayoutData(twoColumnLayout);
scopeExprCombo = new Combo(parent,SWT.DROP_DOWN);
scopeExprCombo.setLayoutData(comboGridData);
scopeExprCombo.addModifyListener(new ExpressionModifier());
scopeExprCombo.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
scopeExprCombo = null;
}
});
scopeExpressionDecoration = new ControlDecoration(scopeExprCombo, SWT.LEFT, parent);
scopeExpressionDecoration.hide();
scopeExpressionDecoration.setDescriptionText(Messages.TCFThreadFilterEditorFormatError);
scopeExpressionDecoration.setImage(fieldDecoration.getImage());
setupScopeExpressionCombo();
Button selectExpression = new Button(parent, SWT.PUSH);
selectExpression.setText(Messages.TCFThreadFilterQueryButtonEdit);
selectExpression.setLayoutData(new GridData(SWT.RIGHT,0, false, false));
selectExpression.addListener(SWT.Selection, new ExpressionSelectButton(parent.getShell()));
Label contextTreeLabel = new Label(parent, SWT.NONE);
contextTreeLabel.setText(Messages.TCFThreadFilterQueryTreeViewLabel); //$NON-NLS-1$
contextTreeLabel.setFont(parent.getFont());
contextTreeLabel.setLayoutData(twoColumnLayout);
GridData data = new GridData(GridData.FILL_BOTH);
data.heightHint = 100;
fThreadViewer = new CheckboxTreeViewer(parent, SWT.BORDER);
fThreadViewer.addCheckStateListener(fCheckHandler);
fThreadViewer.getTree().setLayoutData(data);
fThreadViewer.getTree().setFont(parent.getFont());
fThreadViewer.setContentProvider(fContentProvider);
fThreadViewer.setLabelProvider(new ThreadFilterLabelProvider());
fThreadViewer.setInput(DebugPlugin.getDefault().getLaunchManager());
setInitialCheckedState();
preferencesLink = new Link(parent, SWT.WRAP);
preferencesLink.setLayoutData(twoColumnLayout);
preferencesLink.setText(Messages.TCFThreadFilterEditor_defaultScopePrefsLink);
preferencesLink.addSelectionListener(new linkSelectAdapter(parent.getShell()));
parent.layout();
}
protected ILaunch getAttributeLaunch() {
IAdaptable dbgContext = DebugUITools.getDebugContext();
return (ILaunch)dbgContext.getAdapter(ILaunch.class);
}
protected ILaunch[] getLaunches() {
Object input = fThreadViewer.getInput();
if (!(input instanceof ILaunchManager)) {
return new ILaunch[0];
}
List<ILaunch> tcfLaunches = new ArrayList<ILaunch>();
ILaunch[] launches = ((ILaunchManager) input).getLaunches();
for (int i = 0; i < launches.length; i++) {
ILaunch launch = launches[i];
if (launch instanceof TCFLaunch && !launch.isTerminated()) {
tcfLaunches.add(launch);
}
}
return tcfLaunches.toArray(new ILaunch[tcfLaunches.size()]);
}
/**
* Returns the root contexts that appear in the tree
*/
protected Context[] getRootContexts() {
Object input = fThreadViewer.getInput();
if (!(input instanceof ILaunchManager)) {
return new Context[0];
}
List<Object> targets = new ArrayList<Object>();
ILaunch[] launches = ((ILaunchManager) input).getLaunches();
for (int i = 0; i < launches.length; i++) {
ILaunch launch = launches[i];
if (launch instanceof TCFLaunch && !launch.isTerminated()) {
Context[] targetArray = syncGetContainers((TCFLaunch) launch);
targets.addAll(Arrays.asList(targetArray));
}
}
return targets.toArray(new Context[targets.size()]);
}
protected final CheckboxTreeViewer getThreadViewer() {
return fThreadViewer;
}
protected String getScopeExpression() {
if (scopeExprCombo != null) {
return scopeExprCombo.getText();
}
return null;
}
/**
* Sets the initial checked state of the tree viewer. The initial state
* should reflect the current state of the breakpoint. If the breakpoint has
* a thread filter in a given thread, that thread should be checked.
*/
protected void setInitialCheckedState() {
TCFBreakpointScopeExtension filterExtension = fPage.getFilterExtension();
if (filterExtension == null) return;
String[] ctxIds = filterExtension.getThreadFilters();
// expand all to realize tree items
getThreadViewer().expandAll();
if (ctxIds == null) {
ILaunch[] launches = getLaunches();
for (ILaunch launch : launches) {
fCheckHandler.checkLaunch(launch, true);
}
}
else if (ctxIds.length != 0) {
for (int i = 0; i < ctxIds.length; i++) {
String id = ctxIds[i];
Context ctx = getContext(id);
if (ctx != null) {
fCheckHandler.checkContext(ctx, true);
fCheckHandler.updateParentCheckState(ctx);
}
else if (id.indexOf('/') < 0) {
for (Context context : fContexts) {
if (id.equals(context.fId)) {
fCheckHandler.checkContext(context, true);
fCheckHandler.updateParentCheckState(context);
}
}
}
}
}
// expand checked items only
getThreadViewer().setExpandedElements(getThreadViewer().getCheckedElements());
}
private Context getContainer(Context child) {
String parentId = child.fSessionId != null ? child.fSessionId + '/' + child.fParentId : child.fParentId;
return getContext(parentId);
}
private Context getContext(String id) {
for (Context ctx : fContexts) {
if (ctx.fScopeId.equals(id))
return ctx;
}
return null;
}
void updateExpressionsDialogSettings(IDialogSettings settings, String scopedExpression) {
String[] list = settings.getArray(Messages.TCFThreadFilterQueryExpressionStore);
if (list == null) {
list = new String[20];
}
for (int i = 0; i < list.length; i++) {
String member = list[i];
if (member != null && member.equals(scopedExpression)) {
return;
}
else if (member == null) {
list[i] = scopedExpression;
settings.put(Messages.TCFThreadFilterQueryExpressionStore, list);
return;
}
}
String[] copyList = new String[20];
copyList[0] = scopedExpression;
System.arraycopy(list, 0, copyList, 1, list.length-1);
settings.put(Messages.TCFThreadFilterQueryExpressionStore, copyList);
}
protected void doStore() {
IDialogSettings settings = getDialogSettings(true);
String scopedExpression = getScopeExpression();
if (scopedExpression.length() != 0)
updateExpressionsDialogSettings(settings, scopedExpression);
TCFBreakpointScopeExtension filterExtension = fPage.getFilterExtension();
if (filterExtension == null) return;
filterExtension.setPropertiesFilter(scopedExpression);
CheckboxTreeViewer viewer = getThreadViewer();
Object[] elements = viewer.getCheckedElements();
String[] threadIds = null;
List<String> checkedIds = new ArrayList<String>();
for (int i = 0; i < elements.length; ++i) {
if (elements[i] instanceof Context) {
Context ctx = (Context) elements[i];
if (!viewer.getGrayed(ctx)) {
checkedIds.add(ctx.fScopeId);
}
}
}
if (checkedIds.size() != fFilteredContexts.size()) {
threadIds = checkedIds.toArray(new String[checkedIds.size()]);
}
filterExtension.setThreadFilter(threadIds);
}
private Context[] syncGetContainers(final TCFLaunch launch) {
Context[] result = fContainersPerLaunch.get(launch);
if (result != null) return result;
final String launchCfgName = launch.getLaunchConfiguration().getName();
result = new TCFTask<Context[]>(launch.getChannel()) {
public void run() {
List<Context> containers = new ArrayList<Context>();
TCFChildren children = TCFModelManager.getModelManager().getRootNode(launch).getChildren();
if (!children.validate(this)) return;
for (TCFNode node : children.toArray()) {
TCFNodeExecContext exeCtx = (TCFNodeExecContext) node;
TCFDataCache<IRunControl.RunControlContext> runCtxCache = exeCtx.getRunContext();
if (!runCtxCache.validate(this)) return;
IRunControl.RunControlContext runCtx = runCtxCache.getData();
containers.add(new Context(runCtx, launchCfgName));
}
done(containers.toArray(new Context[containers.size()]));
}
}.getE();
fContainersPerLaunch.put(launch, result);
fContexts.addAll(Arrays.asList(result));
return result;
}
private Context[] syncGetThreads(final Context container) {
Context[] result = fContextsPerContainer.get(container);
if (result != null) return result;
final TCFLaunch launch = getLaunch(container);
result = new TCFTask<Context[]>(launch.getChannel()) {
public void run() {
List<Context> contexts = new ArrayList<Context>();
TCFModel model = TCFModelManager.getModelManager().getModel(launch);
TCFChildren children = ((TCFNodeExecContext) model.getNode(container.fId)).getChildren();
if (!children.validate(this)) return;
for (TCFNode node : children.toArray()) {
TCFNodeExecContext exeCtx = (TCFNodeExecContext) node;
TCFDataCache<IRunControl.RunControlContext> runCtxCache = exeCtx.getRunContext();
if (!runCtxCache.validate(this)) return;
IRunControl.RunControlContext runCtx = runCtxCache.getData();
contexts.add(new Context(runCtx, container));
}
done(contexts.toArray(new Context[contexts.size()]));
}
}.getE();
fContextsPerContainer.put(container, result);
fContexts.addAll(Arrays.asList(result));
return result;
}
private TCFLaunch getLaunch(Context container) {
Context parent = getContainer(container);
while (parent != null) {
container = parent;
parent = getContainer(container);
}
for (TCFLaunch launch : fContainersPerLaunch.keySet()) {
Context[] containers = fContainersPerLaunch.get(launch);
for (Context context : containers) {
if (context.fScopeId.equals(container.fScopeId)) {
return launch;
}
}
}
return null;
}
}