/******************************************************************************* * Copyright (c) 2000, 2016 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 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.help.ui.internal.search; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.help.internal.HelpPlugin; import org.eclipse.help.internal.base.BaseHelpSystem; import org.eclipse.help.internal.criteria.CriterionResource; import org.eclipse.help.internal.workingset.AdaptableHelpResource; import org.eclipse.help.internal.workingset.WorkingSet; import org.eclipse.help.ui.IEngineDescriptor; import org.eclipse.help.ui.RootScopePage; import org.eclipse.help.ui.internal.Messages; import org.eclipse.help.ui.internal.search.HelpCriteriaContentProvider.CriterionName; import org.eclipse.help.ui.internal.search.HelpCriteriaContentProvider.CriterionValue; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTreeViewer; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.ITreeViewerListener; import org.eclipse.jface.viewers.TreeExpansionEvent; 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.graphics.Font; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; /** * Local Help participant in the federated search. */ public class LocalHelpPage extends RootScopePage { private Button searchAll; private Button searchSelected; private CheckboxTreeViewer contentTree; private ITreeContentProvider contentTreeContentProvider; private ILabelProvider contentTreeLabelProvider; private CheckboxTreeViewer criteriaTree; private ITreeContentProvider criteriaTreeContentProvider; private ILabelProvider criteriaTreeLabelProvider; //private boolean firstCheck; private WorkingSet workingSet; @Override public void init(IEngineDescriptor ed, String scopeSetName) { super.init(ed, scopeSetName); if (scopeSetName != null) workingSet = BaseHelpSystem.getWorkingSetManager().getWorkingSet( scopeSetName); } /** * Default constructor. */ public LocalHelpPage() { //firstCheck = true; } @Override protected int createScopeContents(Composite parent) { Font font = parent.getFont(); initializeDialogUnits(parent); searchAll = new Button(parent, SWT.RADIO); searchAll.setText(Messages.selectAll); GridData gd = new GridData(); gd.horizontalSpan = 2; searchAll.setLayoutData(gd); searchAll.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { contentTree.getTree().setEnabled(false); if (criteriaTree != null) { criteriaTree.getTree().setEnabled(false); } } }); searchSelected = new Button(parent, SWT.RADIO); searchSelected.setText(Messages.selectWorkingSet); gd = new GridData(); gd.horizontalSpan = 2; searchSelected.setLayoutData(gd); searchSelected.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { contentTree.getTree().setEnabled(true); if (criteriaTree != null) { criteriaTree.getTree().setEnabled(true); } } }); if (workingSet == null) searchAll.setSelection(true); else searchSelected.setSelection(true); Label contentLabel = new Label(parent, SWT.WRAP); contentLabel.setFont(font); contentLabel.setText(Messages.WorkingSetContent); gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER); gd.horizontalSpan = 2; contentLabel.setLayoutData(gd); createContentTree(parent, font); if (HelpPlugin.getCriteriaManager().isCriteriaEnabled()) { Label criteriaLabel = new Label(parent, SWT.WRAP); criteriaLabel.setFont(font); criteriaLabel.setText(Messages.WorkingSetCriteria); gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER); gd.horizontalSpan = 2; criteriaLabel.setLayoutData(gd); createCriteriaTree(parent, font); } initializeCheckedState(); applyDialogFont(parent); // Set help for the page // WorkbenchHelp.setHelp(tree, "help_workingset_page"); return 1; } protected void createContentTree(Composite parent, Font font) { GridData gd; contentTree = new CheckboxTreeViewer(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); gd = new GridData(GridData.FILL_BOTH | GridData.GRAB_VERTICAL); gd.heightHint = getTreeHeightHint(); gd.horizontalSpan = 2; contentTree.getControl().setLayoutData(gd); contentTree.getControl().setFont(font); contentTreeContentProvider = new HelpWorkingSetTreeContentProvider(); contentTree.setContentProvider(contentTreeContentProvider); contentTreeLabelProvider = new HelpWorkingSetElementLabelProvider(); contentTree.setLabelProvider(contentTreeLabelProvider); contentTree.setUseHashlookup(true); contentTree.setInput(BaseHelpSystem.getWorkingSetManager().getRoot()); contentTree.addCheckStateListener( event -> handleCheckStateChange(event, contentTree, contentTreeContentProvider)); contentTree.addTreeListener(new ITreeViewerListener() { @Override public void treeCollapsed(TreeExpansionEvent event) { } @Override public void treeExpanded(TreeExpansionEvent event) { final Object element = event.getElement(); if (contentTree.getGrayed(element) == false) BusyIndicator.showWhile(getShell().getDisplay(), () -> setSubtreeChecked(element, contentTree.getChecked(element), false, contentTree, contentTreeContentProvider)); } }); contentTree.getTree().setEnabled(workingSet != null); } protected int getTreeHeightHint() { if (HelpPlugin.getCriteriaManager().isCriteriaEnabled()) { return convertHeightInCharsToPixels(8); } return convertHeightInCharsToPixels(15); } protected void createCriteriaTree(Composite parent, Font font) { GridData gd; criteriaTree = new CheckboxTreeViewer(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); gd = new GridData(GridData.FILL_BOTH | GridData.GRAB_VERTICAL); gd.heightHint = getTreeHeightHint(); gd.horizontalSpan = 2; criteriaTree.getControl().setLayoutData(gd); criteriaTree.getControl().setFont(font); criteriaTreeContentProvider = new HelpCriteriaContentProvider(); criteriaTree.setContentProvider(criteriaTreeContentProvider); criteriaTreeLabelProvider = new HelpCriteriaLabelProvider(); criteriaTree.setLabelProvider(criteriaTreeLabelProvider); criteriaTree.setUseHashlookup(true); criteriaTree.setInput(BaseHelpSystem.getWorkingSetManager().getCriterionIds()); criteriaTree.addCheckStateListener( event -> handleCheckStateChange(event, criteriaTree, criteriaTreeContentProvider)); criteriaTree.addTreeListener(new ITreeViewerListener() { @Override public void treeCollapsed(TreeExpansionEvent event) { } @Override public void treeExpanded(TreeExpansionEvent event) { final Object element = event.getElement(); if (criteriaTree.getGrayed(element) == false) BusyIndicator.showWhile(getShell().getDisplay(), () -> setSubtreeChecked(element, criteriaTree.getChecked(element), false, criteriaTree, criteriaTreeContentProvider)); } }); criteriaTree.getTree().setEnabled(workingSet != null); } private void initializeCheckedState() { if (workingSet == null) return; BusyIndicator.showWhile(getShell().getDisplay(), () -> { initializeContentTree(); if (HelpPlugin.getCriteriaManager().isCriteriaEnabled()) { initializeCriteriaTree(); } }); } boolean isExpandable(Object element, ITreeContentProvider contentProvider) { return contentProvider.hasChildren(element); } void updateParentState(Object child, boolean baseChildState, CheckboxTreeViewer tree, ITreeContentProvider contentProvider) { if (child == null) return; Object parent = contentProvider.getParent(child); if (parent == null) return; boolean allSameState = true; Object[] children = null; children = contentProvider.getChildren(parent); for (int i = children.length - 1; i >= 0; i--) { if (tree.getChecked(children[i]) != baseChildState || tree.getGrayed(children[i])) { allSameState = false; break; } } tree.setGrayed(parent, !allSameState); tree.setChecked(parent, !allSameState || baseChildState); updateParentState(parent, baseChildState, tree, contentProvider); } void setSubtreeChecked(Object parent, boolean state, boolean checkExpandedState, CheckboxTreeViewer tree, ITreeContentProvider contentProvider) { Object[] children = contentProvider.getChildren(parent); for (int i = children.length - 1; i >= 0; i--) { Object element = children[i]; if (state) { tree.setChecked(element, true); tree.setGrayed(element, false); } else tree.setGrayChecked(element, false); if (isExpandable(element, contentProvider)) setSubtreeChecked(element, state, checkExpandedState, tree, contentProvider); } } @SuppressWarnings({ "unchecked", "rawtypes" }) private void findCheckedElements(java.util.List checkedResources, Object parent, CheckboxTreeViewer tree, ITreeContentProvider contentProvider) { Object[] children = contentProvider.getChildren(parent); for (int i = 0; i < children.length; i++) { if (tree.getGrayed(children[i])) findCheckedElements(checkedResources, children[i], tree, contentProvider); else if (tree.getChecked(children[i])) checkedResources.add(children[i]); } } private CriterionResource[] findCheckedCriteria(Object parent, CheckboxTreeViewer tree, ITreeContentProvider contentProvider) { Object[] children = contentProvider.getChildren(parent); List<CriterionResource> resources = new ArrayList<>(); for (int i = 0; i < children.length; i++) { // First level children are names CriterionName name = (CriterionName) children[i]; CriterionResource resource = new CriterionResource(name.getId()); Object[] grandChildren = contentProvider.getChildren(name); for (int j = 0; j < grandChildren.length; j++) { if (tree.getChecked(grandChildren[j])) { CriterionValue value = (CriterionValue) grandChildren[j]; resource.addCriterionValue(value.getId()); } } if (resource.getCriterionValues().size() > 0) { resources.add(resource); } } return resources.toArray(new CriterionResource[resources.size()]); } void handleCheckStateChange(final CheckStateChangedEvent event, final CheckboxTreeViewer tree, final ITreeContentProvider contentProvider) { BusyIndicator.showWhile(getShell().getDisplay(), () -> { Object element = event.getElement(); boolean state = event.getChecked(); tree.setGrayed(element, false); if (isExpandable(element, contentProvider)) setSubtreeChecked(element, state, state, tree, contentProvider); // only check subtree if state is set to true updateParentState(element, state, tree, contentProvider); // validateInput(); }); } public WorkingSet getWorkingSet() { ArrayList<AdaptableHelpResource> elements = new ArrayList<>(10); CriterionResource[] criteria; if (!HelpPlugin.getCriteriaManager().isCriteriaEnabled()) { criteria = new CriterionResource[0]; } else { criteria = findCheckedCriteria( criteriaTree.getInput(), criteriaTree, criteriaTreeContentProvider); } findCheckedElements(elements, contentTree.getInput(), contentTree, contentTreeContentProvider); if (workingSet == null) { workingSet = new WorkingSet( getScopeSetName(), elements.toArray(new AdaptableHelpResource[elements.size()]), criteria); } else { workingSet.setName(getScopeSetName()); workingSet.setElements(elements.toArray(new AdaptableHelpResource[elements.size()])); workingSet.setCriteria(criteria); } return workingSet; } @Override public boolean performOk() { if (searchSelected.getSelection()) BaseHelpSystem.getWorkingSetManager() .addWorkingSet(getWorkingSet()); else BaseHelpSystem.getWorkingSetManager().removeWorkingSet( getWorkingSet()); getPreferenceStore().setValue( getKey(LocalSearchScopeFactory.P_WORKING_SET), getScopeSetName()); getPreferenceStore().setValue( getKey(LocalSearchScopeFactory.P_CAPABILITY_FILTERING), false); return super.performOk(); } private String getKey(String key) { return getEngineDescriptor().getId() + "." + key; //$NON-NLS-1$ } protected void initializeContentTree() { Object[] elements = workingSet.getElements(); contentTree.setCheckedElements(elements); for (int i = 0; i < elements.length; i++) { Object element = elements[i]; if (isExpandable(element, contentTreeContentProvider)) setSubtreeChecked(element, true, true, contentTree, contentTreeContentProvider); updateParentState(element, true, contentTree, contentTreeContentProvider); } } protected void initializeCriteriaTree() { CriterionResource[] criteria = workingSet.getCriteria(); criteriaTree.setCheckedElements(criteria); for (int i = 0; i < criteria.length; i++) { CriterionResource element = criteria[i]; CriterionName name = new CriterionName(element.getCriterionName(), null); List<String> values = element.getCriterionValues(); for (Iterator<String> iter = values.iterator(); iter.hasNext();) { String valueString = iter.next(); CriterionValue value = new CriterionValue(valueString, name); criteriaTree.setChecked(value, true); updateParentState(value, true, criteriaTree, criteriaTreeContentProvider); } } } @Override protected void performDefaults() { searchAll.setSelection(true); searchSelected.setSelection(false); contentTree.setCheckedElements(new Object[0]); if (criteriaTree != null) { criteriaTree.setCheckedElements(new Object[0]); } super.performDefaults(); } @Override protected Label createDescriptionLabel(Composite parent) { if ( getContainer() == null ) { return null; } return super.createDescriptionLabel(parent); } }