org.eclipse.mat.ui.internal.query.arguments.ArgumentsTable.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.mat.ui.internal.query.arguments.ArgumentsTable.java

Source

/*******************************************************************************
 * Copyright (c) 2008, 2010 SAP AG 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:
 *    SAP AG - initial API and implementation
 *******************************************************************************/
package org.eclipse.mat.ui.internal.query.arguments;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.resource.FontDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.window.DefaultToolTip;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.mat.SnapshotException;
import org.eclipse.mat.internal.snapshot.HeapObjectContextArgument;
import org.eclipse.mat.internal.snapshot.HeapObjectParamArgument;
import org.eclipse.mat.query.IContextObject;
import org.eclipse.mat.query.IQueryContext;
import org.eclipse.mat.query.annotations.Argument;
import org.eclipse.mat.query.registry.ArgumentDescriptor;
import org.eclipse.mat.query.registry.ArgumentSet;
import org.eclipse.mat.snapshot.ISnapshot;
import org.eclipse.mat.snapshot.SnapshotFactory;
import org.eclipse.mat.snapshot.model.IObject;
import org.eclipse.mat.snapshot.query.IHeapObjectArgument;
import org.eclipse.mat.ui.Messages;
import org.eclipse.mat.ui.accessibility.AccessibleCompositeAdapter;
import org.eclipse.mat.ui.internal.query.arguments.LinkEditor.Mode;
import org.eclipse.mat.ui.internal.query.arguments.TextEditor.DecoratorType;
import org.eclipse.mat.util.MessageUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

public class ArgumentsTable implements ArgumentEditor.IEditorListener {
    private static final int MIN_EDITOR_WIDTH = 50;
    private static final String ADDRESS_PREFIX = "0x";//$NON-NLS-1$

    /**
     * The end of line string for this machine.
     */
    protected static final String EOL = System.getProperty("line.separator", "\n");//$NON-NLS-1$//$NON-NLS-2$

    private static final String ARGUMENT = Messages.ArgumentsTable_Argument;
    private static final String VALUE = Messages.ArgumentsTable_Value;

    private LocalResourceManager resourceManager = new LocalResourceManager(JFaceResources.getResources());

    private Table table;
    private Font boldFont;
    private Font normalFont;
    private int tableRowHeight = SWT.DEFAULT;

    private List<ITableListener> listeners = Collections.synchronizedList(new ArrayList<ITableListener>());

    private Map<ArgumentEditor, String> errors = Collections.synchronizedMap(new HashMap<ArgumentEditor, String>());
    private Mode mode = Mode.SIMPLE_MODE;
    private Map<ArgumentDescriptor, Mode> modeMap;

    private IQueryContext context;
    private ArgumentSet argumentSet;

    public interface ITableListener {
        void onInputChanged();

        void onError(String message);

        void onFocus(String message);

        void onModeChange(Mode mode);
    }

    public ArgumentsTable(Composite parent, int style, IQueryContext context, ArgumentSet argumentSet, Mode mode) {
        this.context = context;
        this.argumentSet = argumentSet;
        this.mode = mode;

        TableColumnLayout tableColumnLayout = new TableColumnLayout();
        parent.setLayout(tableColumnLayout);

        table = new Table(parent, style);
        Font parentFont = parent.getFont();
        table.setFont(parentFont);
        table.setLinesVisible(true);
        table.setHeaderVisible(true);
        AccessibleCompositeAdapter.access(table);

        TableColumn column = new TableColumn(table, SWT.NONE);
        column.setText(ARGUMENT);
        tableColumnLayout.setColumnData(column, new ColumnWeightData(0, 100));

        column = new TableColumn(table, SWT.NONE);
        column.setText(VALUE);
        tableColumnLayout.setColumnData(column, new ColumnWeightData(100, 100));

        boldFont = resourceManager.createFont(FontDescriptor.createFrom(parentFont).setStyle(SWT.BOLD));
        normalFont = resourceManager.createFont(FontDescriptor.createFrom(parentFont).setStyle(SWT.NORMAL));

        modeMap = new HashMap<ArgumentDescriptor, Mode>(argumentSet.getQueryDescriptor().getArguments().size());
        for (ArgumentDescriptor descriptor : argumentSet.getQueryDescriptor().getArguments()) {
            if (isHeapObject(descriptor))
                modeMap.put(descriptor, mode);
        }

        table.addListener(SWT.MeasureItem, new Listener() {
            public void handleEvent(Event event) {
                event.height = tableRowHeight;
            }
        });

        createTableContent();

        new DefaultToolTip(table, ToolTip.NO_RECREATE, false) {
            private ArgumentDescriptor getEntry(Event event) {
                TableItem item = table.getItem(new Point(event.x, event.y));
                if (item != null && item.getData() != null) {
                    return ((ArgumentEditor) item.getData()).getDescriptor();
                }
                return null;
            }

            protected String getText(Event event) {
                ArgumentDescriptor entry = getEntry(event);
                if (entry != null) {
                    return entry.getHelp();
                }
                return null;
            }

            protected boolean shouldCreateToolTip(Event event) {
                table.setToolTipText(""); //$NON-NLS-1$
                return getEntry(event) != null && super.shouldCreateToolTip(event);
            }

            protected Object getToolTipArea(Event event) {
                return getEntry(event);
            }
        }.activate();

    }

