blob: d0432b16bef222c22fd33749ff27caf6b1a62daf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 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
* Alex Blewitt - Bug 474070
*******************************************************************************/
package org.eclipse.help.ui;
import java.util.Hashtable;
import org.eclipse.help.ui.internal.Messages;
import org.eclipse.help.ui.internal.views.EngineDescriptor;
import org.eclipse.help.ui.internal.views.ScopeSet;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.swt.SWT;
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.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
/**
* Clients that contribute search scope root page to the search engine
* definition must extend this class and implement
* <code>createScopeContents</code> method. The page will come preset with the
* engine name, image and description, as well as the master switch that turns
* the engine on or off. When the engine master switch is set to false, all the
* children in the client composite will be disabled.
*
* @since 3.1
*/
public abstract class RootScopePage extends PreferencePage implements
ISearchScopePage {
private IEngineDescriptor ed;
private String scopeSetName;
private Button masterButton;
private Text labelText;
private Text descText;
private Hashtable<Control, Boolean> disabledStates = new Hashtable<>();
private Label spacer;
private Composite contentContainer;
/**
* The default constructor.
*/
public RootScopePage() {
}
@Override
public void init(IEngineDescriptor ed, String scopeSetName) {
this.ed = ed;
this.scopeSetName = scopeSetName;
}
/**
* Creates the initial contents of the page and allocates the area for the
* clients. Classes that extend this class should implement
* <code>createScopeContents(Composite)</code> instead.
*
* @param parent
* the page parent
* @return the page client control
*/
@Override
protected final Control createContents(Composite parent) {
initializeDefaults(getPreferenceStore());
PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
"org.eclipse.help.ui.searchScope"); //$NON-NLS-1$
contentContainer = new Composite(parent, SWT.NULL);
GridLayout layout = new GridLayout();
GridData gd;
//if (ed.isUserDefined())
layout.numColumns = 2;
contentContainer.setLayout(layout);
if (isInPreferenceDialog()) {
masterButton = new Button(contentContainer, SWT.CHECK);
masterButton.setText(Messages.RootScopePage_masterButton);
gd = new GridData();
gd.horizontalSpan = 2;// ed.isUserDefined() ? 2 : 1;
masterButton.setLayoutData(gd);
spacer = new Label(contentContainer, SWT.NULL);
gd = new GridData();
gd.horizontalSpan = 2;// ed.isUserDefined() ? 2 : 1;
spacer.setLayoutData(gd);
boolean masterValue = getPreferenceStore().getBoolean(ScopeSet.getMasterKey(ed.getId()));
masterButton.setSelection(masterValue);
masterButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
masterValueChanged(masterButton.getSelection());
}
});
Label label = new Label(contentContainer, SWT.NULL);
label.setText(Messages.RootScopePage_name);
labelText = new Text(contentContainer, SWT.BORDER);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.widthHint = 200;
labelText.setLayoutData(gd);
labelText.setEditable(ed.isUserDefined());
label = new Label(contentContainer, SWT.NULL);
label.setText(Messages.RootScopePage_desc);
gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
label.setLayoutData(gd);
descText = new Text(contentContainer, SWT.BORDER | SWT.MULTI | SWT.WRAP);
gd = new GridData(GridData.FILL_HORIZONTAL);
descText.setEditable(ed.isUserDefined());
gd.widthHint = 200;
gd.heightHint = 48;
descText.setLayoutData(gd);
}
int ccol = createScopeContents(contentContainer);
// adjust number of columns if needed
if (ccol > layout.numColumns && isInPreferenceDialog()) {
layout.numColumns = ccol;
gd = (GridData) masterButton.getLayoutData();
gd.horizontalSpan = layout.numColumns;
gd = (GridData) spacer.getLayoutData();
gd.horizontalSpan = layout.numColumns;
gd = (GridData) labelText.getLayoutData();
gd.horizontalSpan = layout.numColumns - 1;
gd = (GridData) descText.getLayoutData();
gd.horizontalSpan = layout.numColumns - 1;
}
updateControls(true);
return contentContainer;
}
/**
* Called when the value of the master switch has changed. The default
* implementation disables the scope contents control when the master switch
* is off. Subclass can override this behaviour.
*
* @param value
* <code>true</code> if the master switch is on,
* <code>false</code> otherwise.
*/
protected void masterValueChanged(boolean value) {
updateEnableState(value);
}
private void updateEnableState(boolean enabled) {
Control[] children = contentContainer.getChildren();
boolean first = disabledStates.isEmpty();
for (int i = 0; i < children.length; i++) {
Control child = children[i];
if (child == masterButton)
continue;
if (!enabled) {
disabledStates.put(child, Boolean.valueOf(child.isEnabled()));
child.setEnabled(false);
} else {
Boolean savedState = disabledStates.get(child);
if (!first)
child.setEnabled(savedState != null ? savedState
.booleanValue() : true);
}
}
}
/**
* Returns the scope set name passed to the page during initialization.
*
* @return the name of the current scope set
*/
protected String getScopeSetName() {
return scopeSetName;
}
/**
* Returns the descriptor of the engine associated with this page.
*
* @return the engine descriptor
*/
protected IEngineDescriptor getEngineDescriptor() {
return ed;
}
/**
* Tests whether the search engine has been selected to participate in the
* search.
*
* @return <code>true</code> if the search engine is enabled, </code>false</code>
* otherwise.
*/
protected boolean isEngineEnabled() {
if (!isInPreferenceDialog()) {
return true;
}
return masterButton.getSelection();
}
/**
* Stores the value of the master switch in the preference store. Subclasses
* may override but must call 'super'.
*
* @return <code>true</code> if the wizard can be closed,
* <code>false</code> otherwise.
*/
@Override
public boolean performOk() {
getPreferenceStore().setValue(ScopeSet.getMasterKey(ed.getId()),
isEngineEnabled());
if (labelText != null) {
ed.setLabel(labelText.getText());
ed.setDescription(descText.getText());
}
return true;
}
/**
* Sets the value of the master switch to the initial value from the
* extension. Subclasses may override but must call 'super'.
*/
@Override
protected void performDefaults() {
getPreferenceStore().setToDefault(ScopeSet.getMasterKey(ed.getId()));
updateControls(false);
super.performDefaults();
}
private void updateControls(boolean first) {
if (isInPreferenceDialog()) {
boolean value = getPreferenceStore().getBoolean(ScopeSet.getMasterKey(ed.getId()));
boolean cvalue = masterButton.getSelection();
if (value != cvalue) {
masterButton.setSelection(value);
masterValueChanged(value);
} else if (first) {
masterValueChanged(value);
}
labelText.setText(ed.getLabel());
descText.setText(ed.getDescription());
}
}
private boolean isInPreferenceDialog() {
return getContainer() != null;
}
/**
* Initializes default values of the store to be used when the user presses
* 'Defaults' button. Subclasses may override but must call 'super'.
*
* @param store
* the preference store
*/
protected void initializeDefaults(IPreferenceStore store) {
Boolean value = (Boolean) ed.getParameters().get(
EngineDescriptor.P_MASTER);
store.setDefault(ScopeSet.getMasterKey(ed.getId()), value
.booleanValue());
}
/**
* Abstract method that subclasses must implement in order to provide root
* page content. The parent uses <code>GridLayout</code> to position and
* size the widgets. Widgets created in this method should use
* <code>GridData</code> to configure the way they fit in the overall
* page.
* <p>
* The common widgets created by this page will set number of columns they
* need for themselves only. Clients that implement this method should
* return the required number of columns so that the root page widgets can
* be adjusted if more columns are needed than initially set.
*
* @param parent
* the page parent
* @return number of columns required by the client content
*/
protected abstract int createScopeContents(Composite parent);
}