Added Tabs to Spaces conversion and Source menu; fixed reindenter range bug
diff --git a/org.eclipse.photran.core.vpg/parser/org/eclipse/photran/core/IFortranAST.java b/org.eclipse.photran.core.vpg/parser/org/eclipse/photran/core/IFortranAST.java
index 92ce525..e2d0f18 100644
--- a/org.eclipse.photran.core.vpg/parser/org/eclipse/photran/core/IFortranAST.java
+++ b/org.eclipse.photran.core.vpg/parser/org/eclipse/photran/core/IFortranAST.java
@@ -41,6 +41,8 @@
     public Iterator<Token> iterator();
     public Token findTokenByStreamOffsetLength(int offset, int length);
     public Token findFirstTokenOnLine(int line);
+    public Token findFirstTokenOnOrAfterLine(int line);
     public Token findLastTokenOnLine(int line);
+    public Token findLastTokenOnOrBeforeLine(int line);
 	public Token findTokenByFileOffsetLength(IFile file, int offset, int length);
 }
diff --git a/org.eclipse.photran.core.vpg/parser/org/eclipse/photran/internal/core/FortranAST.java b/org.eclipse.photran.core.vpg/parser/org/eclipse/photran/internal/core/FortranAST.java
index a757b41..9d601fe 100644
--- a/org.eclipse.photran.core.vpg/parser/org/eclipse/photran/internal/core/FortranAST.java
+++ b/org.eclipse.photran.core.vpg/parser/org/eclipse/photran/internal/core/FortranAST.java
@@ -130,9 +130,21 @@
         return tokenList.findFirstTokenOnLine(line);
     }
     
+    public Token findFirstTokenOnOrAfterLine(int line)
+    {
+        // Binary Search
+        return tokenList.findFirstTokenOnOrAfterLine(line);
+    }
+    
     public Token findLastTokenOnLine(int line)
     {
         // Binary Search
         return tokenList.findLastTokenOnLine(line);
     }
+    
+    public Token findLastTokenOnOrBeforeLine(int line)
+    {
+        // Binary Search
+        return tokenList.findLastTokenOnOrBeforeLine(line);
+    }
 }
\ No newline at end of file
diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/reindenter/Reindenter.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/reindenter/Reindenter.java
index 792e138..b9bb447 100644
--- a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/reindenter/Reindenter.java
+++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/reindenter/Reindenter.java
@@ -98,7 +98,7 @@
 
     public static void reindent(int fromLine, int thruLine, IFortranAST ast, Strategy strategy)
     {
-        reindent(ast.findFirstTokenOnLine(fromLine), ast.findLastTokenOnLine(thruLine), ast, strategy);
+        reindent(ast.findFirstTokenOnOrAfterLine(fromLine), ast.findLastTokenOnOrBeforeLine(thruLine), ast, strategy);
     }
     
     private static void reindent(Token firstTokenInRegion, Token lastTokenInRegion, IFortranAST ast, Strategy strategy)
diff --git a/org.eclipse.photran.core/src/org/eclipse/photran/internal/core/preferences/FortranBooleanPreference.java b/org.eclipse.photran.core/src/org/eclipse/photran/internal/core/preferences/FortranBooleanPreference.java
index ef4b894..6e22615 100644
--- a/org.eclipse.photran.core/src/org/eclipse/photran/internal/core/preferences/FortranBooleanPreference.java
+++ b/org.eclipse.photran.core/src/org/eclipse/photran/internal/core/preferences/FortranBooleanPreference.java
@@ -48,6 +48,9 @@
      */
     public boolean getValue()
     {
-        return getPreferenceStore().getBoolean(getName());
+        if (!getPreferenceStore().contains(getName()))
+            return defaultValue;
+        else
+            return getPreferenceStore().getBoolean(getName());
     }
 }
\ No newline at end of file
diff --git a/org.eclipse.photran.core/src/org/eclipse/photran/internal/core/preferences/FortranPreferences.java b/org.eclipse.photran.core/src/org/eclipse/photran/internal/core/preferences/FortranPreferences.java
index 4eb1573..d58cf53 100644
--- a/org.eclipse.photran.core/src/org/eclipse/photran/internal/core/preferences/FortranPreferences.java
+++ b/org.eclipse.photran.core/src/org/eclipse/photran/internal/core/preferences/FortranPreferences.java
@@ -50,6 +50,7 @@
     public static final FortranStringPreference PREFERRED_DOM_PARSER = new FortranStringPreference("domparser", ""); //$NON-NLS-1$ //$NON-NLS-2$
 
     public static final FortranIntegerPreference FIXED_FORM_COMMENT_COLUMN = new FortranIntegerPreference("fixedformcommentcolum", 72, FortranIntegerPreference.NO_LIMIT, 72); //$NON-NLS-1$
