com.arm.cmsis.config.editors.ConfigEditor.java Source code

Java tutorial

Introduction

Here is the source code for com.arm.cmsis.config.editors.ConfigEditor.java

Source

/*******************************************************************************
 * Copyright (c) 2016 ARM Ltd. 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:
 * ARM Ltd and ARM Germany GmbH - Initial API and implementation
 *******************************************************************************/
package com.arm.cmsis.config.editors;

import java.util.Collection;
import java.util.Map;

import org.eclipse.cdt.internal.ui.editor.CEditor;
import org.eclipse.cdt.internal.ui.editor.asm.AsmTextEditor;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.resource.FontDescriptor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.ide.ResourceUtil;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.MultiPageEditorPart;

import com.arm.cmsis.config.IHelpContextIds;
import com.arm.cmsis.config.Messages;
import com.arm.cmsis.config.model.IConfigWizardItem;
import com.arm.cmsis.config.model.IConfigWizardItem.EItemErrorType;
import com.arm.cmsis.config.model.IConfigWizardItem.EItemType;
import com.arm.cmsis.pack.ui.CpPlugInUI;
import com.arm.cmsis.pack.ui.tree.AdvisedCellLabelProvider;
import com.arm.cmsis.pack.ui.tree.AdvisedEditingSupport;
import com.arm.cmsis.pack.ui.tree.ColumnAdvisor;
import com.arm.cmsis.pack.ui.tree.IColumnAdvisor;
import com.arm.cmsis.parser.ConfigWizardParser;
import com.arm.cmsis.parser.ConfigWizardScanner;
import com.arm.cmsis.utils.Utils;

/**
 * An example showing how to create a multi-page editor. This example has 3
 * pages:
 * <ul>
 * <li>page 0 contains a nested text editor.
 * <li>page 1 allows you to use configuration wizard
 * </ul>
 */
@SuppressWarnings("restriction")
public class ConfigEditor extends MultiPageEditorPart implements IResourceChangeListener {

    /** The text editor used in page 0. */
    TextEditor editor;

    /** The document in the editor. */
    private IDocument fDocument;

    /** The resource file in the workspace*/
    IFile fFile;

    /** parser job for the config wizard. */
    Job fParserJob;

    /** parser for the config wizard. */
    ConfigWizardParser fParser;

    /** True if user has changed the text before switch pages */
    boolean fNeedReparse;

    /** The tree viewer */
    TreeViewer fViewer;

    /** The second column's advisor */
    private IColumnAdvisor fColumnAdvisor;

    /** The tooltip text */
    private StyledText fText;

    IConfigWizardItem getConfigWizardItem(Object obj) {
        if (obj instanceof IConfigWizardItem) {
            return (IConfigWizardItem) obj;
        }
        return null;
    }

    /**
     * Creates a multi-page editor example.
     */
    public ConfigEditor() {
        super();
        ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
        fParserJob = new Job(Messages.ConfigEditor_ParsingConfigWizard) {
            @Override
            protected IStatus run(IProgressMonitor monitor) {
                monitor.beginTask(Messages.ConfigEditor_ParsingConfigWizard, 100);
                monitor.worked(98);
                fParser.parse();
                fNeedReparse = false;
                monitor.done();
                return Status.OK_STATUS;
            }
        };
        fParserJob.setUser(true);
        fParserJob.setPriority(Job.INTERACTIVE);
        fParserJob.addJobChangeListener(new JobChangeAdapter() {
            @Override
            public void done(IJobChangeEvent event) {
                Display.getDefault().asyncExec(new Runnable() {
                    @Override
                    public void run() {
                        IConfigWizardItem root = fParser.getConfigWizardRoot();
                        if (root == null) { // parsing error
                            editor.selectAndReveal(fParser.getParsingErrorOffset(), 0);
                        } else if (fViewer.getControl() != null && !fViewer.getControl().isDisposed()) {
                            fViewer.setInput(root);
                        }
                    }
                });
            }
        });
    }