    private void setTableRowHeight(int height) {
        tableRowHeight = Math.max(tableRowHeight, height);
    }

    public void dispose() {
        // clear error messages
        errors.clear();
        errors = null;
        modeMap.clear();
        modeMap = null;
        if (resourceManager != null) {
            resourceManager.dispose();
            resourceManager = null;
        }
    }

    // //////////////////////////////////////////////////////////////
    // private constructor methods
    // //////////////////////////////////////////////////////////////

    private void createTableContent() {
        table.setData(argumentSet);

        for (ArgumentDescriptor descriptor : argumentSet.getQueryDescriptor().getArguments()) {
            if (context.available(descriptor.getType(), descriptor.getAdvice()))
                continue;

            String flag = createArgumentLabel(descriptor);

            boolean isHeapObject = isHeapObject(descriptor);

            Object argumentValue = argumentSet.getArgumentValue(descriptor);

            if (IContextObject.class.isAssignableFrom(descriptor.getType())) {
                TableItem item = new TableItem(table, SWT.NONE);
                item.setFont(normalFont);
                item.setText(new String[] { flag, Messages.ArgumentsTable_selectedRows });
            } else if (descriptor.isMultiple() && !isHeapObject) {
                List<?> values = (List<?>) argumentValue;

                if (values == null)
                    values = (List<?>) descriptor.getDefaultValue();

                if (values == null || values.isEmpty()) {
                    addEditorRow(descriptor, flag, null, -1);
                } else {
                    Iterator<?> valueIt = values.iterator();
                    Object firstValue = valueIt.next();
                    addEditorRow(descriptor, flag, firstValue, -1);
                    while (valueIt.hasNext()) {
                        Object objValue = valueIt.next();
                        addEditorRow(descriptor, "..\"..", objValue, -1); //$NON-NLS-1$
                    }
                    addEditorRow(descriptor, "..\"..", null, -1); //$NON-NLS-1$
                }
            } else if (isHeapObject && argumentValue instanceof HeapObjectContextArgument) {
                // when query is called for the certain object instance (from
                // the view). In that case hoa cannot be modified
                TableItem item = new TableItem(table, SWT.NONE);
                item.setFont(normalFont);
                item.setText(new String[] { flag, String.valueOf(argumentValue) });
            } else if (isHeapObject) {
                addHeapObjectTableItems(descriptor, (HeapObjectParamArgument) argumentValue);
            } else {
                Object value = argumentValue;
                if (value == null)
                    value = descriptor.getDefaultValue();

                addEditorRow(descriptor, flag, value, -1);
            }

        }

        for (Control control : table.getChildren()) {
            if (control instanceof ArgumentEditor)
                ((ArgumentEditor) control).addListener(this);
        }
        try {
            table.getChildren()[0].setFocus();
        } catch (ArrayIndexOutOfBoundsException e) {
            // $JL-EXC$
            // should not happen as we assume that table should have at least
            // one child.
            // If by any reason the exception occurs, the focus will not be set
        }
    }

    private boolean isHeapObject(ArgumentDescriptor descriptor) {
        boolean isHeapObject = descriptor.getAdvice() == Argument.Advice.HEAP_OBJECT //
                || IObject.class.isAssignableFrom(descriptor.getType()) //
                || IHeapObjectArgument.class.isAssignableFrom(descriptor.getType());
        return isHeapObject;
    }