+    public static final FortranBooleanPreference CONVERT_TABS_TO_SPACES = new FortranBooleanPreference("converttabs", true); //$NON-NLS-1$
     
     private FortranPreferences() {}
 
diff --git a/org.eclipse.photran.core/src/org/eclipse/photran/internal/core/preferences/FortranStringPreference.java b/org.eclipse.photran.core/src/org/eclipse/photran/internal/core/preferences/FortranStringPreference.java
index 66d2981..e4b51ad 100644
--- a/org.eclipse.photran.core/src/org/eclipse/photran/internal/core/preferences/FortranStringPreference.java
+++ b/org.eclipse.photran.core/src/org/eclipse/photran/internal/core/preferences/FortranStringPreference.java
@@ -48,6 +48,9 @@
      */
     public String getValue()
     {
-        return getPreferenceStore().getString(getName());
+        if (!getPreferenceStore().contains(getName()))
+            return defaultValue;
+        else
+            return getPreferenceStore().getString(getName());
     }
 }
\ No newline at end of file
diff --git a/org.eclipse.photran.ui.vpg/plugin.xml b/org.eclipse.photran.ui.vpg/plugin.xml
index cc276b4..ff4fb59 100644
--- a/org.eclipse.photran.ui.vpg/plugin.xml
+++ b/org.eclipse.photran.ui.vpg/plugin.xml
@@ -353,7 +353,7 @@
             id="org.eclipse.photran.ui.Reindenter">
 	     <action 
 	           label="%action.label.reindent.0" 
-               menubarPath="edit/additions"
+               menubarPath="org.eclipse.photran.ui.source.menu/indentationActions"
                definitionId="org.eclipse.photran.ui.ReindenterCommand"
 	           class="org.eclipse.photran.internal.ui.actions.ReindentAction"
 	           id="org.eclipse.photran.ui.ReindenterAction">
diff --git a/org.eclipse.photran.ui/META-INF/MANIFEST.MF b/org.eclipse.photran.ui/META-INF/MANIFEST.MF
index 026db4b..23d4bcf 100644
--- a/org.eclipse.photran.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.photran.ui/META-INF/MANIFEST.MF
@@ -28,6 +28,7 @@
  org.eclipse.cdt.debug.ui,
  org.eclipse.cdt.core,
  org.eclipse.debug.ui,
- org.eclipse.rephraserengine.ui.refactoring;resolution:=optional
+ org.eclipse.rephraserengine.ui.refactoring;resolution:=optional,
+ org.eclipse.cdt.ui
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/org.eclipse.photran.ui/plugin.xml b/org.eclipse.photran.ui/plugin.xml
index 5a1306d..2ca57a7 100644
--- a/org.eclipse.photran.ui/plugin.xml
+++ b/org.eclipse.photran.ui/plugin.xml
@@ -73,7 +73,7 @@
             id="org.eclipse.photran.ui.CommentUncomment">
 	     <action 
 	           label="%action.label.0" 
-               menubarPath="edit/additions"
+               menubarPath="org.eclipse.photran.ui.source.menu/commentActions"
                definitionId="org.eclipse.photran.ui.CommentCommand"
 	           class="org.eclipse.photran.internal.ui.actions.FortranBlockCommentActionDelegate" 
 	           id="org.eclipse.photran.ui.BlockCommentAction">
@@ -153,6 +153,40 @@
       </actionSetPartAssociation>      
    </extension>
 
+   <!--=============-->
+   <!-- Source Menu -->
+   <!--=============-->
+   <extension point="org.eclipse.ui.menus">
+      <menuContribution
+            locationURI="menu:org.eclipse.ui.main.menu?after=edit">
+         <menu
+               label="Source"
+               id="org.eclipse.photran.ui.source.menu">
+            <separator
+                  name="commentActions">
+            </separator>
+            <!-- SEPARATOR --><separator name="separator1" visible="true" />
+            <command
+                  commandId="org.eclipse.ui.edit.text.shiftRight"
+                  label="Shift Right"
+                  style="push">
+            </command>
+            <command
+                  commandId="org.eclipse.ui.edit.text.shiftLeft"
+                  label="Shift Left"
+                  style="push">
+            </command>
+            <separator
+                  name="indentationActions">
+            </separator>
+            <!-- SEPARATOR --><separator name="separator1" visible="true" />
+            <separator
+                  name="additions">
+            </separator>
+         </menu>
+      </menuContribution>
+   </extension>
+
    <!--===================================-->
    <!-- Fortran-specific preference pages -->
    <!--===================================-->
