diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/SortLinesTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/SortLinesTest.java
new file mode 100644
index 00000000000..33654a027af
--- /dev/null
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/SortLinesTest.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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.ui.tests.text;
+
+import java.util.ListResourceBundle;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.source.SourceViewer;
+
+import org.eclipse.cdt.core.formatter.DefaultCodeFormatterConstants;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.testplugin.CProjectHelper;
+import org.eclipse.cdt.ui.testplugin.EditorTestHelper;
+import org.eclipse.cdt.ui.testplugin.ResourceTestHelper;
+import org.eclipse.cdt.ui.tests.BaseUITestCase;
+import org.eclipse.cdt.internal.ui.editor.CEditor;
+import org.eclipse.cdt.internal.ui.editor.SortLinesAction;
+
+/**
+ * Tests for the SortLinesAction.
+ *
+ * @since 5.2
+ */
+public class SortLinesTest extends BaseUITestCase {
+ private static final String PROJECT = "SortLinesTest";
+ private static final String FILE = "test.cpp";
+
+ private static final class EmptyBundle extends ListResourceBundle {
+ @Override
+ protected Object[][] getContents() {
+ return new Object[0][];
+ }
+ }
+
+ protected static class SortLinesTestSetup extends TestSetup {
+ private ICProject fCProject;
+
+ public SortLinesTestSetup(Test test) {
+ super(test);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ fCProject= CProjectHelper.createCProject(PROJECT, null);
+ fCProject.setOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, DefaultCodeFormatterConstants.MIXED);
+ fCProject.setOption(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, String.valueOf(8));
+ fCProject.setOption(DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE, String.valueOf(4));
+ IFile file= EditorTestHelper.createFile(fCProject.getProject(), FILE, "", new NullProgressMonitor());
+ }
+
+ @Override
+ protected void tearDown () throws Exception {
+ EditorTestHelper.closeAllEditors();
+ if (fCProject != null) {
+ CProjectHelper.delete(fCProject);
+ }
+ super.tearDown();
+ }
+ }
+
+ private static final Class> THIS= SortLinesTest.class;
+ public static Test suite() {
+ return new SortLinesTestSetup(new TestSuite(THIS));
+ }
+
+ private CEditor fEditor;
+ private SourceViewer fSourceViewer;
+ private IDocument fDocument;
+ private SortLinesTestSetup fProjectSetup;
+
+ /*
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ if (!ResourcesPlugin.getWorkspace().getRoot().exists(new Path(PROJECT))) {
+ fProjectSetup= new SortLinesTestSetup(this);
+ fProjectSetup.setUp();
+ }
+ fEditor= (CEditor) EditorTestHelper.openInEditor(ResourceTestHelper.findFile(PROJECT + '/' + FILE), true);
+ fSourceViewer= EditorTestHelper.getSourceViewer(fEditor);
+ fDocument= fSourceViewer.getDocument();
+ super.setUp();
+ }
+
+ /*
+ * @see junit.framework.TestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ if (fProjectSetup != null) {
+ fProjectSetup.tearDown();
+ }
+ super.tearDown();
+ }
+
+ private void sortLines() throws Exception {
+ new SortLinesAction(fEditor).run();
+ }
+
+ /**
+ * Selects part of the document.
+ *
+ * @param startLine First line of the selection. Zero based.
+ * @param startPosition Start position of the selection in startLine. Zero based.
+ * @param endLine Last line of the selection. Zero based.
+ * @param endPosition Position after the end of the selection in endLine. Zero based.
+ */
+ private void select(int startLine, int startPosition, int endLine, int endPosition)
+ throws BadLocationException {
+ int offset = fDocument.getLineOffset(startLine) + startPosition;
+ fSourceViewer.setSelectedRange(offset, fDocument.getLineOffset(endLine) + endPosition - offset);
+ }
+
+ /**
+ * Selects the whole document.
+ */
+ private void selectAll() {
+ fSourceViewer.setSelectedRange(0, fDocument.getLength());
+ }
+
+ // // e.h
+ // #include "e.h"
+ // #include "bbb.h"
+ // #include "dd.h"
+ // /*
+ // * ccccc.h
+ // */
+ // #include "ccccc.h"
+ // #include "aaaa.h"
+
+ // #include "aaaa.h"
+ // #include "bbb.h"
+ // /*
+ // * ccccc.h
+ // */
+ // #include "ccccc.h"
+ // #include "dd.h"
+ // // e.h
+ // #include "e.h"
+ public void testSortLinesMixed() throws Exception {
+ StringBuffer[] contents= getContentsForTest(2);
+ String before= contents[0].toString();
+ String after= contents[1].toString();
+ fDocument.set(before);
+ selectAll();
+ sortLines();
+ assertEquals(after, fDocument.get());
+ }
+
+ // /*
+ // * Ganymede
+ // * Europa
+ // * Callisto
+ // */
+
+ // /*
+ // * Europa
+ // * Ganymede
+ // * Callisto
+ // */
+ public void testSortLinesCommentsOnly() throws Exception {
+ StringBuffer[] contents= getContentsForTest(2);
+ String before= contents[0].toString();
+ String after= contents[1].toString();
+ fDocument.set(before);
+ select(1, 0, 3, 0);
+ sortLines();
+ assertEquals(after, fDocument.get());
+ }
+}
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/TextTestSuite.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/TextTestSuite.java
index 03a27cbcc00..4a99d7ecc16 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/TextTestSuite.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/TextTestSuite.java
@@ -72,10 +72,11 @@ public class TextTestSuite extends TestSuite {
// compare tests
addTest(CStructureCreatorTest.suite());
- // block comment tests
+ // source manipulation tests
addTest(AddBlockCommentTest.suite());
addTest(RemoveBlockCommentTest.suite());
-
+ addTest(SortLinesTest.suite());
+
// add include
addTest(AddIncludeTest.suite());
}
diff --git a/core/org.eclipse.cdt.ui/plugin.properties b/core/org.eclipse.cdt.ui/plugin.properties
index 021fb4e8407..e8c297ed06e 100644
--- a/core/org.eclipse.cdt.ui/plugin.properties
+++ b/core/org.eclipse.cdt.ui/plugin.properties
@@ -170,7 +170,7 @@ Refactoring.extractLocalVariable.label=Extract &Local Variable
Refactoring.extractFunction.label=Extract &Function...
Refactoring.hideMethod.label=Hide Method...
Refactoring.implementMethod.label=Impl&ement Method...
-Refactoring.gettersAndSetters.label=Generate Getters and Setters...
+Refactoring.gettersAndSetters.label=Gene&rate Getters and Setters...
Source.menu.label = &Source
@@ -253,10 +253,14 @@ OpenTypeAction.tooltip= Open Element
ActionDefinition.openType.name= Open Element
ActionDefinition.openType.description= Open an element in an Editor
-#Add include
+#Add Include
ActionDefinition.addInclude.name= Add Include
ActionDefinition.addInclude.description= Create include statement on selection
+#Sort Lines
+ActionDefinition.sortLines.name= Sort Lines
+ActionDefinition.sortLines.description= Sort selected lines alphabetically
+
#Show outline dialog
ActionDefinition.showOutline.name= Show outline
ActionDefinition.showOutline.description= Shows outline
@@ -555,6 +559,7 @@ renameParticipant.name = Source Folder Rename
FormatAction.label= &Format
IndentAction.label= Correct &Indentation
AddIncludeAction.label= A&dd Include
+SortLinesAction.label= Sor&t Lines
CommentAction.label= Co&mment
UncommentAction.label= &Uncomment
ToggleCommentAction.label= Togg&le Comment
diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml
index 3fdbbe83795..dabfc933d4e 100644
--- a/core/org.eclipse.cdt.ui/plugin.xml
+++ b/core/org.eclipse.cdt.ui/plugin.xml
@@ -1334,6 +1334,13 @@
retarget="true">
+
+
+
+
+
= 0;)
+ for (int i = c.length; --i >= 0;) {
if (s.charAt(i) != c[i])
return false;
+ }
return true;
}
@@ -421,7 +421,32 @@ public class Strings {
else
return text.substring(0, end);
}
-
+
+ /**
+ * Converts tabs to spaces in a line of text.
+ * @param line The line of text.
+ * @param tabWidth Tabulation size.
+ * @return The line with tab characters replaced by spaces.
+ */
+ public static String convertTabsToSpaces(String line, int tabWidth) {
+ StringBuilder buf = null;
+ for (int i = 0; i < line.length(); i++) {
+ char c = line.charAt(i);
+ if (c == '\t') {
+ if (buf == null) {
+ buf = new StringBuilder(line.length() * tabWidth);
+ buf.append(line.subSequence(0, i));
+ }
+ for (int k = tabWidth - i % tabWidth; --k >= 0;) {
+ buf.append(' ');
+ }
+ } else if (buf != null) {
+ buf.append(c);
+ }
+ }
+ return buf != null ? buf.toString() : line;
+ }
+
public static String removeMnemonicIndicator(String string) {
return LegacyActionTools.removeMnemonics(string);
}
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 c2adf580ac6..33de676f576 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
@@ -2191,6 +2191,12 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC
setAction("Format", action); //$NON-NLS-1$
markAsStateDependentAction("Format", true); //$NON-NLS-1$
+ action = new SortLinesAction(this);
+ action.setActionDefinitionId(ICEditorActionDefinitionIds.SORT_LINES);
+ setAction("SortLines", action); //$NON-NLS-1$
+ markAsStateDependentAction("SortLines", true); //$NON-NLS-1$
+ markAsSelectionDependentAction("SortLines", true); //$NON-NLS-1$
+
action = new ContentAssistAction(bundle, "ContentAssistProposal.", this); //$NON-NLS-1$
action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
setAction("ContentAssistProposal", action); //$NON-NLS-1$
@@ -2225,7 +2231,7 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC
action.setActionDefinitionId(ICEditorActionDefinitionIds.OPEN_QUICK_MACRO_EXPLORER);
setAction("OpenMacroExplorer", action); //$NON-NLS-1$*/
- //Assorted action groupings
+ // Assorted action groupings
fSelectionSearchGroup = createSelectionSearchGroup();
fTextSearchGroup= new TextSearchGroup(this);
fRefactoringActionGroup= new CRefactoringActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorActionContributor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorActionContributor.java
index 165f843fa7c..b933b8297f8 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorActionContributor.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorActionContributor.java
@@ -196,6 +196,7 @@ public class CEditorActionContributor extends TextEditorActionContributor {
bars.setGlobalActionHandler(CdtActionConstants.REMOVE_BLOCK_COMMENT, getAction(textEditor, "RemoveBlockComment")); //$NON-NLS-1$
bars.setGlobalActionHandler(CdtActionConstants.INDENT, getAction(textEditor, "Indent")); //$NON-NLS-1$
bars.setGlobalActionHandler(CdtActionConstants.ADD_INCLUDE, getAction(textEditor, "AddIncludeOnSelection")); //$NON-NLS-1$
+ bars.setGlobalActionHandler(CdtActionConstants.SORT_LINES, getAction(textEditor, "SortLines")); //$NON-NLS-1$
IAction action= getAction(textEditor, ITextEditorActionConstants.REFRESH);
bars.setGlobalActionHandler(ITextEditorActionConstants.REFRESH, action);
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties
index 2cd6a8ba026..fc747605b87 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties
@@ -17,6 +17,10 @@ AddIncludeOnSelection.description=Add include statement for selected name
AddIncludeOnSelection.label=Add Include
AddIncludeOnSelection.tooltip=Add Include Statement for Selected Name
+SortLines.description=Sort selected lines alphabetically
+SortLines.label=Sort Lines
+SortLines.tooltip=Sort Selected Lines Alphabetically
+
OpenOutline.label= Quick Out&line
OpenOutline.tooltip= Shows the Quick Outline of Editor Input
OpenOutline.description= Shows the quick outline for the editor input
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ICEditorActionDefinitionIds.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ICEditorActionDefinitionIds.java
index 8cba4ff6a2b..8c7b4a2643f 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ICEditorActionDefinitionIds.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ICEditorActionDefinitionIds.java
@@ -235,11 +235,17 @@ public interface ICEditorActionDefinitionIds extends ITextEditorActionDefinition
*/
public static final String TOGGLE_MARK_OCCURRENCES= "org.eclipse.cdt.ui.edit.text.c.toggleMarkOccurrences"; //$NON-NLS-1$
-
/**
* Action definition ID of the open macro explorer quick view action
* (value "org.eclipse.cdt.ui.edit.open.quick.macro.explorer"
).
* @since 5.0
*/
public static final String OPEN_QUICK_MACRO_EXPLORER = "org.eclipse.cdt.ui.edit.open.quick.macro.explorer"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of sort lines action.
+ * (value: "org.eclipse.cdt.ui.edit.text.c.sort.lines"
).
+ * @since 5.2
+ */
+ public static final String SORT_LINES = "org.eclipse.cdt.ui.edit.text.c.sort.lines"; //$NON-NLS-1$
}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SortLinesAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SortLinesAction.java
new file mode 100644
index 00000000000..db12b664fd4
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SortLinesAction.java
@@ -0,0 +1,329 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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.editor;
+
+import java.util.Arrays;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.TextSelection;
+import org.eclipse.jface.text.TextUtilities;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.text.edits.ReplaceEdit;
+import org.eclipse.text.undo.DocumentUndoManagerRegistry;
+import org.eclipse.text.undo.IDocumentUndoManager;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.texteditor.TextEditorAction;
+
+import com.ibm.icu.text.Collator;
+
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.ui.CUIPlugin;
+import org.eclipse.cdt.ui.text.ICPartitions;
+
+import org.eclipse.cdt.internal.corext.util.CodeFormatterUtil;
+import org.eclipse.cdt.internal.corext.util.Strings;
+
+import org.eclipse.cdt.internal.ui.util.EditorUtility;
+
+/**
+ * Sorts selected lines in alphabetical order. If both, comment and non-comment lines
+ * are selected, the non-comment lines are sorted, and the comments are moved together
+ * with the non-comment lines they precede.
+ *
+ * @since 5.2
+ */
+public final class SortLinesAction extends TextEditorAction {
+
+ public SortLinesAction(ITextEditor editor) {
+ super(CEditorMessages.getBundleForConstructedKeys(), "SortLines.", editor); //$NON-NLS-1$
+ }
+
+ /**
+ * Sorts selected lines.
+ */
+ @Override
+ public void run() {
+ ITextEditor editor= getTextEditor();
+ if (editor == null)
+ return;
+
+ ISelection selection = editor.getSelectionProvider().getSelection();
+ if (!(selection instanceof ITextSelection))
+ return;
+
+ ITextSelection textSelection= (ITextSelection) selection;
+ if (textSelection.getStartLine() < 0 || textSelection.getEndLine() < 0)
+ return;
+
+ IEditorInput editorInput = editor.getEditorInput();
+ ICProject cProject = EditorUtility.getCProject(editorInput);
+ IDocument document= editor.getDocumentProvider().getDocument(editorInput);
+ try {
+ IRegion block= getTextBlockFromSelection(textSelection, document);
+ SortElement[] elements = createSortElements(block, document,
+ CodeFormatterUtil.getTabWidth(cProject));
+ if (elements.length <= 1)
+ return;
+ if (!validateEditorInputState())
+ return;
+
+ Arrays.sort(elements);
+ StringBuilder buf = new StringBuilder();
+ for (SortElement element : elements) {
+ buf.append(document.get(element.getOffset(), element.getLength()));
+ if (!isLastLineTerminated(element, document)) {
+ buf.append(TextUtilities.getDefaultLineDelimiter(document));
+ }
+ }
+ ReplaceEdit edit = new ReplaceEdit(block.getOffset(), block.getLength(), buf.toString());
+ IDocumentUndoManager manager= DocumentUndoManagerRegistry.getDocumentUndoManager(document);
+ manager.beginCompoundChange();
+ edit.apply(document);
+ editor.getSelectionProvider().setSelection(new TextSelection(block.getOffset(), buf.length()));
+ manager.endCompoundChange();
+ } catch (BadLocationException e) {
+ CUIPlugin.log(e);
+ }
+ }
+
+ /**
+ * Creates a region describing the text block (something that consists of full lines)
+ * completely containing the current selection.
+ *
+ * @param selection The selection to use
+ * @param document The document
+ * @return the region describing the text block comprising the given selection
+ */
+ private IRegion getTextBlockFromSelection(ITextSelection selection, IDocument document) {
+ try {
+ IRegion firstLine= document.getLineInformationOfOffset(selection.getOffset());
+ int selectionEnd = selection.getOffset() + selection.getLength();
+ IRegion lastLine= document.getLineInformationOfOffset(selectionEnd);
+ int length = lastLine.getOffset() - firstLine.getOffset();
+ if (selectionEnd > lastLine.getOffset()) {
+ // Last line is included with the line delimiter.
+ length += document.getLineLength(document.getLineOfOffset(selectionEnd));
+ }
+ return new Region(firstLine.getOffset(), length);
+ } catch (BadLocationException e) {
+ CUIPlugin.log(e); // Should not happen
+ }
+ return null;
+ }
+
+ private SortElement[] createSortElements(IRegion block, IDocument document, int tabWidth)
+ throws BadLocationException {
+ ITypedRegion[] regions= TextUtilities.computePartitioning(document, ICPartitions.C_PARTITIONING,
+ block.getOffset(), block.getLength(), false);
+
+ int numLines = document.getNumberOfLines(block.getOffset(), block.getLength());
+ if (endOf(block) <= document.getLineInformationOfOffset(endOf(block)).getOffset()) {
+ numLines--; // Last line is excluded
+ }
+ LineInfo[] lineDescriptors = new LineInfo[numLines];
+ int numNonCommentLines = 0;
+ int i = 0;
+ int k = 0;
+ int line = document.getLineOfOffset(block.getOffset());
+ int endLine = line + numLines;
+ for (; line < endLine; line++) {
+ LineInfo lineInfo = new LineInfo(document, line);
+ lineDescriptors[k++] = lineInfo;
+ while (i < regions.length && endOf(regions[i]) <= lineInfo.getTrimmedOffset())
+ i++;
+ for (; i < regions.length && regions[i].getOffset() < lineInfo.getTrimmedEndOffset(); i++) {
+ ITypedRegion region = regions[i];
+ if (region.getType() != ICPartitions.C_MULTI_LINE_COMMENT &&
+ region.getType() != ICPartitions.C_MULTI_LINE_DOC_COMMENT &&
+ region.getType() != ICPartitions.C_SINGLE_LINE_COMMENT &&
+ region.getType() != ICPartitions.C_SINGLE_LINE_DOC_COMMENT) {
+ lineInfo.nonComment = true;
+ break;
+ }
+ }
+ if (lineInfo.nonComment) {
+ numNonCommentLines++;
+ }
+ }
+ SortElement[] elements;
+ if (numNonCommentLines > 1) {
+ elements = new SortElement[numNonCommentLines];
+ k = 0;
+ int offset = block.getOffset();
+ for (int j = 0; j < lineDescriptors.length; j++) {
+ LineInfo lineInfo = lineDescriptors[j];
+ if (lineInfo.nonComment) {
+ int endOffset = k < numNonCommentLines - 1 ?
+ lineInfo.getEndOffset() : block.getOffset() + block.getLength();
+ elements[k++] = new SortElement(new Region(offset, endOffset - offset), lineInfo,
+ document, tabWidth);
+ offset = lineInfo.getEndOffset();
+ }
+ }
+ } else {
+ elements = new SortElement[numLines];
+ for (int j = 0; j < lineDescriptors.length; j++) {
+ LineInfo lineInfo = lineDescriptors[j];
+ elements[j] = new SortElement(lineInfo, lineInfo, document, tabWidth);
+ }
+ }
+ return elements;
+ }
+
+ /**
+ * Returns end offset of a region.
+ */
+ private int endOf(IRegion region) {
+ return region.getOffset() + region.getLength();
+ }
+
+ /**
+ * Returns true
if the given region is terminated by a line delimiter.
+ */
+ private static boolean isLastLineTerminated(IRegion region, IDocument document) throws BadLocationException {
+ int offset = region.getOffset() + region.getLength();
+ IRegion nextLine = document.getLineInformationOfOffset(offset);
+ return nextLine.getOffset() == offset;
+ }
+
+ @Override
+ public void update() {
+ if (!canModifyEditor()) {
+ setEnabled(false);
+ return;
+ }
+
+ // Enable if two or more lines are selected.
+ boolean enabled = false;
+ ITextEditor editor = getTextEditor();
+ if (editor != null) {
+ ISelection selection = editor.getSelectionProvider().getSelection();
+ if (selection instanceof ITextSelection) {
+ ITextSelection textSelection= (ITextSelection) selection;
+ int startLine = textSelection.getStartLine();
+ int endLine = textSelection.getEndLine();
+ if (startLine >= 0 && endLine > startLine) {
+ if (endLine == startLine + 1) {
+ IDocument document= editor.getDocumentProvider().getDocument(editor.getEditorInput());
+ try {
+ if (textSelection.getOffset() + textSelection.getLength() > document.getLineOffset(endLine)) {
+ enabled = true;
+ }
+ } catch (BadLocationException e) {
+ CUIPlugin.log(e);
+ }
+ } else {
+ enabled = true;
+ }
+ }
+ }
+ }
+ setEnabled(enabled);
+ }
+
+ /*
+ * @see TextEditorAction#setEditor(ITextEditor)
+ */
+ @Override
+ public void setEditor(ITextEditor editor) {
+ super.setEditor(editor);
+ }
+
+ private static class SortElement implements Comparable, IRegion {
+ private static final Collator collator = Collator.getInstance();
+ private final IRegion region;
+ private final String collationKey;
+
+ public SortElement(IRegion region, IRegion collationLine, IDocument document, int tabWidth)
+ throws BadLocationException {
+ super();
+ this.region = region;
+ this.collationKey = Strings.convertTabsToSpaces(Strings.trimTrailingTabsAndSpaces(
+ document.get(collationLine.getOffset(), collationLine.getLength())), tabWidth);
+ }
+
+ public int compareTo(SortElement other) {
+ return collator.compare(collationKey, other.collationKey);
+ }
+
+ public int getOffset() {
+ return region.getOffset();
+ }
+
+ public int getLength() {
+ return region.getLength();
+ }
+ }
+
+ private static class LineInfo implements IRegion {
+ final int offset;
+ final int length;
+ final int trimmedOffset;
+ final int trimmedEndOffset;
+ boolean nonComment;
+
+ LineInfo(IDocument document, int line) throws BadLocationException {
+ offset = document.getLineOffset(line);
+ length = document.getLineLength(line);
+ int begin = offset;
+ int end = offset + length;
+ while (--end >= begin && Character.isWhitespace(document.getChar(end))) {
+ }
+ end++;
+ while (begin < end && Character.isWhitespace(document.getChar(begin))) {
+ begin++;
+ }
+ trimmedOffset = begin;
+ trimmedEndOffset = end;
+ }
+
+ /**
+ * Offset of the line in the document.
+ */
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
+ * Length of the line including line delimiter.
+ */
+ public int getLength() {
+ return length;
+ }
+
+ /**
+ * End offset of the line including line delimiter.
+ */
+ public int getEndOffset() {
+ return offset + length;
+ }
+
+ /**
+ * Document offset of the first non-whitespace character of the line.
+ */
+ public int getTrimmedOffset() {
+ return trimmedOffset;
+ }
+
+ /**
+ * Document offset after the last non-whitespace character of the line.
+ */
+ public int getTrimmedEndOffset() {
+ return trimmedEndOffset;
+ }
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java
index 36eb72bbb15..c7cd47ece82 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java
@@ -733,14 +733,14 @@ public class EditorUtility {
public static ICProject getCProject(IEditorInput input) {
ICProject cProject= null;
if (input instanceof IFileEditorInput) {
- IProject project= ((IFileEditorInput)input).getFile().getProject();
+ IProject project= ((IFileEditorInput) input).getFile().getProject();
if (project != null) {
cProject= CoreModel.getDefault().create(project);
if (!cProject.exists())
cProject= null;
}
} else if (input instanceof ITranslationUnitEditorInput) {
- final ITranslationUnit tu= ((ITranslationUnitEditorInput)input).getTranslationUnit();
+ final ITranslationUnit tu= ((ITranslationUnitEditorInput) input).getTranslationUnit();
if (tu != null) {
cProject= tu.getCProject();
} else if (input instanceof ExternalEditorInput) {
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/CdtActionConstants.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/CdtActionConstants.java
index 581802495de..03eb44c09b4 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/CdtActionConstants.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/CdtActionConstants.java
@@ -132,19 +132,26 @@ public class CdtActionConstants {
* (value "org.eclipse.cdt.ui.actions.Format"
).
*/
public static final String FORMAT= "org.eclipse.cdt.ui.actions.Format"; //$NON-NLS-1$
-
+
/**
* Source menu: name of standard Add Include global action
* (value "org.eclipse.cdt.ui.actions.AddInclude"
).
*/
public static final String ADD_INCLUDE= "org.eclipse.cdt.ui.actions.AddInclude"; //$NON-NLS-1$
-
+
+ /**
+ * Source menu: name of standard Sort Lines global action
+ * (value "org.eclipse.cdt.ui.actions.SortLines"
).
+ * @since 5.2
+ */
+ public static final String SORT_LINES= "org.eclipse.cdt.ui.actions.SortLines"; //$NON-NLS-1$
+
/**
* Source menu: name of standard Sort Members global action (value
* "org.eclipse.cdt.ui.actions.SortMembers"
).
*/
public static final String SORT_MEMBERS= "org.eclipse.cdt.ui.actions.SortMembers"; //$NON-NLS-1$
-
+
/**
* Source menu: name of standard Surround with try/catch block global action
* (value "org.eclipse.cdt.ui.actions.SurroundWithTryCatch"
).
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/GenerateActionGroup.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/GenerateActionGroup.java
index 274e1d50ff3..e7c61a1766e 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/GenerateActionGroup.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/GenerateActionGroup.java
@@ -52,6 +52,7 @@ import org.eclipse.cdt.internal.ui.actions.CDTQuickMenuCreator;
import org.eclipse.cdt.internal.ui.editor.AddIncludeOnSelectionAction;
import org.eclipse.cdt.internal.ui.editor.CEditor;
import org.eclipse.cdt.internal.ui.editor.ICEditorActionDefinitionIds;
+import org.eclipse.cdt.internal.ui.editor.SortLinesAction;
/**
* Action group that adds the source and generate actions to a part's context
@@ -129,6 +130,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
//
// private OrganizeIncludesAction fOrganizeIncludes;
// private SortMembersAction fSortMembers;
+ private SortLinesAction fSortLines;
// private FormatAllAction fFormatAll;
// private CopyQualifiedNameAction fCopyQualifiedNameAction;
//
@@ -161,7 +163,11 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
// fSortMembers= new SortMembersAction(editor);
// fSortMembers.setActionDefinitionId(ICEditorActionDefinitionIds.SORT_MEMBERS);
// editor.setAction("SortMembers", fSortMembers); //$NON-NLS-1$
-//
+
+ fSortLines= new SortLinesAction(editor);
+ fSortLines.setActionDefinitionId(ICEditorActionDefinitionIds.SORT_LINES);
+ editor.setAction("SortLines", fSortLines); //$NON-NLS-1$
+
// IAction pastAction= editor.getAction(ITextEditorActionConstants.PASTE);//IWorkbenchActionDefinitionIds.PASTE);
// fCopyQualifiedNameAction= new CopyQualifiedNameAction(editor, null, pastAction);
// fCopyQualifiedNameAction.setActionDefinitionId(CopyQualifiedNameAction.JAVA_EDITOR_ACTION_DEFINITIONS_ID);
@@ -412,6 +418,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
added+= addAction(source, fAddInclude);
// added+= addAction(source, fOrganizeIncludes);
// added+= addAction(source, fSortMembers);
+ added+= addAction(source, fSortLines);
// added+= addAction(source, fCleanUp);
source.add(new Separator(GROUP_GENERATE));
// added+= addAction(source, fOverrideMethods);