    /**
     * Creates page 0 of the multi-page editor, which contains a text editor.
     */
    void createPage0() {
        try {
            IEditorInput editorInput = getEditorInput();
            if (editorInput.getName().toLowerCase().endsWith(".s")) { //$NON-NLS-1$
                editor = new AsmTextEditor();
            } else {
                editor = new CEditor();
            }
            int index = addPage(editor, getEditorInput());
            setPageText(index, Messages.ConfigEditor_FirstPageText);
            setPartName(editor.getTitle());
            setTitleImage(CpPlugInUI.getImage(CpPlugInUI.ICON_DETAILS));

            fDocument = editor.getDocumentProvider().getDocument(editor.getEditorInput());
        } catch (PartInitException e) {
            ErrorDialog.openError(getSite().getShell(), Messages.ConfigEditor_ErrorInNestedTextEditor, null,
                    e.getStatus());
        }
    }

    /**
     * Creates page 1 of the multi-page editor, which shows the
     * configuration wizard
     */
    void createPage1() {

        Composite composite = new Composite(getContainer(), SWT.NONE);
        composite.setLayout(new GridLayout(3, false));

        buildToolBar(composite);

        buildTreeViewer(composite);

        buildText(composite);

        int index = addPage(composite);
        setPageText(index, Messages.ConfigEditor_SecondPageText);

    }

    /**
     * Creates the pages of the multi-page editor.
     */
    @Override
    protected void createPages() {
        createPage0();
        fParser = new ConfigWizardParser(new ConfigWizardScanner(editor instanceof AsmTextEditor), fDocument);
        if (fParser.containWizard()) {
            fParserJob.schedule();
            createPage1();
            hookDocumentChangeListener();
            setActivePage(1);
        }
    }

    protected void hookDocumentChangeListener() {
        fDocument.addDocumentListener(new IDocumentListener() {
            @Override
            public void documentChanged(DocumentEvent event) {
                fNeedReparse = true;
            }

            @Override
            public void documentAboutToBeChanged(DocumentEvent event) {
                // do nothing
            }
        });
    }

    /**
     * The <code>MultiPageEditorPart</code> implementation of this
     * <code>IWorkbenchPart</code> method disposes all nested editors.
     * Subclasses may extend.
     */
    @Override
    public void dispose() {
        ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
        super.dispose();
    }

    /**
     * Saves the multi-page editor's document.
     */
    @Override
    public void doSave(IProgressMonitor monitor) {
        getEditor(0).doSave(monitor);
    }

    /**
     * Saves the multi-page editor's document as another file. Also updates the
     * text for page 0's tab, and updates this multi-page editor's input to
     * correspond to the nested editor's.
     */
    @Override
    public void doSaveAs() {
        IEditorPart editor = getEditor(0);
        editor.doSaveAs();
        setPartName(editor.getTitle());
        setInput(editor.getEditorInput());
    }

    @Override
    protected void setInput(IEditorInput input) {
        super.setInput(input);
        fFile = ResourceUtil.getFile(input);
        String title = input.getName();
        setPartName(title);
    }

    public void gotoMarker(IMarker marker) {
        setActivePage(0);
        IDE.gotoMarker(getEditor(0), marker);
    }

    /**
     * The <code>MultiPageEditorExample</code> implementation of this method
     * checks that the input is an instance of <code>IFileEditorInput</code>.
     */
    @Override
    public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException {
        if (!(editorInput instanceof IFileEditorInput)) {
            throw new PartInitException(Messages.ConfigEditor_InvalidEditorInput);
        }
        super.init(site, editorInput);
    }

    @Override
    public boolean isSaveAsAllowed() {
        return true;
    }

    /**
     * Calculates the contents of page 2 when the it is activated.
     */
    @Override
    protected void pageChange(int newPageIndex) {
        if (newPageIndex == 1 && fNeedReparse) {
            if (fParser.findConfigurationWizard()) {
                fParserJob.schedule();
                fNeedReparse = false;
                super.pageChange(newPageIndex);
            } else {
                removePage(1);
            }
            return;
        } else if (newPageIndex == 0) {
            fNeedReparse = false;
        }
        super.pageChange(newPageIndex);
    }