diff --git a/org.eclipse.photran.ui/src/org/eclipse/photran/internal/ui/editor/FortranEditor.java b/org.eclipse.photran.ui/src/org/eclipse/photran/internal/ui/editor/FortranEditor.java
index 370720a..3da125d 100644
--- a/org.eclipse.photran.ui/src/org/eclipse/photran/internal/ui/editor/FortranEditor.java
+++ b/org.eclipse.photran.ui/src/org/eclipse/photran/internal/ui/editor/FortranEditor.java
@@ -14,6 +14,8 @@
 import java.util.HashMap;
 
 import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.internal.ui.editor.CDocumentProvider;
+import org.eclipse.cdt.internal.ui.text.TabsToSpacesConverter;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IConfigurationElement;
@@ -23,12 +25,14 @@
 import org.eclipse.jface.action.MenuManager;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.DefaultLineTracker;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.IDocumentPartitioner;
 import org.eclipse.jface.text.IPaintPositionManager;
 import org.eclipse.jface.text.IPainter;
 import org.eclipse.jface.text.ITextSelection;
 import org.eclipse.jface.text.ITextViewerExtension2;
+import org.eclipse.jface.text.ITextViewerExtension7;
 import org.eclipse.jface.text.MarginPainter;
 import org.eclipse.jface.text.Position;
 import org.eclipse.jface.text.presentation.IPresentationReconciler;
@@ -79,12 +83,12 @@
 import org.eclipse.ui.texteditor.WorkbenchChainedTextFontFieldEditor;
 
 /**
- * Base class for the fixed and free-form Fortran editors
+ * Fortran editor
  *
  * @author Jeff Overbey
  * @author Kurt Hendle - folding support
  */
