KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > text > formatter > MultiPassContentFormatter


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.jface.text.formatter;
13
14 import java.util.HashMap JavaDoc;
15 import java.util.Map JavaDoc;
16
17 import org.eclipse.core.runtime.Assert;
18
19 import org.eclipse.jface.text.BadLocationException;
20 import org.eclipse.jface.text.DefaultPositionUpdater;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.jface.text.IRegion;
23 import org.eclipse.jface.text.ITypedRegion;
24 import org.eclipse.jface.text.TextUtilities;
25 import org.eclipse.jface.text.TypedPosition;
26
27 /**
28  * Content formatter for edit-based formatting strategies.
29  * <p>
30  * Two kinds of formatting strategies can be registered with this formatter:
31  * <ul>
32  * <li>one master formatting strategy for the default content type</li>
33  * <li>one formatting strategy for each non-default content type</li>
34  * </ul>
35  * The master formatting strategy always formats the whole region to be
36  * formatted in the first pass. In a second pass, all partitions of the region
37  * to be formatted that are not of master content type are formatted using the
38  * slave formatting strategy registered for the underlying content type. All
39  * formatting strategies must implement {@link IFormattingStrategyExtension}.
40  * <p>
41  * Regions to be formatted with the master formatting strategy always have
42  * an offset aligned to the line start. Regions to be formatted with slave formatting
43  * strategies are aligned on partition boundaries.
44  *
45  * @see IFormattingStrategyExtension
46  * @since 3.0
47  */

