blob: 0117edd80465703cc2d65a828dffa762f4f7dde0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2011 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.jdt.internal.ui.preferences.formatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
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.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.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.util.SWTUtil;
/**
* The line wrapping tab page.
*/
public class LineWrappingTabPage extends FormatterTabPage {
/**
* Represents a line wrapping category. All members are final.
*/
private final static class Category {
public final String key;
public final String name;
public final String previewText;
public final List<Category> children;
public final List<Preference> preferences;
public int index;
public Category(String _key, String _previewText, String _name) {
this.key= _key;
this.name= _name;
this.previewText= _previewText != null ? createPreviewHeader(_name) + _previewText : null;
children= new ArrayList<Category>();
preferences= new ArrayList<Preference>();
}
/**
* @param _name Category name
*/
public Category(String _name) {
this(null, null, _name);
}
@Override
public String toString() {
return name;
}
public void addPreference(Preference specificPreference) {
preferences.add(specificPreference);
}
public Preference[] getSpecificPreferences() {
return preferences.toArray(new Preference[preferences.size()]);
}
public void setEnabled(boolean state) {
for (Preference preference : preferences)
preference.setEnabled(state);
}
}
private final static String PREF_CATEGORY_INDEX= JavaUI.ID_PLUGIN + "formatter_page.line_wrapping_tab_page.last_category_index"; //$NON-NLS-1$
private final class CategoryListener implements ISelectionChangedListener, IDoubleClickListener {
private final List<Category> fCategoriesList;
private int fIndex= 0;
public CategoryListener(List<Category> categoriesTree) {
fCategoriesList= new ArrayList<Category>();
flatten(fCategoriesList, categoriesTree);
}
private void flatten(List<Category> categoriesList, List<Category> categoriesTree) {
for (final Iterator<Category> iter= categoriesTree.iterator(); iter.hasNext(); ) {
final Category category= iter.next();
category.index= fIndex++;
categoriesList.add(category);
flatten(categoriesList, category.children);
}
}
public void selectionChanged(SelectionChangedEvent event) {
if (event != null)
fSelection= (IStructuredSelection)event.getSelection();
if (fSelection.size() == 0) {
disableAll();
return;
}
if (!fOptionsGroup.isEnabled())
enableDefaultComponents(true);
fSelectionState.refreshState(fSelection);
final Category category= (Category)fSelection.getFirstElement();
fDialogSettings.put(PREF_CATEGORY_INDEX, category.index);
fOptionsGroup.setText(getGroupLabel(category));
}
private String getGroupLabel(Category category) {
if (fSelection.size() == 1) {
if (fSelectionState.getElements().size() == 1)
return Messages.format(FormatterMessages.LineWrappingTabPage_group, category.name.toLowerCase());
return Messages.format(FormatterMessages.LineWrappingTabPage_multi_group, new String[] {category.name.toLowerCase(), Integer.toString(fSelectionState.getElements().size())});
}
return Messages.format(FormatterMessages.LineWrappingTabPage_multiple_selections, new String[] {Integer.toString(fSelectionState.getElements().size())});
}
private void disableAll() {
enableDefaultComponents(false);
fIndentStyleCombo.setEnabled(false);
fForceSplit.setEnabled(false);
}
private void enableDefaultComponents(boolean enabled) {
fOptionsGroup.setEnabled(enabled);
fWrappingStyleCombo.setEnabled(enabled);
fWrappingStylePolicy.setEnabled(enabled);
}
public void restoreSelection() {
int index;
try {
index= fDialogSettings.getInt(PREF_CATEGORY_INDEX);
} catch (NumberFormatException ex) {
index= -1;
}
if (index < 0 || index > fCategoriesList.size() - 1) {
index= 1; // In order to select a category with preview initially
}
final Category category= fCategoriesList.get(index);
fCategoriesViewer.setSelection(new StructuredSelection(new Category[] {category}));
}
public void doubleClick(DoubleClickEvent event) {
final ISelection selection= event.getSelection();
if (selection instanceof IStructuredSelection) {
final Category node= (Category)((IStructuredSelection)selection).getFirstElement();
fCategoriesViewer.setExpandedState(node, !fCategoriesViewer.getExpandedState(node));
}
}
}
private class SelectionState {
private List<Category> fElements= new ArrayList<Category>();
private boolean fRequiresRelayout;
public void refreshState(IStructuredSelection selection) {
Map<Object, Integer> wrappingStyleMap= new HashMap<Object, Integer>();
Map<Object, Integer> indentStyleMap= new HashMap<Object, Integer>();
Map<Object, Integer> forceWrappingMap= new HashMap<Object, Integer>();
fRequiresRelayout= false;
showSpecificControls(false);
fElements.clear();
evaluateElements(selection.iterator());
evaluateMaps(wrappingStyleMap, indentStyleMap, forceWrappingMap);
setPreviewText(getPreviewText());
refreshControls(wrappingStyleMap, indentStyleMap, forceWrappingMap);
}
public List<Category> getElements() {
return fElements;
}
private void evaluateElements(Iterator<Category> iterator) {
Category category;
String value;
while (iterator.hasNext()) {
category= iterator.next();
value= fWorkingValues.get(category.key);
if (value != null) {
if (!fElements.contains(category))
fElements.add(category);
}
else {
evaluateElements(category.children.iterator());
}
}
}
private void evaluateMaps(Map<Object, Integer> wrappingStyleMap, Map<Object, Integer> indentStyleMap, Map<Object, Integer> forceWrappingMap) {
Iterator<Category> iterator= fElements.iterator();
while (iterator.hasNext()) {
insertIntoMap(wrappingStyleMap, indentStyleMap, forceWrappingMap, iterator.next());
}
}
private String getPreviewText() {
Iterator<Category> iterator= fElements.iterator();
String previewText= ""; //$NON-NLS-1$
while (iterator.hasNext()) {
Category category= iterator.next();
previewText= previewText + category.previewText + "\n\n"; //$NON-NLS-1$
}
return previewText;
}
private void insertIntoMap(Map<Object, Integer> wrappingMap, Map<Object, Integer> indentMap, Map<Object, Integer> forceMap, Category category) {
final String value= fWorkingValues.get(category.key);
Integer wrappingStyle;
Integer indentStyle;
Boolean forceWrapping;
try {
wrappingStyle= new Integer(DefaultCodeFormatterConstants.getWrappingStyle(value));
indentStyle= new Integer(DefaultCodeFormatterConstants.getIndentStyle(value));
forceWrapping= new Boolean(DefaultCodeFormatterConstants.getForceWrapping(value));
} catch (IllegalArgumentException e) {
forceWrapping= new Boolean(false);
indentStyle= new Integer(DefaultCodeFormatterConstants.INDENT_DEFAULT);
wrappingStyle= new Integer(DefaultCodeFormatterConstants.WRAP_NO_SPLIT);
}
increaseMapEntry(wrappingMap, wrappingStyle);
increaseMapEntry(indentMap, indentStyle);
increaseMapEntry(forceMap, forceWrapping);
}
private void increaseMapEntry(Map<Object, Integer> map, Object type) {
Integer count= map.get(type);
if (count == null) // not in map yet -> count == 0
map.put(type, new Integer(1));
else
map.put(type, new Integer(count.intValue() + 1));
}
private void refreshControls(Map<Object, Integer> wrappingStyleMap, Map<Object, Integer> indentStyleMap, Map<Object, Integer> forceWrappingMap) {
updateCombos(wrappingStyleMap, indentStyleMap);
updateButton(forceWrappingMap);
Integer wrappingStyleMax= getWrappingStyleMax(wrappingStyleMap);
boolean isInhomogeneous= (fElements.size() != wrappingStyleMap.get(wrappingStyleMax).intValue());
updateControlEnablement(isInhomogeneous, wrappingStyleMax.intValue());
showSpecificControls(true);
if (fRequiresRelayout) {
fOptionsComposite.layout(true, true);
}
doUpdatePreview();
notifyValuesModified();
}
private void showSpecificControls(boolean show) {
if (fElements.size() != 1)
return;
Preference[] preferences= fElements.get(0).getSpecificPreferences();
if (preferences.length == 0)
return;
fRequiresRelayout= true;
for (int i= 0; i < preferences.length; i++) {
Preference preference= preferences[i];
Control control= preference.getControl();
control.setVisible(show);
((GridData)control.getLayoutData()).exclude= !show;
}
}
private Integer getWrappingStyleMax(Map<Object, Integer> wrappingStyleMap) {
int maxCount= 0, maxStyle= 0;
for (int i=0; i<WRAPPING_NAMES.length; i++) {
Integer count= wrappingStyleMap.get(new Integer(i));
if (count == null)
continue;
if (count.intValue() > maxCount) {
maxCount= count.intValue();
maxStyle= i;
}
}
return new Integer(maxStyle);
}
private void updateButton(Map<Object, Integer> forceWrappingMap) {
Integer nrOfTrue= forceWrappingMap.get(Boolean.TRUE);
Integer nrOfFalse= forceWrappingMap.get(Boolean.FALSE);
if (nrOfTrue == null || nrOfFalse == null)
fForceSplit.setSelection(nrOfTrue != null);
else
fForceSplit.setSelection(nrOfTrue.intValue() > nrOfFalse.intValue());
int max= getMax(nrOfTrue, nrOfFalse);
String label= FormatterMessages.LineWrappingTabPage_force_split_checkbox_text;
fForceSplit.setText(getLabelText(label, max, fElements.size()));
}
private String getLabelText(String label, int count, int nElements) {
if (nElements == 1 || count == 0)
return label;
return Messages.format(FormatterMessages.LineWrappingTabPage_occurences, new String[] {label, Integer.toString(count), Integer.toString(nElements)});
}
private int getMax(Integer nrOfTrue, Integer nrOfFalse) {
if (nrOfTrue == null)
return nrOfFalse.intValue();
if (nrOfFalse == null)
return nrOfTrue.intValue();
if (nrOfTrue.compareTo(nrOfFalse) >= 0)
return nrOfTrue.intValue();
return nrOfFalse.intValue();
}
private void updateCombos(Map<Object, Integer> wrappingStyleMap, Map<Object, Integer> indentStyleMap) {
updateCombo(fWrappingStyleCombo, wrappingStyleMap, WRAPPING_NAMES);
updateCombo(fIndentStyleCombo, indentStyleMap, INDENT_NAMES);
}
private void updateCombo(Combo combo, Map<Object, Integer> map, final String[] items) {
String[] newItems= new String[items.length];
int maxCount= 0, maxStyle= 0;
for(int i = 0; i < items.length; i++) {
Integer count= map.get(new Integer(i));
int val= (count == null) ? 0 : count.intValue();
if (val > maxCount) {
maxCount= val;
maxStyle= i;
}
newItems[i]= getLabelText(items[i], val, fElements.size());
}
combo.setItems(newItems);
combo.setText(newItems[maxStyle]);
}
}
protected static final String[] INDENT_NAMES = {
FormatterMessages.LineWrappingTabPage_indentation_default,
FormatterMessages.LineWrappingTabPage_indentation_on_column,
FormatterMessages.LineWrappingTabPage_indentation_by_one
};
protected static final String[] WRAPPING_NAMES = {
FormatterMessages.LineWrappingTabPage_splitting_do_not_split,
FormatterMessages.LineWrappingTabPage_splitting_wrap_when_necessary, // COMPACT_SPLIT
FormatterMessages.LineWrappingTabPage_splitting_always_wrap_first_others_when_necessary, // COMPACT_FIRST_BREAK_SPLIT
FormatterMessages.LineWrappingTabPage_splitting_wrap_always, // ONE_PER_LINE_SPLIT
FormatterMessages.LineWrappingTabPage_splitting_wrap_always_indent_all_but_first, // NEXT_SHIFTED_SPLIT
FormatterMessages.LineWrappingTabPage_splitting_wrap_always_except_first_only_if_necessary
};
private final Category fCompactIfCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_COMPACT_IF,
"class Example {" + //$NON-NLS-1$
"int foo(int argument) {" + //$NON-NLS-1$
" if (argument==0) return 0;" + //$NON-NLS-1$
" if (argument==1) return 42; else return 43;" + //$NON-NLS-1$
"}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_compact_if_else
);
private final Category fTryCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_RESOURCES_IN_TRY,
"class Example {" + //$NON-NLS-1$
"void foo() {" + //$NON-NLS-1$
"try (FileReader reader1 = new FileReader(\"file1\"); " + //$NON-NLS-1$
" FileReader reader2 = new FileReader(\"file2\")) {" + //$NON-NLS-1$
"}" + //$NON-NLS-1$
"}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_try
);
private final Category fCatchCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_UNION_TYPE_IN_MULTICATCH,
"class Example {" + //$NON-NLS-1$
"void foo() {" + //$NON-NLS-1$
"try {" + //$NON-NLS-1$
"} catch (IllegalArgumentException | NullPointerException | ClassCastException e) {" + //$NON-NLS-1$
" e.printStackTrace();" + //$NON-NLS-1$
"}" + //$NON-NLS-1$
"}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_catch
);
private final Category fTypeDeclarationSuperclassCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SUPERCLASS_IN_TYPE_DECLARATION,
"class Example extends OtherClass {}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_extends_clause
);
private final Category fTypeDeclarationSuperinterfacesCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SUPERINTERFACES_IN_TYPE_DECLARATION,
"class Example implements I1, I2, I3 {}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_implements_clause
);
private final Category fConstructorDeclarationsParametersCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_PARAMETERS_IN_CONSTRUCTOR_DECLARATION,
"class Example {Example(int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) { this();}" + //$NON-NLS-1$
"Example() {}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_parameters
);
private final Category fMethodDeclarationsCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_METHOD_DECLARATION,
"class Example {public final synchronized java.lang.String a_method_with_a_long_name() {}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_declaration
);
private final Category fMethodDeclarationsParametersCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_PARAMETERS_IN_METHOD_DECLARATION,
"class Example {void foo(int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) {}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_parameters
);
private final Category fMessageSendArgumentsCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION,
"class Example {void foo() {Other.bar( 100,\nnested(200,\n300,\n400,\n500,\n600,\n700,\n800,\n900 ));}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_arguments
);
private final Category fMessageSendSelectorCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SELECTOR_IN_METHOD_INVOCATION,
"class Example {int foo(Some a) {return a.getFirst();}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_qualified_invocations
);
private final Category fMethodThrowsClauseCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_THROWS_CLAUSE_IN_METHOD_DECLARATION,
"class Example {" + //$NON-NLS-1$
"int foo() throws FirstException, SecondException, ThirdException {" + //$NON-NLS-1$
" return Other.doSomething();}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_throws_clause
);
private final Category fConstructorThrowsClauseCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_THROWS_CLAUSE_IN_CONSTRUCTOR_DECLARATION,
"class Example {" + //$NON-NLS-1$
"Example() throws FirstException, SecondException, ThirdException {" + //$NON-NLS-1$
" return Other.doSomething();}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_throws_clause
);
private final Category fAllocationExpressionArgumentsCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_ALLOCATION_EXPRESSION,
"class Example {SomeClass foo() {return new SomeClass(100,\n200,\n300,\n400,\n500,\n600,\n700,\n800,\n900 );}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_object_allocation
);
private final Category fQualifiedAllocationExpressionCategory= new Category (
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_QUALIFIED_ALLOCATION_EXPRESSION,
"class Example {SomeClass foo() {return SomeOtherClass.new SomeClass(100,\n200,\n300,\n400,\n500 );}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_qualified_object_allocation
);
private final Category fArrayInitializerExpressionsCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_ARRAY_INITIALIZER,
"class Example {int [] fArray= {1,\n2,\n3,\n4,\n5,\n6,\n7,\n8,\n9,\n10,\n11,\n12};}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_array_init
);
private final Category fExplicitConstructorArgumentsCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_EXPLICIT_CONSTRUCTOR_CALL,
"class Example extends AnotherClass {Example() {super(100,\n200,\n300,\n400,\n500,\n600,\n700);}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_explicit_constructor_invocations
);
private final Category fConditionalExpressionCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION,
"class Example extends AnotherClass {int Example(boolean Argument) {return argument ? 100000 : 200000;}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_conditionals
);
private final Category fBinaryExpressionCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_BINARY_EXPRESSION,
"class Example extends AnotherClass {" + //$NON-NLS-1$
"int foo() {" + //$NON-NLS-1$
" int sum= 100\n + 200\n + 300\n + 400\n + 500\n + 600\n + 700\n + 800;" + //$NON-NLS-1$
" int product= 1\n * 2\n * 3\n * 4\n * 5\n * 6\n * 7\n * 8\n * 9\n * 10;" + //$NON-NLS-1$
" boolean val= true && false && true && false && true;" + //$NON-NLS-1$
" return product / sum;}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_binary_exprs
);
private final Category fAnnotationArgumentsCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_ANNOTATION,
"@MyAnnotation(value1 = \"this is an example\", value2 = \"of an annotation\", value3 = \"with several arguments\", value4 = \"which may need to be wrapped\")\n" + //$NON-NLS-1$
"class Example {}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_annotations_arguments
);
private final Category fEnumConstArgumentsCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_ENUM_CONSTANT,
"enum Example {" + //$NON-NLS-1$
"GREEN(0, 255, 0), RED(255, 0, 0) }", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_enum_constant_arguments
);
private final Category fEnumDeclInterfacesCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SUPERINTERFACES_IN_ENUM_DECLARATION,
"enum Example implements A, B, C {" + //$NON-NLS-1$
"}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_enum_superinterfaces
);
private final Category fEnumConstantsCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ENUM_CONSTANTS,
"enum Example {" + //$NON-NLS-1$
"CANCELLED, RUNNING, WAITING, FINISHED }" + //$NON-NLS-1$
"enum Example {" + //$NON-NLS-1$
"GREEN(0, 255, 0), RED(255, 0, 0) }", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_enum_constants
);
private final Category fAssignmentCategory= new Category(
DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ASSIGNMENT,
"class Example {" + //$NON-NLS-1$
"private static final String string = \"TextTextText\";" + //$NON-NLS-1$
"void foo() {" + //$NON-NLS-1$
"for (int i = 0; i < 10; i++) {}" + //$NON-NLS-1$
"String s;" + //$NON-NLS-1$
"s = \"TextTextText\";}}", //$NON-NLS-1$
FormatterMessages.LineWrappingTabPage_assignment_alignment
);
/**
* The default preview line width.
*/
private static int DEFAULT_PREVIEW_WINDOW_LINE_WIDTH= 40;
/**
* The key to save the user's preview window width in the dialog settings.
*/
private static final String PREF_PREVIEW_LINE_WIDTH= JavaUI.ID_PLUGIN + ".codeformatter.line_wrapping_tab_page.preview_line_width"; //$NON-NLS-1$
/**
* The dialog settings.
*/
protected final IDialogSettings fDialogSettings;
protected TreeViewer fCategoriesViewer;
protected Label fWrappingStylePolicy;
protected Combo fWrappingStyleCombo;
protected Label fIndentStylePolicy;
protected Combo fIndentStyleCombo;
protected Button fForceSplit;
protected CompilationUnitPreview fPreview;
protected Group fOptionsGroup;
/**
* A collection containing the categories tree. This is used as model for the tree viewer.
* @see TreeViewer
*/
private final List<Category> fCategories;
/**
* The category listener which makes the selection persistent.
*/
protected final CategoryListener fCategoryListener;
/**
* The current selection of elements.
*/
protected IStructuredSelection fSelection;
/**
* An object containing the state for the UI.
*/
SelectionState fSelectionState;
/**
* A special options store wherein the preview line width is kept.
*/
protected final Map<String, String> fPreviewPreferences;
/**
* The key for the preview line width.
*/
private final String LINE_SPLIT= DefaultCodeFormatterConstants.FORMATTER_LINE_SPLIT;
private Composite fOptionsComposite;
/**
* Create a new line wrapping tab page.
*
* @param modifyDialog the modify dialog
* @param workingValues the values
*/
public LineWrappingTabPage(ModifyDialog modifyDialog, Map<String, String> workingValues) {
super(modifyDialog, workingValues);
fDialogSettings= JavaPlugin.getDefault().getDialogSettings();
final String previewLineWidth= fDialogSettings.get(PREF_PREVIEW_LINE_WIDTH);
fPreviewPreferences= new HashMap<String, String>();
fPreviewPreferences.put(LINE_SPLIT, previewLineWidth != null ? previewLineWidth : Integer.toString(DEFAULT_PREVIEW_WINDOW_LINE_WIDTH));
fCategories= createCategories();
fCategoryListener= new CategoryListener(fCategories);
}
/**
* @return Create the categories tree.
*/
protected List<Category> createCategories() {
final Category annotations = new Category(FormatterMessages.LineWrappingTabPage_annotations);
annotations.children.add(fAnnotationArgumentsCategory);
final Category classDeclarations= new Category(FormatterMessages.LineWrappingTabPage_class_decls);
classDeclarations.children.add(fTypeDeclarationSuperclassCategory);
classDeclarations.children.add(fTypeDeclarationSuperinterfacesCategory);
final Category constructorDeclarations= new Category(null, null, FormatterMessages.LineWrappingTabPage_constructor_decls);
constructorDeclarations.children.add(fConstructorDeclarationsParametersCategory);
constructorDeclarations.children.add(fConstructorThrowsClauseCategory);
final Category methodDeclarations= new Category(null, null, FormatterMessages.LineWrappingTabPage_method_decls);
methodDeclarations.children.add(fMethodDeclarationsCategory);
methodDeclarations.children.add(fMethodDeclarationsParametersCategory);
methodDeclarations.children.add(fMethodThrowsClauseCategory);
final Category enumDeclarations= new Category(FormatterMessages.LineWrappingTabPage_enum_decls);
enumDeclarations.children.add(fEnumConstantsCategory);
enumDeclarations.children.add(fEnumDeclInterfacesCategory);
enumDeclarations.children.add(fEnumConstArgumentsCategory);
final Category functionCalls= new Category(FormatterMessages.LineWrappingTabPage_function_calls);
functionCalls.children.add(fMessageSendArgumentsCategory);
functionCalls.children.add(fMessageSendSelectorCategory);
functionCalls.children.add(fExplicitConstructorArgumentsCategory);
functionCalls.children.add(fAllocationExpressionArgumentsCategory);
functionCalls.children.add(fQualifiedAllocationExpressionCategory);
final Category expressions= new Category(FormatterMessages.LineWrappingTabPage_expressions);
expressions.children.add(fBinaryExpressionCategory);
expressions.children.add(fConditionalExpressionCategory);
expressions.children.add(fArrayInitializerExpressionsCategory);
expressions.children.add(fAssignmentCategory);
final Category statements= new Category(FormatterMessages.LineWrappingTabPage_statements);
statements.children.add(fCompactIfCategory);
statements.children.add(fTryCategory);
statements.children.add(fCatchCategory);
final List<Category> root= new ArrayList<Category>();
root.add(annotations);
root.add(classDeclarations);
root.add(constructorDeclarations);
root.add(methodDeclarations);
root.add(enumDeclarations);
root.add(functionCalls);
root.add(expressions);
root.add(statements);
return root;
}
@Override
protected void doCreatePreferences(Composite composite, int numColumns) {
fOptionsComposite= composite;
final Group lineWidthGroup= createGroup(numColumns, composite, FormatterMessages.LineWrappingTabPage_general_settings);
createNumberPref(lineWidthGroup, numColumns, FormatterMessages.LineWrappingTabPage_width_indent_option_max_line_width, DefaultCodeFormatterConstants.FORMATTER_LINE_SPLIT, 0, 9999);
createNumberPref(lineWidthGroup, numColumns, FormatterMessages.LineWrappingTabPage_width_indent_option_default_indent_wrapped, DefaultCodeFormatterConstants.FORMATTER_CONTINUATION_INDENTATION, 0, 9999);
createNumberPref(lineWidthGroup, numColumns, FormatterMessages.LineWrappingTabPage_width_indent_option_default_indent_array, DefaultCodeFormatterConstants.FORMATTER_CONTINUATION_INDENTATION_FOR_ARRAY_INITIALIZER, 0, 9999);
createCheckboxPref(lineWidthGroup, numColumns, FormatterMessages.LineWrappingTabPage_do_not_join_lines, DefaultCodeFormatterConstants.FORMATTER_JOIN_WRAPPED_LINES, TRUE_FALSE);
createCheckboxPref(lineWidthGroup, numColumns, FormatterMessages.LineWrappingTabPage_wrap_outer_expressions_when_nested, DefaultCodeFormatterConstants.FORMATTER_WRAP_OUTER_EXPRESSIONS_WHEN_NESTED, FALSE_TRUE);
fCategoriesViewer= new TreeViewer(composite /*categoryGroup*/, SWT.MULTI | SWT.BORDER | SWT.READ_ONLY | SWT.V_SCROLL );
fCategoriesViewer.setContentProvider(new ITreeContentProvider() {
public Object[] getElements(Object inputElement) {
return ((Collection<?>)inputElement).toArray();
}
public Object[] getChildren(Object parentElement) {
return ((Category)parentElement).children.toArray();
}
public Object getParent(Object element) { return null; }
public boolean hasChildren(Object element) {
return !((Category)element).children.isEmpty();
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
public void dispose() {}
});
fCategoriesViewer.setLabelProvider(new LabelProvider());
fCategoriesViewer.setInput(fCategories);
fCategoriesViewer.setExpandedElements(fCategories.toArray());
final GridData gd= createGridData(numColumns, GridData.FILL_BOTH, SWT.DEFAULT);
gd.heightHint= fPixelConverter.convertHeightInCharsToPixels(5);
fCategoriesViewer.getControl().setLayoutData(gd);
fOptionsGroup = createGroup(numColumns, composite, ""); //$NON-NLS-1$
// label "Select split style:"
fWrappingStylePolicy= createLabel(numColumns, fOptionsGroup, FormatterMessages.LineWrappingTabPage_wrapping_policy_label_text);
// combo SplitStyleCombo
fWrappingStyleCombo= new Combo(fOptionsGroup, SWT.SINGLE | SWT.READ_ONLY);
SWTUtil.setDefaultVisibleItemCount(fWrappingStyleCombo);
fWrappingStyleCombo.setItems(WRAPPING_NAMES);
fWrappingStyleCombo.setLayoutData(createGridData(numColumns, GridData.HORIZONTAL_ALIGN_FILL, 0));
// button "Force split"
fForceSplit= new Button(fOptionsGroup, SWT.CHECK);
String label= FormatterMessages.LineWrappingTabPage_force_split_checkbox_text;
fForceSplit.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, numColumns - 1, 1));
fForceSplit.setText(label);
// button "Wrap before operator"
Preference expressionWrapPositionPreference= createCheckboxPref(fOptionsGroup, 1, FormatterMessages.LineWrappingTabPage_binary_expression_wrap_operator, DefaultCodeFormatterConstants.FORMATTER_WRAP_BEFORE_BINARY_OPERATOR, FALSE_TRUE);
Control control= expressionWrapPositionPreference.getControl();
control.setVisible(false);
GridData layoutData= (GridData)control.getLayoutData();
layoutData.exclude= true;
layoutData.horizontalAlignment= SWT.BEGINNING;
layoutData.horizontalSpan= numColumns - 1;
layoutData.grabExcessHorizontalSpace= false;
fBinaryExpressionCategory.addPreference(expressionWrapPositionPreference);
// button "Wrap before '|' operator" in multi-catch
Preference expressionWrapMulticatchPositionPreference= createCheckboxPref(fOptionsGroup, 1, FormatterMessages.LineWrappingTabPage_multicatch_wrap_operator, DefaultCodeFormatterConstants.FORMATTER_WRAP_BEFORE_OR_OPERATOR_MULTICATCH, FALSE_TRUE);
control= expressionWrapMulticatchPositionPreference.getControl();
control.setVisible(false);
layoutData= (GridData)control.getLayoutData();
layoutData.exclude= true;
layoutData.horizontalAlignment= SWT.BEGINNING;
layoutData.horizontalSpan= numColumns - 1;
layoutData.grabExcessHorizontalSpace= false;
fCatchCategory.addPreference(expressionWrapMulticatchPositionPreference);
// label "Select indentation style:"
fIndentStylePolicy= createLabel(numColumns, fOptionsGroup, FormatterMessages.LineWrappingTabPage_indentation_policy_label_text);
// combo IndentStyleCombo
fIndentStyleCombo= new Combo(fOptionsGroup, SWT.SINGLE | SWT.READ_ONLY);
SWTUtil.setDefaultVisibleItemCount(fIndentStyleCombo);
fIndentStyleCombo.setItems(INDENT_NAMES);
fIndentStyleCombo.setLayoutData(createGridData(numColumns, GridData.HORIZONTAL_ALIGN_FILL, 0));
// selection state object
fSelectionState= new SelectionState();
}
@Override
protected Composite doCreatePreviewPane(Composite composite, int numColumns) {
super.doCreatePreviewPane(composite, numColumns);
Composite previewLineWidthContainer= new Composite(composite, SWT.NONE);
previewLineWidthContainer.setLayout(createGridLayout(2, false));
final NumberPreference previewLineWidth= new NumberPreference(previewLineWidthContainer, 2, fPreviewPreferences, LINE_SPLIT,
0, 9999, FormatterMessages.LineWrappingTabPage_line_width_for_preview_label_text);
fDefaultFocusManager.add(previewLineWidth);
previewLineWidth.addObserver(fUpdater);
previewLineWidth.addObserver(new Observer() {
public void update(Observable o, Object arg) {
fDialogSettings.put(PREF_PREVIEW_LINE_WIDTH, fPreviewPreferences.get(LINE_SPLIT));
}
});
return composite;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.internal.ui.preferences.formatter.ModifyDialogTabPage#doCreateJavaPreview(org.eclipse.swt.widgets.Composite)
*/
@Override
protected JavaPreview doCreateJavaPreview(Composite parent) {
fPreview= new CompilationUnitPreview(fWorkingValues, parent);
return fPreview;
}
@Override
protected void initializePage() {
fCategoriesViewer.addSelectionChangedListener(fCategoryListener);
fCategoriesViewer.addDoubleClickListener(fCategoryListener);
fForceSplit.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
forceSplitChanged(fForceSplit.getSelection());
}
});
fIndentStyleCombo.addSelectionListener( new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
indentStyleChanged(((Combo)e.widget).getSelectionIndex());
}
});
fWrappingStyleCombo.addSelectionListener( new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
wrappingStyleChanged(((Combo)e.widget).getSelectionIndex());
}
});
fCategoryListener.restoreSelection();
fDefaultFocusManager.add(fCategoriesViewer.getControl());
fDefaultFocusManager.add(fWrappingStyleCombo);
fDefaultFocusManager.add(fIndentStyleCombo);
fDefaultFocusManager.add(fForceSplit);
}
@Override
protected void doUpdatePreview() {
super.doUpdatePreview();
final String normalSetting= fWorkingValues.get(LINE_SPLIT);
fWorkingValues.put(LINE_SPLIT, fPreviewPreferences.get(LINE_SPLIT));
fPreview.update();
fWorkingValues.put(LINE_SPLIT, normalSetting);
}
protected void setPreviewText(String text) {
final String normalSetting= fWorkingValues.get(LINE_SPLIT);
fWorkingValues.put(LINE_SPLIT, fPreviewPreferences.get(LINE_SPLIT));
fPreview.setPreviewText(text);
fWorkingValues.put(LINE_SPLIT, normalSetting);
}
protected void forceSplitChanged(boolean forceSplit) {
Iterator<Category> iterator= fSelectionState.fElements.iterator();
String currentKey;
while (iterator.hasNext()) {
currentKey= iterator.next().key;
try {
changeForceSplit(currentKey, forceSplit);
} catch (IllegalArgumentException e) {
fWorkingValues.put(currentKey, DefaultCodeFormatterConstants.createAlignmentValue(forceSplit, DefaultCodeFormatterConstants.WRAP_NO_SPLIT, DefaultCodeFormatterConstants.INDENT_DEFAULT));
JavaPlugin.log(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.OK,
Messages.format(FormatterMessages.LineWrappingTabPage_error_invalid_value, currentKey), e));
}
}
fSelectionState.refreshState(fSelection);
}
private void changeForceSplit(String currentKey, boolean forceSplit) throws IllegalArgumentException{
String value= fWorkingValues.get(currentKey);
value= DefaultCodeFormatterConstants.setForceWrapping(value, forceSplit);
if (value == null)
throw new IllegalArgumentException();
fWorkingValues.put(currentKey, value);
}
protected void wrappingStyleChanged(int wrappingStyle) {
Iterator<Category> iterator= fSelectionState.fElements.iterator();
String currentKey;
while (iterator.hasNext()) {
currentKey= iterator.next().key;
try {
changeWrappingStyle(currentKey, wrappingStyle);
} catch (IllegalArgumentException e) {
fWorkingValues.put(currentKey, DefaultCodeFormatterConstants.createAlignmentValue(false, wrappingStyle, DefaultCodeFormatterConstants.INDENT_DEFAULT));
JavaPlugin.log(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.OK,
Messages.format(FormatterMessages.LineWrappingTabPage_error_invalid_value, currentKey), e));
}
}
fSelectionState.refreshState(fSelection);
}
private void changeWrappingStyle(String currentKey, int wrappingStyle) throws IllegalArgumentException {
String value= fWorkingValues.get(currentKey);
value= DefaultCodeFormatterConstants.setWrappingStyle(value, wrappingStyle);
if (value == null)
throw new IllegalArgumentException();
fWorkingValues.put(currentKey, value);
}
protected void indentStyleChanged(int indentStyle) {
Iterator<Category> iterator= fSelectionState.fElements.iterator();
String currentKey;
while (iterator.hasNext()) {
currentKey= iterator.next().key;
try {
changeIndentStyle(currentKey, indentStyle);
} catch (IllegalArgumentException e) {
fWorkingValues.put(currentKey, DefaultCodeFormatterConstants.createAlignmentValue(false, DefaultCodeFormatterConstants.WRAP_NO_SPLIT, indentStyle));
JavaPlugin.log(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.OK,
Messages.format(FormatterMessages.LineWrappingTabPage_error_invalid_value, currentKey), e));
}
}
fSelectionState.refreshState(fSelection);
}
private void changeIndentStyle(String currentKey, int indentStyle) throws IllegalArgumentException{
String value= fWorkingValues.get(currentKey);
value= DefaultCodeFormatterConstants.setIndentStyle(value, indentStyle);
if (value == null)
throw new IllegalArgumentException();
fWorkingValues.put(currentKey, value);
}
protected void updateControlEnablement(boolean inhomogenous, int wrappingStyle) {
boolean doSplit= wrappingStyle != DefaultCodeFormatterConstants.WRAP_NO_SPLIT;
fIndentStylePolicy.setEnabled(true);
boolean isEnabled= inhomogenous || doSplit;
fIndentStyleCombo.setEnabled(isEnabled);
fForceSplit.setEnabled(isEnabled);
fBinaryExpressionCategory.setEnabled(isEnabled);
fCatchCategory.setEnabled(isEnabled);
}
}