-@SuppressWarnings("deprecation")
+@SuppressWarnings({ "deprecation", "restriction" })
 public class FortranEditor extends CDTBasedTextEditor implements ISelectionChangedListener
 {
     ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -199,6 +203,37 @@
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Tabs to Spaces Conversion
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+
+    // See also FortranSourceViewer
+    
+    @Override
+    protected boolean isTabsToSpacesConversionEnabled() {
+        return FortranPreferences.CONVERT_TABS_TO_SPACES.getValue();
+    }
+
+    @Override
+    protected void installTabsToSpacesConverter() {
+        ISourceViewer sourceViewer= getSourceViewer();
+        SourceViewerConfiguration config= getSourceViewerConfiguration();
+        if (config != null && sourceViewer instanceof ITextViewerExtension7) {
+            int tabWidth= config.getTabWidth(sourceViewer);
+            TabsToSpacesConverter tabToSpacesConverter= new TabsToSpacesConverter();
+            tabToSpacesConverter.setNumberOfSpacesPerTab(tabWidth);
+            IDocumentProvider provider= getDocumentProvider();
+            if (provider instanceof CDocumentProvider) {
+                CDocumentProvider cProvider= (CDocumentProvider) provider;
+                tabToSpacesConverter.setLineTracker(cProvider.createLineTracker(getEditorInput()));
+            } else {
+                tabToSpacesConverter.setLineTracker(new DefaultLineTracker());
+            }
+            ((ITextViewerExtension7) sourceViewer).setTabsToSpacesConverter(tabToSpacesConverter);
+            //updateIndentationMode();
+        }
+    }
+    
+    ///////////////////////////////////////////////////////////////////////////////////////////////
     // Context Menu Contribution
     ///////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -206,7 +241,7 @@
     @Override public void editorContextMenuAboutToShow(IMenuManager menu)
     {
         super.editorContextMenuAboutToShow(menu);
-        
+
         try
         {
             // Instantiate RefactorMenu using reflection since it's in an optional dependency
@@ -237,7 +272,7 @@
         //fAnnotationAccess = createAnnotationAccess();
         //fOverviewRuler = createOverviewRuler(getSharedColors());
 
-        ISourceViewer sourceViewer = new ProjectionViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(), styles);
+        ISourceViewer sourceViewer = new FortranSourceViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(), styles);
 
         getSourceViewerDecorationSupport(sourceViewer); // Ensure decoration support has been created and configured
 
diff --git a/org.eclipse.photran.ui/src/org/eclipse/photran/internal/ui/editor/FortranSourceViewer.java b/org.eclipse.photran.ui/src/org/eclipse/photran/internal/ui/editor/FortranSourceViewer.java
new file mode 100644
index 0000000..5187073
--- /dev/null
+++ b/org.eclipse.photran.ui/src/org/eclipse/photran/internal/ui/editor/FortranSourceViewer.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2009, 2010 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     QNX Software Systems - initial API and implementation
+ *     Sergey Prigogin, Google
+ *     Anton Leherbauer (Wind River Systems)
+ *     Markus Schorn (Wind River Systems)
+ *     Jeff Overbey (UIUC) - Excerpted and modified CSourceViewer for Photran
+ *******************************************************************************/
+package org.eclipse.photran.internal.ui.editor;
+
+import org.eclipse.cdt.internal.ui.editor.IndentUtil;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DocumentRewriteSession;
+import org.eclipse.jface.text.DocumentRewriteSessionType;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentExtension4;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.source.IOverviewRuler;
+import org.eclipse.jface.text.source.IVerticalRuler;
+import org.eclipse.jface.text.source.projection.ProjectionViewer;
+import org.eclipse.photran.internal.core.preferences.FortranPreferences;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Custom source viewer that uses spaces, rather than tabs, to implement the Shift Left
+ * and Shift Right actions if the corresponding workspace preference is enabled.
+ * 
+ * @author Jeff Overbey based on CSourceViewer (see attributions in copyright header)
+ */
+@SuppressWarnings("restriction")
+public class FortranSourceViewer extends ProjectionViewer
+{
+    private static final int TAB_WIDTH = 4;
+    
+    public FortranSourceViewer(
+        Composite parent,
+        IVerticalRuler ruler,
+        IOverviewRuler overviewRuler,
+        boolean showsAnnotationOverview,
+        int styles)
+    {
+        super(parent, ruler, overviewRuler, showsAnnotationOverview, styles);
+    }
+
+    @Override
+    protected void shift(boolean useDefaultPrefixes, boolean right, boolean ignoreWhitespace) {
+        if (!useDefaultPrefixes && FortranPreferences.CONVERT_TABS_TO_SPACES.getValue())
+            adjustIndent(right, TAB_WIDTH, true);
+        else
+            super.shift(useDefaultPrefixes, right, ignoreWhitespace);
+    }
+
+    /**
+     * Increase/decrease indentation of current selection.
+     * 
+     * @param increase  if <code>true</code>, indent is increased by one unit
+     * @param shiftWidth  width in spaces of one indent unit
+     * @param useSpaces  if <code>true</code>, only spaces are used for indentation
+     */
+    protected void adjustIndent(boolean increase, int shiftWidth, boolean useSpaces) {
+        if (fUndoManager != null) {
+            fUndoManager.beginCompoundChange();
+        }
+        IDocument d= getDocument();
+        DocumentRewriteSession rewriteSession= null;
+        try {
+            if (d instanceof IDocumentExtension4) {
+                IDocumentExtension4 extension= (IDocumentExtension4) d;
+                rewriteSession= extension.startRewriteSession(DocumentRewriteSessionType.SEQUENTIAL);
+            }
+
+            Point selection= getSelectedRange();
+
+            // perform the adjustment
+            int tabWidth= getTextWidget().getTabs();
+            int startLine= d.getLineOfOffset(selection.x);
+            int endLine= selection.y == 0 ? startLine : d.getLineOfOffset(selection.x + selection.y - 1);
+            for (int line= startLine; line <= endLine; ++line) {
+                IRegion lineRegion= d.getLineInformation(line);
+                String indent= IndentUtil.getCurrentIndent(d, line, false);
+                int indentWidth= IndentUtil.computeVisualLength(indent, tabWidth);
+                int newIndentWidth= Math.max(0, indentWidth + (increase ? shiftWidth : -shiftWidth));
+                String newIndent= IndentUtil.changePrefix(indent.trim(), newIndentWidth, tabWidth, useSpaces);
+                int commonLen= getCommonPrefixLength(indent, newIndent);
+                if (commonLen < Math.max(indent.length(), newIndent.length())) {
+                    if (commonLen > 0) {
+                        indent= indent.substring(commonLen);
+                        newIndent= newIndent.substring(commonLen);
+                    }
+                    final int offset= lineRegion.getOffset() + commonLen;
+                    if (!increase && newIndent.length() > indent.length() && indent.length() > 0) {
+                        d.replace(offset, indent.length(), ""); //$NON-NLS-1$
+                        d.replace(offset, 0, newIndent);
+                    } else {
+                        d.replace(offset, indent.length(), newIndent);
+                    }
+                }
+            }
+            
+        } catch (BadLocationException x) {
+            // ignored
+        } finally {
+            if (rewriteSession != null) {
+                ((IDocumentExtension4)d).stopRewriteSession(rewriteSession);
+            }
+            if (fUndoManager != null) {
+                fUndoManager.endCompoundChange();
+            }
+        }
+    }
+
+    /**
+     * Compute the length of the common prefix of two strings.
+     * 
+     * @param s1
+     * @param s2
+     * @return the length of the common prefix
+     */
+    private static int getCommonPrefixLength(String s1, String s2) {
+        final int l1= s1.length();
+        final int l2= s2.length();
+        int i= 0;
+        while (i < l1 && i < l2 && s1.charAt(i) == s2.charAt(i)) {
+            ++i;
+        }
+        return i;
+    }
+}
diff --git a/org.eclipse.photran.ui/src/org/eclipse/photran/internal/ui/preferences/EditorPreferencePage.java b/org.eclipse.photran.ui/src/org/eclipse/photran/internal/ui/preferences/EditorPreferencePage.java
index 41f398c..ea88ae6 100644
--- a/org.eclipse.photran.ui/src/org/eclipse/photran/internal/ui/preferences/EditorPreferencePage.java
+++ b/org.eclipse.photran.ui/src/org/eclipse/photran/internal/ui/preferences/EditorPreferencePage.java
@@ -35,7 +35,11 @@
                                         "Enable folding rather than ruler in fixed-form Fortran editors",
                                         getFieldEditorParent()));
         */