48 public class MultiPassContentFormatter implements IContentFormatter, IContentFormatterExtension {
49
50     /**
51      * Position updater that shifts otherwise deleted positions to the next
52      * non-whitespace character. The length of the positions are truncated to
53      * one if the position was shifted.
54      */

55     protected class NonDeletingPositionUpdater extends DefaultPositionUpdater {
56
57         /**
58          * Creates a new non-deleting position updater.
59          *
60          * @param category The position category to update its positions
61          */

62         public NonDeletingPositionUpdater(final String JavaDoc category) {
63             super(category);
64         }
65
66         /*
67          * @see org.eclipse.jface.text.DefaultPositionUpdater#notDeleted()
68          */

69         protected final boolean notDeleted() {
70
71             if (fOffset < fPosition.offset && (fPosition.offset + fPosition.length < fOffset + fLength)) {
72
73                 int offset= fOffset + fLength;
74                 if (offset < fDocument.getLength()) {
75
76                     try {
77
78                         boolean moved= false;
79                         char character= fDocument.getChar(offset);
80
81                         while (offset < fDocument.getLength() && Character.isWhitespace(character)) {
82
83                             moved= true;
84                             character= fDocument.getChar(offset++);
85                         }
86
87                         if (moved)
88                             offset--;
89
90                     } catch (BadLocationException exception) {
91                         // Can not happen
92
}
93
94                     fPosition.offset= offset;
95                     fPosition.length= 0;
96                 }
97             }
98             return true;
99         }
100     }
101
102     /** The master formatting strategy */
103     private IFormattingStrategyExtension fMaster= null;
104     /** The partitioning of this content formatter */
105     private final String JavaDoc fPartitioning;
106     /** The slave formatting strategies */
107     private final Map JavaDoc fSlaves= new HashMap JavaDoc();
108     /** The default content type */
109     private final String JavaDoc fType;
110
111     /**
112      * Creates a new content formatter.
113      *
114      * @param partitioning the document partitioning for this formatter
115      * @param type the default content type
116      */

117     public MultiPassContentFormatter(final String JavaDoc partitioning, final String JavaDoc type) {
118         fPartitioning= partitioning;
119         fType= type;
120     }
121
122     /*
123      * @see org.eclipse.jface.text.formatter.IContentFormatterExtension#format(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.formatter.IFormattingContext)
124      */

125     public final void format(final IDocument medium, final IFormattingContext context) {
126
127         context.setProperty(FormattingContextProperties.CONTEXT_MEDIUM, medium);
128
129         final Boolean JavaDoc document= (Boolean JavaDoc)context.getProperty(FormattingContextProperties.CONTEXT_DOCUMENT);
130         if (document == null || !document.booleanValue()) {
131
132             final IRegion region= (IRegion)context.getProperty(FormattingContextProperties.CONTEXT_REGION);
133             if (region != null) {
134                 try {
135                     formatMaster(context, medium, region.getOffset(), region.getLength());
136                 } finally {
137                     formatSlaves(context, medium, region.getOffset(), region.getLength());
138                 }
139             }
140         } else {
141             try {
142                 formatMaster(context, medium, 0, medium.getLength());
143             } finally {
144                 formatSlaves(context, medium, 0, medium.getLength());
145             }
146         }
147     }
148
149     /*
150      * @see org.eclipse.jface.text.formatter.IContentFormatter#format(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IRegion)
151      */

152     public final void format(final IDocument medium, final IRegion region) {
153
154         final FormattingContext context= new FormattingContext();
155
156         context.setProperty(FormattingContextProperties.CONTEXT_DOCUMENT, Boolean.FALSE);
157         context.setProperty(FormattingContextProperties.CONTEXT_REGION, region);
158
159         format(medium, context);
160     }
161
162     /**
163      * Formats the document specified in the formatting context with the master
164      * formatting strategy.
165      * <p>
166      * The master formatting strategy covers all regions of the document. The
167      * offset of the region to be formatted is aligned on line start boundaries,
168      * whereas the end index of the region remains the same. For this formatting
169      * type the document partitioning is not taken into account.
170      *
171      * @param context The formatting context to use
172      * @param document The document to operate on
173      * @param offset The offset of the region to format
174      * @param length The length of the region to format
175      */

176     protected void formatMaster(final IFormattingContext context, final IDocument document, int offset, int length) {
177
178         try {
179
180             final int delta= offset - document.getLineInformationOfOffset(offset).getOffset();
181             offset -= delta;
182             length += delta;
183
184         } catch (BadLocationException exception) {
185             // Do nothing
186
}
187
188         if (fMaster != null) {
189
190             context.setProperty(FormattingContextProperties.CONTEXT_PARTITION, new TypedPosition(offset, length, fType));
191
192             fMaster.formatterStarts(context);
193             fMaster.format();
194             fMaster.formatterStops();
195         }
196     }
197
198     /**
199      * Formats the document specified in the formatting context with the
200      * formatting strategy registered for the content type.
201      * <p>
202      * For this formatting type only slave strategies are used. The region to be
203      * formatted is aligned on partition boundaries of the underlying content
204      * type. The exact formatting strategy is determined by the underlying
205      * content type of the document partitioning.
206      *
207      * @param context The formatting context to use
208      * @param document The document to operate on
209      * @param offset The offset of the region to format
210      * @param length The length of the region to format
211      * @param type The content type of the region to format
212      */

213     protected void formatSlave(final IFormattingContext context, final IDocument document, final int offset, final int length, final String JavaDoc type) {
214
215         final IFormattingStrategyExtension strategy= (IFormattingStrategyExtension)fSlaves.get(type);
216         if (strategy != null) {
217
218             context.setProperty(FormattingContextProperties.CONTEXT_PARTITION, new TypedPosition(offset, length, type));
219
220             strategy.formatterStarts(context);
221             strategy.format();
222             strategy.formatterStops();
223         }
224     }
225
226     /**
227      * Formats the document specified in the formatting context with the slave
228      * formatting strategies.
229      * <p>
230      * For each content type of the region to be formatted in the document
231      * partitioning, the registered slave formatting strategy is used to format
232      * that particular region. The region to be formatted is aligned on
233      * partition boundaries of the underlying content type. If the content type
234      * is the document's default content type, nothing happens.
235      *
236      * @param context The formatting context to use
237      * @param document The document to operate on
238      * @param offset The offset of the region to format
239      * @param length The length of the region to format
240      */

241     protected void formatSlaves(final IFormattingContext context, final IDocument document, final int offset, final int length) {
242
243         Map JavaDoc partitioners= new HashMap JavaDoc(0);
244         try {
245
246             final ITypedRegion[] partitions= TextUtilities.computePartitioning(document, fPartitioning, offset, length, false);
247
248             if (!fType.equals(partitions[0].getType()))
249                 partitions[0]= TextUtilities.getPartition(document, fPartitioning, partitions[0].getOffset(), false);
250
251             if (partitions.length > 1) {
252
253                 if (!fType.equals(partitions[partitions.length - 1].getType()))
254                     partitions[partitions.length - 1]= TextUtilities.getPartition(document, fPartitioning, partitions[partitions.length - 1].getOffset(), false);
255             }
256
257             String JavaDoc type= null;
258             ITypedRegion partition= null;
259
260             partitioners= TextUtilities.removeDocumentPartitioners(document);
261
262             for (int index= partitions.length - 1; index >= 0; index--) {
263
264                 partition= partitions[index];
265                 type= partition.getType();
266
267                 if (!fType.equals(type))
268                     formatSlave(context, document, partition.getOffset(), partition.getLength(), type);
269             }
270
271         } catch (BadLocationException exception) {
272             // Should not happen
273
} finally {
274             TextUtilities.addDocumentPartitioners(document, partitioners);
275         }
276     }
277
278     /*
279      * @see org.eclipse.jface.text.formatter.IContentFormatter#getFormattingStrategy(java.lang.String)
280      */

281     public final IFormattingStrategy getFormattingStrategy(final String JavaDoc type) {
282         return null;
283     }
284
285     /**
286      * Registers a master formatting strategy.
287      * <p>
288      * The strategy may already be registered with a certain content type as
289      * slave strategy. The master strategy is registered for the default content
290      * type of documents. If a master strategy has already been registered, it
291      * is overridden by the new one.
292      *
293      * @param strategy The master formatting strategy, must implement
294      * {@link IFormattingStrategyExtension}
295      */

296     public final void setMasterStrategy(final IFormattingStrategy strategy) {
297         Assert.isTrue(strategy instanceof IFormattingStrategyExtension);
298         fMaster= (IFormattingStrategyExtension) strategy;
299     }
300
301     /**
302      * Registers a slave formatting strategy for a certain content type.
303      * <p>
304      * The strategy may already be registered as master strategy. An
305      * already registered slave strategy for the specified content type
306      * will be replaced. However, the same strategy may be registered with
307      * several content types. Slave strategies cannot be registered for the
308      * default content type of documents.
309      *
310      * @param strategy The slave formatting strategy
311      * @param type The content type to register this strategy with,
312      * must implement {@link IFormattingStrategyExtension}
313      */

314     public final void setSlaveStrategy(final IFormattingStrategy strategy, final String JavaDoc type) {
315         Assert.isTrue(strategy instanceof IFormattingStrategyExtension);
316         if (!fType.equals(type))
317             fSlaves.put(type, strategy);
318     }
319 }
320
Popular Tags