| /******************************************************************************* |
| * Copyright (c) 2000, 2015 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Semion Chichelnitsky (semion@il.ibm.com) - bug 278064 |
| * Denis Zygann <d.zygann@web.de> - Bug 330453 |
| * Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654 |
| *******************************************************************************/ |
| |
| package org.eclipse.ui.internal.dialogs; |
| |
| import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter; |
| |
| import java.text.Collator; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Comparator; |
| import java.util.Objects; |
| import org.eclipse.e4.ui.model.application.MApplication; |
| import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective; |
| import org.eclipse.e4.ui.workbench.modeling.EModelService; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.PlainMessageDialog; |
| import org.eclipse.jface.dialogs.PlainMessageDialog.Builder; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.preference.PreferencePage; |
| import org.eclipse.jface.resource.ImageDescriptor; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Font; |
| 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.Group; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Table; |
| import org.eclipse.swt.widgets.TableItem; |
| import org.eclipse.swt.widgets.Widget; |
| import org.eclipse.ui.IPerspectiveDescriptor; |
| import org.eclipse.ui.IWorkbench; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchPreferenceConstants; |
| import org.eclipse.ui.IWorkbenchPreferencePage; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.internal.IPreferenceConstants; |
| import org.eclipse.ui.internal.IWorkbenchHelpContextIds; |
| import org.eclipse.ui.internal.Workbench; |
| import org.eclipse.ui.internal.WorkbenchMessages; |
| import org.eclipse.ui.internal.WorkbenchPlugin; |
| import org.eclipse.ui.internal.registry.PerspectiveDescriptor; |
| import org.eclipse.ui.internal.registry.PerspectiveRegistry; |
| import org.eclipse.ui.internal.util.Descriptors; |
| import org.eclipse.ui.internal.util.PrefUtil; |
| |
| /** |
| * The Workbench / Perspectives preference page. |
| */ |
| public class PerspectivesPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { |
| private IWorkbench workbench; |
| |
| private PerspectiveRegistry perspectiveRegistry; |
| |
| // List of perspectives to populate preference page |
| private ArrayList<IPerspectiveDescriptor> perspectives; |
| |
| private String defaultPerspectiveId; |
| |
| private ArrayList<IPerspectiveDescriptor> perspToDelete = new ArrayList<>(); |
| |
| private ArrayList<IPerspectiveDescriptor> perspToRevert = new ArrayList<>(); |
| |
| private Table perspectivesTable; |
| |
| private Button revertButton; |
| |
| private Button deleteButton; |
| |
| private Button setDefaultButton; |
| |
| // widgets for open perspective mode; |
| private Button openSameWindowButton; |
| |
| private Button openNewWindowButton; |
| |
| private int openPerspMode; |
| |
| // labels |
| private final String OPM_TITLE = WorkbenchMessages.OpenPerspectiveMode_optionsTitle; |
| |
| private final String OPM_SAME_WINDOW = WorkbenchMessages.OpenPerspectiveMode_sameWindow; |
| |
| private final String OPM_NEW_WINDOW = WorkbenchMessages.OpenPerspectiveMode_newWindow; |
| |
| /** |
| * <code>Comparator</code> to compare two perspective descriptors |
| */ |
| private Comparator<IPerspectiveDescriptor> comparator = new Comparator<>() { |
| private Collator collator = Collator.getInstance(); |
| |
| @Override |
| public int compare(IPerspectiveDescriptor d1, IPerspectiveDescriptor d2) { |
| return collator.compare(d1.getLabel(), d2.getLabel()); |
| } |
| }; |
| |
| /** |
| * Creates the page's UI content. |
| */ |
| @Override |
| protected Control createContents(Composite parent) { |
| // @issue if the product subclasses this page, then it should provide |
| // the help content |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, |
| IWorkbenchHelpContextIds.PERSPECTIVES_PREFERENCE_PAGE); |
| |
| Composite composite = createComposite(parent); |
| |
| createOpenPerspButtonGroup(composite); |
| createCustomizePerspective(composite); |
| |
| return composite; |
| } |
| |
| /** |
| * Creates the composite which will contain all the preference controls for this |
| * page. |
| * |
| * @param parent the parent composite |
| * @return the composite for this page |
| */ |
| protected Composite createComposite(Composite parent) { |
| Composite composite = new Composite(parent, SWT.NONE); |
| GridData data = new GridData(GridData.FILL_BOTH); |
| composite.setLayoutData(data); |
| composite.setFont(parent.getFont()); |
| GridLayout layout = new GridLayout(); |
| layout.marginWidth = 0; |
| layout.marginHeight = 0; |
| layout.verticalSpacing = 10; |
| composite.setLayout(layout); |
| return composite; |
| } |
| |
| /** |
| * Create a composite that contains buttons for selecting the open perspective |
| * mode. |
| * |
| * @param composite the parent composite |
| */ |
| protected void createOpenPerspButtonGroup(Composite composite) { |
| |
| Font font = composite.getFont(); |
| |
| Group buttonComposite = new Group(composite, SWT.LEFT); |
| buttonComposite.setText(OPM_TITLE); |
| buttonComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| buttonComposite.setFont(composite.getFont()); |
| GridLayout layout = new GridLayout(); |
| layout.numColumns = 2; |
| buttonComposite.setLayout(layout); |
| |
| openSameWindowButton = new Button(buttonComposite, SWT.RADIO); |
| openSameWindowButton.setText(OPM_SAME_WINDOW); |
| openSameWindowButton.setSelection(IPreferenceConstants.OPM_ACTIVE_PAGE == openPerspMode); |
| openSameWindowButton.setFont(font); |
| openSameWindowButton |
| .addSelectionListener(widgetSelectedAdapter(e -> openPerspMode = IPreferenceConstants.OPM_ACTIVE_PAGE)); |
| |
| openNewWindowButton = new Button(buttonComposite, SWT.RADIO); |
| openNewWindowButton.setText(OPM_NEW_WINDOW); |
| openNewWindowButton.setSelection(IPreferenceConstants.OPM_NEW_WINDOW == openPerspMode); |
| openNewWindowButton.setFont(font); |
| openNewWindowButton |
| .addSelectionListener(widgetSelectedAdapter(e -> openPerspMode = IPreferenceConstants.OPM_NEW_WINDOW)); |
| |
| } |
| |
| /** |
| * Create a table of 3 buttons to enable the user to manage customized |
| * perspectives. |
| * |
| * @param parent the parent for the button parent |
| * @return Composite that the buttons are created in. |
| */ |
| protected Composite createCustomizePerspective(Composite parent) { |
| |
| Font font = parent.getFont(); |
| |
| // define container & its gridding |
| Composite perspectivesComponent = new Composite(parent, SWT.NONE); |
| perspectivesComponent.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| perspectivesComponent.setFont(parent.getFont()); |
| |
| GridLayout layout = new GridLayout(); |
| layout.numColumns = 2; |
| layout.marginWidth = 0; |
| layout.marginHeight = 0; |
| perspectivesComponent.setLayout(layout); |
| |
| // Add the label |
| Label label = new Label(perspectivesComponent, SWT.LEFT); |
| label.setText(WorkbenchMessages.PerspectivesPreference_available); |
| GridData data = new GridData(); |
| data.horizontalSpan = 2; |
| label.setLayoutData(data); |
| label.setFont(font); |
| |
| // Add perspectivesTable. |
| perspectivesTable = new Table(perspectivesComponent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); |
| perspectivesTable.addSelectionListener(widgetSelectedAdapter(e -> updateButtons())); |
| perspectivesTable.setFont(font); |
| |
| data = new GridData(GridData.FILL_BOTH); |
| data.grabExcessHorizontalSpace = true; |
| data.grabExcessVerticalSpace = true; |
| perspectivesTable.setLayoutData(data); |
| |
| // Populate the perspectivesTable |
| IPerspectiveDescriptor[] persps = perspectiveRegistry.getPerspectives(); |
| perspectives = new ArrayList<>(persps.length); |
| for (int i = 0; i < persps.length; i++) { |
| perspectives.add(i, persps[i]); |
| } |
| perspectives.sort(comparator); |
| defaultPerspectiveId = perspectiveRegistry.getDefaultPerspective(); |
| updatePerspectivesTable(); |
| |
| // Create vertical button bar. |
| Composite buttonBar = (Composite) createVerticalButtonBar(perspectivesComponent); |
| data = new GridData(GridData.FILL_VERTICAL); |
| buttonBar.setLayoutData(data); |
| |
| // Add note label |
| String NOTE_LABEL = WorkbenchMessages.Preference_note; |
| String REVERT_NOTE = WorkbenchMessages.RevertPerspective_note; |
| Composite noteComposite = createNoteComposite(font, parent, NOTE_LABEL, REVERT_NOTE); |
| GridData noteData = new GridData(); |
| noteData.horizontalSpan = 2; |
| noteComposite.setLayoutData(noteData); |
| return perspectivesComponent; |
| } |
| |
| /** |
| * Creates a new vertical button with the given id. |
| * <p> |
| * The default implementation of this framework method creates a standard push |
| * button, registers for selection events including button presses and help |
| * requests, and registers default buttons with its shell. The button id is |
| * stored as the buttons client data. |
| * </p> |
| * |
| * @param parent the parent composite |
| * @param label the label from the button |
| * @param defaultButton <code>true</code> if the button is to be the default |
| * button, and <code>false</code> otherwise |
| * @return Button The created button. |
| */ |
| protected Button createVerticalButton(Composite parent, String label, boolean defaultButton) { |
| Button button = new Button(parent, SWT.PUSH); |
| |
| button.setText(label); |
| |
| GridData data = setButtonLayoutData(button); |
| data.horizontalAlignment = GridData.FILL; |
| |
| button.addSelectionListener(widgetSelectedAdapter(event -> verticalButtonPressed(event.widget))); |
| button.setToolTipText(label); |
| if (defaultButton) { |
| Shell shell = parent.getShell(); |
| if (shell != null) { |
| shell.setDefaultButton(button); |
| } |
| } |
| button.setFont(parent.getFont()); |
| return button; |
| } |
| |
| /** |
| * Creates and returns the vertical button bar. |
| * |
| * @param parent the parent composite to contain the button bar |
| * @return the button bar control |
| */ |
| protected Control createVerticalButtonBar(Composite parent) { |
| // Create composite. |
| Composite composite = new Composite(parent, SWT.NULL); |
| |
| // create a layout with spacing and margins appropriate for the font |
| // size. |
| GridLayout layout = new GridLayout(); |
| layout.numColumns = 1; |
| layout.marginWidth = 5; |
| layout.marginHeight = 0; |
| layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); |
| layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); |
| composite.setLayout(layout); |
| composite.setFont(parent.getFont()); |
| |
| // Add the buttons to the button bar. |
| setDefaultButton = createVerticalButton(composite, WorkbenchMessages.PerspectivesPreference_MakeDefault, false); |
| setDefaultButton.setToolTipText(WorkbenchMessages.PerspectivesPreference_MakeDefaultTip); |
| |
| revertButton = createVerticalButton(composite, WorkbenchMessages.PerspectivesPreference_Reset, false); |
| revertButton.setToolTipText(WorkbenchMessages.PerspectivesPreference_ResetTip); |
| |
| deleteButton = createVerticalButton(composite, WorkbenchMessages.PerspectivesPreference_Delete, false); |
| deleteButton.setToolTipText(WorkbenchMessages.PerspectivesPreference_DeleteTip); |
| updateButtons(); |
| |
| return composite; |
| } |
| |
| /** |
| * @see IWorkbenchPreferencePage |
| */ |
| @Override |
| public void init(IWorkbench aWorkbench) { |
| this.workbench = aWorkbench; |
| this.perspectiveRegistry = (PerspectiveRegistry) workbench.getPerspectiveRegistry(); |
| IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); |
| setPreferenceStore(store); |
| |
| openPerspMode = store.getInt(IPreferenceConstants.OPEN_PERSP_MODE); |
| } |
| |
| /** |
| * The default button has been pressed. |
| */ |
| @Override |
| protected void performDefaults() { |
| // Project perspective preferences |
| IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); |
| |
| openPerspMode = store.getDefaultInt(IPreferenceConstants.OPEN_PERSP_MODE); |
| openSameWindowButton.setSelection(IPreferenceConstants.OPM_ACTIVE_PAGE == openPerspMode); |
| openNewWindowButton.setSelection(IPreferenceConstants.OPM_NEW_WINDOW == openPerspMode); |
| |
| String currentDefault = perspectiveRegistry.getDefaultPerspective(); |
| |
| int index = indexOf(currentDefault); |
| if (index >= 0) { |
| defaultPerspectiveId = currentDefault; |
| updatePerspectivesTable(); |
| perspectivesTable.setSelection(index); |
| } |
| |
| String newDefault = PrefUtil.getAPIPreferenceStore() |
| .getDefaultString(IWorkbenchPreferenceConstants.DEFAULT_PERSPECTIVE_ID); |
| |
| IPerspectiveDescriptor desc = null; |
| if (newDefault != null) { |
| desc = workbench.getPerspectiveRegistry().findPerspectiveWithId(newDefault); |
| } |
| if (desc == null) { |
| newDefault = workbench.getPerspectiveRegistry().getDefaultPerspective(); |
| } |
| |
| defaultPerspectiveId = newDefault; |
| updatePerspectivesTable(); |
| |
| } |
| |
| /** |
| * Look up the index of the perpective with the given if. |
| * |
| * @param perspectiveId or <code>null</code> |
| * @return int -1 if it cannot be found |
| */ |
| private int indexOf(String perspectiveId) { |
| if (perspectiveId == null) { |
| return -1; |
| } |
| PerspectiveDescriptor[] descriptors = new PerspectiveDescriptor[perspectives.size()]; |
| perspectives.toArray(descriptors); |
| for (int i = 0; i < descriptors.length; i++) { |
| PerspectiveDescriptor descriptor = descriptors[i]; |
| if (descriptor.getId().equals(perspectiveId)) { |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * Return true if there are no open instances of the perspective. If there are |
| * open instances of the perspective prompt the user and return true if the user |
| * answers "yes" to the delete prompt. |
| * |
| * @return boolean <code>true</code> if it is OK to delete the perspective |
| * either because there are no open instances or the user has confirmed |
| * the deletion. |
| */ |
| private boolean canDeletePerspective(IPerspectiveDescriptor desc) { |
| |
| MApplication application = ((Workbench) workbench).getApplication(); |
| EModelService modelService = application.getContext().get(EModelService.class); |
| |
| if (modelService.findElements(application, desc.getId(), MPerspective.class).isEmpty()) |
| return true; |
| |
| Builder builder = PlainMessageDialog.getBuilder(getShell(), |
| WorkbenchMessages.PerspectivesPreference_perspectiveopen_title); |
| builder.message(NLS.bind(WorkbenchMessages.PerspectivesPreference_perspectiveopen_message, desc.getLabel())); |
| builder.image(getShell().getDisplay().getSystemImage(SWT.ICON_QUESTION)); |
| builder.buttonLabels(Arrays.asList(IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL)); |
| return builder.build().open() == 0; |
| } |
| |
| /** |
| * Apply the user's changes if any |
| */ |
| @Override |
| public boolean performOk() { |
| // Set the default perspective |
| if (!Objects.equals(defaultPerspectiveId, perspectiveRegistry.getDefaultPerspective())) { |
| perspectiveRegistry.setDefaultPerspective(defaultPerspectiveId); |
| } |
| |
| // Don't bother figuring out which window a perspective may be open in, |
| // the number of windows will be small. |
| |
| for (IPerspectiveDescriptor perspective : perspToDelete) { |
| IWorkbenchWindow[] windows = workbench.getWorkbenchWindows(); |
| for (IWorkbenchWindow window : windows) { |
| IWorkbenchPage[] pages = window.getPages(); |
| for (IWorkbenchPage page : pages) { |
| page.closePerspective(perspective, true, false); |
| } |
| } |
| perspectiveRegistry.deletePerspectives(perspToDelete); |
| } |
| |
| // Revert perspectives |
| for (IPerspectiveDescriptor perspective : perspToRevert) { |
| perspectiveRegistry.revertPerspective(perspective); |
| } |
| |
| IPreferenceStore store = getPreferenceStore(); |
| |
| // store the open perspective mode setting |
| store.setValue(IPreferenceConstants.OPEN_PERSP_MODE, openPerspMode); |
| |
| // save both the API prefs and the internal prefs |
| // the API prefs are modified by |
| // PerspectiveRegistry.setDefaultPerspective |
| PrefUtil.savePrefs(); |
| |
| return true; |
| } |
| |
| /** |
| * Update the button enablement state. |
| */ |
| protected void updateButtons() { |
| // Get selection. |
| int index = perspectivesTable.getSelectionIndex(); |
| |
| // Map it to the perspective descriptor |
| PerspectiveDescriptor desc = null; |
| if (index > -1) { |
| desc = (PerspectiveDescriptor) perspectives.get(index); |
| } |
| |
| // Do enable. |
| if (desc != null) { |
| revertButton.setEnabled(desc.isPredefined() && desc.hasCustomDefinition() && !perspToRevert.contains(desc)); |
| deleteButton.setEnabled(!desc.isPredefined()); |
| setDefaultButton.setEnabled(true); |
| } else { |
| revertButton.setEnabled(false); |
| deleteButton.setEnabled(false); |
| setDefaultButton.setEnabled(false); |
| } |
| } |
| |
| /** |
| * Update the perspectivesTable. |
| */ |
| protected void updatePerspectivesTable() { |
| // Populate the table with the items |
| perspectivesTable.removeAll(); |
| for (int i = 0; i < perspectives.size(); i++) { |
| PerspectiveDescriptor persp = (PerspectiveDescriptor) perspectives.get(i); |
| newPerspectivesTableItem(persp, i, false); |
| } |
| } |
| |
| /** |
| * Create a new tableItem using given perspective, and set image for the new |
| * item. |
| */ |
| protected TableItem newPerspectivesTableItem(IPerspectiveDescriptor persp, int index, boolean selected) { |
| |
| ImageDescriptor image = persp.getImageDescriptor(); |
| |
| TableItem item = new TableItem(perspectivesTable, SWT.NULL, index); |
| if (image != null) { |
| Descriptors.setImage(item, image); |
| } |
| String label = persp.getLabel(); |
| if (persp.getId().equals(defaultPerspectiveId)) { |
| label = NLS.bind(WorkbenchMessages.PerspectivesPreference_defaultLabel, label); |
| |
| } |
| item.setText(label); |
| item.setData(persp); |
| if (selected) { |
| perspectivesTable.setSelection(index); |
| } |
| |
| return item; |
| } |
| |
| /** |
| * Notifies that this page's button with the given id has been pressed. |
| * |
| * @param button the button that was pressed |
| */ |
| protected void verticalButtonPressed(Widget button) { |
| // Get selection. |
| int index = perspectivesTable.getSelectionIndex(); |
| |
| // Map it to the perspective descriptor |
| PerspectiveDescriptor desc = null; |
| if (index > -1) { |
| desc = (PerspectiveDescriptor) perspectives.get(index); |
| } else { |
| return; |
| } |
| |
| // Take action. |
| if (button == revertButton) { |
| if (!perspToRevert.contains(desc)) { |
| perspToRevert.add(desc); |
| } |
| } else if (button == deleteButton) { |
| if (!perspToDelete.contains(desc)) { |
| if (canDeletePerspective(desc)) { |
| perspToDelete.add(desc); |
| perspToRevert.remove(desc); |
| perspectives.remove(desc); |
| updatePerspectivesTable(); |
| } |
| |
| } |
| } else if (button == setDefaultButton) { |
| defaultPerspectiveId = desc.getId(); |
| updatePerspectivesTable(); |
| perspectivesTable.setSelection(index); |
| } |
| |
| updateButtons(); |
| } |
| } |