/******************************************************************************* * 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); } }