/* * $Id$ * * Copyright (c) 2004-2005 by the TeXlapse Team. * 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 */ package net.sourceforge.texlipse.actions; import java.util.Arrays; import net.sourceforge.texlipse.TexlipsePlugin; import net.sourceforge.texlipse.editor.TexAutoIndentStrategy; import net.sourceforge.texlipse.editor.TexEditorTools; import net.sourceforge.texlipse.properties.TexlipseProperties; import org.eclipse.jface.action.IAction; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.ui.IEditorActionDelegate; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.texteditor.ITextEditor; /** * @author Laura Takkinen * @author Boris von Loesch * * Handles indentation quick fix when user selects text area * and performs "Correct Indentation" action. (Correct Indentation button or Ctrl+I) */ public class TexCorrectIndentationAction implements IEditorActionDelegate { private IEditorPart targetEditor; private TexSelections selection; private TexEditorTools tools; private String indentationString = ""; private String[] indentationItems; private int tabWidth; /* (non-Javadoc) * @see org.eclipse.ui.IEditorActionDelegate#setActiveEditor(org.eclipse.jface.action.IAction, org.eclipse.ui.IEditorPart) */ public void setActiveEditor(IAction action, IEditorPart targetEditor) { this.targetEditor = targetEditor; } /** * Returns the TexEditor. */ private ITextEditor getTexEditor() { if (targetEditor instanceof ITextEditor) { return (ITextEditor) targetEditor; } else { throw new RuntimeException("Expecting text editor. Found:"+targetEditor.getClass().getName()); } } /* (non-Javadoc) * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction) */ public void run(IAction action) { setIndetationPreferenceInfo(); //no environments to indent if (this.indentationItems.length == 0) { return; } else { //check if environments have change selection = new TexSelections(getTexEditor()); if (selection != null) { this.tools = new TexEditorTools(); try { indent(); } catch(BadLocationException e) { TexlipsePlugin.log("TexCorrectIndentationAction.run", e); } } } } /** * Initializes indentation information from preferences */ private void setIndetationPreferenceInfo() { indentationItems = TexlipsePlugin.getPreferenceArray(TexlipseProperties.INDENTATION_ENVS); Arrays.sort(indentationItems); //this.tabWidth = editorPreferenceStore.getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH); indentationString = TexAutoIndentStrategy.getIndentationString(); } /** * Checks if selection needs indentation and corrects it when necessary. * @throws BadLocationException */ private void indent() throws BadLocationException { //FIXME: Refactor int index = 0; boolean fix = false; IDocument document = selection.getDocument(); selection.selectCompleteLines(); String delimiter = document.getLineDelimiter(selection.getStartLineIndex()); String[] lines; try { lines = document.get(document.getLineOffset(selection.getStartLineIndex()), selection.getSelLength()).split(delimiter); } catch(BadLocationException e) {//for example new empty file return; } //fix lines on at the time String selectedLine = ""; String originalIndentation = ""; String correctIndentation = ""; for (int line = selection.getStartLineIndex(); index < lines.length; line++) { selectedLine = document.get(document.getLineOffset(line), document.getLineLength(line)); originalIndentation = this.tools.getIndentation(selectedLine, this.tabWidth); correctIndentation = ""; //first line of end of document if (line == 0 || line == document.getLength()-1) { } else if (line >= document.getLength()){ return; } else if (selectedLine.indexOf("\\end") != -1) { //selected line is \end{...} -line String endText = this.tools.getEndLine(selectedLine.trim(), "\\end"); if (Arrays.binarySearch(this.indentationItems, this.tools.getEnvironment(endText)) >= 0) { int matchingBegin = this.tools.findMatchingBeginEquation(document, line, this.tools.getEnvironment(endText)); if (matchingBegin < selection.getStartLineIndex()) { correctIndentation = this.tools.getIndentation(document, matchingBegin, "\\begin", this.tabWidth); } else { correctIndentation = this.tools.getIndentation(lines[matchingBegin-selection.getStartLineIndex()], this.tabWidth); } } } else { //otherwise indentation is determined by the previous line String lineText = ""; //previous line is outside the selection if (index == 0) { lineText = document.get(document.getLineOffset(line-1), document.getLineLength(line-1)); } else { //previous line is inside the selection lineText = lines[index-1]; } //previous line is \begin{...} -line if (lineText.indexOf("\\begin") != -1) { String endText = this.tools.getEndLine(lineText.trim(), "\\begin"); if (Arrays.binarySearch(this.indentationItems, this.tools.getEnvironment(endText)) >= 0) { correctIndentation = this.tools.getIndentation(lineText, this.tabWidth) + this.indentationString; } } else { //previous line is something else correctIndentation = this.tools.getIndentation(lineText, this.tabWidth); } } if (!correctIndentation.equals(originalIndentation)) { fix = true; } lines[index] = correctIndentation.concat(lines[index].trim()); index++; } String newText = lines[0]; for (int i = 1; i < lines.length; i++) { newText += delimiter; newText += lines[i]; } if (fix) { document.replace(document.getLineOffset(selection.getStartLineIndex()), selection.getSelLength(), newText); } } /* (non-Javadoc) * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection) */ public void selectionChanged(IAction action, ISelection selection) { if (selection instanceof ITextSelection) { action.setEnabled(true); return; } action.setEnabled( targetEditor instanceof ITextEditor); } }