PLSQL/Folding/src/org/netbeans/modules/plsql/fold/NewPlsqlFoldManager.java
changeset 464 e10b2e8563fc
parent 362 9a549f0d1c97
     1.1 --- a/PLSQL/Folding/src/org/netbeans/modules/plsql/fold/NewPlsqlFoldManager.java	Mon Mar 18 15:49:13 2013 +0100
     1.2 +++ b/PLSQL/Folding/src/org/netbeans/modules/plsql/fold/NewPlsqlFoldManager.java	Mon Aug 12 11:26:54 2013 +0530
     1.3 @@ -42,12 +42,15 @@
     1.4  package org.netbeans.modules.plsql.fold;
     1.5  
     1.6  import java.util.ArrayList;
     1.7 +import java.util.Collections;
     1.8 +import java.util.Comparator;
     1.9  import java.util.List;
    1.10  import java.util.Observable;
    1.11  import java.util.Observer;
    1.12  import java.util.logging.Level;
    1.13  import java.util.logging.Logger;
    1.14  import javax.swing.event.DocumentEvent;
    1.15 +import javax.swing.text.AbstractDocument;
    1.16  import javax.swing.text.BadLocationException;
    1.17  import javax.swing.text.Document;
    1.18  import org.netbeans.api.editor.fold.Fold;
    1.19 @@ -61,6 +64,7 @@
    1.20  import org.netbeans.spi.editor.fold.FoldHierarchyTransaction;
    1.21  import org.netbeans.spi.editor.fold.FoldManager;
    1.22  import org.netbeans.spi.editor.fold.FoldOperation;
    1.23 +import org.openide.util.Exceptions;
    1.24  import org.openide.util.Lookup;
    1.25  import org.openide.util.RequestProcessor;
    1.26  
    1.27 @@ -70,281 +74,472 @@
    1.28   */
    1.29  public class NewPlsqlFoldManager implements FoldManager, Runnable, Observer {
    1.30  
    1.31 -   private static final Logger LOG = Logger.getLogger(NewPlsqlFoldManager.class.getName());
    1.32 -   private static final RequestProcessor RP = new RequestProcessor(NewPlsqlFoldManager.class.getName(), 1, false, false);
    1.33 -   private static final int TASK_DELAY = 1000;
    1.34 -   private final RequestProcessor.Task task = RP.create(this);
    1.35 -   private FoldOperation operation;
    1.36 -   private Document doc;
    1.37 -   // Note: FoldSearchObject need to be in a List, otherwise contains doesn't work. Seems HashSet keeps internal list of hash.
    1.38 -   private final List<FoldSearchObject> foldSearchObjects = new ArrayList<FoldSearchObject>();
    1.39 -   private List<Fold> removedFoldList = new ArrayList<Fold>(3);
    1.40 -   private boolean initial = true;
    1.41 -   private PlsqlBlockFactory blockFactory;
    1.42 +    private static final Logger LOG = Logger.getLogger(NewPlsqlFoldManager.class.getName());
    1.43 +    private static final RequestProcessor RP = new RequestProcessor(NewPlsqlFoldManager.class.getName(), 1, false, false);
    1.44 +    private static final int TASK_DELAY = 100;
    1.45 +    private final RequestProcessor.Task task = RP.create(this);
    1.46 +    private FoldOperation operation;
    1.47 +    private Document doc;
    1.48 +    // Note: FoldSearchObject need to be in a List, otherwise contains doesn't work. Seems HashSet keeps internal list of hash.
    1.49 +    private final List<FoldSearchObject> foldSearchObjects = new ArrayList<FoldSearchObject>();
    1.50 +    private List<Fold> removedFoldList = new ArrayList<Fold>(3);
    1.51 +    private boolean initial = true;
    1.52 +    private PlsqlBlockFactory blockFactory;
    1.53  
    1.54 -   @Override
    1.55 -   public void init(FoldOperation operation) {
    1.56 -      this.operation = operation;
    1.57 -      if (LOG.isLoggable(Level.FINE)) {
    1.58 -         LOG.log(Level.FINE, "Initialized: {0}", System.identityHashCode(this));
    1.59 -      }
    1.60 -   }
    1.61 +    @Override
    1.62 +    public void init(FoldOperation operation) {
    1.63 +        this.operation = operation;
    1.64 +        if (LOG.isLoggable(Level.FINE)) {
    1.65 +            LOG.log(Level.FINE, "Initialized: {0}", System.identityHashCode(this));
    1.66 +        }
    1.67 +    }
    1.68  
    1.69 -   private FoldOperation getOperation() {
    1.70 -      return operation;
    1.71 -   }
    1.72 +    private FoldOperation getOperation() {
    1.73 +        return operation;
    1.74 +    }
    1.75  
    1.76 -   @Override
    1.77 -   public void initFolds(FoldHierarchyTransaction transaction) {
    1.78 -      doc = getOperation().getHierarchy().getComponent().getDocument();
    1.79 -      blockFactory = getBlockFactory();
    1.80 -      if (blockFactory != null) {
    1.81 -         blockFactory.addObserver(this);
    1.82 -      }
    1.83 -      task.schedule(TASK_DELAY);
    1.84 -   }
    1.85 +    @Override
    1.86 +    public void initFolds(FoldHierarchyTransaction transaction) {
    1.87 +        doc = getOperation().getHierarchy().getComponent().getDocument();
    1.88 +        blockFactory = getBlockFactory();
    1.89 +        if (blockFactory != null) {
    1.90 +            blockFactory.addObserver(this);
    1.91 +        }
    1.92 +        task.schedule(TASK_DELAY);
    1.93 +    }
    1.94  
    1.95 -   @Override
    1.96 -   public void insertUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
    1.97 -      if (LOG.isLoggable(Level.FINER)) {
    1.98 -         LOG.log(Level.FINER, "insertUpdate: {0}", System.identityHashCode(this));
    1.99 -      }
   1.100 -      processRemovedFolds(transaction);
   1.101 -   }
   1.102 +    @Override
   1.103 +    public void insertUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
   1.104 +        if (LOG.isLoggable(Level.FINER)) {
   1.105 +            LOG.log(Level.FINER, "insertUpdate: {0}", System.identityHashCode(this));
   1.106 +        }
   1.107 +        processRemovedFolds(transaction);
   1.108 +    }
   1.109  
   1.110 -   @Override
   1.111 -   public void removeUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
   1.112 -      if (LOG.isLoggable(Level.FINER)) {
   1.113 -         LOG.log(Level.FINER, "removeUpdate: {0}", System.identityHashCode(this));
   1.114 -      }
   1.115 -      processRemovedFolds(transaction);
   1.116 -   }
   1.117 +    @Override
   1.118 +    public void removeUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
   1.119 +        if (LOG.isLoggable(Level.FINER)) {
   1.120 +            LOG.log(Level.FINER, "removeUpdate: {0}", System.identityHashCode(this));
   1.121 +        }
   1.122 +        processRemovedFolds(transaction);
   1.123 +    }
   1.124  
   1.125 -   @Override
   1.126 -   public void changedUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
   1.127 -   }
   1.128 +    @Override
   1.129 +    public void changedUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
   1.130 +        if (LOG.isLoggable(Level.FINER)) {
   1.131 +            LOG.log(Level.FINER, "changeUpdate: {0}", System.identityHashCode(this));
   1.132 +        }
   1.133 +        processRemovedFolds(transaction);
   1.134 +    }
   1.135  
   1.136 -   @Override
   1.137 -   public void removeEmptyNotify(Fold emptyFold) {
   1.138 -      if (LOG.isLoggable(Level.FINER)) {
   1.139 -         LOG.log(Level.FINER, "removeEmptyNotify: {0}", System.identityHashCode(this));
   1.140 -      }
   1.141 -      removeFoldNotify(emptyFold);
   1.142 -   }
   1.143 +    @Override
   1.144 +    public void removeEmptyNotify(Fold emptyFold) {
   1.145 +        if (LOG.isLoggable(Level.FINER)) {
   1.146 +            LOG.log(Level.FINER, "removeEmptyNotify: {0}", System.identityHashCode(this));
   1.147 +        }
   1.148 +        removeFoldNotify(emptyFold);
   1.149 +    }
   1.150  
   1.151 -   @Override
   1.152 -   public void removeDamagedNotify(Fold damagedFold) {
   1.153 -      if (LOG.isLoggable(Level.FINER)) {
   1.154 -         LOG.log(Level.FINER, "removeDamagedNotify: {0}", System.identityHashCode(this));
   1.155 -      }
   1.156 -      removeFoldNotify(damagedFold);
   1.157 -   }
   1.158 +    @Override
   1.159 +    public void removeDamagedNotify(Fold damagedFold) {
   1.160 +        if (LOG.isLoggable(Level.FINER)) {
   1.161 +            LOG.log(Level.FINER, "removeDamagedNotify: {0}", System.identityHashCode(this));
   1.162 +        }
   1.163 +        removeFoldNotify(damagedFold);
   1.164 +    }
   1.165  
   1.166 -   @Override
   1.167 -   public void expandNotify(Fold expandedFold) {
   1.168 -   }
   1.169 +    @Override
   1.170 +    public void expandNotify(Fold expandedFold) {
   1.171 +    }
   1.172  
   1.173 -   @Override
   1.174 -   public void release() {
   1.175 -      if (LOG.isLoggable(Level.FINE)) {
   1.176 -         LOG.log(Level.FINE, "release: {0}", System.identityHashCode(this));
   1.177 -      }
   1.178 -   }
   1.179 +    @Override
   1.180 +    public void release() {
   1.181 +        if (LOG.isLoggable(Level.FINE)) {
   1.182 +            LOG.log(Level.FINE, "release: {0}", System.identityHashCode(this));
   1.183 +        }
   1.184 +    }
   1.185  
   1.186 -   @Override
   1.187 -   public void update(Observable o, Object arg) {
   1.188 -      if (LOG.isLoggable(Level.FINER)) {
   1.189 -         LOG.log(Level.FINER, "update: {0}", System.identityHashCode(this));
   1.190 -      }
   1.191 -      task.schedule(TASK_DELAY);
   1.192 -   }
   1.193 +    @Override
   1.194 +    public void update(Observable o, Object arg) {
   1.195 +        if (LOG.isLoggable(Level.FINER)) {
   1.196 +            LOG.log(Level.FINER, "update: {0}", System.identityHashCode(this));
   1.197 +        }
   1.198 +        task.schedule(TASK_DELAY);
   1.199 +    }
   1.200  
   1.201 -   @Override
   1.202 -   public void run() {
   1.203 -      if (operation.isReleased()) {
   1.204 -         if (LOG.isLoggable(Level.FINE)) {
   1.205 -            LOG.log(Level.FINE, "Update skipped, already released: {0}", System.identityHashCode(this));
   1.206 -         }
   1.207 -         return;
   1.208 -      }
   1.209 -      ((BaseDocument) doc).readLock();
   1.210 -      try {
   1.211 +    @Override
   1.212 +    public void run() {
   1.213 +        if (operation.isReleased()) {
   1.214 +            if (LOG.isLoggable(Level.FINE)) {
   1.215 +                LOG.log(Level.FINE, "Update skipped, already released: {0}", System.identityHashCode(this));
   1.216 +            }
   1.217 +            return;
   1.218 +        }
   1.219 +        ((BaseDocument) doc).readLock();
   1.220 +        try {
   1.221 +            if (blockFactory != null) {
   1.222 +                FoldHierarchy hierarchy = getOperation().getHierarchy();
   1.223  
   1.224 -         if (blockFactory != null) {
   1.225 -            FoldHierarchy hierarchy = getOperation().getHierarchy();
   1.226 -            hierarchy.lock();
   1.227 +                hierarchy.lock();
   1.228 +                try {
   1.229 +                    if (operation.isReleased()) {
   1.230 +                        if (LOG.isLoggable(Level.FINE)) {
   1.231 +                            LOG.log(Level.FINE, "Update skipped, already released: {0}", System.identityHashCode(this));
   1.232 +                        }
   1.233 +                        return;
   1.234 +                    }
   1.235 +                    if (LOG.isLoggable(Level.FINE)) {
   1.236 +                        LOG.log(Level.FINE, "Updating: {0}", System.identityHashCode(this));
   1.237 +                        LOG.log(Level.FINE, "blockFactory.getBlockHierarchy().size(): {0}", blockFactory.getBlockHierarchy().size());
   1.238 +                        LOG.log(Level.FINE, "blockFactory.getNewBlocks().size(): {0}", blockFactory.getNewBlocks().size());
   1.239 +                        LOG.log(Level.FINE, "blockFactory.getRemovedBlocks().size(): {0}", blockFactory.getRemovedBlocks().size());
   1.240 +                    }
   1.241 +                    FoldHierarchyTransaction transaction = getOperation().openTransaction();
   1.242 +                    try {
   1.243 +
   1.244 +                        final Fold root = hierarchy.getRootFold();
   1.245 +
   1.246 +                        if (initial) {
   1.247 +                            List<PlsqlBlock> blocks = blockFactory.getBlockHierarchy();
   1.248 +                            updateFolds(blocks, transaction, null);
   1.249 +                            //Add custom fold blocks
   1.250 +                            updateFolds(blockFactory.getCustomFolds(), transaction, null);
   1.251 +                            initial = false;
   1.252 +                        } else {
   1.253 +                            final List<FoldSearchObject> collapsedFolds = new ArrayList<FoldSearchObject>();
   1.254 +                            getCollapsedFolds(root, collapsedFolds);
   1.255 +                            final List<PlsqlBlock> oldBlocks = blockFactory.getRemovedBlocks();
   1.256 +
   1.257 +                            //Remove non existing blocks   
   1.258 +                            if (!oldBlocks.isEmpty()) {
   1.259 +                                final int childCount = root.getFoldCount();
   1.260 +                                for (int i = (childCount - 1); i >= 0; i--) {
   1.261 +                                    final Fold child = root.getFold(i);
   1.262 +                                    removeWithChildren(child, oldBlocks, transaction);
   1.263 +                                }
   1.264 +                            }
   1.265 +                            //Add new blocks to the hierarchy
   1.266 +                            List<PlsqlBlock> blocks = blockFactory.getNewBlocks();
   1.267 +                            updateFolds(blocks, transaction, collapsedFolds);
   1.268 +                            //Add custom fold blocks
   1.269 +                            updateFolds(blockFactory.getCustomFolds(), transaction, collapsedFolds);
   1.270 +                        }
   1.271 +                    } catch (BadLocationException ex) {
   1.272 +                        Exceptions.printStackTrace(ex);
   1.273 +                    } finally {
   1.274 +                        transaction.commit();
   1.275 +                    }
   1.276 +                } finally {
   1.277 +                    hierarchy.unlock();
   1.278 +                }
   1.279 +            }
   1.280 +        } finally {
   1.281 +            ((BaseDocument) doc).readUnlock();
   1.282 +        }
   1.283 +    }
   1.284 +
   1.285 +    private void getCollapsedFolds(final Fold parent, final List<FoldSearchObject> foldInfoLst) {
   1.286 +        if (parent.isCollapsed()) {
   1.287 +            final FoldSearchObject tempInfo = new FoldSearchObject(parent.getStartOffset(), parent.getEndOffset(), parent.getType());
   1.288 +            foldInfoLst.add(tempInfo);
   1.289 +        }
   1.290 +        final int count = parent.getFoldCount();
   1.291 +        for (int i = 0; i < count; i++) {
   1.292 +            final Fold temp = parent.getFold(i);
   1.293 +            getCollapsedFolds(temp, foldInfoLst);
   1.294 +        }
   1.295 +    }
   1.296 +
   1.297 +    /**
   1.298 +     * Remove fold with its children
   1.299 +     *
   1.300 +     * @param fold
   1.301 +     * @param blockHier
   1.302 +     * @param transaction
   1.303 +     * @return true if removed all the children
   1.304 +     */
   1.305 +    private void removeWithChildren(final Fold fold, final List<PlsqlBlock> blockHier, final FoldHierarchyTransaction transaction) {
   1.306 +
   1.307 +        final int childCount = fold.getFoldCount();
   1.308 +        for (int i = (childCount - 1); i >= 0; i--) {
   1.309 +            final Fold child = fold.getFold(i);
   1.310 +            removeWithChildren(child, blockHier, transaction);
   1.311 +        }
   1.312 +
   1.313 +        //If a custom fold remove
   1.314 +        if (fold.getType() == PlsqlFoldTypes.CUSTOM || checkExists(fold, blockHier)) {
   1.315 +            operation.removeFromHierarchy(fold, transaction);
   1.316 +            foldSearchObjects.remove(new FoldSearchObject(new FoldAdapter(fold)));
   1.317 +        }
   1.318 +    }
   1.319 +
   1.320 +    /**
   1.321 +     * Method that will check whether given fold exists in block hier
   1.322 +     *
   1.323 +     * @param fold
   1.324 +     * @param blockHier
   1.325 +     * @return
   1.326 +     */
   1.327 +    private boolean checkExists(final Fold fold, final List<PlsqlBlock> blockHier) {
   1.328 +        final Comparator<PlsqlBlock> comparator = new Comparator<PlsqlBlock>() {
   1.329 +            @Override
   1.330 +            public int compare(final PlsqlBlock o1, final PlsqlBlock o2) {
   1.331 +                Integer o1pos, o2pos;
   1.332 +                if (o1.getStartOffset() > -1 && o2.getStartOffset() > -1) {
   1.333 +                    o1pos = Integer.valueOf(o1.getStartOffset());
   1.334 +                    o2pos = Integer.valueOf(o2.getStartOffset());
   1.335 +                } else {
   1.336 +                    o1pos = Integer.valueOf(o1.getEndOffset());
   1.337 +                    o2pos = Integer.valueOf(o2.getEndOffset());
   1.338 +                }
   1.339 +                return o1pos.compareTo(o2pos);
   1.340 +            }
   1.341 +        };
   1.342 +        return checkExists(fold, blockHier, comparator);
   1.343 +    }
   1.344 +
   1.345 +    /**
   1.346 +     * Method that will check whether given fold exists in block hier
   1.347 +     *
   1.348 +     * @param fold
   1.349 +     * @param blockHier
   1.350 +     * @param comparator
   1.351 +     * @return
   1.352 +     */
   1.353 +    private boolean checkExists(final Fold fold, final List<PlsqlBlock> blockHier, final Comparator<PlsqlBlock> comparator) {
   1.354 +        final int size = blockHier.size();
   1.355 +        Collections.sort(blockHier, comparator);
   1.356 +        if (size == 0) {
   1.357 +            return false;
   1.358 +        }
   1.359 +        //make sure that the fold isn't before the first block or after the last block in the hierarchy.
   1.360 +        if (fold.getStartOffset() > blockHier.get(size - 1).getEndOffset()
   1.361 +                || fold.getEndOffset() < blockHier.get(0).getStartOffset()) {
   1.362 +            return false;
   1.363 +        }
   1.364 +        for (int i = 0; i < size; i++) {
   1.365 +            final PlsqlBlock block = blockHier.get(i);
   1.366 +            if (block.getStartOffset() <= fold.getStartOffset() && block.getEndOffset() >= fold.getEndOffset()) {
   1.367 +                return true;
   1.368 +            }
   1.369 +            if (block.getPreviousStart() <= fold.getStartOffset() && block.getPreviousEnd() >= fold.getEndOffset()) {
   1.370 +                return true;
   1.371 +            }
   1.372 +            if ((block.getEndOffset() == fold.getEndOffset() || fold.getEndOffset() == block.getPreviousEnd()
   1.373 +                    || block.getStartOffset() == fold.getStartOffset() || block.getPreviousStart() == fold.getStartOffset())
   1.374 +                    && (getFoldType(block.getType()).equals(fold.getType()))
   1.375 +                    && (getFoldDescription(block).equals(fold.getDescription()))) {
   1.376 +                return true;
   1.377 +            }
   1.378 +
   1.379 +            if (checkExists(fold, block.getChildBlocks(), comparator)) {
   1.380 +                return true;
   1.381 +            }
   1.382 +        }
   1.383 +
   1.384 +        return false;
   1.385 +    }
   1.386 +
   1.387 +    private FoldType getFoldType(final PlsqlBlockType blockType) {
   1.388 +        switch (blockType) {
   1.389 +            case VIEW:
   1.390 +                return PlsqlFoldTypes.VIEW;
   1.391 +            case TABLE_COMMENT:
   1.392 +                return PlsqlFoldTypes.TABLECOMMENT;
   1.393 +            case COLUMN_COMMENT:
   1.394 +                return PlsqlFoldTypes.COLUMNCOMMENT;
   1.395 +            case COMMENT:
   1.396 +                return PlsqlFoldTypes.COMMENT;
   1.397 +            case PACKAGE:
   1.398 +                return PlsqlFoldTypes.PACKAGE;
   1.399 +            case PACKAGE_BODY:
   1.400 +                return PlsqlFoldTypes.PACKAGEBODY;
   1.401 +            case PROCEDURE_IMPL:
   1.402 +                return PlsqlFoldTypes.PROCEDUREIMPL;
   1.403 +            case FUNCTION_IMPL:
   1.404 +                return PlsqlFoldTypes.FUNCTIONIMPL;
   1.405 +            case PROCEDURE_DEF:
   1.406 +                return PlsqlFoldTypes.PROCEDUREDEF;
   1.407 +            case FUNCTION_DEF:
   1.408 +                return PlsqlFoldTypes.FUNCTIONDEF;
   1.409 +            case DECLARE_END:
   1.410 +                return PlsqlFoldTypes.DECLAREEND;
   1.411 +            case BEGIN_END:
   1.412 +                return PlsqlFoldTypes.BEGINEND;
   1.413 +            case TRIGGER:
   1.414 +                return PlsqlFoldTypes.TRIGGER;
   1.415 +            case IF:
   1.416 +                return PlsqlFoldTypes.IF;
   1.417 +            case CASE:
   1.418 +                return PlsqlFoldTypes.CASE;
   1.419 +            case WHILE_LOOP:
   1.420 +                return PlsqlFoldTypes.WHILELOOP;
   1.421 +            case FOR_LOOP:
   1.422 +                return PlsqlFoldTypes.FORLOOP;
   1.423 +            case LOOP:
   1.424 +                return PlsqlFoldTypes.LOOP;
   1.425 +            case CUSTOM_FOLD:
   1.426 +                return PlsqlFoldTypes.CUSTOM;
   1.427 +            case STATEMENT:
   1.428 +                return PlsqlFoldTypes.STATEMENT;
   1.429 +            case CURSOR:
   1.430 +                return PlsqlFoldTypes.CURSOR;
   1.431 +            case JAVA_SOURCE:
   1.432 +                return PlsqlFoldTypes.JAVASOURCE;
   1.433 +            default:
   1.434 +                return null;
   1.435 +        }
   1.436 +    }
   1.437 +
   1.438 +    /**
   1.439 +     * Method that will return the fold description given the Plsql block Used
   1.440 +     * when changing the descriptions only.
   1.441 +     *
   1.442 +     * @param block
   1.443 +     * @return
   1.444 +     */
   1.445 +    private String getFoldDescription(final PlsqlBlock block) {
   1.446 +        switch (block.getType()) {
   1.447 +            case VIEW:
   1.448 +                return block.getPrefix() + "VIEW " + block.getName();
   1.449 +            case TABLE_COMMENT:
   1.450 +                return "COMMENT ON TABLE " + block.getName();
   1.451 +            case COLUMN_COMMENT:
   1.452 +                return "COLUMN COMMENTS ON TABLE " + block.getName();
   1.453 +            case COMMENT:
   1.454 +                return block.getName();
   1.455 +            case PACKAGE:
   1.456 +                return block.getPrefix() + "PACKAGE " + block.getName();
   1.457 +            case PACKAGE_BODY:
   1.458 +                return block.getPrefix() + "PACKAGE BODY " + block.getName();
   1.459 +            case PROCEDURE_IMPL:
   1.460 +                return block.getPrefix() + "PROCEDURE IMPLEMENTATION " + block.getName();
   1.461 +            case FUNCTION_IMPL:
   1.462 +                return block.getPrefix() + "FUNCTION IMPLEMENTATION " + block.getName();
   1.463 +            case PROCEDURE_DEF:
   1.464 +                return "PROCEDURE DEFINITION " + block.getName();
   1.465 +            case FUNCTION_DEF:
   1.466 +                return "FUNCTION DEFINITION " + block.getName();
   1.467 +            case DECLARE_END:
   1.468 +                return "DECLARE BLOCK";
   1.469 +            case BEGIN_END:
   1.470 +                return "BEGIN BLOCK";
   1.471 +            case TRIGGER:
   1.472 +                return block.getPrefix() + "TRIGGER " + block.getName();
   1.473 +            case IF:
   1.474 +                return block.getName();
   1.475 +            case CASE:
   1.476 +                return block.getName();
   1.477 +            case WHILE_LOOP:
   1.478 +                return "WHILE " + block.getName();
   1.479 +            case FOR_LOOP:
   1.480 +                return "FOR " + block.getName();
   1.481 +            case LOOP:
   1.482 +                return "LOOP ";
   1.483 +            case CUSTOM_FOLD:
   1.484 +                return block.getName();
   1.485 +            case STATEMENT:
   1.486 +                return block.getPrefix() + block.getName();
   1.487 +            case CURSOR:
   1.488 +                return "CURSOR " + block.getName();
   1.489 +            case JAVA_SOURCE:
   1.490 +                return block.getPrefix() + "JAVA SOURCE";
   1.491 +            default:
   1.492 +                return "";
   1.493 +        }
   1.494 +    }
   1.495 +
   1.496 +    private void removeFoldNotify(Fold removedFold) {
   1.497 +        removedFoldList.add(removedFold);
   1.498 +    }
   1.499 +
   1.500 +    private void processRemovedFolds(FoldHierarchyTransaction transaction) {
   1.501 +        for (Fold removedFold : removedFoldList) {
   1.502 +            operation.removeFromHierarchy(removedFold, transaction);
   1.503 +            if (LOG.isLoggable(Level.FINE)) {
   1.504 +                LOG.log(Level.FINE, "Fold={0} removed={1}", new Object[]{removedFold, true});
   1.505 +            }
   1.506 +        }
   1.507 +        removedFoldList.clear();
   1.508 +    }
   1.509 +
   1.510 +    private Document getDocument() {
   1.511 +        Object obj = null;
   1.512 +        for (int i = 0; i < 10; i++) {
   1.513 +            obj = getOperation().getHierarchy().getComponent().getDocument();
   1.514 +            if (obj instanceof AbstractDocument) {
   1.515 +                return (Document) obj;
   1.516 +            }
   1.517              try {
   1.518 -               if (operation.isReleased()) {
   1.519 -                  if (LOG.isLoggable(Level.FINE)) {
   1.520 -                     LOG.log(Level.FINE, "Update skipped, already released: {0}", System.identityHashCode(this));
   1.521 -                  }
   1.522 -                  return;
   1.523 -               }
   1.524 -               if (LOG.isLoggable(Level.FINE)) {
   1.525 -                  LOG.log(Level.FINE, "Updating: {0}", System.identityHashCode(this));
   1.526 -                  LOG.log(Level.FINE, "blockFactory.getBlockHierarchy().size(): {0}", blockFactory.getBlockHierarchy().size());
   1.527 -                  LOG.log(Level.FINE, "blockFactory.getNewBlocks().size(): {0}", blockFactory.getNewBlocks().size());
   1.528 -                  LOG.log(Level.FINE, "blockFactory.getRemovedBlocks().size(): {0}", blockFactory.getRemovedBlocks().size());
   1.529 -               }
   1.530 -               FoldHierarchyTransaction transaction = getOperation().openTransaction();
   1.531 -               try {
   1.532 -                  //Add new blocks to the hierarchy
   1.533 -                  List<PlsqlBlock> blocks = blockFactory.getNewBlocks();
   1.534 -                  if (initial) {
   1.535 -                     blocks = blockFactory.getBlockHierarchy();
   1.536 -                     initial = false;
   1.537 -                  }
   1.538 +                Thread.currentThread().sleep(i);
   1.539 +            } catch (InterruptedException e) {
   1.540 +            }
   1.541 +        }
   1.542 +        throw new IllegalStateException("[PLSQLFolding] PLSQLFoldManager.getDocument() NOT returned AbstractDocument, but " + obj.getClass() + "!. This is caused by not yet resolved issue #49497."); //NOI18N
   1.543 +    }
   1.544  
   1.545 -                  updateFolds(blocks, transaction);
   1.546 -                  //Add custom fold blocks
   1.547 -                  updateFolds(blockFactory.getCustomFolds(), transaction);
   1.548 -               } finally {
   1.549 -                  transaction.commit();
   1.550 -               }
   1.551 -            } finally {
   1.552 -               hierarchy.unlock();
   1.553 +    private void updateFolds(final List<PlsqlBlock> blockHier, final FoldHierarchyTransaction transaction, final List<FoldSearchObject> collapsedFolds) throws BadLocationException {
   1.554 +        final int count = blockHier.size();
   1.555 +        Document doc = getDocument();
   1.556 +        for (int i = 0; i < count; i++) {
   1.557 +            final PlsqlBlock block = blockHier.get(i);
   1.558 +            FoldType foldType = null;
   1.559 +            final PlsqlBlockType type = block.getType();
   1.560 +            String description = "";
   1.561 +
   1.562 +            if (!(type == PlsqlBlockType.COMMENT && doc.getText(block.getStartOffset(), block.getEndOffset() - block.getStartOffset()).indexOf("\n") == -1)) { // check for single line comments
   1.563 +                foldType = getFoldType(type);
   1.564 +                description = getFoldDescription(block);
   1.565 +
   1.566 +                if (doc.getEndPosition().getOffset() >= block.getEndOffset()) {                    
   1.567 +                    operation.addToHierarchy(foldType, description, isCollapsed(block, foldType, collapsedFolds),
   1.568 +                            block.getStartOffset(), block.getEndOffset(), 0, 0, null, transaction);
   1.569 +                    //check for any child folds and add them also
   1.570 +                    updateFolds(block.getChildBlocks(), transaction, collapsedFolds);
   1.571 +                }
   1.572              }
   1.573 -         }
   1.574 -      } finally {
   1.575 -         ((BaseDocument) doc).readUnlock();
   1.576 -      }
   1.577 -   }
   1.578 +        }
   1.579 +    }
   1.580  
   1.581 -   private void removeFoldNotify(Fold removedFold) {
   1.582 -      removedFoldList.add(removedFold);
   1.583 -   }
   1.584 +    /**
   1.585 +     * Method that will select and return the corresponding fold to parent from
   1.586 +     * oldRoot fold hierarchy
   1.587 +     *
   1.588 +     * @param parent
   1.589 +     * @param foldInfoLst
   1.590 +     * @return
   1.591 +     */
   1.592 +    private boolean isCollapsed(final PlsqlBlock block, final FoldType foldType, final List<FoldSearchObject> foldInfoLst) {
   1.593 +        if (OptionsUtilities.isPlSqlExpandFolds()) {
   1.594 +            return false;
   1.595 +        }
   1.596 +        if (foldInfoLst == null) {
   1.597 +            return foldType == PlsqlFoldTypes.COMMENT;
   1.598 +        }
   1.599 +        final int size = foldInfoLst.size();
   1.600 +        for (int i = 0; i < size; i++) {
   1.601 +            final FoldSearchObject temp = foldInfoLst.get(i);
   1.602  
   1.603 -   private void processRemovedFolds(FoldHierarchyTransaction transaction) {
   1.604 -      for (Fold removedFold : removedFoldList) {
   1.605 -         boolean remove = foldSearchObjects.remove(new FoldSearchObject(new FoldAdapter(removedFold)));
   1.606 -         if (LOG.isLoggable(Level.FINE)) {
   1.607 -            LOG.log(Level.FINE, "Fold={0} removed={1}", new Object[]{removedFold, remove});
   1.608 -         }
   1.609 -      }
   1.610 -      removedFoldList.clear();
   1.611 -   }
   1.612 +            if ((temp.getFoldType() == foldType)
   1.613 +                    && (temp.getStartOffset() == block.getPreviousStart())
   1.614 +                    && (temp.getEndOffset() == block.getPreviousEnd())) {
   1.615 +                return true;
   1.616 +            }
   1.617 +        }
   1.618  
   1.619 -   private void updateFolds(List<PlsqlBlock> blocks, FoldHierarchyTransaction transaction) {
   1.620 -      for (PlsqlBlock block : blocks) {
   1.621 +        return false;
   1.622 +    }
   1.623  
   1.624 -         FoldType foldType = null;
   1.625 -         final PlsqlBlockType type = block.getType();
   1.626 -         String description = null;
   1.627 -         try {
   1.628 -            if (!(type == PlsqlBlockType.COMMENT && doc.getText(block.getStartOffset(), block.getEndOffset() - block.getStartOffset()).indexOf("\n") == -1)) { // check for single line comments
   1.629 -               if (type == PlsqlBlockType.VIEW) {
   1.630 -                  foldType = PlsqlFoldTypes.VIEW;
   1.631 -                  description = block.getPrefix() + "VIEW " + block.getName();
   1.632 -               } else if (type == PlsqlBlockType.TABLE_COMMENT) {
   1.633 -                  foldType = PlsqlFoldTypes.TABLECOMMENT;
   1.634 -                  description = "COMMENT ON TABLE " + block.getName();
   1.635 -               } else if (type == PlsqlBlockType.COLUMN_COMMENT) {
   1.636 -                  foldType = PlsqlFoldTypes.COLUMNCOMMENT;
   1.637 -                  description = "COLUMN COMMENTS ON TABLE " + block.getName();
   1.638 -               } else if (type == PlsqlBlockType.COMMENT) {
   1.639 -                  foldType = PlsqlFoldTypes.COMMENT;
   1.640 -                  description = block.getName();
   1.641 -               } else if (type == PlsqlBlockType.PACKAGE) {
   1.642 -                  foldType = PlsqlFoldTypes.PACKAGE;
   1.643 -                  description = block.getPrefix() + "PACKAGE " + block.getName();
   1.644 -               } else if (type == PlsqlBlockType.PACKAGE_BODY) {
   1.645 -                  foldType = PlsqlFoldTypes.PACKAGEBODY;
   1.646 -                  description = block.getPrefix() + "PACKAGE BODY " + block.getName();
   1.647 -               } else if (type == PlsqlBlockType.PROCEDURE_IMPL) {
   1.648 -                  foldType = PlsqlFoldTypes.PROCEDUREIMPL;
   1.649 -                  description = block.getPrefix() + "PROCEDURE IMPLEMENTATION " + block.getName();
   1.650 -               } else if (type == PlsqlBlockType.FUNCTION_IMPL) {
   1.651 -                  foldType = PlsqlFoldTypes.FUNCTIONIMPL;
   1.652 -                  description = block.getPrefix() + "FUNCTION IMPLEMENTATION " + block.getName();
   1.653 -               } else if (type == PlsqlBlockType.PROCEDURE_DEF) {
   1.654 -                  foldType = PlsqlFoldTypes.PROCEDUREDEF;
   1.655 -                  description = "PROCEDURE DEFINITION " + block.getName();
   1.656 -               } else if (type == PlsqlBlockType.FUNCTION_DEF) {
   1.657 -                  foldType = PlsqlFoldTypes.FUNCTIONDEF;
   1.658 -                  description = "FUNCTION DEFINITION " + block.getName();
   1.659 -               } else if (type == PlsqlBlockType.DECLARE_END) {
   1.660 -                  foldType = PlsqlFoldTypes.DECLAREEND;
   1.661 -                  description = "DECLARE BLOCK";
   1.662 -               } else if (type == PlsqlBlockType.BEGIN_END) {
   1.663 -                  foldType = PlsqlFoldTypes.BEGINEND;
   1.664 -                  description = "BEGIN BLOCK";
   1.665 -               } else if (type == PlsqlBlockType.TRIGGER) {
   1.666 -                  foldType = PlsqlFoldTypes.TRIGGER;
   1.667 -                  description = block.getPrefix() + "TRIGGER " + block.getName();
   1.668 -               } else if (type == PlsqlBlockType.IF) {
   1.669 -                  foldType = PlsqlFoldTypes.IF;
   1.670 -                  description = block.getName();
   1.671 -               } else if (type == PlsqlBlockType.CASE) {
   1.672 -                  foldType = PlsqlFoldTypes.CASE;
   1.673 -                  description = block.getName();
   1.674 -               } else if (type == PlsqlBlockType.WHILE_LOOP) {
   1.675 -                  foldType = PlsqlFoldTypes.WHILELOOP;
   1.676 -                  description = "WHILE " + block.getName();
   1.677 -               } else if (type == PlsqlBlockType.FOR_LOOP) {
   1.678 -                  foldType = PlsqlFoldTypes.FORLOOP;
   1.679 -                  description = "FOR " + block.getName();
   1.680 -               } else if (type == PlsqlBlockType.LOOP) {
   1.681 -                  foldType = PlsqlFoldTypes.LOOP;
   1.682 -                  description = "LOOP ";
   1.683 -               } else if (type == PlsqlBlockType.CUSTOM_FOLD) {
   1.684 -                  foldType = PlsqlFoldTypes.CUSTOM;
   1.685 -                  description = block.getName();
   1.686 -               } else if (type == PlsqlBlockType.STATEMENT) {
   1.687 -                  foldType = PlsqlFoldTypes.STATEMENT;
   1.688 -                  description = block.getPrefix() + block.getName();
   1.689 -               } else if (type == PlsqlBlockType.CURSOR) {
   1.690 -                  foldType = PlsqlFoldTypes.CURSOR;
   1.691 -                  description = "CURSOR " + block.getName();
   1.692 -               } else if (type == PlsqlBlockType.JAVA_SOURCE) {
   1.693 -                  foldType = PlsqlFoldTypes.JAVASOURCE;
   1.694 -                  description = block.getPrefix() + "JAVA SOURCE";
   1.695 -               }
   1.696 -
   1.697 -               final FoldSearchObject foldSearchObject = new FoldSearchObject(block.getStartOffset(), block.getEndOffset());
   1.698 -               if (!foldSearchObjects.contains(foldSearchObject)) {
   1.699 -                  try {
   1.700 -                     final Fold fold = operation.addToHierarchy(foldType, description, isCollapsed(foldType), block.getStartOffset(), block.getEndOffset(), 0, 0, null, transaction);
   1.701 -                     foldSearchObjects.add(new FoldSearchObject(new FoldAdapter(fold)));
   1.702 -                  } catch (BadLocationException ex) {
   1.703 -                     if (LOG.isLoggable(Level.FINE)) {
   1.704 -                        LOG.log(Level.FINE, "Ignore BadLocationException", ex);
   1.705 -                     }
   1.706 -                  }
   1.707 -               }
   1.708 -               updateFolds(block.getChildBlocks(), transaction);
   1.709 -            }
   1.710 -         } catch (BadLocationException ex) {
   1.711 -            if (LOG.isLoggable(Level.FINE)) {
   1.712 -               LOG.log(Level.FINE, "Ignore BadLocationException", ex);
   1.713 -            }
   1.714 -         }
   1.715 -      }
   1.716 -   }
   1.717 -
   1.718 -   /**
   1.719 -    * Method that will select and return the corresponding fold to parent from oldRoot fold hierarchy
   1.720 -    *
   1.721 -    * @param parent
   1.722 -    * @param foldInfoLst
   1.723 -    * @return
   1.724 -    */
   1.725 -   private boolean isCollapsed(final FoldType foldType) {
   1.726 -      if (OptionsUtilities.isPlSqlExpandFolds()) {
   1.727 -         return false;
   1.728 -      }
   1.729 -      return foldType == PlsqlFoldTypes.COMMENT;
   1.730 -   }
   1.731 -
   1.732 -   /**
   1.733 -    * Method that will return the relevant block factory
   1.734 -    *
   1.735 -    * @return
   1.736 -    */
   1.737 -   private PlsqlBlockFactory getBlockFactory() {
   1.738 -      final Object obj = doc.getProperty(Document.StreamDescriptionProperty);
   1.739 -      if (obj instanceof Lookup.Provider) {
   1.740 -         return ((Lookup.Provider) obj).getLookup().lookup(PlsqlBlockFactory.class);
   1.741 -      }
   1.742 -      return null;
   1.743 -   }
   1.744 +    /**
   1.745 +     * Method that will return the relevant block factory
   1.746 +     *
   1.747 +     * @return
   1.748 +     */
   1.749 +    private PlsqlBlockFactory getBlockFactory() {
   1.750 +        final Object obj = doc.getProperty(Document.StreamDescriptionProperty);
   1.751 +        if (obj instanceof Lookup.Provider) {
   1.752 +            return ((Lookup.Provider) obj).getLookup().lookup(PlsqlBlockFactory.class);
   1.753 +        }
   1.754 +        return null;
   1.755 +    }
   1.756  }