    private String createArgumentLabel(ArgumentDescriptor descriptor) {
        String flag = descriptor.getFlag();
        if (flag == null)
            return descriptor.getName();
        else
            return "-" + flag;//$NON-NLS-1$
    }

    private void addEditorRow(ArgumentDescriptor descriptor, String flag, Object value, int index) {
        TableItem item;
        if (index > 0)
            item = new TableItem(table, SWT.NONE, index);
        else
            item = new TableItem(table, SWT.NONE);

        item.setText(flag);

        setFont(descriptor, item);

        TableEditor editor = createEditor();

        ArgumentEditor aec = TableEditorFactory.createTableEditor(table, context, descriptor, item);
        aec.setFont(item.getFont());
        editor.setEditor(aec, item, 1);
        item.setData(aec);
        // Adjust the table height for the editor
        setTableRowHeight(aec.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);

        // listener should be added only to the new rows, for rows with default
        // values listeners are added after the table is created and filled with
        // default values
        if (index > 0) {
            aec.addListener(this);

            // ugly: w/o pack, the table does not redraw the editors correctly
            table.pack();
            table.getParent().pack();

            setNewTabOrder();
        }

        try {
            if (value != null)
                aec.setValue(value);
        } catch (SnapshotException e) {
            // $JL-EXC$
            // leave editor empty
        }
    }

    private void setFont(ArgumentDescriptor descriptor, TableItem item) {
        // to make the rows in the table a little higher we set the bigger font
        // to the whole table.
        // and in this method we return the normal size and highlight mandatory
        // arguments.
        if (descriptor.isMandatory()) {
            // Normal font for whole row
            item.setFont(normalFont);
            // Bold font for first box in row
            item.setFont(0, boldFont);
        } else
            item.setFont(normalFont);
    }

    private void setNewTabOrder() {
        // this method is called when the new row was inserted to reassure that
        // the "Tab" button works correct.
        TableItem[] items = table.getItems();
        // we need to include to the TabList only those items that are editors
        Control[] newTabOrder = new Control[table.getChildren().length];
        for (int i = 0, j = 0; i < items.length; i++, j++) {
            if (items[i].getData() != null)
                newTabOrder[j] = (ArgumentEditor) items[i].getData();
            else
                j--;
        }

        table.setTabList(newTabOrder);
    }

    private void addHeapObjectTableItems(ArgumentDescriptor descriptor, int index,
            TextEditor.DecoratorType decorator) {
        TableItem item = new TableItem(table, SWT.NONE, index);
        setFont(descriptor, item);

        TableEditor editor = createEditor();

        ImageTextEditor aec = new ImageTextEditor(table, context, descriptor, item, decorator);
        aec.setFont(item.getFont());
        editor.setEditor(aec, item, 1);
        item.setData(aec);
        // Adjust the table height for the image button
        setTableRowHeight(aec.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);

        aec.addListener(this);
        // ugly: w/o pack, the table does not redraw the editors correctly
        table.getParent().pack();

        setNewTabOrder();

    }