    /**
     * Closes all project files on project close.
     */
    @Override
    public void resourceChanged(final IResourceChangeEvent event) {
        // consider only POST_CHANGE events
        if (event.getType() != IResourceChangeEvent.POST_CHANGE) {
            return;
        }
        IResourceDelta resourseDelta = event.getDelta();
        IResourceDeltaVisitor deltaVisitor = new IResourceDeltaVisitor() {
            @Override
            public boolean visit(IResourceDelta delta) {
                IResource resource = delta.getResource();
                int type = resource.getType();
                if (type == IResource.ROOT) {
                    return true; // workspace => visit children
                }

                int kind = delta.getKind();
                int flags = delta.getFlags();

                if (type == IResource.FILE && kind == IResourceDelta.REMOVED && resource.equals(fFile)) {

                    if ((flags & IResourceDelta.MOVED_TO) == IResourceDelta.MOVED_TO) {
                        // renamed
                        IPath newPath = delta.getMovedToPath();
                        IFile r = (IFile) ResourcesPlugin.getWorkspace().getRoot().findMember(newPath);
                        final FileEditorInput fileEditorInput = new FileEditorInput(r);
                        Display.getDefault().asyncExec(() -> setInput(fileEditorInput));
                        return false;
                    } else if (flags == 0 // project deleted
                            || (flags & IResourceDelta.MARKERS) != 0) { // markers have changed
                        Display.getDefault().asyncExec(() -> {
                            ConfigEditor.this.getEditorSite().getPage().closeEditor(ConfigEditor.this, true);
                        });
                        return false;
                    }
                }
                return true;
            }
        };

        try {
            resourseDelta.accept(deltaVisitor);
        } catch (CoreException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected Control getControl(int pageIndex) {
        if (pageIndex == 1) {
            return fViewer.getControl();
        }
        return super.getControl(pageIndex);
    }

    @Override
    public void setFocus() {
        if (fNeedReparse && getActivePage() == 1) {
            if (fParser.findConfigurationWizard()) {
                fParserJob.schedule();
                fNeedReparse = false;
            } else {
                removePage(1);
            }
        }
        super.setFocus();
    }

    /************************* Here begins the Configuration Wizard GUI part *************************/

    class ManagedToolBar {
        ToolBar toolBar;
        ToolBarManager toolBarManager;

        public ManagedToolBar(final Composite parent, int style) {
            toolBarManager = new ToolBarManager(style);
            toolBar = toolBarManager.createControl(parent);
            toolBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL));
            toolBar.addListener(SWT.FOCUSED, new Listener() {
                @Override
                public void handleEvent(Event event) {
                    parent.setFocus();
                }
            });
        }

        public void addAction(IAction action, boolean showText) {
            if (showText) {
                ActionContributionItem aci = new ActionContributionItem(action);
                aci.setMode(ActionContributionItem.MODE_FORCE_TEXT);
                toolBarManager.add(aci);
            } else {
                toolBarManager.add(action);
            }
            toolBarManager.update(true);
        }

        public void dispose() {
            toolBarManager.removeAll();
            toolBarManager.dispose();
            toolBarManager = null;
            toolBar = null;
        }
    }

    private void buildToolBar(Composite parent) {

        Label imageLabel = new Label(parent, SWT.LEFT);
        imageLabel.setImage(CpPlugInUI.getImage(CpPlugInUI.ICON_DETAILS));

        Label title = new Label(parent, SWT.NONE);
        FontDescriptor boldDescriptor = FontDescriptor.createFrom(title.getFont()).setStyle(SWT.BOLD)
                .increaseHeight(1);
        Font boldFont = boldDescriptor.createFont(title.getDisplay());
        title.setFont(boldFont);
        title.setText(Messages.ConfigEditor_SecondPageText);

        ManagedToolBar toolbar = new ManagedToolBar(parent, SWT.FLAT | SWT.RIGHT_TO_LEFT);

        PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, IHelpContextIds.CONFIG_WIZARD);

