diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java index 366b37ff9ed..00778a40f40 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 QNX Software Systems and others. + * Copyright (c) 2000, 2014 QNX Software Systems 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 @@ -9,6 +9,7 @@ * QNX Software Systems - Initial API and implementation * Sergey Prigogin (Google) * Anton Leherbauer (Wind River Systems) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.core.formatter; @@ -55,6 +56,18 @@ public class DefaultCodeFormatterConstants { */ public static final String FORMATTER_TRANSLATION_UNIT = CCorePlugin.PLUGIN_ID + ".formatter.current_translation_unit"; //$NON-NLS-1$ + /** + *
+ * FORMATTER / Option that tells the formatter that the formatting region should be + * extended to the enclosing statement boundaries. + * - option id: "org.eclipse.cdt.core.formatter.statement_scope" + * - possible values: object of class {@link Boolean} or {@code null} + * - default: null + *+ * @since 5.9 + */ + public static final String FORMATTER_STATEMENT_SCOPE = CCorePlugin.PLUGIN_ID + ".formatter.statement_scope"; //$NON-NLS-1$ + /** *
* FORMATTER / Value to set a brace location at the end of a line. diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CCodeFormatter.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CCodeFormatter.java index e5308f20819..5467e1568ef 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CCodeFormatter.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CCodeFormatter.java @@ -17,6 +17,13 @@ import java.util.HashMap; import java.util.Map; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTFileLocation; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTNodeSelector; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement; +import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.gnu.cpp.GPPLanguage; import org.eclipse.cdt.core.formatter.CodeFormatter; @@ -33,6 +40,8 @@ import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.cdt.core.parser.IncludeFileContentProvider; import org.eclipse.cdt.core.parser.ParserUtil; import org.eclipse.cdt.core.parser.ScannerInfo; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; +import org.eclipse.cdt.internal.core.util.TextUtil; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; @@ -185,6 +194,11 @@ public class CCodeFormatter extends CodeFormatter { IASTTranslationUnit ast) { for (int i = 0; i < regions.length; i++) { IRegion region = regions[i]; + if (region.getLength() == 0) { + // An empty region is replaced by the region containing the line corresponding to + // the offset and all statements overlapping with that line. + region = getLineOrStatementRegion(source, region.getOffset(), ast); + } CodeFormatterVisitor codeFormatter = new CodeFormatterVisitor(preferences, region.getOffset(), region.getLength()); edits[i] = codeFormatter.format(source, ast); @@ -195,6 +209,74 @@ public class CCodeFormatter extends CodeFormatter { } } + /** + * Returns the smallest region containing the line corresponding to the given offset and all + * statements overlapping with that line. + */ + private IRegion getLineOrStatementRegion(String source, int offset, IASTTranslationUnit ast) { + int start = TextUtil.getLineStart(source, offset); + int end = TextUtil.skipToNextLine(source, offset); + IASTNode node = findOverlappingPreprocessorStatement(start, end, ast); + if (node != null) { + IASTFileLocation location = node.getFileLocation(); + int nodeOffset = location.getNodeOffset(); + if (nodeOffset < start) + start = nodeOffset; + int nodeEnd = nodeOffset + location.getNodeLength(); + if (nodeEnd > end) + end = nodeEnd; + return new Region(start, end - start); + } + IASTNodeSelector nodeSelector = ast.getNodeSelector(null); + for (int pos = start; pos < end;) { + node = nodeSelector.findFirstContainedNode(pos, end - pos); + if (node != null) { + IASTNode containedNode = node; + node = CPPVisitor.findAncestorWithType(containedNode, IASTStatement.class); + if (node == null) + node = CPPVisitor.findAncestorWithType(containedNode, IASTDeclaration.class); + if (node == null) + node = CPPVisitor.findAncestorWithType(containedNode, IASTPreprocessorMacroExpansion.class); + } + if (node == null) + break; + IASTFileLocation location = node.getFileLocation(); + int nodeOffset = location.getNodeOffset(); + if (nodeOffset < start) + start = nodeOffset; + int nodeEnd = nodeOffset + location.getNodeLength(); + if (nodeEnd > end) + end = nodeEnd; + pos = nodeEnd; + } + + return new Region(start, end - start); + } + + private IASTNode findOverlappingPreprocessorStatement(int start, int end, IASTTranslationUnit ast) { + IASTPreprocessorStatement[] statements = ast.getAllPreprocessorStatements(); + int low = 0; + int high = statements.length; + while (low < high) { + int mid = (low + high) >>> 1; + IASTPreprocessorStatement statement = statements[mid]; + IASTFileLocation location = statement.getFileLocation(); + if (location == null) { + low = mid + 1; + } else { + int statementOffset = location.getNodeOffset(); + if (statementOffset >= end) { + high = mid; + } else if (statementOffset + location.getNodeLength() <= start) { + low = mid + 1; + } else { + return statement; + } + } + } + return null; + } + private ITranslationUnit getTranslationUnit(String source) { ITranslationUnit tu= (ITranslationUnit) options.get(DefaultCodeFormatterConstants.FORMATTER_TRANSLATION_UNIT); if (tu == null) { diff --git a/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF index 7d674f94d52..4690cd405b2 100644 --- a/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF +++ b/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.ui; singleton:=true -Bundle-Version: 5.8.1.qualifier +Bundle-Version: 5.9.0.qualifier Bundle-Activator: org.eclipse.cdt.ui.CUIPlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/core/org.eclipse.cdt.ui/plugin.properties b/core/org.eclipse.cdt.ui/plugin.properties index adcf5ba3a28..22cf46daf96 100755 --- a/core/org.eclipse.cdt.ui/plugin.properties +++ b/core/org.eclipse.cdt.ui/plugin.properties @@ -589,7 +589,7 @@ preferenceKeywords.organizeincludes=include includes organize preferenceKeywords.todo=case sensitive task tag todo xxx fix fixme project comments preferenceKeywords.indexer=index skip references type macro search build configuration cache memory performance -preferenceKeywords.ceditor=editor appearance navigation colors smart caret positioning highlight matching bracket inactive code foreground background save trailing whitespace newline doxygen +preferenceKeywords.ceditor=editor appearance navigation colors smart caret positioning highlight matching bracket inactive code foreground background save trailing whitespace newline doxygen format formatting statement preferenceKeywords.contentassist=editor content code assist complete completion insert overwrite single proposal common prefix automatically auto activation trigger category categories separate specific word hippie template preferenceKeywords.saveactions=editor save trailing whitespace white space end file newline preferenceKeywords.scalability=editor mode large file lines disable performance diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml index 5cfce5c2437..874483ca5e0 100644 --- a/core/org.eclipse.cdt.ui/plugin.xml +++ b/core/org.eclipse.cdt.ui/plugin.xml @@ -4878,6 +4878,8 @@+ + diff --git a/core/org.eclipse.cdt.ui/pom.xml b/core/org.eclipse.cdt.ui/pom.xml index a62a27b8f53..bd872aad568 100644 --- a/core/org.eclipse.cdt.ui/pom.xml +++ b/core/org.eclipse.cdt.ui/pom.xml @@ -11,7 +11,7 @@ ../../pom.xml -5.8.1-SNAPSHOT +5.9.0-SNAPSHOT org.eclipse.cdt.ui eclipse-plugin diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/FormattingScopeDialog.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/FormattingScopeDialog.java new file mode 100644 index 00000000000..e00ef306471 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/FormattingScopeDialog.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2014 Google, Inc 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: + * Sergey Prigogin (Google) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.dialogs; + +import org.eclipse.jface.dialogs.StatusDialog; +import org.eclipse.jface.layout.PixelConverter; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; + +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.PreferenceConstants; + +/** + * Asks user how formatting of an empty selection should be interpreted. + */ +public class FormattingScopeDialog extends StatusDialog { + private Button fDoNotAskAgainCheckBox; + private Button fScopeFileRadio; + private Button fScopeStatementRadio; + private IPreferenceStore preferenceStore; + + public FormattingScopeDialog(Shell shell) { + super(shell); + setTitle(Messages.FormattingScopeDialog_title); + setHelpAvailable(false); + preferenceStore = CUIPlugin.getDefault().getPreferenceStore(); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + + PixelConverter converter = new PixelConverter(composite); + + createLabel(composite, Messages.FormattingScopeDialog_message); + int indent = converter.convertHorizontalDLUsToPixels(8); + fScopeFileRadio = + createRadioButton(composite, Messages.FormattingScopeDialog_format_file, indent); + fScopeStatementRadio = + createRadioButton(composite, Messages.FormattingScopeDialog_format_statement, indent); + createLabel(composite, ""); // Separator //$NON-NLS-1$ + fDoNotAskAgainCheckBox = + createCheckBox(composite, Messages.FormattingScopeDialog_do_not_ask_again); + + String scope = preferenceStore.getString(PreferenceConstants.FORMATTING_SCOPE_FOR_EMPTY_SELECTION); + if (PreferenceConstants.FORMATTING_SCOPE_DOCUMENT.equals(scope)) { + fScopeFileRadio.setSelection(true); + } else { + fScopeStatementRadio.setSelection(true); + } + applyDialogFont(composite); + return composite; + } + + @Override + protected void okPressed() { + String scope = fScopeFileRadio.getSelection() ? + PreferenceConstants.FORMATTING_SCOPE_DOCUMENT : PreferenceConstants.FORMATTING_SCOPE_STATEMENT; + preferenceStore.setValue(PreferenceConstants.FORMATTING_SCOPE_FOR_EMPTY_SELECTION, scope); + if (fDoNotAskAgainCheckBox.getSelection()) { + preferenceStore.setValue(PreferenceConstants.FORMATTING_CONFIRM_SCOPE_FOR_EMPTY_SELECTION, false); + } + super.okPressed(); + } + + private Button createRadioButton(Composite container, String text, int indent) { + return createButton(SWT.RADIO, container, text, indent); + } + + private Button createCheckBox(Composite container, String text) { + return createButton(SWT.CHECK, container, text, 0); + } + + private Button createButton(int style, Composite container, String text, int indent) { + Button button = new Button(container, style); + GridData layoutData = new GridData(); + layoutData.horizontalIndent = indent; + button.setLayoutData(layoutData); + button.setText(text); + return button; + } + + private Label createLabel(Composite container, String text) { + Label label = new Label(container, SWT.NONE); + label.setLayoutData(new GridData()); + label.setText(text); + return label; + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/Messages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/Messages.java new file mode 100644 index 00000000000..b71c0a3d71f --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/Messages.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2014 Google, Inc 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: + * Sergey Prigogin (Google) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.dialogs; + +import org.eclipse.osgi.util.NLS; + +class Messages extends NLS { + public static String FormattingScopeDialog_do_not_ask_again; + public static String FormattingScopeDialog_format_file; + public static String FormattingScopeDialog_format_statement; + public static String FormattingScopeDialog_message; + public static String FormattingScopeDialog_title; + + static { + // Initialize resource bundle. + NLS.initializeMessages(Messages.class.getName(), Messages.class); + } + + private Messages() { + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/Messages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/Messages.properties new file mode 100644 index 00000000000..6f9268f6d7a --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/Messages.properties @@ -0,0 +1,15 @@ +############################################################################### +# Copyright (c) 2014 Google, Inc 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: +# Sergey Prigogin (Google) - initial API and implementation +############################################################################### +FormattingScopeDialog_title=Select Formatting Scope +FormattingScopeDialog_format_file=The entire &file +FormattingScopeDialog_format_statement=The &statement on the current line +FormattingScopeDialog_message=No code is selected. Choose the scope of formatting. +FormattingScopeDialog_do_not_ask_again=&Remember this choice and do not ask again \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java index ad8de793cc3..645e8bc1692 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java @@ -37,9 +37,11 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.preferences.IPreferencesService; import org.eclipse.help.IContext; import org.eclipse.help.IContextProvider; import org.eclipse.jface.action.GroupMarker; @@ -48,6 +50,7 @@ import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; +import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.MessageDialogWithToggle; @@ -112,6 +115,7 @@ import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.window.Window; import org.eclipse.search.ui.actions.TextSearchGroup; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; @@ -213,6 +217,7 @@ import org.eclipse.cdt.internal.ui.actions.StructureSelectNextAction; import org.eclipse.cdt.internal.ui.actions.StructureSelectPreviousAction; import org.eclipse.cdt.internal.ui.actions.StructureSelectionAction; import org.eclipse.cdt.internal.ui.actions.SurroundWithActionGroup; +import org.eclipse.cdt.internal.ui.dialogs.FormattingScopeDialog; import org.eclipse.cdt.internal.ui.search.IOccurrencesFinder; import org.eclipse.cdt.internal.ui.search.IOccurrencesFinder.OccurrenceLocation; import org.eclipse.cdt.internal.ui.search.OccurrencesFinder; @@ -358,8 +363,23 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi return super.requestWidgetToken(requester, priority); } + // This method is called only when the Platform version is below 4.5. + // TODO(sprigogin): Remove this override once compatibility with Platform 4.4 is no longer + // required. @Override - public IFormattingContext createFormattingContext() { + protected IFormattingContext createFormattingContext() { + Point selectedRange = getSelectedRange(); + return createFormattingContext(selectedRange.x, selectedRange.y, false); + } + + // This method is called when the Platform version is 4.5 or higher. + // @Override + protected IFormattingContext createFormattingContext(int selectionOffset, int selectionLength) { + return createFormattingContext(selectionOffset, selectionLength, true); + } + + private IFormattingContext createFormattingContext(int selectionOffset, int selectionLength, + boolean formattingScopeForEmptySelectionSupported) { IFormattingContext context= new FormattingContext(); Mappreferences; @@ -383,6 +403,30 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi preferences.put(DefaultCodeFormatterConstants.FORMATTER_TRANSLATION_UNIT, tu); preferences.put(DefaultCodeFormatterConstants.FORMATTER_LANGUAGE, language); preferences.put(DefaultCodeFormatterConstants.FORMATTER_CURRENT_FILE, tu.getResource()); + boolean formatWholeDocument = false; + if (formattingScopeForEmptySelectionSupported && selectionLength == 0) { + // The selection is empty. Determine how it should be interpreted. + IPreferencesService preferenceService = Platform.getPreferencesService(); + boolean showDialog = preferenceService.getBoolean(CUIPlugin.PLUGIN_ID, + PreferenceConstants.FORMATTING_CONFIRM_SCOPE_FOR_EMPTY_SELECTION, true, null); + if (showDialog) { + if (!confirmFormattingScope()) { + // The user clicked Cancel. Abort the formatting operation. + context.dispose(); + return null; + } + } + String scope = preferenceService.getString(CUIPlugin.PLUGIN_ID, + PreferenceConstants.FORMATTING_SCOPE_FOR_EMPTY_SELECTION, + PreferenceConstants.FORMATTING_SCOPE_DOCUMENT, null); + if (PreferenceConstants.FORMATTING_SCOPE_DOCUMENT.equals(scope)) { + formatWholeDocument = true; + } + } + if (!formatWholeDocument) { + context.setProperty(FormattingContextProperties.CONTEXT_REGION, + new Region(selectionOffset, selectionLength)); + } } if (cProject == null) { @@ -396,6 +440,22 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi return context; } + + private boolean confirmFormattingScope() { + int redrawCount = 0; + while (!redraws()) { + redrawCount++; + setRedraw(true); + } + try { + Dialog dialog = new FormattingScopeDialog(getSite().getShell()); + return dialog.open() == Window.OK; + } finally { + while (--redrawCount >= 0) { + setRedraw(false); + } + } + } } private class ExitPolicy implements IExitPolicy { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CEditorPreferencePage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CEditorPreferencePage.java index 6ed0dd248b2..932941a4aed 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CEditorPreferencePage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CEditorPreferencePage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2011 IBM Corporation and others. + * Copyright (c) 2005, 2014 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 @@ -10,11 +10,18 @@ * QNX Software System * Anton Leherbauer (Wind River Systems) * Andrew Ferguson (Symbian) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.ui.preferences; +import static org.eclipse.cdt.ui.PreferenceConstants.FORMATTING_CONFIRM_SCOPE_FOR_EMPTY_SELECTION; +import static org.eclipse.cdt.ui.PreferenceConstants.FORMATTING_SCOPE_DOCUMENT; +import static org.eclipse.cdt.ui.PreferenceConstants.FORMATTING_SCOPE_FOR_EMPTY_SELECTION; +import static org.eclipse.cdt.ui.PreferenceConstants.FORMATTING_SCOPE_STATEMENT; + import java.util.ArrayList; +import org.eclipse.core.runtime.Platform; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.preference.ColorSelector; import org.eclipse.jface.preference.IPreferenceStore; @@ -37,6 +44,8 @@ import org.eclipse.swt.widgets.List; import org.eclipse.swt.widgets.Listener; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.PreferencesUtil; +import org.osgi.framework.Bundle; +import org.osgi.framework.Version; import org.eclipse.cdt.ui.PreferenceConstants; import org.eclipse.cdt.ui.dialogs.DocCommentOwnerComposite; @@ -50,11 +59,10 @@ import org.eclipse.cdt.internal.ui.text.c.hover.SourceViewerInformationControl; import org.eclipse.cdt.internal.ui.text.contentassist.ContentAssistPreference; import org.eclipse.cdt.internal.ui.text.doctools.DocCommentOwnerManager; -/* - * The page for setting the editor options. +/** + * The preference page for setting the editor options. */ public class CEditorPreferencePage extends AbstractPreferencePage { - protected final String[][] fAppearanceColorListModel = new String[][] { {PreferencesMessages.CEditorPreferencePage_behaviorPage_matchingBracketColor, CEditor.MATCHING_BRACKETS_COLOR, null }, {PreferencesMessages.CEditorPreferencePage_behaviorPage_inactiveCodeColor, CEditor.INACTIVE_CODE_COLOR, null }, @@ -69,14 +77,19 @@ public class CEditorPreferencePage extends AbstractPreferencePage { private ColorSelector fAppearanceColorEditor; private Button fAppearanceColorDefault; private DocCommentOwnerComposite fDocCommentOwnerComposite; + // TODO(sprigogin): Remove once compatibility with Platform 4.4 is no longer required. + private final boolean formattingScopeForEmptySelectionSupported; public CEditorPreferencePage() { super(); + Bundle jfaceText = Platform.getBundle("org.eclipse.jface.text"); //$NON-NLS-1$ + formattingScopeForEmptySelectionSupported = + jfaceText.getVersion().compareTo(new Version(3, 10, 0)) >= 0; } @Override protected OverlayPreferenceStore.OverlayKey[] createOverlayStoreKeys() { - ArrayList overlayKeys = new ArrayList (); + ArrayList overlayKeys = new ArrayList<>(); overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, CEditor.SUB_WORD_NAVIGATION)); overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_EVALUATE_TEMPORARY_PROBLEMS)); @@ -90,6 +103,10 @@ public class CEditorPreferencePage extends AbstractPreferencePage { overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, ContentAssistPreference.PARAMETERS_FOREGROUND)); overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, PreferenceConstants.EDITOR_SOURCE_HOVER_BACKGROUND_COLOR)); overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_SOURCE_HOVER_BACKGROUND_COLOR_SYSTEM_DEFAULT)); + if (formattingScopeForEmptySelectionSupported) { + overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, FORMATTING_SCOPE_FOR_EMPTY_SELECTION)); + overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, FORMATTING_CONFIRM_SCOPE_FOR_EMPTY_SELECTION)); + } OverlayPreferenceStore.OverlayKey[] keys = new OverlayPreferenceStore.OverlayKey[overlayKeys.size()]; overlayKeys.toArray(keys); @@ -100,22 +117,21 @@ public class CEditorPreferencePage extends AbstractPreferencePage { store.setDefault(CEditor.SUB_WORD_NAVIGATION, true); store.setDefault(CEditor.MATCHING_BRACKETS, true); - PreferenceConverter.setDefault(store, CEditor.MATCHING_BRACKETS_COLOR, new RGB(170,170,170)); + PreferenceConverter.setDefault(store, CEditor.MATCHING_BRACKETS_COLOR, new RGB(170, 170, 170)); store.setDefault(CEditor.INACTIVE_CODE_ENABLE, true); PreferenceConverter.setDefault(store, CEditor.INACTIVE_CODE_COLOR, new RGB(224, 224, 224)); } - /* - * @see PreferencePage#createControl(Composite) - */ @Override public void createControl(Composite parent) { super.createControl(parent); PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), ICHelpContextIds.C_EDITOR_PREF_PAGE); } - // sets enabled flag for a control and all its sub-tree + /** + * Sets enabled flag for a control and all its sub-tree. + */ protected static void setEnabled(Control control, boolean enable) { control.setEnabled(enable); if (control instanceof Composite) { @@ -133,6 +149,8 @@ public class CEditorPreferencePage extends AbstractPreferencePage { layout.numColumns = 2; behaviorComposite.setLayout(layout); + int indent = convertHorizontalDLUsToPixels(8); + String label= PreferencesMessages.CEditorPreferencePage_behaviorPage_subWordNavigation; addCheckBox(behaviorComposite, label, CEditor.SUB_WORD_NAVIGATION, 0); @@ -145,6 +163,23 @@ public class CEditorPreferencePage extends AbstractPreferencePage { label = PreferencesMessages.CEditorPreferencePage_behaviorPage_inactiveCode; addCheckBox(behaviorComposite, label, CEditor.INACTIVE_CODE_ENABLE, 0); + if (formattingScopeForEmptySelectionSupported) { + Label l = new Label(behaviorComposite, SWT.LEFT); + l.setText(PreferencesMessages.CEditorPreferencePage_behaviorPage_formattingWithEmptySelection); + GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL); + gd.horizontalSpan = 2; + l.setLayoutData(gd); + + label = PreferencesMessages.CEditorPreferencePage_behaviorPage_formatFile; + addRadioButton(behaviorComposite, label, FORMATTING_SCOPE_FOR_EMPTY_SELECTION, FORMATTING_SCOPE_DOCUMENT, indent); + + label = PreferencesMessages.CEditorPreferencePage_behaviorPage_formatStatement; + addRadioButton(behaviorComposite, label, FORMATTING_SCOPE_FOR_EMPTY_SELECTION, FORMATTING_SCOPE_STATEMENT, indent); + + label = PreferencesMessages.CEditorPreferencePage_behaviorPage_confirmFormattingScope; + addCheckBox(behaviorComposite, label, FORMATTING_CONFIRM_SCOPE_FOR_EMPTY_SELECTION, indent); + } + Label l = new Label(behaviorComposite, SWT.LEFT); GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL); gd.horizontalSpan = 2; @@ -257,7 +292,7 @@ public class CEditorPreferencePage extends AbstractPreferencePage { String text = PreferencesMessages.CEditorPreferencePage_link; Link link = new Link(parent, SWT.NONE); link.setText(text); - link.addListener (SWT.Selection, new Listener () { + link.addListener (SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { String u = event.text; @@ -274,9 +309,6 @@ public class CEditorPreferencePage extends AbstractPreferencePage { return link; } - /* - * @see PreferencePage#createContents(Composite) - */ @Override protected Control createContents(Composite parent) { fOverlayStore.load(); @@ -319,9 +351,6 @@ public class CEditorPreferencePage extends AbstractPreferencePage { }); } - /* - * @see org.eclipse.cdt.internal.ui.preferences.AbstractPreferencePage#performOk() - */ @Override public boolean performOk() { DocCommentOwnerManager.getInstance().setWorkspaceCommentOwner(fDocCommentOwnerComposite.getSelectedDocCommentOwner()); @@ -341,9 +370,6 @@ public class CEditorPreferencePage extends AbstractPreferencePage { } } - /* - * @see org.eclipse.cdt.internal.ui.preferences.AbstractPreferencePage#performDefaults() - */ @Override protected void performDefaults() { super.performDefaults(); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.java index 074be583b9b..8b812b517b6 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.java @@ -100,6 +100,10 @@ public final class PreferencesMessages extends NLS { public static String CEditorPreferencePage_behaviorPage_matchingBrackets; public static String CEditorPreferencePage_behaviorPage_subWordNavigation; public static String CEditorPreferencePage_behaviorPage_inactiveCode; + public static String CEditorPreferencePage_behaviorPage_formattingWithEmptySelection; + public static String CEditorPreferencePage_behaviorPage_formatFile; + public static String CEditorPreferencePage_behaviorPage_formatStatement; + public static String CEditorPreferencePage_behaviorPage_confirmFormattingScope; public static String CEditorPreferencePage_behaviorPage_appearanceColorOptions; public static String CEditorPreferencePage_behaviorPage_matchingBracketColor; public static String CEditorPreferencePage_behaviorPage_inactiveCodeColor; @@ -581,4 +585,4 @@ public final class PreferencesMessages extends NLS { static { NLS.initializeMessages(PreferencesMessages.class.getName(), PreferencesMessages.class); } -} \ No newline at end of file +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties index c3f4874407c..2b6c5c06e93 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties @@ -103,6 +103,10 @@ CEditorPreferencePage_colorPage_systemDefault=S&ystem Default CEditorPreferencePage_behaviorPage_matchingBrackets=Highlight &matching brackets CEditorPreferencePage_behaviorPage_subWordNavigation=Smart &caret positioning in identifiers CEditorPreferencePage_behaviorPage_inactiveCode=Highlight &inactive code +CEditorPreferencePage_behaviorPage_formattingWithEmptySelection=When formatting code with an empty selection: +CEditorPreferencePage_behaviorPage_formatFile=Format the entire &file +CEditorPreferencePage_behaviorPage_formatStatement=Format the &statement on the current line +CEditorPreferencePage_behaviorPage_confirmFormattingScope=&Ask for confirmation CEditorPreferencePage_behaviorPage_appearanceColorOptions=Appearance color options: CEditorPreferencePage_behaviorPage_matchingBracketColor=Matching brackets highlight CEditorPreferencePage_behaviorPage_inactiveCodeColor=Inactive code highlight diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/PreferenceConstants.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/PreferenceConstants.java index c5f25813ecd..08d16e0f2e1 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/PreferenceConstants.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/PreferenceConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2012 IBM Corporation and others. + * Copyright (c) 2005, 2014 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 @@ -930,6 +930,41 @@ public class PreferenceConstants { */ public static final String FORMATTER_PROFILE = "formatter_profile"; //$NON-NLS-1$ + /** + * Preference key determining the scope of formatting when the selection is empty. + * + * Value is of type {@code String}. + * + * @since 5.9 + */ + public final static String FORMATTING_SCOPE_FOR_EMPTY_SELECTION = "formattingScopeForEmptySelection"; //$NON-NLS-1$ + + /** + * The value of {@link #FORMATTING_SCOPE_FOR_EMPTY_SELECTION} specifying that the formatting + * applies to the whole document. + * + * @since 5.9 + */ + public static final String FORMATTING_SCOPE_DOCUMENT = "document"; //$NON-NLS-1$ + + /** + * The value of {@link #FORMATTING_SCOPE_FOR_EMPTY_SELECTION} specifying that the formatting + * applies to the containing statement. + * + * @since 5.9 + */ + public static final String FORMATTING_SCOPE_STATEMENT = "statement"; //$NON-NLS-1$ + + /** + * Preference key for whether to ask user for how formatting of an empty selection + * should be interpreted. + *
+ * Value is of type {@code Boolean}. The default is {@code true}. + * + * @since 5.9 + */ + public final static String FORMATTING_CONFIRM_SCOPE_FOR_EMPTY_SELECTION = "formattingConfirmScopeForEmptySelection"; //$NON-NLS-1$ + /** * Preference key for whether to ensure a newline at the end of files when saving. * @@ -2159,6 +2194,10 @@ public class PreferenceConstants { // Formatter profile store.setDefault(FORMATTER_PROFILE, FormatterProfileManager.DEFAULT_PROFILE); + // Formatting behavior. + store.setDefault(FORMATTING_SCOPE_FOR_EMPTY_SELECTION, FORMATTING_SCOPE_DOCUMENT); + store.setDefault(FORMATTING_CONFIRM_SCOPE_FOR_EMPTY_SELECTION, true); + // Content assist store.setDefault(CODEASSIST_EXCLUDED_CATEGORIES, "org.eclipse.cdt.ui.textProposalCategory\0"); //$NON-NLS-1$ store.setDefault(CODEASSIST_CATEGORY_ORDER, "org.eclipse.cdt.ui.parserProposalCategory:65539\0org.eclipse.cdt.ui.textProposalCategory:65541\0org.eclipse.cdt.ui.templateProposalCategory:2\0org.eclipse.cdt.ui.helpProposalCategory:5\0"); //$NON-NLS-1$