ext.org.eclipse.jdt.internal.ui.callhierarchy.ExpandWithConstructorsConfigurationBlock.java Source code

Java tutorial

Introduction

Here is the source code for ext.org.eclipse.jdt.internal.ui.callhierarchy.ExpandWithConstructorsConfigurationBlock.java

Source

/*******************************************************************************
 * Copyright (c) 2009, 2011 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 *******************************************************************************/

package ext.org.eclipse.jdt.internal.ui.callhierarchy;

import java.util.Arrays;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IStatus;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.StatusDialog;
import org.eclipse.jface.layout.PixelConverter;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.window.Window;

import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.SelectionDialog;
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;

import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaConventions;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.ui.IJavaElementSearchConstants;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.ui.PreferenceConstants;

import ext.org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
import ext.org.eclipse.jdt.internal.ui.JavaPluginImages;
import ext.org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
import ext.org.eclipse.jdt.internal.ui.dialogs.TextFieldNavigationHandler;
import ext.org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock;
import ext.org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext;
import ext.org.eclipse.jdt.internal.ui.util.ExceptionHandler;
import ext.org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
import ext.org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider;
import ext.org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener;
import ext.org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
import ext.org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
import ext.org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter;
import ext.org.eclipse.jdt.internal.ui.wizards.dialogfields.IStringButtonAdapter;
import ext.org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil;
import ext.org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField;
import ext.org.eclipse.jdt.internal.ui.wizards.dialogfields.StringButtonDialogField;

/**
 * Call hierarchy expand with constructors configuration block.
 *
 * @since 3.6
 */
public class ExpandWithConstructorsConfigurationBlock extends OptionsConfigurationBlock {

    /**
     * Call hierarchy expand with constructors dialog for types and members.
     */
    private static class CallHierarchyTypesOrMembersDialog extends StatusDialog {

        /**
         * The change listener class for the dialog field and the string button dialog field.
         *
         */
        private class StringButtonAdapter implements IDialogFieldListener, IStringButtonAdapter {
            /*
             * @see IDialogFieldListener#dialogFieldChanged(DialogField)
             */
            public void dialogFieldChanged(DialogField field) {
                doValidation();
            }

            /*
             * @see IStringButtonAdapter#changeControlPressed(DialogField)
             */
            public void changeControlPressed(DialogField field) {
                doBrowseTypes();
            }
        }

        /**
         * The name dialog field to hold the default expand with constructors list.
         */
        private StringButtonDialogField fNameDialogField;

        /**
         * The list of previously existing entries.
         */
        private List<String> fExistingEntries;

        /**
         * Tells whether it is an member or type.
         */
        private final boolean fIsEditingMember;

        /**
         * Creates a call hierarchy preference dialog for members or types.
         *
         * @param parent the parent shell
         * @param existingEntries the existing list of types and members
         * @param isEditingMember <code>true</code if its a member, <code>false</code> otherwise
         */
        public CallHierarchyTypesOrMembersDialog(Shell parent, List<String> existingEntries,
                boolean isEditingMember) {
            super(parent);
            fIsEditingMember = isEditingMember;
            fExistingEntries = existingEntries;

            String label, title;
            if (isEditingMember) {
                title = CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_member_title;
                label = CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_member_labelText;
            } else {
                title = CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_type_title;
                label = CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_type_labelText;
            }
            setTitle(title);

            StringButtonAdapter adapter = new StringButtonAdapter();

            fNameDialogField = new StringButtonDialogField(adapter);
            fNameDialogField.setLabelText(label);
            fNameDialogField.setButtonLabel(CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_browse_button);
            fNameDialogField.setDialogFieldListener(adapter);
            fNameDialogField.setText(""); //$NON-NLS-1$
        }

        /*
         * @see org.eclipse.jface.dialogs.Dialog#isResizable()       *
         */
        @Override
        protected boolean isResizable() {
            return true;
        }