    private void addHeapObjectTableItems(ArgumentDescriptor descriptor, HeapObjectParamArgument initialInput) {
        // Some queries can only cope with one object
        boolean singleObject = isSingleObjectDescriptor(descriptor);
        DecoratorType types[] = TextEditor.DecoratorType.values();
        if (singleObject) {
            // The query is only expecting one object so make the object address
            // query first
            types = new DecoratorType[] { TextEditor.DecoratorType.OBJECT_ADDRESS, TextEditor.DecoratorType.PATTERN,
                    TextEditor.DecoratorType.QUERY };
        }
        // If an initial input would be hidden in simple mode then switch to advanced
        if (initialInput != null
                && (types[0] != TextEditor.DecoratorType.OBJECT_ADDRESS && !initialInput.getAddresses().isEmpty()
                        || types[0] != TextEditor.DecoratorType.QUERY && !initialInput.getOqls().isEmpty()
                        || types[0] != TextEditor.DecoratorType.PATTERN && !initialInput.getPatterns().isEmpty())) {
            // check whether Mode.ADVANCED_MODE and switch to it if not the case
            verifyMode();
        }

        if (modeMap.get(descriptor).equals(Mode.SIMPLE_MODE)) {
            // Only have one type in simple mode
            types = new TextEditor.DecoratorType[] { types[0] };
        }

        String label = createArgumentLabel(descriptor);
        for (TextEditor.DecoratorType decorator : types) {
            boolean createExtra = true;
            if (decorator.equals(TextEditor.DecoratorType.PATTERN)) {
                // when the mode of the table is switched after a pattern was
                // provided - keep the pattern
                List<Pattern> patterns = null;

                if (initialInput != null) {
                    patterns = initialInput.getPatterns();
                }
                // create a new row for each pattern
                if (patterns != null) {
                    for (Pattern pattern : patterns) {
                        createHeapObjectRow(descriptor, pattern.toString(), decorator, label);
                        // a work around: to avoid "objects" label for each of
                        // the three editors
                        label = "";//$NON-NLS-1$
                    }
                }
            } else if (decorator.equals(TextEditor.DecoratorType.OBJECT_ADDRESS)) {
                List<Long> addresses = null;
                if (initialInput != null) {
                    addresses = initialInput.getAddresses();
                }
                // create a new row for each pattern
                if (addresses != null) {
                    for (Long address : addresses) {
                        createHeapObjectRow(descriptor, ADDRESS_PREFIX + Long.toHexString(address), decorator,
                                label);
                        label = "";//$NON-NLS-1$
                        // Don't create a spare row when we only need one object
                        createExtra &= !singleObject;
                    }
                }
            } else
            // TextEditor.DecoratorType.QUERY
            {
                List<String> oqls = null;
                if (initialInput != null) {
                    oqls = initialInput.getOqls();
                }
                // create a new row for each pattern
                if (oqls != null) {
                    for (String oql : oqls) {
                        createHeapObjectRow(descriptor, oql, decorator, label);
                        label = "";//$NON-NLS-1$
                        // Don't create a spare row when we only need one object
                        createExtra &= !singleObject;
                    }
                }
            }

            if (createExtra) {
                // plus one empty row for this type of decorator in any case
                createHeapObjectRow(descriptor, null, decorator, label);
                label = "";//$NON-NLS-1$
            }
        }

        for (TextEditor.DecoratorType decorator : types) {
            if (decorator.equals(TextEditor.DecoratorType.PATTERN)) {
                // Add the subclass instance box if the class name pattern is visible
                addCheckBoxRows(descriptor, CheckBoxEditor.Type.INCLUDE_CLASS_INSTANCE,
                        (initialInput != null) ? initialInput.isIncludeClassInstance() : false);
                break;
            }
        }

        if (modeMap.get(descriptor).equals(Mode.ADVANCED_MODE)) {
            addCheckBoxRows(descriptor, CheckBoxEditor.Type.INCLUDE_SUBCLASSES,
                    (initialInput != null) ? initialInput.isIncludeSubclasses() : false);
            addCheckBoxRows(descriptor, CheckBoxEditor.Type.INTEPRET_AS_CLASSLOADER,
                    (initialInput != null) ? initialInput.isIncludeLoadedInstances() : false);
            addCheckBoxRows(descriptor, CheckBoxEditor.Type.RETAINED,
                    (initialInput != null) ? initialInput.isRetained() : false);
        }

        addLink(descriptor, modeMap.get(descriptor));
        table.getParent().pack();
    }

    private boolean isSingleObjectDescriptor(ArgumentDescriptor descriptor) {
        return !descriptor.isMultiple() && isHeapObject(descriptor)
                && (IObject.class.isAssignableFrom(descriptor.getType()) || descriptor.getType() == int.class
                        || descriptor.getType() == Integer.class);
    }

    private void verifyMode() {
        if (mode.equals(Mode.SIMPLE_MODE))
            mode = Mode.ADVANCED_MODE;

    }

    private void createHeapObjectRow(ArgumentDescriptor descriptor, String value,
            TextEditor.DecoratorType decorator, String label) {
        TableItem item = new TableItem(table, SWT.NONE);
        item.setText(label);
        setFont(descriptor, item);

        TableEditor editor = createEditor();

        ImageTextEditor aec = new ImageTextEditor(table, context, descriptor, item, decorator);
        aec.setFont(item.getFont());
        editor.setEditor(aec, item, 1);
        item.setData(aec);
        // Adjust the table height for the image button
        setTableRowHeight(aec.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);

        if (value != null) {
            try {
                if (decorator.equals(TextEditor.DecoratorType.OBJECT_ADDRESS)) {
                    // This is a bit strange - the value gets resolved as an objectid
                    ISnapshot snapshot = (ISnapshot) context.get(ISnapshot.class, null);
                    long addr = new BigInteger(value.substring(2), 16).longValue();
                    // Check address is valid
                    Integer ival = Integer.valueOf(snapshot.mapAddressToId(addr));
                    // but set the hex value
                    aec.setValue(value);
                } else {
                    aec.setValue(value);
                }
            } catch (SnapshotException e) {
                // $JL-EXC$
                // leave editor empty
            }
        }
    }

