|
What this is
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-2003 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.editor; import java.awt.Graphics; import java.awt.Shape; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.swing.Timer; import javax.swing.event.DocumentEvent; import javax.swing.plaf.TextUI; import javax.swing.text.AbstractDocument; import javax.swing.text.BadLocationException; import javax.swing.text.Element; import javax.swing.text.JTextComponent; import javax.swing.text.Position; import javax.swing.text.View; import javax.swing.text.ViewFactory; import org.netbeans.editor.BaseDocumentEvent; 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.api.editor.fold.FoldHierarchyEvent; import org.netbeans.api.editor.fold.FoldHierarchyListener; import org.netbeans.editor.ext.java.JavaFoldManager; import org.netbeans.lib.editor.view.GapDocumentView; import org.netbeans.lib.editor.view.GapMultiLineView; import org.netbeans.editor.view.spi.LockView; import org.netbeans.editor.view.spi.ViewLayoutQueue; /** * View of the whole document supporting the code folding. * * @author Miloslav Metelka */ class DrawEngineDocView extends GapDocumentView implements FoldHierarchyListener, PropertyChangeListener { private static final boolean debugRebuild = Boolean.getBoolean("netbeans.debug.editor.view.rebuild"); // NOI18N private FoldHierarchy foldHierarchy; /** Editor UI listening to */ private EditorUI editorUI; private Iterator collapsedFoldIterator; private Fold collapsedFold; private int collapsedFoldStartOffset; private int collapsedFoldEndOffset; private boolean collapsedFoldsInPresentViews; private boolean estimatedSpanResetInitiated; private static Element getParagraphRootElement(JTextComponent component) { return ((BaseDocument)component.getDocument()).getParagraphElement(0).getParentElement(); } DrawEngineDocView(Element elem) { super(elem); setEstimatedSpan(true); } public void setParent(View parent) { if (parent != null) { // start listening JTextComponent component = (JTextComponent)parent.getContainer(); foldHierarchy = FoldHierarchy.get(component); foldHierarchy.addFoldHierarchyListener(this); TextUI tui = component.getUI(); if (tui instanceof BaseTextUI){ editorUI = ((BaseTextUI)tui).getEditorUI(); if (editorUI!=null){ editorUI.addPropertyChangeListener(this); } } } super.setParent(parent); if (parent == null) { foldHierarchy.removeFoldHierarchyListener(this); foldHierarchy = null; if (editorUI!=null){ editorUI.removePropertyChangeListener(this); editorUI = null; } } } protected void attachListeners(){ if (foldHierarchy != null) { } } private FoldHierarchy getFoldHierarchy() { return foldHierarchy; } protected boolean useCustomReloadChildren() { return true; } /** * Find next collapsed fold in the given offset range. * @param lastCollapsedFold last collapsed fold returned by this method. * @param startOffset starting offset of the area in which the collapsed folds * should be searched. * @param endOffset ending offset of the area in which the collapsed folds * should be searched. */ protected Fold nextCollapsedFold() { while (true) { Fold fold = collapsedFoldIterator.hasNext() ? (Fold)collapsedFoldIterator.next() : null; // Check whether the fold is not past the doc if (fold != null) { collapsedFoldStartOffset = fold.getStartOffset(); collapsedFoldEndOffset = fold.getEndOffset(); /* Ignore the empty folds as they would make up * no visible view anyway. * Although the fold hierarchy removes the empty views * automatically it may happen that the document listener * that the fold hierarchy attaches may not be notified yet. */ if (collapsedFoldStartOffset == collapsedFoldEndOffset) { if (debugRebuild) { /*DEBUG*/System.err.println( "GapBoxView.nextCollapsedFold(): ignored empty fold " // NOI18N + fold ); } continue; // skip empty fold } if (collapsedFoldEndOffset > getDocument().getLength()) { /* The fold is past the end of the document. * If a document is going to be switched in the component * the view hierarchy may be notified sooner * than fold hierarchy about that change which * can lead to this state. * That fold is ignored together with the rest of the folds * that would follow it. */ fold = null; } } if (fold != null) { collapsedFoldsInPresentViews = true; } return fold; } } /** * Extra initialization for custom reload of children. */ protected void initCustomReloadChildren(FoldHierarchy hierarchy, int startOffset, int endOffset) { collapsedFoldIterator = FoldUtilities.collapsedFoldIterator(hierarchy, startOffset, endOffset); collapsedFold = nextCollapsedFold(); } /** * Free any resources required for custom reload of children. */ protected void finishCustomReloadChildren(FoldHierarchy hierarchy) { collapsedFoldIterator = null; collapsedFold = null; } protected void customReloadChildren(int index, int removeLength, int startOffset, int endOffset) { // if removing all the views reset the flag if (index == 0 && removeLength == getViewCount()) { collapsedFoldsInPresentViews = false; // suppose there will be no folds in line views } FoldHierarchy hierarchy = getFoldHierarchy(); // Assuming the document lock was already acquired if (hierarchy != null) { hierarchy.lock(); try { initCustomReloadChildren(hierarchy, startOffset, endOffset); super.customReloadChildren(index, removeLength, startOffset, endOffset); finishCustomReloadChildren(hierarchy); } finally { hierarchy.unlock(); } } } protected View createCustomView(ViewFactory f, int startOffset, int maxEndOffset, int elementIndex) { if (elementIndex == -1) { throw new IllegalStateException("Need underlying line element structure"); // NOI18N } View view = null; Element elem = getElement(); Element lineElem = elem.getElement(elementIndex); boolean createCollapsed = (collapsedFold != null); if (createCollapsed) { // collapsedFold != null int lineElemEndOffset = lineElem.getEndOffset(); createCollapsed = (collapsedFoldStartOffset < lineElemEndOffset); if (createCollapsed) { // need to find end of collapsed area Element firstLineElem = lineElem; List foldAndEndLineElemList = new ArrayList(); while (true) { int collapsedFoldEndOffset = collapsedFold.getEndOffset(); // Find line element index of the line in which the collapsed fold ends while (collapsedFoldEndOffset > lineElemEndOffset) { elementIndex++; lineElem = elem.getElement(elementIndex); lineElemEndOffset = lineElem.getEndOffset(); } foldAndEndLineElemList.add(collapsedFold); foldAndEndLineElemList.add(lineElem); collapsedFold = nextCollapsedFold(); // No more collapsed or next collapsed does not start on current line if (collapsedFold == null || collapsedFoldStartOffset >= lineElemEndOffset) { break; } } // Create the multi-line-view with collapsed fold(s) view = new FoldMultiLineView(firstLineElem, foldAndEndLineElemList); } } if (!createCollapsed) { view = f.create(lineElem); } return view; } public void foldHierarchyChanged(FoldHierarchyEvent evt) { LockView lockView = LockView.get(this); lockView.lock(); try { layoutLock(); try { FoldHierarchy hierarchy = (FoldHierarchy)evt.getSource(); if (hierarchy.getComponent().getDocument() != lockView.getDocument()) { // Comonent already has a different document assigned // so this view will be abandoned anyway => do not rebuild // the current chilren because of this change return; } boolean rebuildViews = true; int affectedStartOffset = evt.getAffectedStartOffset(); int affectedEndOffset = evt.getAffectedEndOffset(); // Check whether it is not a case when there were // no collapsed folds before and no collapsed folds now if (!collapsedFoldsInPresentViews) { // no collapsed folds previously // TODO Could Integer.MAX_VALUE be used? if (FoldUtilities.findCollapsedFold(hierarchy, affectedStartOffset, affectedEndOffset) == null ) { // no collapsed folds => no need to rebuild rebuildViews = false; } } if (rebuildViews) { /** * Check the affected offsets against the current document boundaries */ int docLength = getDocument().getLength(); int rebuildStartOffset = Math.min(affectedStartOffset, docLength); int rebuildEndOffset = Math.min(affectedEndOffset, docLength); offsetRebuild(rebuildStartOffset, rebuildEndOffset); } } finally { updateLayout(); layoutUnlock(); } } finally { lockView.unlock(); } } public void paint(Graphics g, Shape allocation) { super.paint(g, allocation); if (getContainer() instanceof javax.swing.text.JTextComponent){ TextUI textUI = ((javax.swing.text.JTextComponent)getContainer()).getUI(); if (textUI instanceof BaseTextUI){ ((BaseTextUI) textUI).getEditorUI().paint(g); } } } public void setSize(float width, float height) { super.setSize(width, height); // Schedule estimated span reset if (!estimatedSpanResetInitiated && isEstimatedSpan()) { estimatedSpanResetInitiated = true; Timer timer = new Timer(4000, new ActionListener() { public void actionPerformed(ActionEvent evt) { AbstractDocument doc = (AbstractDocument)getDocument(); if (doc!=null) { doc.readLock(); try { LockView lockView = LockView.get(DrawEngineDocView.this); if (lockView != null) { // if there is no lock view no async layout is done lockView.lock(); try { setEstimatedSpan(false); } finally { lockView.unlock(); } } } finally { doc.readUnlock(); } } } }); timer.setRepeats(false); timer.start(); } } protected boolean isChildrenResizeDisabled() { return true; } public void propertyChange(java.beans.PropertyChangeEvent evt) { JTextComponent component = (JTextComponent)getContainer(); if (component==null || evt==null || !EditorUI.LINE_HEIGHT_CHANGED_PROP.equals(evt.getPropertyName())) return; AbstractDocument doc = (AbstractDocument)getDocument(); if (doc!=null) { doc.readLock(); try{ LockView lockView = LockView.get(this); lockView.lock(); try { rebuild(0, getViewCount()); } finally { lockView.unlock(); } } finally { doc.readUnlock(); } component.revalidate(); } } } |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
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.