        /**
         * Sets the initial selection in the name dialog field.
         *
         * @param editedEntry the edited entry
         */
        public void setInitialSelection(String editedEntry) {
            Assert.isNotNull(editedEntry);
            if (editedEntry.length() == 0)
                fNameDialogField.setText(""); //$NON-NLS-1$
            else
                fNameDialogField.setText(editedEntry);
        }

        /**
         * Returns the resulting text from the name dialog field.
         *
         * @return the resulting text from the name dialog field
         */
        public String getResult() {
            String val = fNameDialogField.getText();
            if (!fIsEditingMember)
                val = val + WILDCARD;
            return val;
        }

        /*
         * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
         */
        @Override
        protected Control createDialogArea(Composite parent) {
            Composite composite = (Composite) super.createDialogArea(parent);
            initializeDialogUnits(composite);

            GridLayout layout = (GridLayout) composite.getLayout();
            layout.numColumns = 2;

            fNameDialogField.doFillIntoGrid(composite, 3);

            fNameDialogField.getChangeControl(null).setVisible(!fIsEditingMember);

            LayoutUtil.setHorizontalSpan(fNameDialogField.getLabelControl(null), 2);

            int fieldWidthHint = convertWidthInCharsToPixels(60);
            Text text = fNameDialogField.getTextControl(null);
            LayoutUtil.setWidthHint(text, fieldWidthHint);
            LayoutUtil.setHorizontalGrabbing(text);
            LayoutUtil.setHorizontalSpan(text, fIsEditingMember ? 2 : 1);
            TextFieldNavigationHandler.install(text);

            DialogField.createEmptySpace(composite, 1);

            fNameDialogField.postSetFocusOnDialogField(parent.getDisplay());

            applyDialogFont(composite);
            return composite;
        }

        /**
         * Creates the type hierarchy for type selection.
         */
        private void doBrowseTypes() {
            IRunnableContext context = new BusyIndicatorRunnableContext();
            IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
            int style = IJavaElementSearchConstants.CONSIDER_ALL_TYPES;
            try {
                SelectionDialog dialog = JavaUI.createTypeDialog(getShell(), context, scope, style, false,
                        fNameDialogField.getText());
                dialog.setTitle(CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_ChooseTypeDialog_title);
                dialog.setMessage(
                        CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_ChooseTypeDialog_description);
                if (dialog.open() == Window.OK) {
                    IType res = (IType) dialog.getResult()[0];
                    fNameDialogField.setText(res.getFullyQualifiedName('.'));
                }
            } catch (JavaModelException e) {
                ExceptionHandler.handle(e, getShell(),
                        CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_ChooseTypeDialog_title,
                        CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_ChooseTypeDialog_error_message);
            }
        }

        /**
         * Validates the entered type or member and updates the status.
         */
        private void doValidation() {
            StatusInfo status = new StatusInfo();
            String newText = fNameDialogField.getText();
            if (newText.length() == 0) {
                status.setError(""); //$NON-NLS-1$
            } else {
                IStatus val = JavaConventions.validateJavaTypeName(newText, JavaCore.VERSION_1_3,
                        JavaCore.VERSION_1_3);
                if (val.matches(IStatus.ERROR)) {
                    if (fIsEditingMember)
                        status.setError(
                                CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_error_invalidMemberName);
                    else
                        status.setError(
                                CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_error_invalidTypeName);
                } else {
                    if (doesExist(newText)) {
                        status.setError(CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_error_entryExists);
                    }
                }
            }
            updateStatus(status);
        }

        /**
         * Checks if the entry already exists.
         *
         * @param name the type or member name
         * @return <code>true</code> if it already exists in the list of types and members,
         *         <code>false</code> otherwise
         */
        private boolean doesExist(String name) {
            for (int i = 0; i < fExistingEntries.size(); i++) {
                String entry = fExistingEntries.get(i);
                if (name.equals(entry)) {
                    return true;
                }
            }
            return false;
        }

