EADS-3516 - Still getting: "Adding a fold that is identical with another previously added fold from the same FoldManager is not allowed."
authorchrislovsund@netbeans.org
Fri, 15 Mar 2013 14:16:18 +0100
changeset 360612b49b47f2f
parent 359 90f94cad9154
child 361 263576d44506
EADS-3516 - Still getting: "Adding a fold that is identical with another previously added fold from the same FoldManager is not allowed."
- NewPlsqlFoldManager now includes way to remember old fold, should avoid issue at hand.
- added SimplePlsqlFoldManager for testing. It always removes all fold then add existing back. Will probably remove if NewPlsqlFoldManager fixes issue.
PLSQL/Folding/nbproject/project.xml
PLSQL/Folding/src/org/netbeans/modules/plsql/fold/FoldAdapter.java
PLSQL/Folding/src/org/netbeans/modules/plsql/fold/FoldSearchObject.java
PLSQL/Folding/src/org/netbeans/modules/plsql/fold/NewPlsqlFoldManager.java
PLSQL/Folding/src/org/netbeans/modules/plsql/fold/PlsqlFoldManagerFactory.java
PLSQL/Folding/src/org/netbeans/modules/plsql/fold/SimplePlsqlFoldManager.java
PLSQL/Folding/test/unit/src/org/netbeans/modules/plsql/fold/FoldSearchObjectTest.java
     1.1 --- a/PLSQL/Folding/nbproject/project.xml	Fri Mar 15 14:14:52 2013 +0100
     1.2 +++ b/PLSQL/Folding/nbproject/project.xml	Fri Mar 15 14:16:18 2013 +0100
     1.3 @@ -91,6 +91,19 @@
     1.4                      </run-dependency>
     1.5                  </dependency>
     1.6              </module-dependencies>
     1.7 +            <test-dependencies>
     1.8 +                <test-type>
     1.9 +                    <name>unit</name>
    1.10 +                    <test-dependency>
    1.11 +                        <code-name-base>org.mockito.all</code-name-base>
    1.12 +                        <compile-dependency/>
    1.13 +                    </test-dependency>
    1.14 +                    <test-dependency>
    1.15 +                        <code-name-base>org.netbeans.libs.junit4</code-name-base>
    1.16 +                        <compile-dependency/>
    1.17 +                    </test-dependency>
    1.18 +                </test-type>
    1.19 +            </test-dependencies>
    1.20              <public-packages/>
    1.21          </data>
    1.22      </configuration>
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/PLSQL/Folding/src/org/netbeans/modules/plsql/fold/FoldAdapter.java	Fri Mar 15 14:16:18 2013 +0100
     2.3 @@ -0,0 +1,28 @@
     2.4 +/*
     2.5 + * To change this template, choose Tools | Templates
     2.6 + * and open the template in the editor.
     2.7 + */
     2.8 +package org.netbeans.modules.plsql.fold;
     2.9 +
    2.10 +import org.netbeans.api.editor.fold.Fold;
    2.11 +
    2.12 +/**
    2.13 + *
    2.14 + * @author ChrLSE
    2.15 + */
    2.16 +class FoldAdapter {
    2.17 +
    2.18 +   private final Fold fold;
    2.19 +
    2.20 +   FoldAdapter(Fold fold) {
    2.21 +      this.fold = fold;
    2.22 +   }
    2.23 +
    2.24 +   int getStartOffset() {
    2.25 +      return fold.getStartOffset();
    2.26 +   }
    2.27 +
    2.28 +   int getEndOffset() {
    2.29 +      return fold.getEndOffset();
    2.30 +   }
    2.31 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/PLSQL/Folding/src/org/netbeans/modules/plsql/fold/FoldSearchObject.java	Fri Mar 15 14:16:18 2013 +0100
     3.3 @@ -0,0 +1,74 @@
     3.4 +/*
     3.5 + * To change this template, choose Tools | Templates
     3.6 + * and open the template in the editor.
     3.7 + */
     3.8 +package org.netbeans.modules.plsql.fold;
     3.9 +
    3.10 +import java.io.Serializable;
    3.11 +
    3.12 +/**
    3.13 + *
    3.14 + * @author ChrLSE
    3.15 + */
    3.16 +class FoldSearchObject implements Serializable {
    3.17 +
    3.18 +   private static final long serialVersionUID = 1L;
    3.19 +   private final int startOffset;
    3.20 +   private final int endOffset;
    3.21 +   private FoldAdapter fold;
    3.22 +
    3.23 +   FoldSearchObject(int startOffset, int endOffset) {
    3.24 +      this.startOffset = startOffset;
    3.25 +      this.endOffset = endOffset;
    3.26 +   }
    3.27 +
    3.28 +   FoldSearchObject(FoldAdapter fold) {
    3.29 +      this(-1, -1);
    3.30 +      this.fold = fold;
    3.31 +   }
    3.32 +
    3.33 +   public int getStartOffset() {
    3.34 +      if (startOffset == -1) {
    3.35 +         return fold.getStartOffset();
    3.36 +      }
    3.37 +      return startOffset;
    3.38 +   }
    3.39 +
    3.40 +   public int getEndOffset() {
    3.41 +      if (endOffset == -1) {
    3.42 +         return fold.getEndOffset();
    3.43 +      }
    3.44 +      return endOffset;
    3.45 +   }
    3.46 +
    3.47 +   @Override
    3.48 +   public int hashCode() {
    3.49 +      int hash = 7;
    3.50 +      hash = 13 * hash + this.getStartOffset();
    3.51 +      hash = 13 * hash + this.getEndOffset();
    3.52 +      return hash;
    3.53 +   }
    3.54 +
    3.55 +   @Override
    3.56 +   public boolean equals(Object obj) {
    3.57 +      if (obj == null) {
    3.58 +         return false;
    3.59 +      }
    3.60 +      if (getClass() != obj.getClass()) {
    3.61 +         return false;
    3.62 +      }
    3.63 +      final FoldSearchObject other = (FoldSearchObject) obj;
    3.64 +      if (this.getStartOffset() != other.getStartOffset()) {
    3.65 +         return false;
    3.66 +      }
    3.67 +      if (this.getEndOffset() != other.getEndOffset()) {
    3.68 +         return false;
    3.69 +      }
    3.70 +      return true;
    3.71 +   }
    3.72 +
    3.73 +   @Override
    3.74 +   public String toString() {
    3.75 +      return "FoldSearchObject{" + "startOffset=" + getStartOffset() + ", endOffset=" + getEndOffset() + '}';
    3.76 +   }
    3.77 +}
     4.1 --- a/PLSQL/Folding/src/org/netbeans/modules/plsql/fold/NewPlsqlFoldManager.java	Fri Mar 15 14:14:52 2013 +0100
     4.2 +++ b/PLSQL/Folding/src/org/netbeans/modules/plsql/fold/NewPlsqlFoldManager.java	Fri Mar 15 14:16:18 2013 +0100
     4.3 @@ -42,9 +42,7 @@
     4.4  package org.netbeans.modules.plsql.fold;
     4.5  
     4.6  import java.util.ArrayList;
     4.7 -import java.util.HashMap;
     4.8  import java.util.List;
     4.9 -import java.util.Map;
    4.10  import java.util.Observable;
    4.11  import java.util.Observer;
    4.12  import java.util.logging.Level;
    4.13 @@ -52,7 +50,6 @@
    4.14  import javax.swing.event.DocumentEvent;
    4.15  import javax.swing.text.BadLocationException;
    4.16  import javax.swing.text.Document;
    4.17 -import javax.swing.text.Position;
    4.18  import org.netbeans.api.editor.fold.Fold;
    4.19  import org.netbeans.api.editor.fold.FoldHierarchy;
    4.20  import org.netbeans.api.editor.fold.FoldType;
    4.21 @@ -74,17 +71,14 @@
    4.22  public class NewPlsqlFoldManager implements FoldManager, Runnable, Observer {
    4.23  
    4.24     private static final Logger LOG = Logger.getLogger(NewPlsqlFoldManager.class.getName());
    4.25 +   private static final RequestProcessor RP = new RequestProcessor(NewPlsqlFoldManager.class.getName(), 1, false, false);
    4.26 +   private static final int TASK_DELAY = 300;
    4.27 +   private final RequestProcessor.Task task = RP.create(this);
    4.28     private FoldOperation operation;
    4.29     private Document doc;
    4.30 -   // XXX replace with Map to be able to test if mark already exist before adding new fold.
    4.31 -//   private Map<Integer, FoldMarkInfo> markArray = new HashMap<Integer, FoldMarkInfo>();
    4.32 -   private org.netbeans.editor.GapObjectArray markArray = new org.netbeans.editor.GapObjectArray();
    4.33 -   private int minUpdateMarkOffset = Integer.MAX_VALUE;
    4.34 -   private int maxUpdateMarkOffset = -1;
    4.35 -   private List<Fold> removedFoldList;
    4.36 -   private Map<String, Boolean> customFoldId = new HashMap<String, Boolean>();
    4.37 -   private static final RequestProcessor RP = new RequestProcessor(NewPlsqlFoldManager.class.getName(), 1, false, false);
    4.38 -   private final RequestProcessor.Task task = RP.create(this);
    4.39 +   // Note: FoldSearchObject need to be in a List, otherwise contains doesn't work. Seems HashSet keeps internal list of hash.
    4.40 +   private final List<FoldSearchObject> foldSearchObjects = new ArrayList<FoldSearchObject>();
    4.41 +   private List<Fold> removedFoldList = new ArrayList<Fold>(3);
    4.42     private boolean initial = true;
    4.43     private PlsqlBlockFactory blockFactory;
    4.44  
    4.45 @@ -107,18 +101,23 @@
    4.46        if (blockFactory != null) {
    4.47           blockFactory.addObserver(this);
    4.48        }
    4.49 -      task.schedule(300);
    4.50 +      task.schedule(TASK_DELAY);
    4.51     }
    4.52  
    4.53     @Override
    4.54     public void insertUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
    4.55 +      if (LOG.isLoggable(Level.FINER)) {
    4.56 +         LOG.log(Level.FINER, "insertUpdate: {0}", System.identityHashCode(this));
    4.57 +      }
    4.58        processRemovedFolds(transaction);
    4.59     }
    4.60  
    4.61     @Override
    4.62     public void removeUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
    4.63 +      if (LOG.isLoggable(Level.FINER)) {
    4.64 +         LOG.log(Level.FINER, "removeUpdate: {0}", System.identityHashCode(this));
    4.65 +      }
    4.66        processRemovedFolds(transaction);
    4.67 -      removeAffectedMarks(evt, transaction);
    4.68     }
    4.69  
    4.70     @Override
    4.71 @@ -127,11 +126,17 @@
    4.72  
    4.73     @Override
    4.74     public void removeEmptyNotify(Fold emptyFold) {
    4.75 +      if (LOG.isLoggable(Level.FINER)) {
    4.76 +         LOG.log(Level.FINER, "removeEmptyNotify: {0}", System.identityHashCode(this));
    4.77 +      }
    4.78        removeFoldNotify(emptyFold);
    4.79     }
    4.80  
    4.81     @Override
    4.82     public void removeDamagedNotify(Fold damagedFold) {
    4.83 +      if (LOG.isLoggable(Level.FINER)) {
    4.84 +         LOG.log(Level.FINER, "removeDamagedNotify: {0}", System.identityHashCode(this));
    4.85 +      }
    4.86        removeFoldNotify(damagedFold);
    4.87     }
    4.88  
    4.89 @@ -142,13 +147,16 @@
    4.90     @Override
    4.91     public void release() {
    4.92        if (LOG.isLoggable(Level.FINE)) {
    4.93 -         LOG.log(Level.FINE, "Released: {0}", System.identityHashCode(this));
    4.94 +         LOG.log(Level.FINE, "release: {0}", System.identityHashCode(this));
    4.95        }
    4.96     }
    4.97  
    4.98     @Override
    4.99     public void update(Observable o, Object arg) {
   4.100 -      task.schedule(300);
   4.101 +      if (LOG.isLoggable(Level.FINER)) {
   4.102 +         LOG.log(Level.FINER, "update: {0}", System.identityHashCode(this));
   4.103 +      }
   4.104 +      task.schedule(TASK_DELAY);
   4.105     }
   4.106  
   4.107     @Override
   4.108 @@ -203,616 +211,114 @@
   4.109     }
   4.110  
   4.111     private void removeFoldNotify(Fold removedFold) {
   4.112 -      if (removedFoldList == null) {
   4.113 -         removedFoldList = new ArrayList<Fold>(3);
   4.114 -      }
   4.115        removedFoldList.add(removedFold);
   4.116     }
   4.117  
   4.118 -   private void removeAffectedMarks(DocumentEvent evt, FoldHierarchyTransaction transaction) {
   4.119 -      int removeOffset = evt.getOffset();
   4.120 -      int markIndex = findMarkIndex(removeOffset);
   4.121 -      if (markIndex < getMarkCount()) {
   4.122 -         FoldMarkInfo mark;
   4.123 -         while (markIndex >= 0 && (mark = getMark(markIndex)).getOffset() == removeOffset) {
   4.124 -            mark.release(false, transaction);
   4.125 -            removeMark(markIndex);
   4.126 -            markIndex--;
   4.127 +   private void processRemovedFolds(FoldHierarchyTransaction transaction) {
   4.128 +      for (Fold removedFold : removedFoldList) {
   4.129 +         boolean remove = foldSearchObjects.remove(new FoldSearchObject(new FoldAdapter(removedFold)));
   4.130 +         if (LOG.isLoggable(Level.FINE)) {
   4.131 +            LOG.log(Level.FINE, "Fold={0} removed={1}", new Object[]{removedFold, remove});
   4.132           }
   4.133        }
   4.134 -   }
   4.135 -
   4.136 -   private void processRemovedFolds(FoldHierarchyTransaction transaction) {
   4.137 -      if (removedFoldList != null) {
   4.138 -         for (int i = removedFoldList.size() - 1; i >= 0; i--) {
   4.139 -            Fold removedFold = removedFoldList.get(i);
   4.140 -            FoldMarkInfo startMark = (FoldMarkInfo) getOperation().getExtraInfo(removedFold);
   4.141 -            if (startMark.getId() != null) {
   4.142 -               customFoldId.put(startMark.getId(), Boolean.valueOf(removedFold.isCollapsed())); // remember the last fold's state before remove
   4.143 -            }
   4.144 -            FoldMarkInfo endMark = startMark.getPairMark(); // get prior releasing
   4.145 -            if (getOperation().isStartDamaged(removedFold)) { // start mark area was damaged
   4.146 -               startMark.release(true, transaction); // forced remove
   4.147 -            }
   4.148 -            if (getOperation().isEndDamaged(removedFold)) {
   4.149 -               endMark.release(true, transaction);
   4.150 -            }
   4.151 -         }
   4.152 -      }
   4.153 -      removedFoldList = null;
   4.154 -   }
   4.155 -
   4.156 -   private void markUpdate(FoldMarkInfo mark) {
   4.157 -      markUpdate(mark.getOffset());
   4.158 -   }
   4.159 -
   4.160 -   private void markUpdate(int offset) {
   4.161 -      if (offset < minUpdateMarkOffset) {
   4.162 -         minUpdateMarkOffset = offset;
   4.163 -      }
   4.164 -      if (offset > maxUpdateMarkOffset) {
   4.165 -         maxUpdateMarkOffset = offset;
   4.166 -      }
   4.167 -   }
   4.168 -
   4.169 -   private FoldMarkInfo getMark(int index) {
   4.170 -      return (FoldMarkInfo) markArray.getItem(index);
   4.171 -//      return markArray.get(index);
   4.172 -   }
   4.173 -
   4.174 -   private int getMarkCount() {
   4.175 -      return markArray.getItemCount();
   4.176 -//      return markArray.size();
   4.177 -   }
   4.178 -
   4.179 -   private void removeMark(int index) {
   4.180 -      if (LOG.isLoggable(Level.FINER)) {
   4.181 -         LOG.log(Level.FINER, "Removing mark from ind={0}: {1}", new Object[]{index, getMark(index)}); // NOI18N
   4.182 -      }
   4.183 -      markArray.remove(index, 1);
   4.184 -//      markArray.remove(index);
   4.185 -   }
   4.186 -
   4.187 -   private void insertMark(int index, FoldMarkInfo mark) {
   4.188 -//      markArray.put(index, mark);
   4.189 -      markArray.insertItem(index, mark);
   4.190 -      if (LOG.isLoggable(Level.FINER)) {
   4.191 -         LOG.log(Level.FINER, "Inserted mark at ind={0}: {1}", new Object[]{index, mark}); // NOI18N
   4.192 -      }
   4.193 -   }
   4.194 -
   4.195 -   private int findMarkIndex(int offset) {
   4.196 -      int markCount = getMarkCount();
   4.197 -      int low = 0;
   4.198 -      int high = markCount - 1;
   4.199 -
   4.200 -      while (low <= high) {
   4.201 -         int mid = (low + high) / 2;
   4.202 -         int midMarkOffset = getMark(mid).getOffset();
   4.203 -
   4.204 -         if (midMarkOffset < offset) {
   4.205 -            low = mid + 1;
   4.206 -         } else if (midMarkOffset > offset) {
   4.207 -            high = mid - 1;
   4.208 -         } else {
   4.209 -            // mark starting exactly at the given offset found
   4.210 -            // If multiple -> find the one with highest index
   4.211 -            mid++;
   4.212 -            while (mid < markCount && getMark(mid).getOffset() == offset) {
   4.213 -               mid++;
   4.214 -            }
   4.215 -            mid--;
   4.216 -            return mid;
   4.217 -         }
   4.218 -      }
   4.219 -      return low; // return higher index (e.g. for insert)
   4.220 -   }
   4.221 -
   4.222 -   private List<FoldMarkInfo> getMarkList(List<PlsqlBlock> blocks) {
   4.223 -      List<FoldMarkInfo> markList = new ArrayList<FoldMarkInfo>();
   4.224 -      try {
   4.225 -         scanBlocks(markList, blocks);
   4.226 -      } catch (BadLocationException e) {
   4.227 -         LOG.log(Level.WARNING, null, e);
   4.228 -      }
   4.229 -      return markList;
   4.230 -   }
   4.231 -
   4.232 -   private void processBlocks(List<PlsqlBlock> blocks, FoldHierarchyTransaction transaction) {
   4.233 -      List<FoldMarkInfo> markList = getMarkList(blocks);
   4.234 -      int markListSize;
   4.235 -      if (markList != null && ((markListSize = markList.size()) > 0)) {
   4.236 -         // Find the index for insertion
   4.237 -         int offset = (markList.get(0)).getOffset();
   4.238 -         int arrayMarkIndex = findMarkIndex(offset);
   4.239 -         // Remember the corresponding mark in the array as well
   4.240 -         FoldMarkInfo arrayMark;
   4.241 -         int arrayMarkOffset;
   4.242 -         if (arrayMarkIndex < getMarkCount()) {
   4.243 -            arrayMark = getMark(arrayMarkIndex);
   4.244 -            arrayMarkOffset = arrayMark.getOffset();
   4.245 -         } else { // at last mark
   4.246 -            arrayMark = null;
   4.247 -            arrayMarkOffset = Integer.MAX_VALUE;
   4.248 -         }
   4.249 -
   4.250 -         for (int i = 0; i < markListSize; i++) {
   4.251 -            FoldMarkInfo listMark = markList.get(i);
   4.252 -            int listMarkOffset = listMark.getOffset();
   4.253 -            if (i == 0 || i == markListSize - 1) {
   4.254 -               // Update the update-offsets by the first and last marks in the list
   4.255 -               markUpdate(listMarkOffset);
   4.256 -            }
   4.257 -            while (listMarkOffset >= arrayMarkOffset) {
   4.258 -               if (listMarkOffset == arrayMarkOffset) {
   4.259 -                  // At the same offset - likely the same mark
   4.260 -                  //   -> retain the collapsed state
   4.261 -                  listMark.setCollapsed(arrayMark.isCollapsed());
   4.262 -               }
   4.263 -               if (!arrayMark.isReleased()) { // make sure that the mark is released
   4.264 -                  arrayMark.release(false, transaction);
   4.265 -               }
   4.266 -               removeMark(arrayMarkIndex);
   4.267 -               if (LOG.isLoggable(Level.FINER)) {
   4.268 -                  LOG.log(Level.FINER, "Removed dup mark from ind={0}: {1}", new Object[]{arrayMarkIndex, arrayMark}); // NOI18N
   4.269 -               }
   4.270 -               if (arrayMarkIndex < getMarkCount()) {
   4.271 -                  arrayMark = getMark(arrayMarkIndex);
   4.272 -                  arrayMarkOffset = arrayMark.getOffset();
   4.273 -               } else { // no more marks
   4.274 -                  arrayMark = null;
   4.275 -                  arrayMarkOffset = Integer.MAX_VALUE;
   4.276 -               }
   4.277 -            }
   4.278 -            // Insert the listmark
   4.279 -            insertMark(arrayMarkIndex, listMark);
   4.280 -            if (LOG.isLoggable(Level.FINER)) {
   4.281 -               LOG.log(Level.FINER, "Inserted mark at ind={0}: {1}", new Object[]{arrayMarkIndex, listMark}); // NOI18N
   4.282 -            }
   4.283 -            arrayMarkIndex++;
   4.284 -         }
   4.285 -      }
   4.286 +      removedFoldList.clear();
   4.287     }
   4.288  
   4.289     private void updateFolds(List<PlsqlBlock> blocks, FoldHierarchyTransaction transaction) {
   4.290 -
   4.291 -      if (blocks != null && !blocks.isEmpty()) {
   4.292 -         processBlocks(blocks, transaction);
   4.293 -      }
   4.294 -
   4.295 -      if (maxUpdateMarkOffset == -1) { // no updates
   4.296 -         return;
   4.297 -      }
   4.298 -
   4.299 -      // Find the first mark to update and init the prevMark and parentMark prior the loop
   4.300 -      int index = findMarkIndex(minUpdateMarkOffset);
   4.301 -      FoldMarkInfo prevMark;
   4.302 -      FoldMarkInfo parentMark;
   4.303 -      if (index == 0) { // start from begining
   4.304 -         prevMark = null;
   4.305 -         parentMark = null;
   4.306 -      } else {
   4.307 -         prevMark = getMark(index - 1);
   4.308 -         parentMark = prevMark.getParentMark();
   4.309 -      }
   4.310 -
   4.311 -      // Iterate through the changed marks in the mark array 
   4.312 -      int markCount = getMarkCount();
   4.313 -      while (index < markCount) { // process the marks
   4.314 -         FoldMarkInfo mark = getMark(index);
   4.315 -
   4.316 -         // If the mark was released then it must be removed
   4.317 -         if (mark.isReleased()) {
   4.318 -            if (LOG.isLoggable(Level.FINE)) {
   4.319 -               LOG.log(Level.FINE, "Removing released mark at ind={0}: {1}", new Object[]{index, mark}); // NOI18N
   4.320 -            }
   4.321 -            removeMark(index);
   4.322 -            markCount--;
   4.323 -            continue;
   4.324 -         }
   4.325 -
   4.326 -         // Update mark's status (folds, parentMark etc.)
   4.327 -         if (mark.isStartMark()) { // starting a new fold
   4.328 -            if (prevMark == null || prevMark.isStartMark()) { // new level
   4.329 -               mark.setParentMark(prevMark); // prevMark == null means root level
   4.330 -               parentMark = prevMark;
   4.331 -
   4.332 -            } // same level => parent to the parent of the prevMark
   4.333 -
   4.334 -         } else { // end mark
   4.335 -            if (prevMark != null) {
   4.336 -               if (prevMark.isStartMark()) { // closing nearest fold
   4.337 -                  prevMark.setEndMark(mark, false, transaction);
   4.338 -
   4.339 -               } else { // prevMark is end mark - closing its parent fold
   4.340 -                  if (parentMark != null) {
   4.341 -                     // mark's parent gets set as well
   4.342 -                     parentMark.setEndMark(mark, false, transaction);
   4.343 -                     parentMark = parentMark.getParentMark();
   4.344 -
   4.345 -                  } else { // prevMark's parentMark is null (top level)
   4.346 -                     mark.makeSolitaire(false, transaction);
   4.347 -                  }
   4.348 -               }
   4.349 -
   4.350 -            } else { // prevMark is null
   4.351 -               mark.makeSolitaire(false, transaction);
   4.352 -            }
   4.353 -         }
   4.354 -
   4.355 -         // Set parent mark of the mark
   4.356 -         mark.setParentMark(parentMark);
   4.357 -
   4.358 -
   4.359 -         prevMark = mark;
   4.360 -         index++;
   4.361 -      }
   4.362 -
   4.363 -      minUpdateMarkOffset = Integer.MAX_VALUE;
   4.364 -      maxUpdateMarkOffset = -1;
   4.365 -
   4.366 -      if (LOG.isLoggable(Level.FINEST)) {
   4.367 -         LOG.log(Level.FINEST, "MARKS DUMP:\n{0}", this); //NOI18N
   4.368 -      }
   4.369 -   }
   4.370 -
   4.371 -   public @Override
   4.372 -   String toString() {
   4.373 -      StringBuffer sb = new StringBuffer();
   4.374 -      int markCount = getMarkCount();
   4.375 -      int markCountDigitCount = Integer.toString(markCount).length();
   4.376 -      for (int i = 0; i < markCount; i++) {
   4.377 -         sb.append("["); // NOI18N
   4.378 -         String iStr = Integer.toString(i);
   4.379 -         appendSpaces(sb, markCountDigitCount - iStr.length());
   4.380 -         sb.append(iStr);
   4.381 -         sb.append("]:"); // NOI18N
   4.382 -         FoldMarkInfo mark = getMark(i);
   4.383 -
   4.384 -         // Add extra indent regarding the depth in hierarchy
   4.385 -         int indent = 0;
   4.386 -         FoldMarkInfo parentMark = mark.getParentMark();
   4.387 -         while (parentMark != null) {
   4.388 -            indent += 4;
   4.389 -            parentMark = parentMark.getParentMark();
   4.390 -         }
   4.391 -         appendSpaces(sb, indent);
   4.392 -
   4.393 -         sb.append(mark);
   4.394 -         sb.append('\n');
   4.395 -      }
   4.396 -      return sb.toString();
   4.397 -   }
   4.398 -
   4.399 -   private static void appendSpaces(StringBuffer sb, int spaces) {
   4.400 -      while (--spaces >= 0) {
   4.401 -         sb.append(' ');
   4.402 -      }
   4.403 -   }
   4.404 -
   4.405 -   private void scanBlocks(List<FoldMarkInfo> list, List<PlsqlBlock> blocks) throws BadLocationException {
   4.406        for (PlsqlBlock block : blocks) {
   4.407  
   4.408           FoldType foldType = null;
   4.409           final PlsqlBlockType type = block.getType();
   4.410           String description = null;
   4.411 +         try {
   4.412 +            if (!(type == PlsqlBlockType.COMMENT && doc.getText(block.getStartOffset(), block.getEndOffset() - block.getStartOffset()).indexOf("\n") == -1)) { // check for single line comments
   4.413 +               if (type == PlsqlBlockType.VIEW) {
   4.414 +                  foldType = PlsqlFoldTypes.VIEW;
   4.415 +                  description = block.getPrefix() + "VIEW " + block.getName();
   4.416 +               } else if (type == PlsqlBlockType.TABLE_COMMENT) {
   4.417 +                  foldType = PlsqlFoldTypes.TABLECOMMENT;
   4.418 +                  description = "COMMENT ON TABLE " + block.getName();
   4.419 +               } else if (type == PlsqlBlockType.COLUMN_COMMENT) {
   4.420 +                  foldType = PlsqlFoldTypes.COLUMNCOMMENT;
   4.421 +                  description = "COLUMN COMMENTS ON TABLE " + block.getName();
   4.422 +               } else if (type == PlsqlBlockType.COMMENT) {
   4.423 +                  foldType = PlsqlFoldTypes.COMMENT;
   4.424 +                  description = block.getName();
   4.425 +               } else if (type == PlsqlBlockType.PACKAGE) {
   4.426 +                  foldType = PlsqlFoldTypes.PACKAGE;
   4.427 +                  description = block.getPrefix() + "PACKAGE " + block.getName();
   4.428 +               } else if (type == PlsqlBlockType.PACKAGE_BODY) {
   4.429 +                  foldType = PlsqlFoldTypes.PACKAGEBODY;
   4.430 +                  description = block.getPrefix() + "PACKAGE BODY " + block.getName();
   4.431 +               } else if (type == PlsqlBlockType.PROCEDURE_IMPL) {
   4.432 +                  foldType = PlsqlFoldTypes.PROCEDUREIMPL;
   4.433 +                  description = block.getPrefix() + "PROCEDURE IMPLEMENTATION " + block.getName();
   4.434 +               } else if (type == PlsqlBlockType.FUNCTION_IMPL) {
   4.435 +                  foldType = PlsqlFoldTypes.FUNCTIONIMPL;
   4.436 +                  description = block.getPrefix() + "FUNCTION IMPLEMENTATION " + block.getName();
   4.437 +               } else if (type == PlsqlBlockType.PROCEDURE_DEF) {
   4.438 +                  foldType = PlsqlFoldTypes.PROCEDUREDEF;
   4.439 +                  description = "PROCEDURE DEFINITION " + block.getName();
   4.440 +               } else if (type == PlsqlBlockType.FUNCTION_DEF) {
   4.441 +                  foldType = PlsqlFoldTypes.FUNCTIONDEF;
   4.442 +                  description = "FUNCTION DEFINITION " + block.getName();
   4.443 +               } else if (type == PlsqlBlockType.DECLARE_END) {
   4.444 +                  foldType = PlsqlFoldTypes.DECLAREEND;
   4.445 +                  description = "DECLARE BLOCK";
   4.446 +               } else if (type == PlsqlBlockType.BEGIN_END) {
   4.447 +                  foldType = PlsqlFoldTypes.BEGINEND;
   4.448 +                  description = "BEGIN BLOCK";
   4.449 +               } else if (type == PlsqlBlockType.TRIGGER) {
   4.450 +                  foldType = PlsqlFoldTypes.TRIGGER;
   4.451 +                  description = block.getPrefix() + "TRIGGER " + block.getName();
   4.452 +               } else if (type == PlsqlBlockType.IF) {
   4.453 +                  foldType = PlsqlFoldTypes.IF;
   4.454 +                  description = block.getName();
   4.455 +               } else if (type == PlsqlBlockType.CASE) {
   4.456 +                  foldType = PlsqlFoldTypes.CASE;
   4.457 +                  description = block.getName();
   4.458 +               } else if (type == PlsqlBlockType.WHILE_LOOP) {
   4.459 +                  foldType = PlsqlFoldTypes.WHILELOOP;
   4.460 +                  description = "WHILE " + block.getName();
   4.461 +               } else if (type == PlsqlBlockType.FOR_LOOP) {
   4.462 +                  foldType = PlsqlFoldTypes.FORLOOP;
   4.463 +                  description = "FOR " + block.getName();
   4.464 +               } else if (type == PlsqlBlockType.LOOP) {
   4.465 +                  foldType = PlsqlFoldTypes.LOOP;
   4.466 +                  description = "LOOP ";
   4.467 +               } else if (type == PlsqlBlockType.CUSTOM_FOLD) {
   4.468 +                  foldType = PlsqlFoldTypes.CUSTOM;
   4.469 +                  description = block.getName();
   4.470 +               } else if (type == PlsqlBlockType.STATEMENT) {
   4.471 +                  foldType = PlsqlFoldTypes.STATEMENT;
   4.472 +                  description = block.getPrefix() + block.getName();
   4.473 +               } else if (type == PlsqlBlockType.CURSOR) {
   4.474 +                  foldType = PlsqlFoldTypes.CURSOR;
   4.475 +                  description = "CURSOR " + block.getName();
   4.476 +               } else if (type == PlsqlBlockType.JAVA_SOURCE) {
   4.477 +                  foldType = PlsqlFoldTypes.JAVASOURCE;
   4.478 +                  description = block.getPrefix() + "JAVA SOURCE";
   4.479 +               }
   4.480  
   4.481 -         if (!(type == PlsqlBlockType.COMMENT && doc.getText(block.getStartOffset(), block.getEndOffset() - block.getStartOffset()).indexOf("\n") == -1)) { // check for single line comments
   4.482 -            if (type == PlsqlBlockType.VIEW) {
   4.483 -               foldType = PlsqlFoldTypes.VIEW;
   4.484 -               description = block.getPrefix() + "VIEW " + block.getName();
   4.485 -            } else if (type == PlsqlBlockType.TABLE_COMMENT) {
   4.486 -               foldType = PlsqlFoldTypes.TABLECOMMENT;
   4.487 -               description = "COMMENT ON TABLE " + block.getName();
   4.488 -            } else if (type == PlsqlBlockType.COLUMN_COMMENT) {
   4.489 -               foldType = PlsqlFoldTypes.COLUMNCOMMENT;
   4.490 -               description = "COLUMN COMMENTS ON TABLE " + block.getName();
   4.491 -            } else if (type == PlsqlBlockType.COMMENT) {
   4.492 -               foldType = PlsqlFoldTypes.COMMENT;
   4.493 -               description = block.getName();
   4.494 -            } else if (type == PlsqlBlockType.PACKAGE) {
   4.495 -               foldType = PlsqlFoldTypes.PACKAGE;
   4.496 -               description = block.getPrefix() + "PACKAGE " + block.getName();
   4.497 -            } else if (type == PlsqlBlockType.PACKAGE_BODY) {
   4.498 -               foldType = PlsqlFoldTypes.PACKAGEBODY;
   4.499 -               description = block.getPrefix() + "PACKAGE BODY " + block.getName();
   4.500 -            } else if (type == PlsqlBlockType.PROCEDURE_IMPL) {
   4.501 -               foldType = PlsqlFoldTypes.PROCEDUREIMPL;
   4.502 -               description = block.getPrefix() + "PROCEDURE IMPLEMENTATION " + block.getName();
   4.503 -            } else if (type == PlsqlBlockType.FUNCTION_IMPL) {
   4.504 -               foldType = PlsqlFoldTypes.FUNCTIONIMPL;
   4.505 -               description = block.getPrefix() + "FUNCTION IMPLEMENTATION " + block.getName();
   4.506 -            } else if (type == PlsqlBlockType.PROCEDURE_DEF) {
   4.507 -               foldType = PlsqlFoldTypes.PROCEDUREDEF;
   4.508 -               description = "PROCEDURE DEFINITION " + block.getName();
   4.509 -            } else if (type == PlsqlBlockType.FUNCTION_DEF) {
   4.510 -               foldType = PlsqlFoldTypes.FUNCTIONDEF;
   4.511 -               description = "FUNCTION DEFINITION " + block.getName();
   4.512 -            } else if (type == PlsqlBlockType.DECLARE_END) {
   4.513 -               foldType = PlsqlFoldTypes.DECLAREEND;
   4.514 -               description = "DECLARE BLOCK";
   4.515 -            } else if (type == PlsqlBlockType.BEGIN_END) {
   4.516 -               foldType = PlsqlFoldTypes.BEGINEND;
   4.517 -               description = "BEGIN BLOCK";
   4.518 -            } else if (type == PlsqlBlockType.TRIGGER) {
   4.519 -               foldType = PlsqlFoldTypes.TRIGGER;
   4.520 -               description = block.getPrefix() + "TRIGGER " + block.getName();
   4.521 -            } else if (type == PlsqlBlockType.IF) {
   4.522 -               foldType = PlsqlFoldTypes.IF;
   4.523 -               description = block.getName();
   4.524 -            } else if (type == PlsqlBlockType.CASE) {
   4.525 -               foldType = PlsqlFoldTypes.CASE;
   4.526 -               description = block.getName();
   4.527 -            } else if (type == PlsqlBlockType.WHILE_LOOP) {
   4.528 -               foldType = PlsqlFoldTypes.WHILELOOP;
   4.529 -               description = "WHILE " + block.getName();
   4.530 -            } else if (type == PlsqlBlockType.FOR_LOOP) {
   4.531 -               foldType = PlsqlFoldTypes.FORLOOP;
   4.532 -               description = "FOR " + block.getName();
   4.533 -            } else if (type == PlsqlBlockType.LOOP) {
   4.534 -               foldType = PlsqlFoldTypes.LOOP;
   4.535 -               description = "LOOP ";
   4.536 -            } else if (type == PlsqlBlockType.CUSTOM_FOLD) {
   4.537 -               foldType = PlsqlFoldTypes.CUSTOM;
   4.538 -               description = block.getName();
   4.539 -            } else if (type == PlsqlBlockType.STATEMENT) {
   4.540 -               foldType = PlsqlFoldTypes.STATEMENT;
   4.541 -               description = block.getPrefix() + block.getName();
   4.542 -            } else if (type == PlsqlBlockType.CURSOR) {
   4.543 -               foldType = PlsqlFoldTypes.CURSOR;
   4.544 -               description = "CURSOR " + block.getName();
   4.545 -            } else if (type == PlsqlBlockType.JAVA_SOURCE) {
   4.546 -               foldType = PlsqlFoldTypes.JAVASOURCE;
   4.547 -               description = block.getPrefix() + "JAVA SOURCE";
   4.548 +               final FoldSearchObject foldSearchObject = new FoldSearchObject(block.getStartOffset(), block.getEndOffset());
   4.549 +               if (!foldSearchObjects.contains(foldSearchObject)) {
   4.550 +                  try {
   4.551 +                     final Fold fold = operation.addToHierarchy(foldType, description, isCollapsed(foldType), block.getStartOffset(), block.getEndOffset(), 0, 0, null, transaction);
   4.552 +                     foldSearchObjects.add(new FoldSearchObject(new FoldAdapter(fold)));
   4.553 +                  } catch (BadLocationException ex) {
   4.554 +                     if (LOG.isLoggable(Level.FINE)) {
   4.555 +                        LOG.log(Level.FINE, "Ignore BadLocationException", ex);
   4.556 +                     }
   4.557 +                  }
   4.558 +               }
   4.559 +               updateFolds(block.getChildBlocks(), transaction);
   4.560              }
   4.561 -            //XXX: find out what offsets are needed (check CustomFoldManager when .php is run):
   4.562 -            final FoldMarkInfo foldMarkInfo = new FoldMarkInfo(foldType, true, block.getStartOffset(), 0, block.getName(), isCollapsed(foldType), description);
   4.563 -            // XXX: check if mark exist
   4.564 -            list.add(foldMarkInfo);
   4.565 -            list.add(new FoldMarkInfo(foldType, false, block.getEndOffset(), 0, null, false, null));
   4.566 -            scanBlocks(list, block.getChildBlocks());
   4.567 -         }
   4.568 -      }
   4.569 -   }
   4.570 -
   4.571 -   private final class FoldMarkInfo {
   4.572 -
   4.573 -      private boolean startMark;
   4.574 -      private Position pos;
   4.575 -      private int length;
   4.576 -      private String id;
   4.577 -      private boolean collapsed;
   4.578 -      private String description;
   4.579 -      /**
   4.580 -       * Matching pair mark used for fold construction
   4.581 -       */
   4.582 -      private FoldMarkInfo pairMark;
   4.583 -      /**
   4.584 -       * Parent mark defining nesting in the mark hierarchy.
   4.585 -       */
   4.586 -      private FoldMarkInfo parentMark;
   4.587 -      /**
   4.588 -       * Fold that corresponds to this mark (if it's start mark). It can be null if this mark is end mark or if it
   4.589 -       * currently does not have the fold assigned.
   4.590 -       */
   4.591 -      private Fold fold;
   4.592 -      private boolean released;
   4.593 -      private final FoldType foldType;
   4.594 -
   4.595 -      private FoldMarkInfo(FoldType foldType, boolean startMark, int offset,
   4.596 -              int length, String id, boolean collapsed, String description)
   4.597 -              throws BadLocationException {
   4.598 -         this.foldType = foldType;
   4.599 -         this.startMark = startMark;
   4.600 -         this.pos = doc.createPosition(offset);
   4.601 -         this.length = length;
   4.602 -         this.id = id;
   4.603 -         this.collapsed = collapsed;
   4.604 -         this.description = description;
   4.605 -      }
   4.606 -
   4.607 -      public String getId() {
   4.608 -         return id;
   4.609 -      }
   4.610 -
   4.611 -      public String getDescription() {
   4.612 -         return description;
   4.613 -      }
   4.614 -
   4.615 -      public boolean isStartMark() {
   4.616 -         return startMark;
   4.617 -      }
   4.618 -
   4.619 -      public int getLength() {
   4.620 -         return length;
   4.621 -      }
   4.622 -
   4.623 -      public int getOffset() {
   4.624 -         return pos.getOffset();
   4.625 -      }
   4.626 -
   4.627 -      public int getEndOffset() {
   4.628 -         return getOffset() + getLength();
   4.629 -      }
   4.630 -
   4.631 -      public boolean isCollapsed() {
   4.632 -         return (fold != null) ? fold.isCollapsed() : collapsed;
   4.633 -      }
   4.634 -
   4.635 -      public boolean hasFold() {
   4.636 -         return (fold != null);
   4.637 -      }
   4.638 -
   4.639 -      public void setCollapsed(boolean collapsed) {
   4.640 -         this.collapsed = collapsed;
   4.641 -      }
   4.642 -
   4.643 -      public boolean isSolitaire() {
   4.644 -         return (pairMark == null);
   4.645 -      }
   4.646 -
   4.647 -      public void makeSolitaire(boolean forced, FoldHierarchyTransaction transaction) {
   4.648 -         if (!isSolitaire()) {
   4.649 -            if (isStartMark()) {
   4.650 -               setEndMark(null, forced, transaction);
   4.651 -            } else { // end mark
   4.652 -               getPairMark().setEndMark(null, forced, transaction);
   4.653 +         } catch (BadLocationException ex) {
   4.654 +            if (LOG.isLoggable(Level.FINE)) {
   4.655 +               LOG.log(Level.FINE, "Ignore BadLocationException", ex);
   4.656              }
   4.657           }
   4.658        }
   4.659 -
   4.660 -      public boolean isReleased() {
   4.661 -         return released;
   4.662 -      }
   4.663 -
   4.664 -      /**
   4.665 -       * Release this mark and mark for update.
   4.666 -       */
   4.667 -      public void release(boolean forced, FoldHierarchyTransaction transaction) {
   4.668 -         if (!released) {
   4.669 -            makeSolitaire(forced, transaction);
   4.670 -            released = true;
   4.671 -            markUpdate(this);
   4.672 -         }
   4.673 -      }
   4.674 -
   4.675 -      public FoldMarkInfo getPairMark() {
   4.676 -         return pairMark;
   4.677 -      }
   4.678 -
   4.679 -      private void setPairMark(FoldMarkInfo pairMark) {
   4.680 -         this.pairMark = pairMark;
   4.681 -      }
   4.682 -
   4.683 -      public void setEndMark(FoldMarkInfo endMark, boolean forced,
   4.684 -              FoldHierarchyTransaction transaction) {
   4.685 -         if (!isStartMark()) {
   4.686 -            throw new IllegalStateException("Not start mark"); // NOI18N
   4.687 -         }
   4.688 -         if (pairMark == endMark) {
   4.689 -            return;
   4.690 -         }
   4.691 -
   4.692 -         if (pairMark != null) { // is currently paired to an end mark
   4.693 -            releaseFold(forced, transaction);
   4.694 -            pairMark.setPairMark(null);
   4.695 -         }
   4.696 -
   4.697 -         pairMark = endMark;
   4.698 -         if (endMark != null) {
   4.699 -            if (!endMark.isSolitaire()) { // make solitaire first
   4.700 -               endMark.makeSolitaire(false, transaction); // not forced here
   4.701 -            }
   4.702 -            endMark.setPairMark(this);
   4.703 -            endMark.setParentMark(this.getParentMark());
   4.704 -            ensureFoldExists(transaction);
   4.705 -         }
   4.706 -      }
   4.707 -
   4.708 -      public FoldMarkInfo getParentMark() {
   4.709 -         return parentMark;
   4.710 -      }
   4.711 -
   4.712 -      public void setParentMark(FoldMarkInfo parentMark) {
   4.713 -         this.parentMark = parentMark;
   4.714 -      }
   4.715 -
   4.716 -      private void releaseFold(boolean forced, FoldHierarchyTransaction transaction) {
   4.717 -         if (isSolitaire() || !isStartMark()) {
   4.718 -            throw new IllegalStateException();
   4.719 -         }
   4.720 -
   4.721 -         if (fold != null) {
   4.722 -            setCollapsed(fold.isCollapsed()); // serialize the collapsed info
   4.723 -            if (!forced) {
   4.724 -               getOperation().removeFromHierarchy(fold, transaction);
   4.725 -            }
   4.726 -            fold = null;
   4.727 -         }
   4.728 -      }
   4.729 -
   4.730 -      public Fold getFold() {
   4.731 -         if (isSolitaire()) {
   4.732 -            return null;
   4.733 -         }
   4.734 -         if (!isStartMark()) {
   4.735 -            return pairMark.getFold();
   4.736 -         }
   4.737 -         return fold;
   4.738 -      }
   4.739 -
   4.740 -      public void ensureFoldExists(FoldHierarchyTransaction transaction) {
   4.741 -         if (isSolitaire() || !isStartMark()) {
   4.742 -            throw new IllegalStateException();
   4.743 -         }
   4.744 -
   4.745 -         if (fold == null) {
   4.746 -            try {
   4.747 -               if (!startMark) {
   4.748 -                  throw new IllegalStateException("Not start mark: " + this); // NOI18N
   4.749 -               }
   4.750 -               if (pairMark == null) {
   4.751 -                  throw new IllegalStateException("No pairMark for mark:" + this); // NOI18N
   4.752 -               }
   4.753 -               int startOffset = getOffset();
   4.754 -               int startGuardedLength = getLength();
   4.755 -               int endGuardedLength = pairMark.getLength();
   4.756 -               int endOffset = pairMark.getOffset() + endGuardedLength;
   4.757 -               // XXX: check if Fold exist before adding
   4.758 -               fold = getOperation().addToHierarchy(
   4.759 -                       foldType, getDescription(), collapsed,
   4.760 -                       startOffset, endOffset,
   4.761 -                       startGuardedLength, endGuardedLength,
   4.762 -                       this,
   4.763 -                       transaction);
   4.764 -            } catch (BadLocationException e) {
   4.765 -               LOG.log(Level.WARNING, null, e);
   4.766 -            }
   4.767 -         }
   4.768 -      }
   4.769 -
   4.770 -      @Override
   4.771 -      public String toString() {
   4.772 -         StringBuilder sb = new StringBuilder();
   4.773 -         sb.append(isStartMark() ? 'S' : 'E');  // NOI18N
   4.774 -
   4.775 -         // Check whether this mark (or its pair) has fold
   4.776 -         if (hasFold() || (!isSolitaire() && getPairMark().hasFold())) {
   4.777 -            sb.append("F"); // NOI18N
   4.778 -
   4.779 -            // Check fold's status
   4.780 -            if (isStartMark() && (isSolitaire()
   4.781 -                    || getOffset() != fold.getStartOffset()
   4.782 -                    || getPairMark().getEndOffset() != fold.getEndOffset())) {
   4.783 -               sb.append("!!<"); // NOI18N
   4.784 -               sb.append(fold.getStartOffset());
   4.785 -               sb.append(","); // NOI18N
   4.786 -               sb.append(fold.getEndOffset());
   4.787 -               sb.append(">!!"); // NOI18N
   4.788 -            }
   4.789 -         }
   4.790 -
   4.791 -         // Append mark's internal status
   4.792 -         sb.append(" ("); // NOI18N
   4.793 -         sb.append("o="); // NOI18N
   4.794 -         sb.append(pos.getOffset());
   4.795 -         sb.append(", l="); // NOI18N
   4.796 -         sb.append(length);
   4.797 -         sb.append(", d='"); // NOI18N
   4.798 -         sb.append(description);
   4.799 -         sb.append('\'');
   4.800 -         if (getPairMark() != null) {
   4.801 -            sb.append(", <->"); // NOI18N
   4.802 -            sb.append(getPairMark().getOffset());
   4.803 -         }
   4.804 -         if (getParentMark() != null) {
   4.805 -            sb.append(", ^"); // NOI18N
   4.806 -            sb.append(getParentMark().getOffset());
   4.807 -         }
   4.808 -         sb.append(')');
   4.809 -
   4.810 -         return sb.toString();
   4.811 -      }
   4.812     }
   4.813  
   4.814     /**
     5.1 --- a/PLSQL/Folding/src/org/netbeans/modules/plsql/fold/PlsqlFoldManagerFactory.java	Fri Mar 15 14:14:52 2013 +0100
     5.2 +++ b/PLSQL/Folding/src/org/netbeans/modules/plsql/fold/PlsqlFoldManagerFactory.java	Fri Mar 15 14:16:18 2013 +0100
     5.3 @@ -60,6 +60,9 @@
     5.4        if ("old".equals(property)) {
     5.5           return new PlsqlFoldManager();
     5.6        }
     5.7 +      if ("simple".equals(property)) {
     5.8 +         return new SimplePlsqlFoldManager();
     5.9 +      }
    5.10        return new NewPlsqlFoldManager();
    5.11     }
    5.12  }
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/PLSQL/Folding/src/org/netbeans/modules/plsql/fold/SimplePlsqlFoldManager.java	Fri Mar 15 14:16:18 2013 +0100
     6.3 @@ -0,0 +1,366 @@
     6.4 +/*
     6.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     6.6 + *
     6.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
     6.8 + *
     6.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    6.10 + * Other names may be trademarks of their respective owners.
    6.11 + *
    6.12 + * The contents of this file are subject to the terms of either the GNU
    6.13 + * General Public License Version 2 only ("GPL") or the Common
    6.14 + * Development and Distribution License("CDDL") (collectively, the
    6.15 + * "License"). You may not use this file except in compliance with the
    6.16 + * License. You can obtain a copy of the License at
    6.17 + * http://www.netbeans.org/cddl-gplv2.html
    6.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    6.19 + * specific language governing permissions and limitations under the
    6.20 + * License.  When distributing the software, include this License Header
    6.21 + * Notice in each file and include the License file at
    6.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    6.23 + * particular file as subject to the "Classpath" exception as provided
    6.24 + * by Oracle in the GPL Version 2 section of the License file that
    6.25 + * accompanied this code. If applicable, add the following below the
    6.26 + * License Header, with the fields enclosed by brackets [] replaced by
    6.27 + * your own identifying information:
    6.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    6.29 + *
    6.30 + * If you wish your version of this file to be governed by only the CDDL
    6.31 + * or only the GPL Version 2, indicate your decision by adding
    6.32 + * "[Contributor] elects to include this software in this distribution
    6.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    6.34 + * single choice of license, a recipient has the option to distribute
    6.35 + * your version of this file under either the CDDL, the GPL Version 2 or
    6.36 + * to extend the choice of license to its licensees as provided above.
    6.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    6.38 + * Version 2 license, then the option applies only if the new code is
    6.39 + * made subject to such option by the copyright holder.
    6.40 + *
    6.41 + * Contributor(s):
    6.42 + *
    6.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
    6.44 + */
    6.45 +package org.netbeans.modules.plsql.fold;
    6.46 +
    6.47 +import java.util.ArrayList;
    6.48 +import java.util.List;
    6.49 +import java.util.Observable;
    6.50 +import java.util.Observer;
    6.51 +import java.util.logging.Level;
    6.52 +import java.util.logging.Logger;
    6.53 +import javax.swing.event.DocumentEvent;
    6.54 +import javax.swing.text.BadLocationException;
    6.55 +import javax.swing.text.Document;
    6.56 +import org.netbeans.api.editor.fold.Fold;
    6.57 +import org.netbeans.api.editor.fold.FoldHierarchy;
    6.58 +import org.netbeans.api.editor.fold.FoldType;
    6.59 +import org.netbeans.api.editor.fold.FoldUtilities;
    6.60 +import org.netbeans.editor.BaseDocument;
    6.61 +import org.netbeans.modules.plsql.lexer.PlsqlBlock;
    6.62 +import org.netbeans.modules.plsql.lexer.PlsqlBlockFactory;
    6.63 +import org.netbeans.modules.plsql.lexer.PlsqlBlockType;
    6.64 +import org.netbeans.modules.plsqlsupport.options.OptionsUtilities;
    6.65 +import org.netbeans.spi.editor.fold.FoldHierarchyTransaction;
    6.66 +import org.netbeans.spi.editor.fold.FoldManager;
    6.67 +import org.netbeans.spi.editor.fold.FoldOperation;
    6.68 +import org.openide.util.Lookup;
    6.69 +import org.openide.util.RequestProcessor;
    6.70 +
    6.71 +/**
    6.72 + *
    6.73 + * @author chrlse
    6.74 + */
    6.75 +public class SimplePlsqlFoldManager implements FoldManager, Runnable, Observer {
    6.76 +
    6.77 +   private static final Logger LOG = Logger.getLogger(SimplePlsqlFoldManager.class.getName());
    6.78 +   private static final int TASK_DELAY = 500;
    6.79 +   private FoldOperation operation;
    6.80 +   private Document doc;
    6.81 +   private static final RequestProcessor RP = new RequestProcessor(SimplePlsqlFoldManager.class.getName(), 1, false, false);
    6.82 +   private final RequestProcessor.Task task = RP.create(this);
    6.83 +   private PlsqlBlockFactory blockFactory;
    6.84 +
    6.85 +   @Override
    6.86 +   public void init(FoldOperation operation) {
    6.87 +      this.operation = operation;
    6.88 +      if (LOG.isLoggable(Level.FINE)) {
    6.89 +         LOG.log(Level.FINE, "Initialized: {0}", System.identityHashCode(this));
    6.90 +      }
    6.91 +   }
    6.92 +
    6.93 +   private FoldOperation getOperation() {
    6.94 +      return operation;
    6.95 +   }
    6.96 +
    6.97 +   @Override
    6.98 +   public void initFolds(FoldHierarchyTransaction transaction) {
    6.99 +      doc = getOperation().getHierarchy().getComponent().getDocument();
   6.100 +      blockFactory = getBlockFactory();
   6.101 +      if (blockFactory != null) {
   6.102 +         blockFactory.addObserver(this);
   6.103 +      }
   6.104 +      task.schedule(TASK_DELAY);
   6.105 +   }
   6.106 +
   6.107 +   @Override
   6.108 +   public void insertUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
   6.109 +//      task.schedule(300);
   6.110 +//      processRemovedFolds(transaction);
   6.111 +      if (LOG.isLoggable(Level.FINE)) {
   6.112 +         LOG.log(Level.FINE, "insertUpdate: {0}", System.identityHashCode(this));
   6.113 +      }
   6.114 +   }
   6.115 +
   6.116 +   @Override
   6.117 +   public void removeUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
   6.118 +      if (LOG.isLoggable(Level.FINE)) {
   6.119 +         LOG.log(Level.FINE, "removeUpdate: {0}", System.identityHashCode(this));
   6.120 +      }
   6.121 +      task.schedule(TASK_DELAY);
   6.122 +//      processRemovedFolds(transaction);
   6.123 +//      removeAffectedMarks(evt, transaction);
   6.124 +   }
   6.125 +
   6.126 +   @Override
   6.127 +   public void changedUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
   6.128 +      if (LOG.isLoggable(Level.FINE)) {
   6.129 +         LOG.log(Level.FINE, "changedUpdate: {0}", System.identityHashCode(this));
   6.130 +      }
   6.131 +//      task.schedule(300);
   6.132 +   }
   6.133 +
   6.134 +   @Override
   6.135 +   public void removeEmptyNotify(Fold emptyFold) {
   6.136 +//      removeFoldNotify(emptyFold);
   6.137 +   }
   6.138 +
   6.139 +   @Override
   6.140 +   public void removeDamagedNotify(Fold damagedFold) {
   6.141 +//      removeFoldNotify(damagedFold);
   6.142 +   }
   6.143 +
   6.144 +   @Override
   6.145 +   public void expandNotify(Fold expandedFold) {
   6.146 +   }
   6.147 +
   6.148 +   @Override
   6.149 +   public void release() {
   6.150 +      if (LOG.isLoggable(Level.FINE)) {
   6.151 +         LOG.log(Level.FINE, "release: {0}", System.identityHashCode(this));
   6.152 +      }
   6.153 +   }
   6.154 +
   6.155 +   @Override
   6.156 +   public void update(Observable o, Object arg) {
   6.157 +      if (LOG.isLoggable(Level.FINE)) {
   6.158 +         LOG.log(Level.FINE, "update: {0}", System.identityHashCode(this));
   6.159 +      }
   6.160 +      task.schedule(TASK_DELAY);
   6.161 +   }
   6.162 +
   6.163 +   @Override
   6.164 +   public void run() {
   6.165 +      if (operation.isReleased()) {
   6.166 +         if (LOG.isLoggable(Level.FINE)) {
   6.167 +            LOG.log(Level.FINE, "Update skipped, already released: {0}", System.identityHashCode(this));
   6.168 +         }
   6.169 +         return;
   6.170 +      }
   6.171 +      ((BaseDocument) doc).readLock();
   6.172 +      try {
   6.173 +
   6.174 +         if (blockFactory != null) {
   6.175 +            FoldHierarchy hierarchy = getOperation().getHierarchy();
   6.176 +            hierarchy.lock();
   6.177 +            try {
   6.178 +               if (operation.isReleased()) {
   6.179 +                  if (LOG.isLoggable(Level.FINE)) {
   6.180 +                     LOG.log(Level.FINE, "Update skipped, already released: {0}", System.identityHashCode(this));
   6.181 +                  }
   6.182 +                  return;
   6.183 +               }
   6.184 +               if (LOG.isLoggable(Level.FINE)) {
   6.185 +                  LOG.log(Level.FINE, "Updating: {0}", System.identityHashCode(this));
   6.186 +                  LOG.log(Level.FINE, "blockFactory.getBlockHierarchy().size(): {0}", blockFactory.getBlockHierarchy().size());
   6.187 +                  LOG.log(Level.FINE, "blockFactory.getNewBlocks().size(): {0}", blockFactory.getNewBlocks().size());
   6.188 +                  LOG.log(Level.FINE, "blockFactory.getRemovedBlocks().size(): {0}", blockFactory.getRemovedBlocks().size());
   6.189 +               }
   6.190 +               FoldHierarchyTransaction transaction = getOperation().openTransaction();
   6.191 +               try {
   6.192 +                  //Add new blocks to the hierarchy
   6.193 +                  ArrayList<Fold> existingFolds = new ArrayList<Fold>();
   6.194 +                  collectExistingFolds(hierarchy.getRootFold(), existingFolds);
   6.195 +                  for (Fold f : existingFolds) {
   6.196 +                     getOperation().removeFromHierarchy(f, transaction);
   6.197 +                  }
   6.198 +                  List<PlsqlBlock> blocks = blockFactory.getBlockHierarchy();
   6.199 +                  createFolds(blocks, transaction);
   6.200 +               } finally {
   6.201 +                  transaction.commit();
   6.202 +               }
   6.203 +            } finally {
   6.204 +               hierarchy.unlock();
   6.205 +            }
   6.206 +         }
   6.207 +      } finally {
   6.208 +         ((BaseDocument) doc).readUnlock();
   6.209 +      }
   6.210 +   }
   6.211 +
   6.212 +   /**
   6.213 +    * Collects all folds from the hierarchy that were created by this manager and are not the root fold.
   6.214 +    *
   6.215 +    * @param fold
   6.216 +    * @param list
   6.217 +    */
   6.218 +   private void collectExistingFolds(Fold fold, List<Fold> list) {
   6.219 +      for (int i = 0; i < fold.getFoldCount(); i++) {
   6.220 +         collectExistingFolds(fold.getFold(i), list);
   6.221 +      }
   6.222 +      if (!FoldUtilities.isRootFold(fold) && getOperation().owns(fold)) {
   6.223 +         list.add(fold);
   6.224 +      }
   6.225 +   }
   6.226 +
   6.227 +   /**
   6.228 +    * Creates a new fold and adds to the fold hierarchy.
   6.229 +    */
   6.230 +//    private Fold createFold(FoldType type, String description, boolean collapsed,
   6.231 +//            int startOffset, int endOffset, FoldHierarchyTransaction transaction)
   6.232 +//                throws BadLocationException {
   6.233 +//        Fold fold = null;
   6.234 +//        if ( startOffset >= 0 &&
   6.235 +//             endOffset >= 0 &&
   6.236 +//             startOffset < endOffset &&
   6.237 +//             endOffset <= getDocument().getLength() ) {
   6.238 +//            fold = getOperation().addToHierarchy(
   6.239 +//                    type,
   6.240 +//                    description.intern(), //save some memory
   6.241 +//                    collapsed,
   6.242 +//                    startOffset,
   6.243 +//                    endOffset,
   6.244 +//                    description.length(),
   6.245 +//                    0,
   6.246 +//                    null,
   6.247 +//                    transaction);
   6.248 +//        }
   6.249 +//        return fold;
   6.250 +//    }
   6.251 +   private void createFolds(List<PlsqlBlock> blocks, FoldHierarchyTransaction transaction) {
   6.252 +      for (PlsqlBlock block : blocks) {
   6.253 +
   6.254 +         FoldType foldType = null;
   6.255 +         final PlsqlBlockType type = block.getType();
   6.256 +         String description = null;
   6.257 +         try {
   6.258 +            if (!(type == PlsqlBlockType.COMMENT && doc.getText(block.getStartOffset(), block.getEndOffset() - block.getStartOffset()).indexOf("\n") == -1)) { // check for single line comments
   6.259 +               if (type == PlsqlBlockType.VIEW) {
   6.260 +                  foldType = PlsqlFoldTypes.VIEW;
   6.261 +                  description = block.getPrefix() + "VIEW " + block.getName();
   6.262 +               } else if (type == PlsqlBlockType.TABLE_COMMENT) {
   6.263 +                  foldType = PlsqlFoldTypes.TABLECOMMENT;
   6.264 +                  description = "COMMENT ON TABLE " + block.getName();
   6.265 +               } else if (type == PlsqlBlockType.COLUMN_COMMENT) {
   6.266 +                  foldType = PlsqlFoldTypes.COLUMNCOMMENT;
   6.267 +                  description = "COLUMN COMMENTS ON TABLE " + block.getName();
   6.268 +               } else if (type == PlsqlBlockType.COMMENT) {
   6.269 +                  foldType = PlsqlFoldTypes.COMMENT;
   6.270 +                  description = block.getName();
   6.271 +               } else if (type == PlsqlBlockType.PACKAGE) {
   6.272 +                  foldType = PlsqlFoldTypes.PACKAGE;
   6.273 +                  description = block.getPrefix() + "PACKAGE " + block.getName();
   6.274 +               } else if (type == PlsqlBlockType.PACKAGE_BODY) {
   6.275 +                  foldType = PlsqlFoldTypes.PACKAGEBODY;
   6.276 +                  description = block.getPrefix() + "PACKAGE BODY " + block.getName();
   6.277 +               } else if (type == PlsqlBlockType.PROCEDURE_IMPL) {
   6.278 +                  foldType = PlsqlFoldTypes.PROCEDUREIMPL;
   6.279 +                  description = block.getPrefix() + "PROCEDURE IMPLEMENTATION " + block.getName();
   6.280 +               } else if (type == PlsqlBlockType.FUNCTION_IMPL) {
   6.281 +                  foldType = PlsqlFoldTypes.FUNCTIONIMPL;
   6.282 +                  description = block.getPrefix() + "FUNCTION IMPLEMENTATION " + block.getName();
   6.283 +               } else if (type == PlsqlBlockType.PROCEDURE_DEF) {
   6.284 +                  foldType = PlsqlFoldTypes.PROCEDUREDEF;
   6.285 +                  description = "PROCEDURE DEFINITION " + block.getName();
   6.286 +               } else if (type == PlsqlBlockType.FUNCTION_DEF) {
   6.287 +                  foldType = PlsqlFoldTypes.FUNCTIONDEF;
   6.288 +                  description = "FUNCTION DEFINITION " + block.getName();
   6.289 +               } else if (type == PlsqlBlockType.DECLARE_END) {
   6.290 +                  foldType = PlsqlFoldTypes.DECLAREEND;
   6.291 +                  description = "DECLARE BLOCK";
   6.292 +               } else if (type == PlsqlBlockType.BEGIN_END) {
   6.293 +                  foldType = PlsqlFoldTypes.BEGINEND;
   6.294 +                  description = "BEGIN BLOCK";
   6.295 +               } else if (type == PlsqlBlockType.TRIGGER) {
   6.296 +                  foldType = PlsqlFoldTypes.TRIGGER;
   6.297 +                  description = block.getPrefix() + "TRIGGER " + block.getName();
   6.298 +               } else if (type == PlsqlBlockType.IF) {
   6.299 +                  foldType = PlsqlFoldTypes.IF;
   6.300 +                  description = block.getName();
   6.301 +               } else if (type == PlsqlBlockType.CASE) {
   6.302 +                  foldType = PlsqlFoldTypes.CASE;
   6.303 +                  description = block.getName();
   6.304 +               } else if (type == PlsqlBlockType.WHILE_LOOP) {
   6.305 +                  foldType = PlsqlFoldTypes.WHILELOOP;
   6.306 +                  description = "WHILE " + block.getName();
   6.307 +               } else if (type == PlsqlBlockType.FOR_LOOP) {
   6.308 +                  foldType = PlsqlFoldTypes.FORLOOP;
   6.309 +                  description = "FOR " + block.getName();
   6.310 +               } else if (type == PlsqlBlockType.LOOP) {
   6.311 +                  foldType = PlsqlFoldTypes.LOOP;
   6.312 +                  description = "LOOP ";
   6.313 +               } else if (type == PlsqlBlockType.CUSTOM_FOLD) {
   6.314 +                  foldType = PlsqlFoldTypes.CUSTOM;
   6.315 +                  description = block.getName();
   6.316 +               } else if (type == PlsqlBlockType.STATEMENT) {
   6.317 +                  foldType = PlsqlFoldTypes.STATEMENT;
   6.318 +                  description = block.getPrefix() + block.getName();
   6.319 +               } else if (type == PlsqlBlockType.CURSOR) {
   6.320 +                  foldType = PlsqlFoldTypes.CURSOR;
   6.321 +                  description = "CURSOR " + block.getName();
   6.322 +               } else if (type == PlsqlBlockType.JAVA_SOURCE) {
   6.323 +                  foldType = PlsqlFoldTypes.JAVASOURCE;
   6.324 +                  description = block.getPrefix() + "JAVA SOURCE";
   6.325 +               }
   6.326 +               try {
   6.327 +                  operation.addToHierarchy(foldType, description, isCollapsed(foldType), block.getStartOffset(), block.getEndOffset(), 0, 0, null, transaction);
   6.328 +               } catch (BadLocationException ex) {
   6.329 +                  if (LOG.isLoggable(Level.FINE)) {
   6.330 +                     LOG.log(Level.FINE, "Ignore BadLocationException", ex);
   6.331 +                  }
   6.332 +               }
   6.333 +               createFolds(block.getChildBlocks(), transaction);
   6.334 +            }
   6.335 +         } catch (BadLocationException ex) {
   6.336 +            if (LOG.isLoggable(Level.FINE)) {
   6.337 +               LOG.log(Level.FINE, "Ignore BadLocationException", ex);
   6.338 +            }
   6.339 +         }
   6.340 +      }
   6.341 +   }
   6.342 +
   6.343 +   /**
   6.344 +    * Method that will select and return the corresponding fold to parent from oldRoot fold hierarchy
   6.345 +    *
   6.346 +    * @param parent
   6.347 +    * @param foldInfoLst
   6.348 +    * @return
   6.349 +    */
   6.350 +   private boolean isCollapsed(final FoldType foldType) {
   6.351 +      if (OptionsUtilities.isPlSqlExpandFolds()) {
   6.352 +         return false;
   6.353 +      }
   6.354 +      return foldType == PlsqlFoldTypes.COMMENT;
   6.355 +   }
   6.356 +
   6.357 +   /**
   6.358 +    * Method that will return the relevant block factory
   6.359 +    *
   6.360 +    * @return
   6.361 +    */
   6.362 +   private PlsqlBlockFactory getBlockFactory() {
   6.363 +      final Object obj = doc.getProperty(Document.StreamDescriptionProperty);
   6.364 +      if (obj instanceof Lookup.Provider) {
   6.365 +         return ((Lookup.Provider) obj).getLookup().lookup(PlsqlBlockFactory.class);
   6.366 +      }
   6.367 +      return null;
   6.368 +   }
   6.369 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/PLSQL/Folding/test/unit/src/org/netbeans/modules/plsql/fold/FoldSearchObjectTest.java	Fri Mar 15 14:16:18 2013 +0100
     7.3 @@ -0,0 +1,28 @@
     7.4 +/*
     7.5 + * To change this template, choose Tools | Templates
     7.6 + * and open the template in the editor.
     7.7 + */
     7.8 +package org.netbeans.modules.plsql.fold;
     7.9 +
    7.10 +import org.junit.Test;
    7.11 +import static org.junit.Assert.*;
    7.12 +import static org.mockito.Mockito.*;
    7.13 +
    7.14 +/**
    7.15 + *
    7.16 + * @author ChrLSE
    7.17 + */
    7.18 +public class FoldSearchObjectTest {
    7.19 +
    7.20 +   @Test
    7.21 +   public void shouldBeEqualWithAndWithoutBackingFoldObject() {
    7.22 +      int startOffset = 100;
    7.23 +      int endOffset = 200;
    7.24 +      FoldSearchObject searchObject1 = new FoldSearchObject(startOffset, endOffset);
    7.25 +      FoldAdapter fold = mock(FoldAdapter.class);
    7.26 +      FoldSearchObject searchObject2 = new FoldSearchObject(fold);
    7.27 +      when(fold.getStartOffset()).thenReturn(startOffset);
    7.28 +      when(fold.getEndOffset()).thenReturn(endOffset);
    7.29 +      assertEquals(searchObject1, searchObject2);
    7.30 +   }
    7.31 +}
    7.32 \ No newline at end of file