/******************************************************************************* * Copyright (c) 2000, 2017 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 org.eclipse.dltk.internal.ui.workingsets; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.IProjectFragment; import org.eclipse.dltk.core.IScriptFolder; import org.eclipse.dltk.core.IScriptModel; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.internal.ui.actions.SelectionConverter; import org.eclipse.dltk.internal.ui.util.SWTUtil; import org.eclipse.dltk.ui.DLTKPluginImages; import org.eclipse.dltk.ui.DLTKUIPlugin; import org.eclipse.dltk.ui.ModelElementSorter; import org.eclipse.dltk.ui.ScriptElementImageProvider; import org.eclipse.dltk.ui.ScriptElementLabels; import org.eclipse.dltk.ui.viewsupport.AppearanceAwareLabelProvider; import org.eclipse.dltk.ui.viewsupport.StyledDecoratingModelLabelProvider; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTreeViewer; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.ITreeViewerListener; import org.eclipse.jface.viewers.TreeExpansionEvent; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; 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.Label; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkingSet; import org.eclipse.ui.IWorkingSetManager; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.IWorkingSetPage; /** * The Script working set page allows the user to create and edit a Script * working set. * <p> * Working set elements are presented as a Script element tree. * </p> * * */ public class ScriptWorkingSetPage extends WizardPage implements IWorkingSetPage { final private static String PAGE_TITLE = WorkingSetMessages.ScriptWorkingSetPage_title; final private static String PAGE_ID = "ScriptWorkingSetPage"; //$NON-NLS-1$ private Text fWorkingSetName; private CheckboxTreeViewer fTree; private ITreeContentProvider fTreeContentProvider; private boolean fFirstCheck; private IWorkingSet fWorkingSet; /** * Default constructor. */ public ScriptWorkingSetPage() { super(PAGE_ID, PAGE_TITLE, DLTKPluginImages.DESC_WIZBAN_SCRIPT_WORKINGSET); setDescription( WorkingSetMessages.ScriptWorkingSetPage_workingSet_description); fFirstCheck = true; } /* * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt. * widgets.Composite) */ @Override public void createControl(Composite parent) { initializeDialogUnits(parent); Composite composite = new Composite(parent, SWT.NONE); composite.setLayout(new GridLayout()); composite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); setControl(composite); Label label = new Label(composite, SWT.WRAP); label.setText(WorkingSetMessages.ScriptWorkingSetPage_workingSet_name); GridData gd = new GridData( GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER); label.setLayoutData(gd); fWorkingSetName = new Text(composite, SWT.SINGLE | SWT.BORDER); fWorkingSetName.setLayoutData(new GridData( GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); fWorkingSetName.addModifyListener(e -> validateInput()); fWorkingSetName.setFocus(); label = new Label(composite, SWT.WRAP); label.setText( WorkingSetMessages.ScriptWorkingSetPage_workingSet_content); gd = new GridData( GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER); label.setLayoutData(gd); fTree = new CheckboxTreeViewer(composite, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); gd = new GridData(GridData.FILL_BOTH | GridData.GRAB_VERTICAL); gd.heightHint = convertHeightInCharsToPixels(15); fTree.getControl().setLayoutData(gd); fTreeContentProvider = new ScriptWorkingSetPageContentProvider(); fTree.setContentProvider(fTreeContentProvider); AppearanceAwareLabelProvider fScriptElementLabelProvider = new AppearanceAwareLabelProvider( AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS | ScriptElementLabels.P_COMPRESSED, AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS | ScriptElementImageProvider.SMALL_ICONS, DLTKUIPlugin.getDefault().getPreferenceStore()); fTree.setLabelProvider(new StyledDecoratingModelLabelProvider( fScriptElementLabelProvider)); fTree.setComparator(new ModelElementSorter()); if (DLTKCore.DEBUG) { System.err .println("Add empty inner package filter support here..."); //$NON-NLS-1$ } // fTree.addFilter(new EmptyInnerPackageFilter()); fTree.setUseHashlookup(true); fTree.setInput( DLTKCore.create(ResourcesPlugin.getWorkspace().getRoot())); fTree.addCheckStateListener(event -> handleCheckStateChange(event)); fTree.addTreeListener(new ITreeViewerListener() { @Override public void treeCollapsed(TreeExpansionEvent event) { } @Override public void treeExpanded(TreeExpansionEvent event) { final Object element = event.getElement(); if (fTree.getGrayed(element) == false) BusyIndicator.showWhile(getShell().getDisplay(), () -> setSubtreeChecked(element, fTree.getChecked(element), false)); } }); // Add select / deselect all buttons for bug 46669 Composite buttonComposite = new Composite(composite, SWT.NONE); GridLayout layout = new GridLayout(2, false); layout.marginWidth = 0; layout.marginHeight = 0; buttonComposite.setLayout(layout); buttonComposite .setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); Button selectAllButton = new Button(buttonComposite, SWT.PUSH); selectAllButton.setText( WorkingSetMessages.ScriptWorkingSetPage_selectAll_label); selectAllButton.setToolTipText( WorkingSetMessages.ScriptWorkingSetPage_selectAll_toolTip); selectAllButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent selectionEvent) { fTree.setCheckedElements( fTreeContentProvider.getElements(fTree.getInput())); validateInput(); } }); selectAllButton.setLayoutData(new GridData()); SWTUtil.setButtonDimensionHint(selectAllButton); Button deselectAllButton = new Button(buttonComposite, SWT.PUSH); deselectAllButton.setText( WorkingSetMessages.ScriptWorkingSetPage_deselectAll_label); deselectAllButton.setToolTipText( WorkingSetMessages.ScriptWorkingSetPage_deselectAll_toolTip); deselectAllButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent selectionEvent) { fTree.setCheckedElements(new Object[0]); validateInput(); } }); deselectAllButton.setLayoutData(new GridData()); SWTUtil.setButtonDimensionHint(deselectAllButton); if (fWorkingSet != null) fWorkingSetName.setText(fWorkingSet.getName()); initializeCheckedState(); validateInput(); Dialog.applyDialogFont(composite); // Set help for the page if (DLTKCore.DEBUG) { System.err.println("Add help support here..."); //$NON-NLS-1$ } // ScriptUIHelp.setHelp(fTree, // IScriptHelpContextIds.Script_WORKING_SET_PAGE); } /* * Implements method from IWorkingSetPage */ @Override public IWorkingSet getSelection() { return fWorkingSet; } /* * Implements method from IWorkingSetPage */ @Override public void setSelection(IWorkingSet workingSet) { Assert.isNotNull(workingSet, "Working set must not be null"); //$NON-NLS-1$ fWorkingSet = workingSet; if (getContainer() != null && getShell() != null && fWorkingSetName != null) { fFirstCheck = false; fWorkingSetName.setText(fWorkingSet.getName()); initializeCheckedState(); validateInput(); } } /* * Implements method from IWorkingSetPage */ @Override public void finish() { String workingSetName = fWorkingSetName.getText(); ArrayList<IAdaptable> elements = new ArrayList<>(10); findCheckedElements(elements, fTree.getInput()); if (fWorkingSet == null) { IWorkingSetManager workingSetManager = PlatformUI.getWorkbench() .getWorkingSetManager(); fWorkingSet = workingSetManager.createWorkingSet(workingSetName, elements.toArray(new IAdaptable[elements.size()])); } else { // Add inaccessible resources IAdaptable[] oldItems = fWorkingSet.getElements(); ArrayList closedWithChildren = new ArrayList(elements.size()); for (int i = 0; i < oldItems.length; i++) { IResource oldResource = null; if (oldItems[i] instanceof IResource) { oldResource = (IResource) oldItems[i]; } else { oldResource = oldItems[i].getAdapter(IResource.class); } if (oldResource != null && oldResource.isAccessible() == false) { IProject project = oldResource.getProject(); if (elements.contains(project) || closedWithChildren.contains(project)) { elements.add(oldItems[i]); elements.remove(project); closedWithChildren.add(project); } } } fWorkingSet.setName(workingSetName); fWorkingSet.setElements( elements.toArray(new IAdaptable[elements.size()])); } } private void validateInput() { String errorMessage = null; String infoMessage = null; String newText = fWorkingSetName.getText(); if (newText.equals(newText.trim()) == false) errorMessage = WorkingSetMessages.ScriptWorkingSetPage_warning_nameWhitespace; if (newText.equals("")) { //$NON-NLS-1$ if (fFirstCheck) { setPageComplete(false); fFirstCheck = false; return; } else errorMessage = WorkingSetMessages.ScriptWorkingSetPage_warning_nameMustNotBeEmpty; } fFirstCheck = false; if (errorMessage == null && (fWorkingSet == null || newText.equals(fWorkingSet.getName()) == false)) { IWorkingSet[] workingSets = PlatformUI.getWorkbench() .getWorkingSetManager().getWorkingSets(); for (int i = 0; i < workingSets.length; i++) { if (newText.equals(workingSets[i].getName())) { errorMessage = WorkingSetMessages.ScriptWorkingSetPage_warning_workingSetExists; } } } if (!hasCheckedElement()) infoMessage = WorkingSetMessages.ScriptWorkingSetPage_warning_resourceMustBeChecked; setMessage(infoMessage, INFORMATION); setErrorMessage(errorMessage); setPageComplete(errorMessage == null); } private boolean hasCheckedElement() { TreeItem[] items = fTree.getTree().getItems(); for (int i = 0; i < items.length; i++) { if (items[i].getChecked()) return true; } return false; } private void findCheckedElements(List checkedResources, Object parent) { Object[] children = fTreeContentProvider.getChildren(parent); for (int i = 0; i < children.length; i++) { if (fTree.getGrayed(children[i])) findCheckedElements(checkedResources, children[i]); else if (fTree.getChecked(children[i])) checkedResources.add(children[i]); } } void handleCheckStateChange(final CheckStateChangedEvent event) { BusyIndicator.showWhile(getShell().getDisplay(), () -> { IAdaptable element = (IAdaptable) event.getElement(); boolean state = event.getChecked(); fTree.setGrayed(element, false); if (isExpandable(element)) setSubtreeChecked(element, state, state); // only check subtree // if state is set // to true updateParentState(element, state); validateInput(); }); } private void setSubtreeChecked(Object parent, boolean state, boolean checkExpandedState) { if (!(parent instanceof IAdaptable)) return; IContainer container = ((IAdaptable) parent) .getAdapter(IContainer.class); if ((!fTree.getExpandedState(parent) && checkExpandedState) || (container != null && !container.isAccessible())) return; Object[] children = fTreeContentProvider.getChildren(parent); for (int i = children.length - 1; i >= 0; i--) { Object element = children[i]; if (state) { fTree.setChecked(element, true); fTree.setGrayed(element, false); } else fTree.setGrayChecked(element, false); if (isExpandable(element)) setSubtreeChecked(element, state, true); } } private void updateParentState(Object child, boolean baseChildState) { if (child == null) return; if (child instanceof IAdaptable) { IResource resource = ((IAdaptable) child) .getAdapter(IResource.class); if (resource != null && !resource.isAccessible()) return; } Object parent = fTreeContentProvider.getParent(child); if (parent == null) return; boolean allSameState = true; Object[] children = null; children = fTreeContentProvider.getChildren(parent); for (int i = children.length - 1; i >= 0; i--) { if (fTree.getChecked(children[i]) != baseChildState || fTree.getGrayed(children[i])) { allSameState = false; break; } } fTree.setGrayed(parent, !allSameState); fTree.setChecked(parent, !allSameState || baseChildState); updateParentState(parent, baseChildState); } private void initializeCheckedState() { BusyIndicator.showWhile(getShell().getDisplay(), () -> { Object[] elements; if (fWorkingSet == null) { // Use current part's selection for initialization IWorkbenchPage page = DLTKUIPlugin.getActivePage(); if (page == null) return; IWorkbenchPart part = DLTKUIPlugin.getActivePage() .getActivePart(); if (part == null) return; try { elements = SelectionConverter.getStructuredSelection(part) .toArray(); for (int i1 = 0; i1 < elements.length; i1++) { if (elements[i1] instanceof IResource) { IModelElement je = ((IResource) elements[i1]) .getAdapter(IModelElement.class); if (je != null && je.exists() && je.getScriptProject().isOnBuildpath( (IResource) elements[i1])) elements[i1] = je; } } } catch (ModelException e) { return; } } else elements = fWorkingSet.getElements(); // Use closed project for elements in closed project for (int i2 = 0; i2 < elements.length; i2++) { Object element1 = elements[i2]; if (element1 instanceof IResource) { IProject project = ((IResource) element1).getProject(); if (!project.isAccessible()) elements[i2] = project; } if (element1 instanceof IModelElement) { IScriptProject jProject = ((IModelElement) element1) .getScriptProject(); if (jProject != null && !jProject.getProject().isAccessible()) elements[i2] = jProject.getProject(); } } fTree.setCheckedElements(elements); for (int i3 = 0; i3 < elements.length; i3++) { Object element2 = elements[i3]; if (isExpandable(element2)) setSubtreeChecked(element2, true, true); updateParentState(element2, true); } }); } private boolean isExpandable(Object element) { return (element instanceof IScriptProject || element instanceof IProjectFragment || element instanceof IScriptFolder || element instanceof IScriptModel || element instanceof IContainer); } }