alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.editor.java;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.Position;
import org.netbeans.editor.BaseDocument;
import org.netbeans.editor.SettingsUtil;
import org.netbeans.editor.TokenProcessor;
import org.netbeans.editor.ext.java.JavaFoldManager;
import org.netbeans.editor.ext.java.JavaSettingsNames;
import org.netbeans.editor.ext.java.JavaSyntaxSupport;
import org.netbeans.editor.ext.java.JavaTokenContext;
import org.netbeans.api.editor.fold.Fold;
import org.netbeans.api.editor.fold.FoldHierarchy;
import org.netbeans.api.editor.fold.FoldType;
import org.netbeans.api.editor.fold.FoldUtilities;
import org.netbeans.editor.SettingsChangeEvent;
import org.netbeans.editor.SettingsChangeListener;
import org.netbeans.jmi.javamodel.ClassMember;
import org.netbeans.jmi.javamodel.Constructor;
import org.netbeans.jmi.javamodel.Element;
import org.netbeans.jmi.javamodel.Feature;
import org.netbeans.jmi.javamodel.Field;
import org.netbeans.jmi.javamodel.Import;
import org.netbeans.jmi.javamodel.JavaClass;
import org.netbeans.jmi.javamodel.JavaDoc;
import org.netbeans.jmi.javamodel.JavaModelPackage;
import org.netbeans.jmi.javamodel.Method;
import org.netbeans.jmi.javamodel.Resource;
import org.netbeans.modules.editor.NbEditorUtilities;
import org.netbeans.modules.javacore.internalapi.ParsingListener;
import org.netbeans.modules.javacore.internalapi.JavaMetamodel;
import org.netbeans.spi.editor.fold.FoldHierarchyTransaction;
import org.netbeans.spi.editor.fold.FoldManager;
import org.netbeans.spi.editor.fold.FoldManagerFactory;
import org.netbeans.spi.editor.fold.FoldOperation;
import org.openide.ErrorManager;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
import org.openide.text.PositionBounds;
import org.openide.util.RequestProcessor;

/**
 * Java fold maintainer creates and updates folds for java sources.
 *
 * @author Miloslav Metelka, Martin Roskanin
 * @version 1.00
 */

