/*******************************************************************************
* Copyright (c) 2000, 2006 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.rubypeople.rdt.internal.ui.preferences;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
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.forms.widgets.ExpandableComposite;
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.internal.corext.util.Messages;
import org.rubypeople.rdt.internal.ui.RubyPlugin;
import org.rubypeople.rdt.internal.ui.dialogs.StatusInfo;
import org.rubypeople.rdt.internal.ui.dialogs.StatusUtil;
import org.rubypeople.rdt.internal.ui.util.PixelConverter;
import org.rubypeople.rdt.internal.ui.wizards.IStatusChangeListener;
/**
*/
public class ProblemSeveritiesConfigurationBlock extends OptionsConfigurationBlock {
private static final String SETTINGS_SECTION_NAME= null; //"ProblemSeveritiesConfigurationBlock";
// values
private static final String ERROR= RubyCore.ERROR;
private static final String WARNING= RubyCore.WARNING;
private static final String IGNORE= RubyCore.IGNORE;
private static final String ENABLED= RubyCore.ENABLED;
private static final String DISABLED= RubyCore.DISABLED;
private static Key[] fgKeys;
private static Map<String, String> fgCategories;
private static HashMap<String, List<Error>> fgErrors;
private PixelConverter fPixelConverter;
private IStatus fStatus;
public ProblemSeveritiesConfigurationBlock(IStatusChangeListener context, IProject project, IWorkbenchPreferenceContainer container) {
super(context, project, getKeys(), container);
fStatus= new StatusInfo();
}
private static List<IConfigurationElement> getErrorProviderElements() {
List<IConfigurationElement> elements = new ArrayList<IConfigurationElement>();
IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(RubyCore.PLUGIN_ID, "errorProvider");
if (extension == null)
return elements;
IExtension[] extensions = extension.getExtensions();
for(int i = 0; i < extensions.length; i++) {
IConfigurationElement[] configElements = extensions[i].getConfigurationElements();
for (int j = 0; j < configElements.length; j++) elements.add(configElements[j]);
}
return elements;
}
private static Map<String, String> getErrorCategories() {
if (fgCategories != null) return fgCategories;
Map<String, String> categories = new HashMap<String, String>();
List<IConfigurationElement> configElements = getErrorProviderElements();
for (IConfigurationElement configElement : configElements) {
String name = configElement.getName();
String contributorName = configElement.getContributor().getName();
if (name.equals("category")) { // Grab the categories
categories.put(configElement.getAttribute("id"), configElement.getAttribute("name"));
}
}
fgCategories = categories;
return fgCategories;
}
private static class Error {
private String id;
private String label;
private String contributor;
private String argument;
private String type;
private String argumentLabel;
Error(IConfigurationElement element) {
this.id = element.getAttribute("prefKey");
this.label = element.getAttribute("label");
this.contributor = element.getContributor().getName();
IConfigurationElement[] elements = element.getChildren("argument");
if (elements != null && elements.length > 0) {
this.argument = elements[0].getAttribute("prefKey");
this.type = elements[0].getAttribute("type");
if (type == null) {
type = "int";
}
this.argumentLabel = elements[0].getAttribute("label");
if (this.argumentLabel == null)
{
this.argumentLabel = "";
}
}
}
public boolean hasArgument() {
return argument != null;
}
public String getContributor() {
return contributor;
}
public String getId() {
return id;
}
public String getLabel() {
return label;
}
public String getArgument() {
return argument;
}
public String getArgumentLabel() {
return argumentLabel;
}
public boolean argumentIsInt() {
return hasArgument() && type.equals("int");
}
}
private static Key[] getKeys() {
if (fgKeys != null) return fgKeys;
List<Key> keys = new ArrayList<Key>();
Map<String, String> categories = getErrorCategories();
for (String categoryId : categories.keySet()) {
List<Error> errors = getErrors(categoryId);
for (Error error : errors) {
keys.add(getKey(error.getContributor(), error.getId()));
}
}
fgKeys = keys.toArray(new Key[keys.size()]);
return fgKeys;
}
/*
* @see org.eclipse.jface.preference.PreferencePage#createContents(Composite)
*/
protected Control createContents(Composite parent) {
fPixelConverter= new PixelConverter(parent);
setShell(parent.getShell());
Composite mainComp= new Composite(parent, SWT.NONE);
mainComp.setFont(parent.getFont());
GridLayout layout= new GridLayout();
layout.marginHeight= 0;
layout.marginWidth= 0;
mainComp.setLayout(layout);
Composite commonComposite= createStyleTabContent(mainComp);
GridData gridData= new GridData(GridData.FILL, GridData.FILL, true, true);
gridData.heightHint= fPixelConverter.convertHeightInCharsToPixels(20);
commonComposite.setLayoutData(gridData);
validateSettings(null, null, null);
return mainComp;
}
private Composite createStyleTabContent(Composite folder) {
String[] errorWarningIgnore= new String[] { ERROR, WARNING, IGNORE };
String[] errorWarningIgnoreLabels= new String[] {
PreferencesMessages.ProblemSeveritiesConfigurationBlock_error,
PreferencesMessages.ProblemSeveritiesConfigurationBlock_warning,
PreferencesMessages.ProblemSeveritiesConfigurationBlock_ignore
};
String[] enabledDisabled= new String[] { ENABLED, DISABLED };
int nColumns= 3;
final ScrolledPageContent sc1 = new ScrolledPageContent(folder);
Composite composite= sc1.getBody();
GridLayout layout= new GridLayout(nColumns, false);
layout.marginHeight= 0;
layout.marginWidth= 0;
composite.setLayout(layout);
Label description= new Label(composite, SWT.LEFT | SWT.WRAP);
description.setFont(description.getFont());
description.setText(PreferencesMessages.ProblemSeveritiesConfigurationBlock_common_description);
description.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, true, false, nColumns - 1, 1));
int indentStep= fPixelConverter.convertWidthInCharsToPixels(1);
int defaultIndent= indentStep * 0;
int extraIndent= indentStep * 2;
String label;
ExpandableComposite excomposite;
Composite inner;
Map<String, String> categories = getErrorCategories();
for (String categoryId : categories.keySet()) {
List<Error> errors = getErrors(categoryId);
if (errors == null || errors.isEmpty()) continue;
excomposite= createStyleSection(composite, categories.get(categoryId), nColumns);
inner= new Composite(excomposite, SWT.NONE);
inner.setFont(composite.getFont());
inner.setLayout(new GridLayout(nColumns, false));
excomposite.setClient(inner);
for (Error error : errors) {
addComboBox(inner, error.label + ':', getKey(error.getContributor(), error.getId()), errorWarningIgnore, errorWarningIgnoreLabels, defaultIndent);
if (error.hasArgument()) {
Text text= addTextField(inner, error.getArgumentLabel(), getKey(error.getContributor(), error.getArgument()), 0, 0);
GridData gd= (GridData) text.getLayoutData();
gd.widthHint= fPixelConverter.convertWidthInCharsToPixels(8);
gd.horizontalAlignment= GridData.END;
text.setTextLimit(6);
}
}
}
IDialogSettings section= RubyPlugin.getDefault().getDialogSettings().getSection(SETTINGS_SECTION_NAME);
restoreSectionExpansionStates(section);
return sc1;
}
private static List<Error> getErrors(String categoryId) {
if (fgErrors == null) {
fgErrors = new HashMap<String, List<Error>>();
}
if (fgErrors.get(categoryId) != null) return fgErrors.get(categoryId);
List<Error> categories = new ArrayList<Error>();
List<IConfigurationElement> configElements = getErrorProviderElements();
for (IConfigurationElement configElement : configElements) {
String name = configElement.getName();
if (name.equals("error") && configElement.getAttribute("categoryId").equals(categoryId)) { // Grab the errors for this category
categories.add(new Error(configElement));
}
}
fgErrors.put(categoryId, categories);
return categories;
}
/* (non-javadoc)
* Update fields and validate.
* @param changedKey Key that changed, or null, if all changed.
*/
protected void validateSettings(Key changedKey, String oldValue, String newValue) {
if (!areSettingsEnabled()) {
return;
}
if (changedKey != null) {
List<Error> errors = getErrors();
for (Error error : errors) {
if (error.hasArgument() && error.argumentIsInt() && changedKey.getName().equals(error.getArgument())) {
fStatus = validateMaxNumber(changedKey, error.getLabel());
fContext.statusChanged(fStatus);
return;
}
}
} else {
updateEnableStates();
}
IStatus status= StatusUtil.getMostSevere(new IStatus[] { fStatus });
fContext.statusChanged(status);
}
private static List<Error> getErrors() {
List<Error> errors = new ArrayList<Error>();
Map<String, String> categories = getErrorCategories();
for (String categoryId : categories.keySet()) {
errors.addAll(getErrors(categoryId));
}
return errors;
}
private IStatus validateMaxNumber(Key key, String label) {
String number= getValue(key);
StatusInfo status= new StatusInfo();
if (number.length() == 0) {
status.setError(PreferencesMessages.RubyBuildConfigurationBlock_empty_input);
} else {
try {
int value= Integer.parseInt(number);
if (value <= 0) {
status.setError(Messages.format(PreferencesMessages.RubyBuildConfigurationBlock_invalid_input, new Object[] {number, label}));
}
} catch (NumberFormatException e) {
status.setError(Messages.format(PreferencesMessages.RubyBuildConfigurationBlock_invalid_input, new Object[] {number, label}));
}
}
return status;
}
private void updateEnableStates() {
// TODO Handle enabling/disabling checkboxes as prefs change
// FIXME Iterate through errors which have "arguments", if error is set to ignore, disable value textbox!
}
protected String[] getFullBuildDialogStrings(boolean workspaceSettings) {
String title= PreferencesMessages.ProblemSeveritiesConfigurationBlock_needsbuild_title;
String message;
if (workspaceSettings) {
message= PreferencesMessages.ProblemSeveritiesConfigurationBlock_needsfullbuild_message;
} else {
message= PreferencesMessages.ProblemSeveritiesConfigurationBlock_needsprojectbuild_message;
}
return new String[] { title, message };
}
/* (non-Javadoc)
* @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#dispose()
*/
public void dispose() {
IDialogSettings section= RubyPlugin.getDefault().getDialogSettings().addNewSection(SETTINGS_SECTION_NAME);
storeSectionExpansionStates(section);
super.dispose();
}
}