001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.vmd.api.codegen;
042:
043: import org.netbeans.api.editor.guards.GuardedSection;
044: import org.netbeans.api.editor.guards.GuardedSectionManager;
045: import org.netbeans.api.editor.guards.SimpleSection;
046: import org.netbeans.modules.vmd.api.model.Debug;
047: import org.netbeans.modules.vmd.codegen.CodeUtils;
048: import org.openide.ErrorManager;
049:
050: import javax.swing.text.BadLocationException;
051: import javax.swing.text.Position;
052: import javax.swing.text.StyledDocument;
053: import java.beans.PropertyVetoException;
054: import java.util.ArrayList;
055: import java.util.Iterator;
056:
057: /**
058: * @author David Kaspar
059: */
060: public final class MultiGuardedSection {
061:
062: // TODO - no other guarded-section (besides MultiGuardedSection) must start with '|' character
063: // TODO - add support for deleting whole MultiGuardedSection
064:
065: private StyledDocument document;
066: private String multiGuardedID;
067:
068: private ArrayList<SimpleSection> guardedSections = new ArrayList<SimpleSection>();
069: private ArrayList<String> editableSectionIDs = new ArrayList<String>();
070: private int index = 0;
071: private boolean guarded = true;
072: private CodeWriter writer;
073:
074: private MultiGuardedSection(StyledDocument document,
075: String multiGuardedID) {
076: assert multiGuardedID.indexOf('|') < 0;
077: this .document = document;
078: this .multiGuardedID = multiGuardedID;
079: initialize();
080: JavaCodeGenerator.getDefault().registerUsedMultiGuardedSection(
081: document, this );
082: }
083:
084: private void initialize() {
085: GuardedSectionManager instance = GuardedSectionManager
086: .getInstance(document);
087: Iterable<GuardedSection> allSections = instance
088: .getGuardedSections();
089: // TODO - check if any other section of multiGuardedID is still there
090: for (;;) {
091: String prefix = createSectionID(guardedSections.size(),
092: null);
093: SimpleSection section = CodeUtils.findSectionByPrefix(
094: allSections, prefix);
095: if (section == null)
096: break;
097: String editableSectionID = section.getName().substring(
098: prefix.length());
099: addSection(section, editableSectionID);
100: }
101: if (guardedSections.size() <= 0) {
102: String sectionID = createSectionID(0, null);
103: addSection(CodeUtils.createSimpleSectionAfter(document,
104: CodeUtils.findLast(allSections), sectionID), null);
105: }
106: }
107:
108: public void switchToGuarded() {
109: if (index < 0)
110: throw Debug.illegalState("Section is closed already",
111: multiGuardedID); // NOI18N
112: if (guarded)
113: throw Debug.illegalState(
114: "Cannot switch to guarded from guarded",
115: multiGuardedID, index); // NOI18N
116: if (!isWriterCommitted())
117: throw Debug.illegalState("Writer is not committed yet",
118: multiGuardedID, index); // NOI18N
119: writer = null;
120: index++;
121: guarded = !guarded;
122: }
123:
124: public void switchToEditable(String editableSectionID) {
125: if (index < 0)
126: throw Debug.illegalState("Section is already closed",
127: multiGuardedID); // NOI18N
128: if (!guarded)
129: throw Debug.illegalState(
130: "Cannot switch from editable to editable",
131: multiGuardedID, index, editableSectionID); // NOI18N
132: if (!isWriterCommitted())
133: throw Debug.illegalState("Writer is not committed yet",
134: multiGuardedID, index); // NOI18N
135: writer = null;
136: if (index + 1 >= guardedSections.size()) {
137: GuardedSection last = CodeUtils.findLast(guardedSections);
138: String sectionID = createSectionID(guardedSections.size(),
139: null);
140: SimpleSection newGuardedSection = CodeUtils
141: .createSimpleSectionAfter(document, last, sectionID);
142: addSection(newGuardedSection, null);
143: }
144: editableSectionIDs.set(index, editableSectionID);
145: guarded = !guarded;
146: }
147:
148: public CodeWriter getWriter() {
149: if (index < 0)
150: throw Debug.illegalState("Section is closed already",
151: multiGuardedID); // NOI18N
152: if (writer == null) {
153: if (guarded) {
154: writer = new CodeWriter(document, guardedSections
155: .get(index));
156: } else {
157: String editableID = editableSectionIDs.get(index);
158: writer = new CodeWriter(document, guardedSections
159: .get(index), guardedSections.get(index + 1),
160: JavaCodeGenerator.getDefault().getUserCode(
161: document, multiGuardedID, editableID));
162: }
163: }
164: return writer;
165: }
166:
167: public void close() {
168: if (index < 0)
169: throw Debug.illegalState("Section is closed already",
170: multiGuardedID); // NOI18N
171: if (!guarded || !isWriterCommitted())
172: throw Debug
173: .illegalState(
174: "Cannot close - last section is not properly commited",
175: multiGuardedID, guarded,
176: isWriterCommitted()); // NOI18N
177:
178: int size = guardedSections.size();
179: if (size > 0)
180: editableSectionIDs.set(size - 1, ""); // NOI18N
181: for (int a = 0; a < size; a++)
182: try {
183: guardedSections.get(a).setName(
184: createSectionID(a, editableSectionIDs.get(a)));
185: } catch (PropertyVetoException e) {
186: throw Debug.error(e);
187: }
188:
189: Position begin = guardedSections.get(index).getEndPosition();
190: Position end = guardedSections.get(size - 1).getEndPosition();
191: for (int a = index + 1; a < size; a++)
192: guardedSections.get(a).removeSection();
193: try {
194: // TODO - check if there is no gurded section between begin and end. if so, then do not do anything to prevent data-lost
195: document.remove(begin.getOffset() + 1, end.getOffset()
196: - (begin.getOffset() + 1));
197: } catch (BadLocationException e) {
198: throw Debug.error(e);
199: }
200:
201: index = -1;
202: }
203:
204: public static MultiGuardedSection create(StyledDocument document,
205: String multiGuardedID) {
206: return multiGuardedID != null ? new MultiGuardedSection(
207: document, multiGuardedID) : null;
208: }
209:
210: String getMultiGuardedID() {
211: return multiGuardedID;
212: }
213:
214: private void addSection(SimpleSection section,
215: String editableSectionID) {
216: guardedSections.add(section);
217: editableSectionIDs.add(editableSectionID);
218: }
219:
220: private String createSectionID(int index, String editableID) {
221: return '|' + multiGuardedID + '|' + index + '|'
222: + (editableID != null ? editableID : ""); // NOI18N
223: }
224:
225: static String createSectionIDPrefix(String multiGuardedID) {
226: return '|' + multiGuardedID + '|';
227: }
228:
229: private static String createSectionID(String multiGuardedID,
230: int index, String editableID) {
231: return '|' + multiGuardedID + '|' + index + '|'
232: + (editableID != null ? editableID : ""); // NOI18N
233: }
234:
235: private boolean isWriterCommitted() {
236: return writer != null && writer.isCommitted();
237: }
238:
239: public boolean isGuarded() {
240: return guarded;
241: }
242:
243: public static boolean isPartOfMultiGuardedSection(
244: GuardedSection section) {
245: return section.getName().startsWith("|"); // NOI18N
246: }
247:
248: /**
249: * Parses the section name.
250: * @param section the guarded section
251: * @return the array of 3 objects: multiGuardedID:String, index:Integer, editableID:String
252: */
253: static Object[] parsePartOfMultiGuardedSection(
254: GuardedSection section) {
255: assert isPartOfMultiGuardedSection(section);
256: String name = section.getName();
257: Object[] result = new Object[3];
258:
259: int secondSeparator = name.indexOf('|', 1); // NOI18N
260: assert secondSeparator >= 1;
261: result[0] = name.substring(1, secondSeparator);
262:
263: secondSeparator++;
264: int thirdSeparator = name.indexOf('|', secondSeparator); // NOI18N
265: assert thirdSeparator >= 1;
266: result[1] = Integer.parseInt(name.substring(secondSeparator,
267: thirdSeparator));
268:
269: thirdSeparator++;
270: result[2] = name.substring(thirdSeparator);
271:
272: return result;
273: }
274:
275: public static boolean matches(GuardedSection section,
276: String multiGuardedID, int index) {
277: Object[] objects = parsePartOfMultiGuardedSection(section);
278: return multiGuardedID.equals(objects[0])
279: && index == (Integer) objects[1];
280: }
281:
282: public static boolean matches(GuardedSection section,
283: String multiGuardedID, String editableID) {
284: Object[] objects = parsePartOfMultiGuardedSection(section);
285: return multiGuardedID.equals(objects[0])
286: && editableID.equals(objects[2]);
287: }
288:
289: static GuardedSection findNextPartOfMultiGuardedSectionAfter(
290: StyledDocument document, Object[] info) {
291: GuardedSectionManager instance = GuardedSectionManager
292: .getInstance(document);
293: return CodeUtils.findSectionByPrefix(instance
294: .getGuardedSections(), createSectionID(
295: (String) info[0], (Integer) info[1] + 1, null));
296: }
297:
298: public static void remove(StyledDocument document,
299: String multiGuardedID) {
300: Iterable<GuardedSection> allSections = GuardedSectionManager
301: .getInstance(document).getGuardedSections();
302: // TODO - check if there is any other section in between the guarded-section of multiGuardedID
303: ArrayList<SimpleSection> sections = CodeUtils
304: .findSectionsByPrefix(allSections, MultiGuardedSection
305: .createSectionIDPrefix(multiGuardedID));
306: CodeUtils.sortSections(sections);
307:
308: Iterator<SimpleSection> iterator = sections.iterator();
309: if (!iterator.hasNext())
310: return;
311:
312: SimpleSection firstSection = iterator.next();
313: ArrayList<SimpleSection> sectionsBlock = new ArrayList<SimpleSection>();
314: sectionsBlock.add(firstSection);
315: int lastIndex = (Integer) MultiGuardedSection
316: .parsePartOfMultiGuardedSection(firstSection)[1];
317:
318: while (iterator.hasNext()) {
319: SimpleSection nextSection = iterator.next();
320: int nextIndex = (Integer) MultiGuardedSection
321: .parsePartOfMultiGuardedSection(nextSection)[1];
322: if (lastIndex + 1 != nextIndex) {
323: removeSectionsBlock(document, sectionsBlock);
324: Debug.warning("Broken multi-guarded-section",
325: "Missing sections between", lastIndex,
326: nextIndex); // NOI18N
327: }
328: sectionsBlock.add(nextSection);
329: lastIndex = nextIndex;
330: }
331: removeSectionsBlock(document, sectionsBlock);
332: }
333:
334: private static void removeSectionsBlock(StyledDocument document,
335: ArrayList<SimpleSection> sectionsBlock) {
336: Position begin = sectionsBlock.get(0).getStartPosition();
337: Position end = sectionsBlock.get(sectionsBlock.size() - 1)
338: .getEndPosition();
339: for (SimpleSection section : sectionsBlock)
340: section.removeSection();
341: try {
342: document.remove(begin.getOffset(), end.getOffset()
343: - begin.getOffset());
344: } catch (BadLocationException e) {
345: ErrorManager.getDefault().notify(e);
346: }
347: sectionsBlock.clear();
348: }
349:
350: }
|