blob: 4a0ef29449a74007a063f95810fa459197a2ccec [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2008 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.ui.internal.editors.text;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.ui.texteditor.spelling.IPreferenceStatusMonitor;
import org.eclipse.ui.texteditor.spelling.ISpellingPreferenceBlock;
import org.eclipse.ui.texteditor.spelling.SpellingEngineDescriptor;
import org.eclipse.ui.texteditor.spelling.SpellingService;
import org.eclipse.ui.editors.text.EditorsUI;
/**
* Configures spelling preferences.
*
* @since 3.1
*/
class SpellingConfigurationBlock implements IPreferenceConfigurationBlock {
/**
* Error preferences block.
*/
private static class ErrorPreferences implements ISpellingPreferenceBlock {
/** Error message */
private String fMessage;
/** Error label */
private Label fLabel;
/**
* Initialize with the given error message.
*
* @param message the error message
*/
protected ErrorPreferences(String message) {
fMessage= message;
}
/*
* @see org.eclipse.ui.texteditor.spelling.ISpellingPreferenceBlock#createControl(org.eclipse.swt.widgets.Composite)
*/
public Control createControl(Composite composite) {
Composite inner= new Composite(composite, SWT.NONE);
inner.setLayout(new FillLayout(SWT.VERTICAL));
fLabel= new Label(inner, SWT.CENTER);
fLabel.setText(fMessage);
return inner;
}
/*
* @see org.eclipse.ui.texteditor.spelling.ISpellingPreferenceBlock#initialize(org.eclipse.ui.texteditor.spelling.IStatusMonitor)
*/
public void initialize(IPreferenceStatusMonitor statusMonitor) {
}
/*
* @see org.eclipse.ui.texteditor.spelling.ISpellingPreferenceBlock#canPerformOk()
*/
public boolean canPerformOk() {
return true;
}
/*
* @see org.eclipse.ui.texteditor.spelling.ISpellingPreferenceBlock#performOk()
*/
public void performOk() {
}
/*
* @see org.eclipse.ui.texteditor.spelling.ISpellingPreferenceBlock#performDefaults()
*/
public void performDefaults() {
}
/*
* @see org.eclipse.ui.texteditor.spelling.ISpellingPreferenceBlock#performRevert()
*/
public void performRevert() {
}
/*
* @see org.eclipse.ui.texteditor.spelling.ISpellingPreferenceBlock#dispose()
*/
public void dispose() {
}
/*
* @see org.eclipse.ui.texteditor.spelling.ISpellingPreferenceBlock#setEnabled(boolean)
*/
public void setEnabled(boolean enabled) {
fLabel.setEnabled(enabled);
}
}
/**
* Forwarding status monitor for accessing the current status.
*/
private static class ForwardingStatusMonitor implements IPreferenceStatusMonitor {
/** Status monitor to which status changes are forwarded */
private IPreferenceStatusMonitor fForwardedMonitor;
/** Latest reported status */
private IStatus fStatus;
/**
* Initializes with the given status monitor to which status changes are forwarded.
*
* @param forwardedMonitor the status monitor to which changes are forwarded
*/
public ForwardingStatusMonitor(IPreferenceStatusMonitor forwardedMonitor) {
fForwardedMonitor= forwardedMonitor;
}
/*
* @see org.eclipse.ui.texteditor.spelling.IPreferenceStatusMonitor#statusChanged(org.eclipse.core.runtime.IStatus)
*/
public void statusChanged(IStatus status) {
fStatus= status;
fForwardedMonitor.statusChanged(status);
}
/**
* Returns the latest reported status.
*
* @return the latest reported status, can be <code>null</code>
*/
public IStatus getStatus() {
return fStatus;
}
}
/** The overlay preference store. */
private final OverlayPreferenceStore fStore;
/* The controls */
private Combo fProviderCombo;
private Button fEnablementCheckbox;
private ComboViewer fProviderViewer;
private Composite fComboGroup;
private Composite fGroup;
private StackLayout fStackLayout;
/* the model */
private final Map fProviderDescriptors;
private final Map fProviderPreferences;
private final Map fProviderControls;
private ForwardingStatusMonitor fStatusMonitor;
private ISpellingPreferenceBlock fCurrentBlock;
public SpellingConfigurationBlock(OverlayPreferenceStore store, IPreferenceStatusMonitor statusMonitor) {
Assert.isNotNull(store);
fStore= store;
fStore.addKeys(createOverlayStoreKeys());
fStatusMonitor= new ForwardingStatusMonitor(statusMonitor);
fProviderDescriptors= createListModel();
fProviderPreferences= new HashMap();
fProviderControls= new HashMap();
}
private Map createListModel() {
SpellingEngineDescriptor[] descs= EditorsUI.getSpellingService().getSpellingEngineDescriptors();
Map map= new HashMap();
for (int i= 0; i < descs.length; i++) {
map.put(descs[i].getId(), descs[i]);
}
return map;
}
private OverlayPreferenceStore.OverlayKey[] createOverlayStoreKeys() {
ArrayList overlayKeys= new ArrayList();
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, SpellingService.PREFERENCE_SPELLING_ENABLED));
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, SpellingService.PREFERENCE_SPELLING_ENGINE));
OverlayPreferenceStore.OverlayKey[] keys= new OverlayPreferenceStore.OverlayKey[overlayKeys.size()];
overlayKeys.toArray(keys);
return keys;
}
/**
* Creates page for spelling preferences.
*
* @param parent the parent composite
* @return the control for the preference page
*/
public Control createControl(Composite parent) {
Composite composite= new Composite(parent, SWT.NULL);
// assume parent page uses grid-data
GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_CENTER | GridData.VERTICAL_ALIGN_FILL);
composite.setLayoutData(gd);
GridLayout layout= new GridLayout();
layout.numColumns= 2;
layout.marginHeight= 0;
layout.marginWidth= 0;
PixelConverter pc= new PixelConverter(composite);
layout.verticalSpacing= pc.convertHeightInCharsToPixels(1) / 2;
composite.setLayout(layout);
if (EditorsUI.getSpellingService().getSpellingEngineDescriptors().length == 0) {
Label label= new Label(composite, SWT.NONE);
label.setText(TextEditorMessages.SpellingConfigurationBlock_error_not_installed);
return composite;
}
/* check box for new editors */
fEnablementCheckbox= new Button(composite, SWT.CHECK);
fEnablementCheckbox.setText(TextEditorMessages.SpellingConfigurationBlock_enable);
gd= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_BEGINNING);
fEnablementCheckbox.setLayoutData(gd);
fEnablementCheckbox.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
boolean enabled= fEnablementCheckbox.getSelection();
fStore.setValue(SpellingService.PREFERENCE_SPELLING_ENABLED, enabled);
updateCheckboxDependencies();
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
Label label= new Label(composite, SWT.CENTER);
gd= new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING);
label.setLayoutData(gd);
if (fProviderDescriptors.size() > 1) {
fComboGroup= new Composite(composite, SWT.NONE);
gd= new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING);
gd.horizontalIndent= 10;
fComboGroup.setLayoutData(gd);
GridLayout gridLayout= new GridLayout(2, false);
gridLayout.marginWidth= 0;
fComboGroup.setLayout(gridLayout);
Label comboLabel= new Label(fComboGroup, SWT.CENTER);
gd= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_CENTER);
comboLabel.setLayoutData(gd);
comboLabel.setText(TextEditorMessages.SpellingConfigurationBlock_combo_caption);
label= new Label(composite, SWT.CENTER);
gd= new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING);
label.setLayoutData(gd);
fProviderCombo= new Combo(fComboGroup, SWT.READ_ONLY | SWT.DROP_DOWN);
gd= new GridData(GridData.HORIZONTAL_ALIGN_END | GridData.VERTICAL_ALIGN_CENTER);
fProviderCombo.setLayoutData(gd);
fProviderViewer= createProviderViewer();
}
Composite groupComp= new Composite(composite, SWT.NONE);
gd= new GridData(GridData.FILL_BOTH);
gd.horizontalSpan= 2;
groupComp.setLayoutData(gd);
GridLayout gridLayout= new GridLayout(1, false);
gridLayout.marginWidth= 0;
groupComp.setLayout(gridLayout);
/* contributed provider preferences. */
fGroup= new Composite(groupComp, SWT.NONE);
gd= new GridData(SWT.FILL, SWT.FILL, true, true);
gd.horizontalIndent= 10;
fGroup.setLayoutData(gd);
fStackLayout= new StackLayout();
fGroup.setLayout(fStackLayout);
return composite;
}
/*
* @see org.eclipse.ui.internal.editors.text.IPreferenceConfigurationBlock#applyData(java.lang.Object)
* @since 3.4
*/
public void applyData(Object data) {
}
private ComboViewer createProviderViewer() {
/* list viewer */
final ComboViewer viewer= new ComboViewer(fProviderCombo);
viewer.setContentProvider(new IStructuredContentProvider() {
/*
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
public void dispose() {
}
/*
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
}
/*
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
*/
public Object[] getElements(Object inputElement) {
return fProviderDescriptors.values().toArray();
}
});
viewer.setLabelProvider(new LabelProvider() {
/*
* @see org.eclipse.jface.viewers.LabelProvider#getImage(java.lang.Object)
*/
public Image getImage(Object element) {
return null;
}
/*
* @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
*/
public String getText(Object element) {
return ((SpellingEngineDescriptor) element).getLabel();
}
});
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection sel= (IStructuredSelection) event.getSelection();
if (sel.isEmpty())
return;
if (fCurrentBlock != null && fStatusMonitor.getStatus() != null && fStatusMonitor.getStatus().matches(IStatus.ERROR))
if (isPerformRevert()) {
ISafeRunnable runnable= new ISafeRunnable() {
public void run() throws Exception {
fCurrentBlock.performRevert();
}
public void handleException(Throwable x) {
}
};
SafeRunner.run(runnable);
} else {
revertSelection();
return;
}
fStore.setValue(SpellingService.PREFERENCE_SPELLING_ENGINE, ((SpellingEngineDescriptor) sel.getFirstElement()).getId());
updateListDependencies();
}
private boolean isPerformRevert() {
Shell shell= viewer.getControl().getShell();
MessageDialog dialog= new MessageDialog(shell, TextEditorMessages.SpellingConfigurationBlock_error_title, null, TextEditorMessages.SpellingConfigurationBlock_error_message, MessageDialog.QUESTION, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 1);
return dialog.open() == 0;
}
private void revertSelection() {
try {
viewer.removeSelectionChangedListener(this);
SpellingEngineDescriptor desc= EditorsUI.getSpellingService().getActiveSpellingEngineDescriptor(fStore);
if (desc != null)
viewer.setSelection(new StructuredSelection(desc), true);
} finally {
viewer.addSelectionChangedListener(this);
}
}
});
viewer.setInput(fProviderDescriptors);
viewer.refresh();
return viewer;
}
private void updateCheckboxDependencies() {
final boolean enabled= fEnablementCheckbox.getSelection();
if (fComboGroup != null)
setEnabled(fComboGroup, enabled);
SpellingEngineDescriptor desc= EditorsUI.getSpellingService().getActiveSpellingEngineDescriptor(fStore);
String id= desc != null ? desc.getId() : ""; //$NON-NLS-1$
final ISpellingPreferenceBlock preferenceBlock= (ISpellingPreferenceBlock) fProviderPreferences.get(id);
if (preferenceBlock != null) {
ISafeRunnable runnable= new ISafeRunnable() {
public void run() throws Exception {
preferenceBlock.setEnabled(enabled);
}
public void handleException(Throwable x) {
}
};
SafeRunner.run(runnable);
}
}
private void setEnabled(Control control, boolean enabled) {
if (control instanceof Composite) {
Control[] children= ((Composite) control).getChildren();
for (int i= 0; i < children.length; i++)
setEnabled(children[i], enabled);
}
control.setEnabled(enabled);
}
void updateListDependencies() {
SpellingEngineDescriptor desc= EditorsUI.getSpellingService().getActiveSpellingEngineDescriptor(fStore);
String id;
if (desc == null) {
// safety in case there is no such descriptor
id= ""; //$NON-NLS-1$
String message= TextEditorMessages.SpellingConfigurationBlock_error_not_exist;
EditorsPlugin.log(new Status(IStatus.WARNING, EditorsUI.PLUGIN_ID, IStatus.OK, message, null));
fCurrentBlock= new ErrorPreferences(message);
} else {
id= desc.getId();
fCurrentBlock= (ISpellingPreferenceBlock) fProviderPreferences.get(id);
if (fCurrentBlock == null) {
try {
fCurrentBlock= desc.createPreferences();
fProviderPreferences.put(id, fCurrentBlock);
} catch (CoreException e) {
EditorsPlugin.log(e);
fCurrentBlock= new ErrorPreferences(e.getLocalizedMessage());
}
}
}
Control control= (Control) fProviderControls.get(id);
if (control == null) {
final Control[] result= new Control[1];
ISafeRunnable runnable= new ISafeRunnable() {
public void run() throws Exception {
result[0]= fCurrentBlock.createControl(fGroup);
}
public void handleException(Throwable x) {
}
};
SafeRunner.run(runnable);
control= result[0];
if (control == null) {
String message= TextEditorMessages.SpellingConfigurationBlock_info_no_preferences;
EditorsPlugin.log(new Status(IStatus.WARNING, EditorsUI.PLUGIN_ID, IStatus.OK, message, null));
control= new ErrorPreferences(message).createControl(fGroup);
} else {
fProviderControls.put(id, control);
}
}
Dialog.applyDialogFont(control);
fStackLayout.topControl= control;
control.pack();
fGroup.layout();
fGroup.getParent().layout();
fStatusMonitor.statusChanged(new StatusInfo());
ISafeRunnable runnable= new ISafeRunnable() {
public void run() throws Exception {
fCurrentBlock.initialize(fStatusMonitor);
}
public void handleException(Throwable x) {
}
};
SafeRunner.run(runnable);
}
public void initialize() {
restoreFromPreferences();
}
public boolean canPerformOk() {
SpellingEngineDescriptor desc= EditorsUI.getSpellingService().getActiveSpellingEngineDescriptor(fStore);
String id= desc != null ? desc.getId() : ""; //$NON-NLS-1$
final ISpellingPreferenceBlock block= (ISpellingPreferenceBlock) fProviderPreferences.get(id);
if (block == null)
return true;
final Boolean[] result= new Boolean[] { Boolean.TRUE };
ISafeRunnable runnable= new ISafeRunnable() {
public void run() throws Exception {
result[0]= Boolean.valueOf(block.canPerformOk());
}
public void handleException(Throwable x) {
}
};
SafeRunner.run(runnable);
return result[0].booleanValue();
}
public void performOk() {
for (Iterator it= fProviderPreferences.values().iterator(); it.hasNext();) {
final ISpellingPreferenceBlock block= (ISpellingPreferenceBlock) it.next();
ISafeRunnable runnable= new ISafeRunnable() {
public void run() throws Exception {
block.performOk();
}
public void handleException(Throwable x) {
}
};
SafeRunner.run(runnable);
}
}
public void performDefaults() {
restoreFromPreferences();
for (Iterator it= fProviderPreferences.values().iterator(); it.hasNext();) {
final ISpellingPreferenceBlock block= (ISpellingPreferenceBlock) it.next();
ISafeRunnable runnable= new ISafeRunnable() {
public void run() throws Exception {
block.performDefaults();
}
public void handleException(Throwable x) {
}
};
SafeRunner.run(runnable);
}
}
public void dispose() {
for (Iterator it= fProviderPreferences.values().iterator(); it.hasNext();) {
final ISpellingPreferenceBlock block= (ISpellingPreferenceBlock) it.next();
ISafeRunnable runnable= new ISafeRunnable() {
public void run() throws Exception {
block.dispose();
}
public void handleException(Throwable x) {
}
};
SafeRunner.run(runnable);
}
}
private void restoreFromPreferences() {
if (fEnablementCheckbox == null)
return;
boolean enabled= fStore.getBoolean(SpellingService.PREFERENCE_SPELLING_ENABLED);
fEnablementCheckbox.setSelection(enabled);
if (fProviderViewer == null)
updateListDependencies();
else {
SpellingEngineDescriptor desc= EditorsUI.getSpellingService().getActiveSpellingEngineDescriptor(fStore);
if (desc != null)
fProviderViewer.setSelection(new StructuredSelection(desc), true);
}
updateCheckboxDependencies();
}
}