-        
+
+        addField(new BooleanFieldEditor(FortranPreferences.CONVERT_TABS_TO_SPACES.getName(),
+            "Convert tabs to spaces",
+            getFieldEditorParent()));
+
         IntegerFieldEditor intEditor = new IntegerFieldEditor(FortranPreferences.FIXED_FORM_COMMENT_COLUMN.getName(),
                                                               Messages.EditorPreferencePage_FixedFormLineLength,
                                                                getFieldEditorParent());
diff --git a/org.eclipse.rephraserengine.core/src/org/eclipse/rephraserengine/core/util/TokenList.java b/org.eclipse.rephraserengine.core/src/org/eclipse/rephraserengine/core/util/TokenList.java
index 4607c48..a4797de 100644
--- a/org.eclipse.rephraserengine.core/src/org/eclipse/rephraserengine/core/util/TokenList.java
+++ b/org.eclipse.rephraserengine.core/src/org/eclipse/rephraserengine/core/util/TokenList.java
@@ -158,6 +158,20 @@
         return array[index];
     }
     
+    public T findFirstTokenOnOrAfterLine(int line)
+    {
+        T result = findFirstTokenOnLine(line);
+        if (result != null)
+            return result;
+        else
+        {
+            for (int index = 0; index < size; index++)
+                if (getLine(array[index]) >= line)
+                    return array[index];
+            return null;
+        }
+    }
+
     private int findIndexOfAnyTokenOnLine(int line)
     {
         int low = 0, high = size - 1;
@@ -182,6 +196,27 @@
             index++;
         return array[index];
     }
+    
+    public T findLastTokenOnOrBeforeLine(int line)
+    {
+        T result = findLastTokenOnLine(line);
+        if (result != null)
+            return result;
+        else
+        {
+            for (int index = 0; index < size; index++)
+            {
+                if (getLine(array[index]) > line)
+                {
+                    if (index == 0)
+                        return null;
+                    else
+                        return array[index-1];
+                }
+            }
+            return array[size-1];
+        }
+    }
 
     public Iterator<T> iterator()
     {
diff --git a/org.eclipse.rephraserengine.ui.refactoring/plugin.xml b/org.eclipse.rephraserengine.ui.refactoring/plugin.xml
index 86399a5..7dd13f4 100644
--- a/org.eclipse.rephraserengine.ui.refactoring/plugin.xml
+++ b/org.eclipse.rephraserengine.ui.refactoring/plugin.xml
@@ -16,7 +16,7 @@
       <!-- ============================= -->
       <!-- Always visible -->
       <menuContribution
-            locationURI="menu:org.eclipse.ui.main.menu?after=edit">
+            locationURI="menu:org.eclipse.ui.main.menu?before=navigate">
          <!-- Menu mimicks org.eclipse.jdt.ui's (as does CDT's Refactor menu)
               http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.ui/plugin.xml?view=markup -->
          <menu