        /*
         * @see org.eclipse.jface.window.Window#configureShell(Shell)
         */
        @Override
        protected void configureShell(Shell newShell) {
            super.configureShell(newShell);
            PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell,
                    IJavaHelpContextIds.CALL_HIERARCHY_EXPAND_WITH_CONSTRUCTORS_DIALOG);
        }

    }

    /*
     * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#performOk()
     */
    @Override
    public boolean performOk() {
        setValue(ANONYMOUS_EXPAND_WITH_CONSTRUCTORS, fIsAnonymous);
        return super.performOk();
    }

    /**
     * The list label provider class.
     */
    private static class ListLabelProvider extends LabelProvider {

        public final Image MEMBER_ICON;

        private final Image CLASS_ICON;

        /**
         * Create the member and class icons.
         */
        public ListLabelProvider() {
            MEMBER_ICON = JavaElementImageProvider.getDecoratedImage(JavaPluginImages.DESC_MISC_PUBLIC, 0,
                    JavaElementImageProvider.SMALL_SIZE);
            CLASS_ICON = JavaElementImageProvider.getDecoratedImage(JavaPluginImages.DESC_OBJS_CLASS, 0,
                    JavaElementImageProvider.SMALL_SIZE);
        }

        /*
         * @see org.eclipse.jface.viewers.LabelProvider#getImage(java.lang.Object)
         */
        @Override
        public Image getImage(Object element) {
            return ((String) element).endsWith(WILDCARD) ? CLASS_ICON : MEMBER_ICON;
        }

        /*
         * @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
         */
        @Override
        public String getText(Object element) {
            return BasicElementLabels.getJavaElementName((String) element);
        }
    }

    /**
     * The change listener for <code>ListDialogField</code>.
     */
    private class ListAdapter implements IListAdapter<String>, IDialogFieldListener {

        /**
         * Checks if field can be edited.
         *
         * @param field the list dialog field
         * @return <code>true</code> if it can be edited, <code>false</code> otherwise
         */
        private boolean canEdit(ListDialogField<String> field) {
            List<String> selected = field.getSelectedElements();
            return selected.size() == 1;
        }

        /*
         * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter#customButtonPressed(org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField, int)
         */
        public void customButtonPressed(ListDialogField<String> field, int index) {
            doButtonPressed(index);
        }

        /*
         * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter#selectionChanged(org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField)
         */
        public void selectionChanged(ListDialogField<String> field) {
            fList.enableButton(IDX_EDIT, canEdit(field));
            fList.enableButton(IDX_REMOVE, canRemove(field));
        }

        /**
         * Checks if the field can be removed.
         *
         * @param field the list dialog field
         * @return <code>true</code> if it can be removed, <code>false</code> otherwise
         */
        private boolean canRemove(ListDialogField<String> field) {
            List<String> selected = field.getSelectedElements();
            return selected.size() != 0;
        }

        /* )
         * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener#dialogFieldChanged(org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField)
         */
        public void dialogFieldChanged(DialogField field) {
            doDialogFieldChanged(field);
        }

        /*
         * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter#doubleClicked(org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField)
         */
        public void doubleClicked(ListDialogField<String> field) {
            if (canEdit(field)) {
                doButtonPressed(IDX_EDIT);
            }
        }
    }

    private static final String WILDCARD = ".*"; //$NON-NLS-1$

    private static final int IDX_NEW_TYPE = 0;
    private static final int IDX_NEW_MEMBER = 1;
    private static final int IDX_EDIT = 2;
    private static final int IDX_REMOVE = 3;
    private static final int IDX_RESTORE_DEFAULTS = 4;

    private ListDialogField<String> fList;

    private Button fAnonymousButton;

    protected boolean fIsAnonymous;

    /**
     * A key that holds the list of methods or types whose methods are by default expanded with constructors in the Call Hierarchy.
     */
    private static Key DEFAULT_EXPAND_WITH_CONSTRUCTORS_MEMBERS = getJDTUIKey(
            PreferenceConstants.PREF_DEFAULT_EXPAND_WITH_CONSTRUCTORS_MEMBERS);

    /**
     * A key that controls whether the methods from anonymous types are by default expanded with constructors in the Call Hierarchy.
     */
    private static Key ANONYMOUS_EXPAND_WITH_CONSTRUCTORS = getJDTUIKey(
            PreferenceConstants.PREF_ANONYMOUS_EXPAND_WITH_CONSTRUCTORS);

    /**
     * Returns all the key values.
     *
     * @return array of keys
     */
    public static Key[] getAllKeys() {
        return new Key[] { DEFAULT_EXPAND_WITH_CONSTRUCTORS_MEMBERS, ANONYMOUS_EXPAND_WITH_CONSTRUCTORS };
    }

    /**
     * Creates the call hierarchy preferences configuration block.
     *
     * @param context the status
     * @param container the preference container
     */
    public ExpandWithConstructorsConfigurationBlock(IStatusChangeListener context,
            IWorkbenchPreferenceContainer container) {
        super(context, null, getAllKeys(), container);
    }

    /*
     * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#createContents(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected Control createContents(Composite parent) {
        Composite control = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.numColumns = 2;
        layout.marginWidth = 10;
        layout.marginHeight = 10;
        control.setLayout(layout);

        createPreferenceList(control);

        fAnonymousButton = new Button(control, SWT.CHECK);
        fAnonymousButton.setText(CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_anonymousTypes_label);
        fIsAnonymous = getBooleanValue(ANONYMOUS_EXPAND_WITH_CONSTRUCTORS);
        fAnonymousButton.setSelection(fIsAnonymous);
        fAnonymousButton.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
        fAnonymousButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                fIsAnonymous = fAnonymousButton.getSelection();
            }

        });

        initialize();

        Dialog.applyDialogFont(control);

        return control;
    }

    /**
     * Create a list dialog field.
     *
     * @param parent the composite
     */
    private void createPreferenceList(Composite parent) {
        String[] buttonLabels = new String[] {
                CallHierarchyMessages.ExpandWithConstructorsConfigurationBlock_newType_button,
                CallHierarchyMessages.ExpandWithConstructorsConfigurationBlock_newMember_button,
                CallHierarchyMessages.ExpandWithConstructorsConfigurationBlock_edit_button,
                CallHierarchyMessages.ExpandWithConstructorsConfigurationBlock_remove_button,
                CallHierarchyMessages.ExpandWithConstructorsConfigurationBlock_restoreDefaults_button };

        ListAdapter adapter = new ListAdapter();

        fList = new ListDialogField<String>(adapter, buttonLabels, new ListLabelProvider());
        fList.setDialogFieldListener(adapter);
        fList.setLabelText(CallHierarchyMessages.ExpandWithConstructorsConfigurationBlock_description);
        fList.setRemoveButtonIndex(IDX_REMOVE);
        fList.enableButton(IDX_EDIT, false);
        fList.setViewerComparator(new ViewerComparator());

        PixelConverter pixelConverter = new PixelConverter(parent);

        fList.doFillIntoGrid(parent, 3);
        LayoutUtil.setHorizontalSpan(fList.getLabelControl(null), 2);
        LayoutUtil.setWidthHint(fList.getLabelControl(null), pixelConverter.convertWidthInCharsToPixels(60));
        LayoutUtil.setHorizontalGrabbing(fList.getListControl(null));

        Control listControl = fList.getListControl(null);
        GridData gd = (GridData) listControl.getLayoutData();
        gd.verticalAlignment = GridData.FILL;
        gd.grabExcessVerticalSpace = true;
        gd.heightHint = pixelConverter.convertHeightInCharsToPixels(10);
    }

    /**
     * Initialize the elements of the list dialog field.
     */
    public void initialize() {
        fList.setElements(Arrays.asList(getDefaultExpandWithConstructorsMembers()));
    }

    /*
     * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#performDefaults()
     */
    @Override
    public void performDefaults() {
        String str = PreferenceConstants.getPreferenceStore()
                .getDefaultString(PreferenceConstants.PREF_DEFAULT_EXPAND_WITH_CONSTRUCTORS_MEMBERS);
        fList.setElements(Arrays.asList(deserializeMembers(str)));
        fIsAnonymous = PreferenceConstants.getPreferenceStore()
                .getDefaultBoolean(PreferenceConstants.PREF_ANONYMOUS_EXPAND_WITH_CONSTRUCTORS);
        fAnonymousButton.setSelection(fIsAnonymous);
        super.performDefaults();
    }

    /*
     * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#getFullBuildDialogStrings(boolean)
     */
    @Override
    protected String[] getFullBuildDialogStrings(boolean workspaceSettings) {
        return null;
    }

    /*
     * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#validateSettings(org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock.Key, java.lang.String, java.lang.String)
     */
    @Override
    protected void validateSettings(Key changedKey, String oldValue, String newValue) {

    }

    /**
     * Perform the 'New' and 'Edit' button operations by opening the respective call hierarchy
     * preferences dialog, and 'Restore Defaults' button by restoring to default values for the list dialog.
     *
     * @param index the index of the button
     */
    private void doButtonPressed(int index) {
        if (index == IDX_NEW_TYPE || index == IDX_NEW_MEMBER) { // add new
            List<String> existing = fList.getElements();
            CallHierarchyTypesOrMembersDialog dialog = new CallHierarchyTypesOrMembersDialog(getShell(), existing,
                    index == IDX_NEW_MEMBER);
            if (dialog.open() == Window.OK) {
                fList.addElement(dialog.getResult());
            }
        } else if (index == IDX_EDIT) { // edit
            List<String> selected = fList.getSelectedElements();
            if (selected.isEmpty())
                return;

            String editedEntry = selected.get(0);

            List<String> existing = fList.getElements();
            existing.remove(editedEntry);
            boolean isType = editedEntry.endsWith(WILDCARD);
            CallHierarchyTypesOrMembersDialog dialog = new CallHierarchyTypesOrMembersDialog(getShell(), existing,
                    !isType);
            if (isType)
                dialog.setInitialSelection(editedEntry.substring(0, editedEntry.length() - 2));
            else
                dialog.setInitialSelection(editedEntry);

            if (dialog.open() == Window.OK) {
                fList.replaceElement(editedEntry, dialog.getResult());
            }
        } else if (index == IDX_RESTORE_DEFAULTS) {
            performDefaults();
        }
    }

    /**
     * Update the key on dialog field change.
     *
     * @param field the dialog field
     */
    protected final void doDialogFieldChanged(DialogField field) {
        // set values in working copy
        if (field == fList) {
            setValue(DEFAULT_EXPAND_WITH_CONSTRUCTORS_MEMBERS, serializeMembers(fList.getElements()));
        }
    }

    /**
     * Returns the array of strings containing the types or methods for default expand with constructors.
     *
     * @return the array of strings containing the types or methods for default expand with constructors
     */
    private String[] getDefaultExpandWithConstructorsMembers() {
        String str = getValue(DEFAULT_EXPAND_WITH_CONSTRUCTORS_MEMBERS);
        if (str != null && str.length() > 0) {
            return deserializeMembers(str);
        }
        return new String[0];
    }

    /**
     * Return the array of types and/or methods after splitting the stored preference string.
     *
     * @param str the input string
     * @return the array of types and/or methods
     */
    private static String[] deserializeMembers(String str) {
        return str.split(";"); //$NON-NLS-1$
    }

    /**
     * Creates a single output string from the list of strings using a delimiter.
     * 
     * @param list the input list of types and/or methods
     * @return the single output string from the list of strings using a delimiter
     */
    public static String serializeMembers(List<String> list) {
        int size = list.size();
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < size; i++) {
            buf.append(list.get(i));
            if (i < size - 1)
                buf.append(';');
        }
        return buf.toString();
    }

}