final class NbJavaFoldManager extends JavaFoldManager
implements SettingsChangeListener, ParsingListener, Runnable {
    
    private static final int INIT_FOLDS_PARSING_FOLD_UPDATES_DELAY = 1000;
    
    private static boolean debug
        = Boolean.getBoolean("netbeans.debug.editor.fold.manager.java");
    
    private FoldOperation operation;
    
    /**
     * Map holding [mof-id, JavaFoldInfo] pairs for currently present folds.
     * Must use type 'HashMap' instead of 'Map' to be able to clone() without casting.
     */
    private final HashMap id2foldInfo = new HashMap();

    /** Fold for the initial comment in the file */
    private Fold initialCommentFold;

    /** Fold for imports section. */
    private Fold importsFold;

    // Folding presets
    private boolean foldImportsPreset;
    private boolean foldInnerClassesPreset;
    private boolean foldJavadocsPreset;
    private boolean foldCodeBlocksPreset;
    private boolean foldInitialCommentsPreset;

    private boolean listeningOnParsing;
    
    private boolean documentModified;
    
    private static RequestProcessor javaFoldsRP;
    
    private static synchronized RequestProcessor getJavaFoldsRP() {
        if (javaFoldsRP == null) {
            javaFoldsRP = new RequestProcessor("Java-Folds", 1); // NOI18N
        }
        return javaFoldsRP;
    }

    public NbJavaFoldManager() {
    }

    public void init(FoldOperation operation) {
        this.operation = operation;
        settingsChange(null);
    }
    
    private FoldOperation getOperation() {
        return operation;
    }

    public void initFolds(FoldHierarchyTransaction transaction) {
        if (foldImportsPreset || foldCodeBlocksPreset || foldInnerClassesPreset || foldJavadocsPreset) {
            // Do immediately but asynchronously as well (due to #46175)
            getJavaFoldsRP().post(this);
        } else {
            // Post asynchronously (will use a separate transaction)
            getJavaFoldsRP().post(this, 1000, Thread.MIN_PRIORITY);
        }
    }
    
    public void insertUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
        documentModified = true;
    }
    
    public void removeUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
        documentModified = true;
    }
    
    public void changedUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) {
    }
    
    public void removeEmptyNotify(Fold emptyFold) {
        removeFoldNotify(emptyFold);
    }
    
    public void removeDamagedNotify(Fold damagedFold) {
        removeFoldNotify(damagedFold);
    }
    
    public void expandNotify(Fold expandedFold) {
    }

    public void release() {
    }
    
    public void resourceParsed(Resource resource) {
        DataObject dob = getDataObject();
        if (dob != null) {
            FileObject primaryFile = dob.getPrimaryFile();
            if (primaryFile != null) {
                // Initially check whether FO's name ends with resource name
                // as a quick exclusion test
                String resourceName;
                try {
                    resourceName = resource.getName();
                } catch (Exception e) { // fixes #47871 - InvalidObjectException may be thrown
                    resourceName = null;
                }

                if (resourceName != null && primaryFile.getPath().endsWith(resourceName)) {
                    // Check whether the resouces instances are really the same
                    if (JavaMetamodel.getManager().getFileObject(resource) == primaryFile) {
                        updateFolds(null);
                    }
                }
            }
        }
    }
    
    public void run() {
        try {
            Resource resource = getResource();
            if (resource != null) {
                if (!listeningOnParsing) {
                    listeningOnParsing = true;
                    new WeakParsingListener(this).startListening();
                }

                updateFolds(null);
            }
        } catch (ThreadDeath e) {
            throw e;
        } catch (Throwable t) {
            ErrorManager.getDefault().notify(t);
        }
    }

    /**
     * Collect all fold creations and removals
     * and either do them synchronously in the given transaction
     * or post them into AWT.
     */
    private void updateFolds(FoldHierarchyTransaction transaction) {
        if (!getOperation().isReleased()) {
            // First collect the fold updates from JMI
            final UpdateFoldsRequest request = collectFoldUpdates(transaction != null);
            
            // Now apply the collected changes - create physical folds etc.
            if (transaction != null) { // do synchronously
                processUpdateFoldRequest(request, transaction);
            } else { // update the physical folds asynchronously in AWT
                Runnable hierarchyUpdate = new Runnable() {
                    public void run() {
                        Document doc = getDocument();
                        if (!(doc instanceof AbstractDocument)) {
                            return; // can happen (e.g. after component close)
                        }

                        AbstractDocument adoc = (AbstractDocument)doc;
                        adoc.readLock();
                        try {
                            FoldHierarchy hierarchy = getOperation().getHierarchy();
                            hierarchy.lock();
                            try {
                                FoldHierarchyTransaction t = getOperation().openTransaction();
                                try {
                                    processUpdateFoldRequest(request, t);
                                } finally {
                                    t.commit();
                                }
                            } finally {
                                hierarchy.unlock();
                            }
                        } finally {
                            adoc.readUnlock();
                        }
                    }
                };
                // Do fold updates in AWT
                SwingUtilities.invokeLater(hierarchyUpdate);
            }
        }
    }
    
    /**
     * Collect all updates into an update request.
     *
     * @param inInitFolds if set to true an additional call
     *  to isAnydFoldPresetRequiringParsing()
     *  is done and if it returns false then only folds
     *  that do not require parsing (initial comment fold)
     *  will be processed and a separate request for the rest
     *  of the folds will be initiated.
     *  
* This special processing should speed up the file opening. */ private UpdateFoldsRequest collectFoldUpdates(boolean inInitFolds) { UpdateFoldsRequest request = new UpdateFoldsRequest(); Resource resource = getResource(); Document doc = getDocument(); if (getOperation().isReleased() || resource == null || !(doc instanceof AbstractDocument)) { return request; } AbstractDocument adoc = (AbstractDocument)doc; if (inInitFolds && !isAnydFoldPresetRequiringParsing()) { // Only requests that do not require parsing will be processed // and an extra task will be scheduled adoc.readLock(); try { collectNonParsingFoldUpdates(request, adoc); } catch (BadLocationException e) { ErrorManager.getDefault().notify(e); } finally { adoc.readUnlock(); } getJavaFoldsRP().post(this, INIT_FOLDS_PARSING_FOLD_UPDATES_DELAY); } else { // must do all fold updates // First lock jmi then document JavaMetamodel.getManager().getDefaultRepository().beginTrans(false); try { adoc.readLock(); try { collectNonParsingFoldUpdates(request, adoc); int docLength = adoc.getLength(); // Imports section int importsStartOffset = Integer.MAX_VALUE; int importsEndOffset = Integer.MIN_VALUE; for (Iterator it = resource.getImports().iterator(); it.hasNext();) { Import imp = (Import)it.next(); importsStartOffset = Math.min(importsStartOffset, imp.getStartOffset()); importsEndOffset = Math.max(importsEndOffset, imp.getEndOffset()); } if (importsStartOffset != Integer.MAX_VALUE && importsStartOffset >= 0) { // Valid imports section importsStartOffset += 7; //#46547 - start after "import " if (importsStartOffset < importsEndOffset && importsEndOffset <= docLength) { request.setImportsFoldInfo( new ImportsFoldInfo( adoc.createPosition(importsStartOffset), adoc.createPosition(importsEndOffset) ) ); } } // Classes and features List l = resource.getClassifiers(); for (Iterator it = l.iterator(); it.hasNext();) { JavaClass cls = (JavaClass)it.next(); if (debug) { /*DEBUG*/System.err.println("JavaFoldManager: found Class: " + cls); } collectClassFoldUpdates(request, cls, true, adoc); } } catch (BadLocationException e) { ErrorManager.getDefault().notify(e); } finally { adoc.readUnlock(); } } finally { JavaMetamodel.getManager().getDefaultRepository().endTrans(); } } return request; } private void collectNonParsingFoldUpdates(UpdateFoldsRequest request, AbstractDocument doc) throws BadLocationException { int docLength = doc.getLength(); BaseDocument bdoc = (BaseDocument)doc; NbJavaSyntaxSupport sup = (NbJavaSyntaxSupport)bdoc.getSyntaxSupport(); // Initial comment InitialCommentProcessor icp = new InitialCommentProcessor(); sup.tokenizeText(icp, 0, docLength, false); int icStartOffset = icp.getCommentStartOffset(); int icEndOffset = icp.getCommentEndOffset(); if (icStartOffset >= 0 && icStartOffset < icEndOffset && icEndOffset <= docLength ) { // initial comment exists request.setInitialCommentFoldInfo( new InitialCommentFoldInfo( bdoc.createPosition(icStartOffset), bdoc.createPosition(icEndOffset) ) ); } } private void collectClassFoldUpdates(UpdateFoldsRequest request, JavaClass cls, boolean topLevel, AbstractDocument doc) throws BadLocationException { ClassMemberFoldInfo clsInfo = new ClassMemberFoldInfo(cls, topLevel, doc); request.addMemberFoldInfo(clsInfo); // Process features for (Iterator it = cls.getFeatures().iterator(); it.hasNext();) { Feature f = (Feature)it.next(); if (debug) { /*DEBUG*/System.err.println("JavaFoldManager: found Feature: " + f); // NOI18N } if (f instanceof JavaClass) { JavaClass subCls = (JavaClass)f; if (debug) { /*DEBUG*/System.err.println("JavaFoldManager: found SubClass: " + subCls); // NOI18N } collectClassFoldUpdates(request, subCls, false, doc); } else { boolean javadocOnly = (f instanceof Field); ClassMemberFoldInfo featureInfo = new ClassMemberFoldInfo(f, javadocOnly, doc); request.addMemberFoldInfo(featureInfo); } } } private void processUpdateFoldRequest(UpdateFoldsRequest request, FoldHierarchyTransaction transaction) { if (request.isValid()) { Fold origFold = getInitialCommentFold(); InitialCommentFoldInfo icInfo = request.getInitialCommentFoldInfo(); if (icInfo != null) { if (icInfo.isUpdateNecessary(origFold)) { boolean collapsed = (origFold != null) ? origFold.isCollapsed() : (documentModified ? false : foldInitialCommentsPreset); // Remove original fold first if (origFold != null) { getOperation().removeFromHierarchy(origFold, transaction); setInitialCommentFold(null); } // Add new fold try { icInfo.updateHierarchy(transaction, collapsed); } catch (BadLocationException e) { ErrorManager.getDefault().notify(e); } } } else { // no new fold // Remove original fold only if (origFold != null) { getOperation().removeFromHierarchy(origFold, transaction); setInitialCommentFold(null); } } origFold = getImportsFold(); ImportsFoldInfo impsInfo = request.getImportsFoldInfo(); if (impsInfo != null) { if (impsInfo.isUpdateNecessary(origFold)) { boolean collapsed = (origFold != null) ? origFold.isCollapsed() : (documentModified ? false : foldImportsPreset); // Remove original fold first if (origFold != null) { getOperation().removeFromHierarchy(origFold, transaction); setImportsFold(null); } // Add new fold try { impsInfo.updateHierarchy(transaction, collapsed); } catch (BadLocationException e) { ErrorManager.getDefault().notify(e); } } } else { // no new fold // Remove original fold only if (origFold != null) { getOperation().removeFromHierarchy(origFold, transaction); setImportsFold(null); } } // Process member fold infos in the request Map obsoleteId2FoldInfo = (Map)id2foldInfo.clone(); List infoList = request.getMemberFoldInfos(); if (infoList != null) { for (Iterator it = infoList.iterator(); it.hasNext();) { ClassMemberFoldInfo info = (ClassMemberFoldInfo)it.next(); String id = info.getId(); ClassMemberFoldInfo orig = findClassMemberFoldInfo(id); if (info.isUpdateNecessary(orig)) { // Remove original folds first if (orig != null) { orig.removeFromHierarchy(transaction); } // Add the new folds try { info.updateHierarchy(transaction, orig); } catch (BadLocationException e) { ErrorManager.getDefault().notify(e); } // Remember the new info putClassMemberFoldInfo(id, info); } if (orig != null) { // Folds with the particular id already existed // and will continue to exist so they are not obsolete obsoleteId2FoldInfo.remove(id); } } } // Remove the obsolete folds for (Iterator it = obsoleteId2FoldInfo.entrySet().iterator(); it.hasNext();) { Map.Entry e = (Map.Entry)it.next(); String id = (String)e.getKey(); ClassMemberFoldInfo foldInfo = (ClassMemberFoldInfo)e.getValue(); foldInfo.removeFromHierarchy(transaction); removeClassMemberFoldInfo(id); if (debug) { /*DEBUG*/System.err.println("Removing obsolete foldInfo: " + foldInfo); } } } } private boolean isAnydFoldPresetRequiringParsing() { return foldImportsPreset || foldCodeBlocksPreset || foldInnerClassesPreset || foldJavadocsPreset; } Fold getInitialCommentFold() { return initialCommentFold; } void setInitialCommentFold(Fold initialCommentFold) { this.initialCommentFold = initialCommentFold; } Fold getImportsFold() { return importsFold; } void setImportsFold(Fold importsFold) { this.importsFold = importsFold; } private ClassMemberFoldInfo findClassMemberFoldInfo(String id) { return (ClassMemberFoldInfo)id2foldInfo.get(id); } private void removeClassMemberFoldInfo(String id) { id2foldInfo.remove(id); } private void putClassMemberFoldInfo(String id, ClassMemberFoldInfo info) { id2foldInfo.put(id, info); } public void settingsChange(SettingsChangeEvent evt) { // Get folding presets foldInitialCommentsPreset = getSetting(JavaSettingsNames.CODE_FOLDING_COLLAPSE_INITIAL_COMMENT); foldImportsPreset = getSetting(JavaSettingsNames.CODE_FOLDING_COLLAPSE_IMPORT); foldCodeBlocksPreset = getSetting(JavaSettingsNames.CODE_FOLDING_COLLAPSE_METHOD); foldInnerClassesPreset = getSetting(JavaSettingsNames.CODE_FOLDING_COLLAPSE_INNERCLASS); foldJavadocsPreset = getSetting(JavaSettingsNames.CODE_FOLDING_COLLAPSE_JAVADOC); } private boolean getSetting(String settingName){ JTextComponent tc = getOperation().getHierarchy().getComponent(); return SettingsUtil.getBoolean(org.netbeans.editor.Utilities.getKitClass(tc), settingName, false); } Document getDocument() { return getOperation().getHierarchy().getComponent().getDocument(); } DataObject getDataObject() { Document doc = getDocument(); return (doc != null) ? NbEditorUtilities.getDataObject(doc) : null; } Resource getResource() { DataObject dob = getDataObject(); return (dob != null) ? JavaMetamodel.getManager().getResource(dob.getPrimaryFile()) : null; } private void removeFoldNotify(Fold fold){ // No additional locking is necessary as the hierarchy is locked // during this op as well as during folds updating which guarantees exclusivity if (fold == getInitialCommentFold()) { setInitialCommentFold(null); } else if (fold == getImportsFold()) { setImportsFold(null); } else { // class member fold ClassMemberFoldInfo info = (ClassMemberFoldInfo)getOperation().getExtraInfo(fold); info.removeFoldNotify(fold); } } private final class InitialCommentProcessor implements TokenProcessor { private int bufferStartOffset; private int commentStartOffset = -1; private int commentEndOffset = -1; public int eot(int offset) { return 0; } public void nextBuffer(char[] buffer, int offset, int len, int startPos, int preScan, boolean lastBuffer) { bufferStartOffset = startPos - offset; } public boolean token(org.netbeans.editor.TokenID tokenID, org.netbeans.editor.TokenContextPath tokenContextPath, int tokenBufferOffset, int tokenLength) { Document doc = getOperation().getHierarchy().getComponent().getDocument(); if (JavaTokenContext.BLOCK_COMMENT.equals(tokenID) && doc!=null) { // initial comment int startOffset = bufferStartOffset + tokenBufferOffset; try{ String text = doc.getText(startOffset, 3); if (!("/**".equals(text))){ //NOI18N commentStartOffset = bufferStartOffset + tokenBufferOffset; commentEndOffset = commentStartOffset + tokenLength; } }catch(BadLocationException ble){ ble.printStackTrace(); } return false; } else { return (JavaTokenContext.WHITESPACE.equals(tokenID)); // skip WS } } public int getCommentStartOffset() { return commentStartOffset; } public int getCommentEndOffset() { return commentEndOffset; } } private static final class OpeningBraceProcessor implements TokenProcessor { private int bufferStartOffset; private int limitOffset = -1; /** Opening brace of the method block */ private int openingBraceOffset = -1; public int eot(int offset) { return 0; } OpeningBraceProcessor(int limitOffset) { this.limitOffset = limitOffset; } public void nextBuffer(char[] buffer, int offset, int len, int startPos, int preScan, boolean lastBuffer) { bufferStartOffset = startPos - offset; } public boolean token(org.netbeans.editor.TokenID tokenID, org.netbeans.editor.TokenContextPath tokenContextPath, int tokenBufferOffset, int tokenLength) { int offset = bufferStartOffset + tokenBufferOffset; if (JavaTokenContext.LBRACE.equals(tokenID)) { // found '{' openingBraceOffset = offset; return false; } return (offset < limitOffset); } public int getOpeningBraceOffset() { return openingBraceOffset; } } private final class InitialCommentFoldInfo { private Position initialCommentStartPos; private Position initialCommentEndPos; InitialCommentFoldInfo(Position initialCommentStartPos, Position initialCommentEndPos) { this.initialCommentStartPos = initialCommentStartPos; this.initialCommentEndPos = initialCommentEndPos; } public boolean isUpdateNecessary(Fold origInitialCommentFold) { return (origInitialCommentFold == null || origInitialCommentFold.getStartOffset() != initialCommentStartPos.getOffset() || origInitialCommentFold.getEndOffset() != initialCommentEndPos.getOffset() ); } public void updateHierarchy(FoldHierarchyTransaction transaction, boolean collapsed) throws BadLocationException { int startOffset = initialCommentStartPos.getOffset(); int endOffset = initialCommentEndPos.getOffset(); if (FoldOperation.isBoundsValid(startOffset, endOffset, JavaFoldManager.INITIAL_COMMENT_FOLD_TEMPLATE.getStartGuardedLength(), JavaFoldManager.INITIAL_COMMENT_FOLD_TEMPLATE.getEndGuardedLength()) ) { Fold fold = getOperation().addToHierarchy( JavaFoldManager.INITIAL_COMMENT_FOLD_TEMPLATE.getType(), JavaFoldManager.INITIAL_COMMENT_FOLD_TEMPLATE.getDescription(), collapsed, startOffset, endOffset, JavaFoldManager.INITIAL_COMMENT_FOLD_TEMPLATE.getStartGuardedLength(), JavaFoldManager.INITIAL_COMMENT_FOLD_TEMPLATE.getEndGuardedLength(), this, transaction ); setInitialCommentFold(fold); } } } private final class ImportsFoldInfo { private Position importsStartPos; private Position importsEndPos; ImportsFoldInfo(Position importsStartPos, Position importsEndPos) { this.importsStartPos = importsStartPos; this.importsEndPos = importsEndPos; } public boolean isUpdateNecessary(Fold origImportsFold) { return (origImportsFold == null || origImportsFold.getStartOffset() != importsStartPos.getOffset() || origImportsFold.getEndOffset() != importsEndPos.getOffset() ); } public void updateHierarchy(FoldHierarchyTransaction transaction, boolean collapsed) throws BadLocationException { int startOffset = importsStartPos.getOffset(); int endOffset = importsEndPos.getOffset(); if (FoldOperation.isBoundsValid(startOffset, endOffset, JavaFoldManager.IMPORTS_FOLD_TEMPLATE.getStartGuardedLength(), JavaFoldManager.IMPORTS_FOLD_TEMPLATE.getEndGuardedLength()) ) { Fold fold = getOperation().addToHierarchy( JavaFoldManager.IMPORTS_FOLD_TEMPLATE.getType(), JavaFoldManager.IMPORTS_FOLD_TEMPLATE.getDescription(), collapsed, startOffset, endOffset, JavaFoldManager.IMPORTS_FOLD_TEMPLATE.getStartGuardedLength(), JavaFoldManager.IMPORTS_FOLD_TEMPLATE.getEndGuardedLength(), this, transaction ); setImportsFold(fold); } } } private final class ClassMemberFoldInfo { private String id; private ClassMember classMember; private JavaDoc javadoc; private Fold fold; private Fold javadocFold; private boolean javadocFoldOnly; private FoldTemplate template; private FoldTemplate javadocTemplate; private Position classMemberStartPos; private Position classMemberEndPos; private Position javadocStartPos; private Position javadocEndPos; public ClassMemberFoldInfo(ClassMember classMember, boolean javadocFoldOnly, AbstractDocument doc) throws BadLocationException { this.classMember = classMember; this.javadocFoldOnly = javadocFoldOnly; this.template = JavaFoldManager.CODE_BLOCK_FOLD_TEMPLATE; this.javadocTemplate = JavaFoldManager.JAVADOC_FOLD_TEMPLATE; id = classMember.refMofId(); this.javadoc = classMember.getJavadoc(); int docLength = doc.getLength(); JavaMetamodel jmm = JavaMetamodel.getManager(); if (!javadocFoldOnly) { // Use statement block boundaries instead of the whole method Element elem = classMember; if (elem instanceof Method) { // getBody() not used - very slow e.g. for JTable cca. 40 seconds // elem = ((Method)classMember).getBody(); } PositionBounds bounds = jmm.getElementPosition(elem); if (bounds != null){ int startOffset = bounds.getBegin().getOffset(); int endOffset = bounds.getEnd().getOffset(); if (startOffset >= 0 && startOffset < endOffset && endOffset <= docLength) { if ((elem instanceof Method) || (elem instanceof Constructor) || (elem instanceof JavaClass) ) { if (doc instanceof BaseDocument) { BaseDocument bdoc = (BaseDocument)doc; NbJavaSyntaxSupport sup = (NbJavaSyntaxSupport)bdoc.getSyntaxSupport(); // Skip method/class declaration up to the opening brace OpeningBraceProcessor obp = new OpeningBraceProcessor(endOffset); sup.tokenizeText(obp, startOffset, endOffset, false); int braceOffset = obp.getOpeningBraceOffset(); if (braceOffset >= 0 && braceOffset < endOffset) { startOffset = braceOffset; } else { // Opening brace not found => e.g. interface's method startOffset = -1; // Assign invalid offset } } } if (startOffset >= 0) { // only if valid start offset classMemberStartPos = doc.createPosition(startOffset); classMemberEndPos = doc.createPosition(endOffset); } } } } if (javadoc != null) { PositionBounds bounds = jmm.getElementPosition(javadoc); if (bounds != null){ int startOffset = bounds.getBegin().getOffset(); int endOffset = bounds.getEnd().getOffset(); if (startOffset >= 0 && startOffset < endOffset && endOffset <= docLength) { javadocStartPos = doc.createPosition(startOffset); javadocEndPos = doc.createPosition(endOffset); } } } } public String getId() { return id; } public boolean isUpdateNecessary(ClassMemberFoldInfo orig) { boolean update = false; if (orig == null) { update = true; } else { // original info already exists -> compare if (!javadocFoldOnly) { // compare class member folds Fold origFold = orig.getFold(); if (classMemberStartPos != null && (origFold == null || classMemberStartPos.getOffset() != origFold.getStartOffset() || classMemberEndPos.getOffset() != origFold.getEndOffset() ) ) { update = true; } } if (!update && javadoc != null) { Fold origJavadocFold = orig.getJavadocFold(); if (javadocStartPos != null && origJavadocFold != null) { if (javadocStartPos.getOffset() != origJavadocFold.getStartOffset() || javadocEndPos.getOffset() != origJavadocFold.getEndOffset() ) { update = true; } } else { // orig javadoc fold does not exist update = true; } } } return update; } public void updateHierarchy(FoldHierarchyTransaction transaction, ClassMemberFoldInfo origInfo) throws BadLocationException { if (debug) { /*DEBUG*/System.err.println( "JavaFoldManager.updateHierarchy(): classMember=" // NOI18N + classMember ); } if (!javadocFoldOnly && classMemberStartPos != null) { int startOffset = classMemberStartPos.getOffset(); int endOffset = classMemberEndPos.getOffset(); if (FoldOperation.isBoundsValid(startOffset, endOffset, template.getStartGuardedLength(), template.getEndGuardedLength()) ) { // Determine whether the fold should be collapsed or expanded Fold origFold; boolean collapsed = (origInfo != null && (origFold = origInfo.getFold()) != null) ? origFold.isCollapsed() : documentModified ? false : (classMember instanceof JavaClass) ? foldInnerClassesPreset : foldCodeBlocksPreset; this.fold = getOperation().addToHierarchy( template.getType(), template.getDescription(), collapsed, startOffset, endOffset, template.getStartGuardedLength(), template.getEndGuardedLength(), this, transaction ); } } if (javadoc != null && javadocStartPos != null) { int startOffset = javadocStartPos.getOffset(); int endOffset = javadocEndPos.getOffset(); if (FoldOperation.isBoundsValid(startOffset, endOffset, javadocTemplate.getStartGuardedLength(), javadocTemplate.getEndGuardedLength()) ) { // Determine whether the javadoc fold should be collapsed or expanded Fold origJavadocFold; boolean javadocCollapsed = (origInfo != null && (origJavadocFold = origInfo.getJavadocFold()) != null) ? origJavadocFold.isCollapsed() : documentModified ? false : foldJavadocsPreset; this.javadocFold = getOperation().addToHierarchy( javadocTemplate.getType(), javadocTemplate.getDescription(), javadocCollapsed, startOffset, endOffset, javadocTemplate.getStartGuardedLength(), javadocTemplate.getEndGuardedLength(), this, transaction ); } } } public void removeFromHierarchy(FoldHierarchyTransaction transaction) { if (debug) { // Cannot refer to classMember - throws InvalidObjectExc from MDR /*DEBUG*/System.err.println( "JavaFoldManager.removeFromHierarchy(): " + this); // NOI18N } if (fold != null) { getOperation().removeFromHierarchy(fold, transaction); } if (javadocFold != null) { getOperation().removeFromHierarchy(javadocFold, transaction); } } public Fold getFold() { return fold; } public Fold getJavadocFold() { return javadocFold; } public void removeFoldNotify(Fold removedFold) { if (removedFold == fold) { fold = null; } else if (removedFold == javadocFold) { javadocFold = null; } else { assert false; // Invalid fold supplied } } public ClassMember getClassMember(){ return classMember; } public JavaDoc getJavadoc() { return javadoc; } public String toString() { return "fold=" + fold + ", javadocFold=" + javadocFold; } } private final class UpdateFoldsRequest { private Document creationTimeDoc; /** Fold for the initial comment in the file */ private InitialCommentFoldInfo initialCommentFoldInfo; /** Fold for imports section. */ private ImportsFoldInfo importsFoldInfo; /** List of the java members (methods, classes etc.) folds */ private List memberFoldInfos; UpdateFoldsRequest() { this.creationTimeDoc = getDocument(); } boolean isValid() { // Check whether request creation time document // is still in use by the fold hierarchy return (creationTimeDoc == getDocument()); } InitialCommentFoldInfo getInitialCommentFoldInfo() { return initialCommentFoldInfo; } void setInitialCommentFoldInfo(InitialCommentFoldInfo initialCommentFoldInfo) { this.initialCommentFoldInfo = initialCommentFoldInfo; } ImportsFoldInfo getImportsFoldInfo() { return importsFoldInfo; } void setImportsFoldInfo(ImportsFoldInfo importsFoldInfo) { this.importsFoldInfo = importsFoldInfo; } List getMemberFoldInfos() { return memberFoldInfos; } void addMemberFoldInfo(ClassMemberFoldInfo foldInfo) { if (memberFoldInfos == null) { memberFoldInfos = new ArrayList(); } memberFoldInfos.add(foldInfo); } } private static final class WeakParsingListener implements ParsingListener { private WeakReference ref; WeakParsingListener(ParsingListener l) { ref = new WeakReference(l); } public void startListening() { JavaMetamodel.getManager().addParsingListener(this); } public void resourceParsed(Resource r) { ParsingListener l = (ParsingListener)ref.get(); if (l != null) { l.resourceParsed(r); } else { JavaMetamodel.getManager().removeParsingListener(this); } } } public static final class Factory implements FoldManagerFactory { public Factory(){ } public FoldManager createFoldManager() { return new NbJavaFoldManager(); } } }
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.