    private void addLink(ArgumentDescriptor descriptor, Mode mode) {
        TableItem item = new TableItem(table, SWT.NONE);
        item.setFont(normalFont);
        item.setText("");//$NON-NLS-1$
        TableEditor editor = createEditor();

        LinkEditor aec = new LinkEditor(table, context, descriptor, item, mode);
        aec.setFont(item.getFont());
        editor.setEditor(aec, item, 1);
        item.setData(aec);
        // Adjust the table height for the editor
        setTableRowHeight(aec.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
    }

    private TableEditor createEditor() {
        TableEditor editor = new TableEditor(table);
        editor.horizontalAlignment = SWT.LEFT;
        editor.grabHorizontal = true;
        editor.minimumWidth = MIN_EDITOR_WIDTH;

        return editor;
    }

    private void addCheckBoxRows(ArgumentDescriptor descriptor, CheckBoxEditor.Type type, boolean selected) {
        TableItem item = new TableItem(table, SWT.NONE);
        item.setFont(normalFont);
        item.setText("");//$NON-NLS-1$

        TableEditor editor = createEditor();

        CheckBoxEditor aec = new CheckBoxEditor(table, context, descriptor, item, type);
        aec.setFont(item.getFont());
        editor.setEditor(aec, item, 1);
        item.setData(aec);
        // Adjust the table height for the editor
        setTableRowHeight(aec.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);

        try {
            aec.setValue(selected);
        } catch (SnapshotException e) {
            // $JL-EXC$
            // leave unselected
        }
    }

    public synchronized void onValueChanged(Object value, ArgumentDescriptor descriptor, TableItem item,
            ArgumentEditor argEditor) {
        int myIndex = table.indexOf(item);

        // remove error message
        onError(argEditor, null);
        onError(null, null);

        boolean isHeapObject = isHeapObject(descriptor);

        boolean isLastOne = descriptor.isMultiple() && !isHeapObject && (myIndex + 1 == table.getItemCount()
                || ((ArgumentEditor) table.getItem(myIndex + 1).getData()).getDescriptor() != descriptor);

        // update argument set -- heap objects
        if (isHeapObject) {
            // if (value == null)
            // return;

            if (argEditor instanceof ImageTextEditor) {
                // verify current modification
                verifyHeapObjectTextEditorInput((ImageTextEditor) argEditor);
            }
            // if there are no errors in all the fields describing the hoa -
            // create HeapObject and add it to the argumentSet
            if (noErrorsInHoa()) {
                // overwrite hoa on every modification
                argumentSet.removeArgumentValue(descriptor);
                HeapObjectParamArgument hoa = createHeapObjectDefinition(descriptor);

                if (hoa.isComplete()) {
                    argumentSet.setArgumentValue(descriptor, hoa);
                    // add new row only when there are no errors
                    if ((argEditor instanceof ImageTextEditor)
                            && isNewRowNeeded(descriptor, ((ImageTextEditor) argEditor).getDecorator())) {
                        addHeapObjectTableItems(descriptor, myIndex + 1,
                                ((ImageTextEditor) argEditor).getDecorator());
                    }
                } else if (descriptor.isMandatory()) {
                    // add error message on null argument
                    onError(null, Messages.ArgumentsTable_ProvidePattern);
                }

            }
        }
        // update lists
        else if (descriptor.isMultiple()) {
            List<Object> values = new ArrayList<Object>();

            Control[] children = table.getChildren();
            for (int ii = 0; ii < children.length; ii++) {
                if (!(children[ii] instanceof ArgumentEditor))
                    continue;

                ArgumentEditor editor = (ArgumentEditor) children[ii];
                if (editor.getDescriptor() == descriptor) {
                    Object v = editor.getValue();
                    if (v != null)
                        values.add(v);
                }
            }

            if (values.isEmpty())
                values = null;

            Object defaultValue = descriptor.getDefaultValue();
            if (defaultValue == null || !defaultValue.equals(values))
                argumentSet.setArgumentValue(descriptor, values);
            else
                argumentSet.removeArgumentValue(descriptor);

            // warn a/b mandatory arguments
            if (descriptor.isMandatory() && values == null)
                onError(argEditor, MessageUtil.format(Messages.ArgumentsTable_isMandatory, descriptor.getName()));

            // insert new row at myIndex + 1
            if (isLastOne && value != null)
                addEditorRow(descriptor, "..\"..", null, myIndex + 1);//$NON-NLS-1$
        } else {
            Object defaultValue = descriptor.getDefaultValue();

            if (defaultValue == null || !defaultValue.equals(value)) {
                argumentSet.setArgumentValue(descriptor, value);
            } else {
                argumentSet.removeArgumentValue(descriptor);
            }

            // warn a/b mandatory arguments
            if (descriptor.isMandatory() && value == null)
                onError(argEditor, MessageUtil.format(Messages.ArgumentsTable_isMandatory, descriptor.getName()));
        }

        // inform about value changes
        fireInputChangedEvent();
    }

    private boolean isNewRowNeeded(ArgumentDescriptor descriptor, DecoratorType decorator) {
        boolean notEmpty = true;
        Control[] children = table.getChildren();
        for (Control control : children) {
            if ((control instanceof ImageTextEditor)
                    && ((ImageTextEditor) control).getDescriptor().equals(descriptor)
                    && ((ImageTextEditor) control).getDecorator().equals(decorator)) {
                notEmpty = notEmpty && ((ImageTextEditor) control).getValue() != null
                        && !((ImageTextEditor) control).getValue().equals("");//$NON-NLS-1$
                // If the decorator is not a pattern and we only need one argument then only have one
                notEmpty &= decorator.equals(TextEditor.DecoratorType.PATTERN)
                        || !isSingleObjectDescriptor(descriptor);
            }
        }
        return notEmpty;
    }

    private HeapObjectParamArgument createHeapObjectDefinition(ArgumentDescriptor descriptor) {
        ISnapshot snapshot = (ISnapshot) context.get(ISnapshot.class, null);
        HeapObjectParamArgument hoa = new HeapObjectParamArgument(snapshot);

        Control[] children = table.getChildren();
        for (Control control : children) {
            if (!descriptor.equals(((ArgumentEditor) control).getDescriptor()))
                continue;

            if (control instanceof CheckBoxEditor) {
                Boolean value = (Boolean) ((CheckBoxEditor) control).getValue();
                switch (((CheckBoxEditor) control).getType()) {
                case INCLUDE_CLASS_INSTANCE: {
                    hoa.setIncludeClassInstance(value);
                    break;
                }
                case INCLUDE_SUBCLASSES: {
                    hoa.setIncludeSubclasses(value);
                    break;
                }
                case INTEPRET_AS_CLASSLOADER: {
                    hoa.setIncludeLoadedInstances(value);
                    break;
                }
                case RETAINED: {
                    hoa.setRetained(value);
                    break;
                }
                case VERBOSE: {
                    hoa.setVerbose(value);
                    break;
                }
                }
            } else if (control instanceof ImageTextEditor) {
                ImageTextEditor editor = (ImageTextEditor) control;
                if (editor.getValue() != null) {
                    DecoratorType decorator = editor.getDecorator();
                    String line = ((ImageTextEditor) control).getValue().toString().trim();
                    // Ensure that types and values are appropriate
                    if (decorator == TextEditor.DecoratorType.QUERY
                            && line.toLowerCase(Locale.ENGLISH).startsWith("select")) //$NON-NLS-1$
                    {
                        hoa.addOql(line);
                    } else if (decorator == TextEditor.DecoratorType.OBJECT_ADDRESS
                            && line.startsWith(ADDRESS_PREFIX)) {
                        hoa.addObjectAddress(new BigInteger(line.substring(2), 16).longValue());

                    } else
                    // Pattern
                    {
                        if (decorator == TextEditor.DecoratorType.PATTERN && !line.equals(""))//$NON-NLS-1$
                        {
                            hoa.addPattern(Pattern.compile(line));
                        }

                    }
                }
            } // control of other types do not belong to the HeapObject
              // arguments
        }
        return hoa;
    }

    private void verifyHeapObjectTextEditorInput(ImageTextEditor editor) {
        TextEditor.DecoratorType decorator = editor.getDecorator();
        if (editor.getValue() != null) {
            onError(editor, null);

            String line = editor.getValue().toString().trim();

            if (decorator.equals(TextEditor.DecoratorType.QUERY)) {
                if (line.equals(""))//$NON-NLS-1$
                    return;
                try {
                    SnapshotFactory.createQuery(line);
                } catch (SnapshotException e) {
                    // $JL-EXC$

                    // fix: reformat message for proper displaying
                    String msg = e.getMessage();

                    if (msg.startsWith(Messages.ArgumentsTable_Encountered)) {
                        int p = msg.indexOf(Messages.ArgumentsTable_WasExpecting);
                        if (p >= 0)
                            msg = msg.substring(p, msg.length()).replace(EOL, " ");//$NON-NLS-1$
                    }

                    onError(editor, msg);
                }
            } else if (decorator.equals(TextEditor.DecoratorType.OBJECT_ADDRESS)) {
                if (line.length() > 2 && ADDRESS_PREFIX.equals(line.substring(0, 2))) {
                    try {
                        new BigInteger(line.substring(2), 16).longValue();
                    } catch (NumberFormatException e) {
                        // $JL-EXC$
                        onError(editor, Messages.ArgumentsTable_InvalidAddress + e.getMessage());
                    }
                } else if (line.length() < 2 && !line.startsWith(ADDRESS_PREFIX.substring(0, line.length()))
                        || line.length() >= 2 && !line.startsWith(ADDRESS_PREFIX.substring(0, 2))) {

                    onError(editor, Messages.ArgumentsTable_InvalidAddress + line);
                } else if (line.length() != 0) {
                    onError(editor, Messages.ArgumentsTable_AddressNotComplete);
                }
            } else
            // Pattern
            {
                if (!line.equals(""))//$NON-NLS-1$
                {
                    try {
                        Pattern.compile(line);
                    } catch (PatternSyntaxException e) {
                        // $JL-EXC$
                        int idx = Math.max(0, Math.min(e.getIndex(), line.length()));
                        onError(editor, MessageUtil.format(Messages.ArgumentsTable_InvalidClassNamePattern,
                                e.getIndex(), line.substring(0, idx), e.getDescription()));
                    }
                }

            }
        }
    }

    private boolean noErrorsInHoa() {
        for (Map.Entry<ArgumentEditor, String> entry : errors.entrySet()) {
            if (entry.getKey() instanceof ImageTextEditor) {
                return false;
            }
        }
        return true;
    }

    public synchronized void onError(ArgumentEditor editor, String message) {
        synchronized (errors) {
            if (message == null) {
                if (errors.remove(editor) != null) {

                    if (errors.isEmpty())
                        fireErrorMessageEvent(null);
                    else
                        fireErrorMessageEvent(errors.values().iterator().next());

                }
            } else {
                errors.put(editor, message);
                fireErrorMessageEvent(message);
            }
        }
    }

    // //////////////////////////////////////////////////////////////
    // table listener implementation
    // //////////////////////////////////////////////////////////////

    public void addListener(ITableListener listener) {
        this.listeners.add(listener);
    }

    public void removeListener(ITableListener listener) {
        this.listeners.remove(listener);
    }

    private void fireInputChangedEvent() {
        synchronized (listeners) {
            for (ITableListener listener : listeners)
                listener.onInputChanged();
        }
    }

    private void fireErrorMessageEvent(String message) {
        synchronized (listeners) {
            for (ITableListener listener : listeners)
                listener.onError(message);
        }
    }

    public void fireFocusChangedEvent(String message) {
        synchronized (listeners) {
            for (ITableListener listener : listeners)
                listener.onFocus(message);
        }
    }

    public void onFocus(String message) {
        fireFocusChangedEvent(message);
    }

    public void onModeChange(Mode mode, ArgumentDescriptor descriptor) {
        // add new mode for this descriptor to the HashMap to be able to proceed
        // different descriptors independently
        if (modeMap == null) {
            modeMap = new HashMap<ArgumentDescriptor, Mode>();
        }

        modeMap.put(descriptor, mode);

        List<ITableListener> copy = new ArrayList<ITableListener>(listeners);
        for (ITableListener listener : copy)
            listener.onModeChange(mode);
        // clear error messages
        errors.clear();
        fireErrorMessageEvent(null);

        table.removeAll();
        Control[] children = table.getChildren();
        for (Control control : children) {
            control.dispose();
        }

        this.createTableContent();
    }

}