1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.eclipse.org/org/documents/epl-v10.php
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.ide.eclipse.adt.internal.editors.formatting;
17 
18 import com.android.annotations.NonNull;
19 import com.android.annotations.Nullable;
20 import com.android.annotations.VisibleForTesting;
21 import com.android.ide.common.xml.XmlFormatPreferences;
22 import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
23 import com.android.ide.common.xml.XmlAttributeSortOrder;
24 
25 import org.eclipse.core.runtime.Preferences;
26 import org.eclipse.jface.preference.IPreferenceStore;
27 import org.eclipse.ui.internal.editors.text.EditorsPlugin;
28 import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
29 import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
30 import org.eclipse.wst.xml.core.internal.XMLCorePlugin;
31 import org.eclipse.wst.xml.core.internal.preferences.XMLCorePreferenceNames;
32 import org.w3c.dom.Attr;
33 
34 import java.util.Comparator;
35 
36 /**
37  * Formatting preferences used by the Android XML formatter.
38  */
39 public class EclipseXmlFormatPreferences extends XmlFormatPreferences {
40     @VisibleForTesting
EclipseXmlFormatPreferences()41     protected EclipseXmlFormatPreferences() {
42     }
43 
44     /**
45      * Creates a new {@link EclipseXmlFormatPreferences} based on the current settings
46      * in {@link AdtPrefs}
47      *
48      * @return an {@link EclipseXmlFormatPreferences} object
49      */
50     @NonNull
create()51     public static EclipseXmlFormatPreferences create() {
52         EclipseXmlFormatPreferences p = new EclipseXmlFormatPreferences();
53         AdtPrefs prefs = AdtPrefs.getPrefs();
54 
55         p.useEclipseIndent = prefs.isUseEclipseIndent();
56         p.removeEmptyLines = prefs.isRemoveEmptyLines();
57         p.oneAttributeOnFirstLine = prefs.isOneAttributeOnFirstLine();
58         p.sortAttributes = prefs.getAttributeSort();
59         p.spaceBeforeClose = prefs.isSpaceBeforeClose();
60 
61         return p;
62     }
63 
64     @Override
65     @Nullable
getAttributeComparator()66     public Comparator<Attr> getAttributeComparator() {
67         // Can't just skip sorting; the attribute table moves attributes out of order
68         // due to hashing, so sort by node positions
69         if (sortAttributes == XmlAttributeSortOrder.NO_SORTING) {
70             return EXISTING_ORDER_COMPARATOR;
71         }
72         return sortAttributes.getAttributeComparator();
73     }
74 
75     private static final Comparator<Attr> EXISTING_ORDER_COMPARATOR = new Comparator<Attr>() {
76         @Override
77         public int compare(Attr attr1, Attr attr2) {
78             IndexedRegion region1 = (IndexedRegion) attr1;
79             IndexedRegion region2 = (IndexedRegion) attr2;
80 
81             return region1.getStartOffset() - region2.getStartOffset();
82         }
83     };
84 
85     // The XML module settings do not have a public API. We should replace this with JDT
86     // settings anyway since that's more likely what users have configured and want applied
87     // to their XML files
88 
89     /**
90      * Returns the string to use to indent one indentation level
91      *
92      * @return the string used to indent one indentation level
93      */
94     @Override
95     @SuppressWarnings({
96             "restriction", "deprecation"
97     })
getOneIndentUnit()98     public String getOneIndentUnit() {
99         if (useEclipseIndent) {
100             // Look up Eclipse indent preferences
101             // TODO: Use the JDT preferences instead, which make more sense
102             Preferences preferences = XMLCorePlugin.getDefault().getPluginPreferences();
103             int indentationWidth = preferences.getInt(XMLCorePreferenceNames.INDENTATION_SIZE);
104             String indentCharPref = preferences.getString(XMLCorePreferenceNames.INDENTATION_CHAR);
105             boolean useSpaces = XMLCorePreferenceNames.SPACE.equals(indentCharPref);
106 
107             StringBuilder indentString = new StringBuilder();
108             for (int j = 0; j < indentationWidth; j++) {
109                 if (useSpaces) {
110                     indentString.append(' ');
111                 } else {
112                     indentString.append('\t');
113                 }
114             }
115             mOneIndentUnit = indentString.toString();
116         }
117 
118         return mOneIndentUnit;
119     }
120 
121     /**
122      * Returns the number of spaces used to display a single tab character
123      *
124      * @return the number of spaces used to display a single tab character
125      */
126     @Override
127     @SuppressWarnings("restriction") // Editor settings
getTabWidth()128     public int getTabWidth() {
129         if (mTabWidth == -1) {
130             String key = AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH;
131             try {
132                 IPreferenceStore prefs = EditorsPlugin.getDefault().getPreferenceStore();
133                 mTabWidth = prefs.getInt(key);
134             } catch (Throwable t) {
135                 // Pass: We'll pick a suitable default instead below
136             }
137             if (mTabWidth <= 0) {
138                 mTabWidth = 4;
139             }
140         }
141 
142         return mTabWidth;
143     }
144 }
145