        Action help = new Action(Messages.ConfigEditor_Help, IAction.AS_PUSH_BUTTON) {
            @Override
            public void run() {
                parent.notifyListeners(SWT.Help, new Event());
            }
        };
        help.setToolTipText(Messages.ConfigEditor_HelpForConfigWizard);
        help.setImageDescriptor(CpPlugInUI.getImageDescriptor(CpPlugInUI.ICON_HELP));
        toolbar.addAction(help, false);

        Action collapseAll = new Action(Messages.ConfigEditor_CollapseAll, IAction.AS_PUSH_BUTTON) {
            @Override
            public void run() {
                fViewer.collapseAll();
            }
        };
        collapseAll.setToolTipText(Messages.ConfigEditor_CollapseAllItems);
        collapseAll.setImageDescriptor(CpPlugInUI.getImageDescriptor(CpPlugInUI.ICON_COLLAPSE_ALL));
        toolbar.addAction(collapseAll, false);

        Action expandAll = new Action(Messages.ConfigEditor_ExpandAll, IAction.AS_PUSH_BUTTON) {
            @Override
            public void run() {
                fViewer.expandAll();
            }
        };
        expandAll.setToolTipText(Messages.ConfigEditor_ExpandAllItems);
        expandAll.setImageDescriptor(CpPlugInUI.getImageDescriptor(CpPlugInUI.ICON_EXPAND_ALL));
        toolbar.addAction(expandAll, false);
    }

    private void buildText(Composite parent) {
        fText = new StyledText(parent, SWT.MULTI | SWT.BORDER);
        fText.setEnabled(false);
        fText.setEditable(false);
        GridData gd_text = new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1);
        gd_text.heightHint = 80;
        fText.setLayoutData(gd_text);
    }

    class ContentProvider implements ITreeContentProvider {

        @Override
        public void dispose() {
        }

        @Override
        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        }

        @Override
        public Object[] getElements(Object inputElement) {
            return getChildren(inputElement);
        }

        @Override
        public Object[] getChildren(Object parentElement) {
            IConfigWizardItem item = getConfigWizardItem(parentElement);
            if (item != null) {
                return item.getChildren().toArray();
            }
            return new Object[0];
        }

        @Override
        public Object getParent(Object element) {
            IConfigWizardItem item = getConfigWizardItem(element);
            if (item != null) {
                return item.getParent();
            }
            return null;
        }

        @Override
        public boolean hasChildren(Object element) {
            return getChildren(element) != null && getChildren(element).length > 0;
        }

    }

    class FirstColumnLabelProvider extends ColumnLabelProvider {
        @Override
        public String getText(Object obj) {
            IConfigWizardItem item = getConfigWizardItem(obj);
            if (item != null) {
                return item.getName();
            }
            return null;
        }

        @Override
        public Color getForeground(Object element) {
            IConfigWizardItem item = getConfigWizardItem(element);
            if (item.isInconsistent()) {
                return new Color(Display.getDefault(), 255, 0, 0);
            }
            return super.getForeground(element);
        }

        @Override
        public String getToolTipText(Object obj) {
            IConfigWizardItem item = getConfigWizardItem(obj);
            if (item != null && !item.getTooltip().isEmpty()) {
                return item.getTooltip();
            }
            return null;
        }
    }

    private static final int COLEDIT = 1;

    private class ConfigColumnAdvisor extends ColumnAdvisor {

        public ConfigColumnAdvisor(ColumnViewer columnViewer) {
            super(columnViewer);
        }

        @Override
        public CellControlType getCellControlType(Object obj, int columnIndex) {
            IConfigWizardItem item = getConfigWizardItem(obj);
            EItemType type = item.getItemType();
            switch (type) {
            case HEADING_ENABLE:
            case OPTION_CHECK:
            case CODE_ENABLE:
            case CODE_DISABLE:
                return CellControlType.CHECK;
            case OPTION_SELECT:
                return CellControlType.MENU;
            case OPTION:
                if (item.getSpinStep() != 0) {
                    return CellControlType.SPIN;
                }
                break;
            default:
                break;
            }

            return CellControlType.TEXT;
        }

        @Override
        public boolean isEnabled(Object obj, int columnIndex) {
            IConfigWizardItem item = getConfigWizardItem(obj);
            return item.canModify();
        }

        @Override
        public boolean canEdit(Object obj, int columnIndex) {
            IConfigWizardItem item = getConfigWizardItem(obj);
            EItemType type = item.getItemType();
            switch (type) {
            case HEADING:
                return false;
            case HEADING_ENABLE:
            case CODE_ENABLE:
            case CODE_DISABLE:
                return isEnabled(item.getParent(), columnIndex);
            case OPTION:
            case OPTION_CHECK:
            case OPTION_SELECT:
            case OPTION_STRING:
                return isEnabled(obj, columnIndex);

            default:
                break;
            }
            return false;
        }

        @Override
        public boolean getCheck(Object obj, int columnIndex) {
            IConfigWizardItem item = getConfigWizardItem(obj);
            return item.getValue() > 0;
        }

        @Override
        public void setCheck(Object element, int columnIndex, boolean newVal) {
            IConfigWizardItem item = getConfigWizardItem(element);
            fParser.updateModel(item, newVal);
            fViewer.update(item, null);
            fViewer.refresh();
        }

        @Override
        public Image getImage(Object obj, int columnIndex) {
            if (getCellControlType(obj, columnIndex) == CellControlType.INPLACE_CHECK
                    || getCellControlType(obj, columnIndex) == CellControlType.CHECK) {
                boolean check = getCheck(obj, columnIndex);
                boolean enabled = canEdit(obj, columnIndex);
                Image image;
                if (enabled) {
                    image = check ? CpPlugInUI.getImage(CpPlugInUI.ICON_CHECKED)
                            : CpPlugInUI.getImage(CpPlugInUI.ICON_UNCHECKED);
                } else {
                    image = check ? CpPlugInUI.getImage(CpPlugInUI.ICON_CHECKED_GREY)
                            : CpPlugInUI.getImage(CpPlugInUI.ICON_UNCHECKED_GREY);
                }
                return image;
            }
            return super.getImage(obj, columnIndex);
        }

        @Override
        public String getString(Object obj, int columnIndex) {
            CellControlType type = getCellControlType(obj, columnIndex);
            if (type == CellControlType.CHECK) {
                return null;
            }
            IConfigWizardItem item = getConfigWizardItem(obj);
            EItemErrorType errorType = item.getItemErrorType();
            if (errorType == EItemErrorType.NUMBER_PARSE_ERROR) {
                return "<<< Invalid number >>>"; //$NON-NLS-1$
            } else if (errorType == EItemErrorType.LOCATE_POSITION_ERROR) {
                return "<<< Unable to locate value position >>>"; //$NON-NLS-1$
            }

            if (item.getItemType() == EItemType.OPTION_STRING) {
                return item.getString().replace("\\\"", "\""); //$NON-NLS-1$ //$NON-NLS-2$
            }
            if (item.getItemType() == EItemType.HEADING || item.getItemType() == EItemType.ROOT) {
                return null;
            }

            long value = item.getValue();
            long modifier = item.getModifier();
            char op = item.getModification();
            long realValue = Utils.modifyValueR(value, op, modifier, item.getMaxValue(), item.getMinValue());

            if (type == CellControlType.MENU) {
                Map<Long, String> items = item.getItems();
                if (items.containsKey(realValue)) {
                    return items.get(realValue);
                }
                return "<<< Invalid Index >>>"; //$NON-NLS-1$
            }
            if (item.getBase() == 10) {
                return String.valueOf(realValue);
            } else if (item.getBase() == 2) {
                String str = Long.toBinaryString(realValue);
                StringBuilder sb = new StringBuilder(str);
                int idx = sb.length() - 4;

                while (idx > 0) {
                    sb.insert(idx, " "); //$NON-NLS-1$
                    idx = idx - 4;
                }
                return "0b" + sb.toString().toUpperCase(); //$NON-NLS-1$
            } else if (item.getBase() == 8) {
                String str = Long.toOctalString(realValue);
                return "0" + str; //$NON-NLS-1$
            } else {
                String str = Long.toHexString(realValue);
                if (!str.startsWith("0") && str.length() % 2 != 0) { //$NON-NLS-1$
                    str = "0" + str; //$NON-NLS-1$
                }
                StringBuilder sb = new StringBuilder(str);
                int idx = sb.length() - 4;

                while (idx > 0) {
                    sb.insert(idx, " "); //$NON-NLS-1$
                    idx = idx - 4;
                }
                return "0x" + sb.toString().toUpperCase(); //$NON-NLS-1$
            }
        }

        @Override
        public long getCurrentSelectedIndex(Object element, int columnIndex) {
            IConfigWizardItem item = getConfigWizardItem(element);
            // This is selection
            if (item.getItemType() == EItemType.OPTION_SELECT) {
                long key = item.getValue();
                int i = 0;
                for (Long k : item.getItems().keySet()) {
                    if (k == key) {
                        return i;
                    }
                    i++;
                }
                return 0;
            }
            long modifier = item.getModifier();
            char op = item.getModification();
            long realValue = Utils.modifyValueR(item.getValue(), op, modifier, item.getMaxValue(),
                    item.getMinValue());
            return realValue;
        }

        @Override
        public void setCurrentSelectedIndex(Object obj, int columnIndex, long newVal) {
            IConfigWizardItem item = getConfigWizardItem(obj);
            // This is selection
            fParser.updateModel(item, newVal);
            fViewer.update(item, null);
        }

        @Override
        public String[] getStringArray(Object obj, int columnIndex) {
            IConfigWizardItem item = getConfigWizardItem(obj);
            Assert.isTrue(item.getItemType() == EItemType.OPTION_SELECT);
            Collection<String> str = item.getItems().values();
            return str.toArray(new String[str.size()]);
        }

        @Override
        public long getMaxCount(Object obj, int columnIndex) {
            IConfigWizardItem item = getConfigWizardItem(obj);
            long max = item.getMaxValue();
            return max;
        }

        @Override
        public long getMinCount(Object obj, int columnIndex) {
            IConfigWizardItem item = getConfigWizardItem(obj);
            long min = item.getMinValue();
            if (min < 0) {
                min = 0;
            }
            return min;
        }

        @Override
        public long getSpinStep(Object obj, int columnIndex) {
            IConfigWizardItem item = getConfigWizardItem(obj);
            long spinStep = item.getSpinStep();
            return spinStep;
        }

        @Override
        public int getItemBase(Object obj, int columnIndex) {
            IConfigWizardItem item = getConfigWizardItem(obj);
            return item.getBase();
        }

        @Override
        public void setString(Object obj, int columnIndex, String newVal) {
            if (getCellControlType(obj, columnIndex) == CellControlType.CHECK) {
                return;
            }
            IConfigWizardItem item = getConfigWizardItem(obj);
            fParser.updateModel(item, newVal);
            fViewer.update(item, null);
        }

        @Override
        public String getTooltipText(Object obj, int columnIndex) {
            IConfigWizardItem item = getConfigWizardItem(obj);
            if (item.getTooltip().isEmpty()) {
                return null;
            }
            return item.getTooltip();
        }

    }

    private void buildTreeViewer(Composite parent) {
        fViewer = new TreeViewer(parent, SWT.FULL_SELECTION | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
        Tree tree = fViewer.getTree();
        tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
        tree.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                TreeItem item = (TreeItem) e.item;
                if (item != null) {
                    IConfigWizardItem configItem = getConfigWizardItem(item.getData());
                    if (configItem != null) {
                        setCursorAndRevealAt(configItem.getStartLine());
                        showTooltipText(configItem);
                    }
                }
            }
        });
        tree.setLinesVisible(true);
        tree.setHeaderVisible(true);
        fColumnAdvisor = new ConfigColumnAdvisor(fViewer);

        TreeViewerColumn column0 = new TreeViewerColumn(fViewer, SWT.LEFT);
        column0.getColumn().setText(Messages.ConfigEditor_Option);
        column0.getColumn().setWidth(320);
        column0.setLabelProvider(new FirstColumnLabelProvider());

        TreeViewerColumn column1 = new TreeViewerColumn(fViewer, SWT.LEFT);
        column1.getColumn().setText(Messages.ConfigEditor_Value);
        column1.getColumn().setWidth(100);
        column1.setEditingSupport(new AdvisedEditingSupport(fViewer, fColumnAdvisor, COLEDIT));
        column1.setLabelProvider(new AdvisedCellLabelProvider(fColumnAdvisor, COLEDIT));

        // Add an empty column and adjust its width automatically for better looking
        TreeViewerColumn column2 = new TreeViewerColumn(fViewer, SWT.LEFT);
        column2.getColumn().setWidth(1);
        column2.setLabelProvider(new ColumnLabelProvider() {
            @Override
            public String getText(Object element) {
                return ""; //$NON-NLS-1$
            }
        });

        if (System.getProperty("os.name").startsWith("Windows")) { //$NON-NLS-1$ //$NON-NLS-2$
            parent.addControlListener(new ControlAdapter() {
                @Override
                public void controlResized(ControlEvent e) {
                    Tree tree = (Tree) fViewer.getControl();
                    Rectangle area = parent.getClientArea();
                    Point preferredSize = tree.computeSize(SWT.DEFAULT, SWT.DEFAULT);
                    int width = area.width - 2 * tree.getBorderWidth();
                    if (preferredSize.y > tree.getBounds().height) {
                        // Subtract the scrollbar width from the total column width
                        // if a vertical scrollbar will be required
                        Point vBarSize = tree.getVerticalBar().getSize();
                        width -= vBarSize.x;
                    }
                    Point oldSize = tree.getSize();
                    if (oldSize.x > area.width) {
                        // tree is getting smaller so make the columns
                        // smaller first and then resize the tree to
                        // match the client area width
                        column2.getColumn().setWidth(Math.max(0,
                                width - column0.getColumn().getWidth() - column1.getColumn().getWidth() - 10));
                        tree.setSize(area.width, area.height);
                    } else {
                        // tree is getting bigger so make the tree
                        // bigger first and then make the columns wider
                        // to match the client area width
                        tree.setSize(area.width, area.height);
                        column2.getColumn().setWidth(Math.max(0,
                                width - column0.getColumn().getWidth() - column1.getColumn().getWidth() - 10));
                    }
                }
            });
        }

        fViewer.setContentProvider(new ContentProvider());
        fViewer.setInput(fParser.getConfigWizardRoot());

        ColumnViewerToolTipSupport.enableFor(fViewer);
    }

    void setCursorAndRevealAt(int line) {
        try {
            int offset = fDocument.getLineOffset(line);
            editor.selectAndReveal(offset, 0);
        } catch (BadLocationException e) {
            e.printStackTrace();
        }
    }

    void showTooltipText(IConfigWizardItem configItem) {
        if (configItem.getTooltip().isEmpty()) {
            fText.setText(""); //$NON-NLS-1$
            return;
        }
        String name = configItem.getName() + System.lineSeparator();
        String tooltip = configItem.getTooltip();
        fText.setText(name + tooltip);

        StyleRange styleRange = new StyleRange();
        styleRange.start = 0;
        styleRange.length = name.length();
        styleRange.fontStyle = SWT.BOLD;
        styleRange.foreground = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
        fText.setStyleRange(styleRange);
    }

}