|
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.*; import java.awt.event.ActionEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; import java.util.List; import java.util.Iterator; import javax.swing.text.*; import javax.swing.event.DocumentListener; import javax.swing.event.DocumentEvent; import javax.swing.plaf.TextUI; import javax.swing.plaf.ComponentUI; import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.SwingUtilities; import javax.swing.Action; import javax.swing.UIManager; import javax.swing.plaf.basic.BasicTextUI; import org.netbeans.editor.SettingsChangeListener; import org.netbeans.editor.view.spi.LockView; /** * Text UI implementation * * @author Miloslav Metelka, Martin Roskanin * @version 1.00 */ public class BaseTextUI extends BasicTextUI implements PropertyChangeListener, DocumentListener, SettingsChangeListener { /** Extended UI */ private EditorUI editorUI; private boolean foldingEnabled; private boolean needsRefresh = false; /** ID of the component in registry */ int componentID = -1; private AbstractDocument lastDocument; /** Instance of the GetFocusedComponentAction */ private static final GetFocusedComponentAction gfcAction = new GetFocusedComponentAction(); public BaseTextUI() { } protected String getPropertyPrefix() { return "EditorPane"; //NOI18N } public static JTextComponent getFocusedComponent() { return gfcAction.getFocusedComponent2(); } protected boolean isRootViewReplaceNecessary() { boolean replaceNecessary = false; Document doc = getComponent().getDocument(); if (doc != lastDocument) { replaceNecessary = true; } return replaceNecessary; } protected void rootViewReplaceNotify() { // update the newly used document lastDocument = (AbstractDocument)getComponent().getDocument(); } /** Called when the model of component is changed */ protected void modelChanged() { JTextComponent component = getComponent(); // [TODO] assert (component != null); Document doc = component.getDocument(); if (doc != null && !(doc instanceof AbstractDocument)) { // This UI works with AbstractDocument document instances only return; // return silently } AbstractDocument adoc = (AbstractDocument)doc; // Possibly rebuild fold hierarchy prior to rebuilding views. // Views have optimization in fold hierarchy rebuild listening // so that the actual views rebuild is only done once. // Readlock on both last and current docs. /* if (doc != lastDocument) { if (lastDocument != null) { lastDocument.readLock(); } try { if (adoc != null) { adoc.readLock(); } try { FoldHierarchySpi.get(component).rebuild(); } finally { if (adoc != null) { adoc.readUnlock(); } } } finally { if (lastDocument != null) { lastDocument.readUnlock(); } } } */ if (doc != null) { ViewFactory f = getRootView(component).getViewFactory(); BaseKit kit = (BaseKit)getEditorKit(component); component.removeAll(); if (isRootViewReplaceNecessary()) { rootViewReplaceNotify(); Element elem = doc.getDefaultRootElement(); View v = f.create(elem); setView(v); } component.revalidate(); // Execute actions related to document installaction into the component Settings.KitAndValue[] kv = Settings.getValueHierarchy(kit.getClass(), SettingsNames.DOC_INSTALL_ACTION_NAME_LIST); for (int i = kv.length - 1; i >= 0; i--) { List actList = (List)kv[i].value; actList = kit.translateActionNameList(actList); // translate names to actions if (actList != null) { for (Iterator iter = actList.iterator(); iter.hasNext();) { Action a = (Action)iter.next(); a.actionPerformed(new ActionEvent(component, ActionEvent.ACTION_PERFORMED, "")); // NOI18N } } } } } /* XXX - workaround bugfix of issue #45487 and #45678 * The hack can be removed if JDK bug * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5067948 * will be fixed. */ protected void installKeyboardActions() { String mapName = getPropertyPrefix() + ".actionMap"; //NOI18N // XXX - workaround bugfix of issue #45487 // Because the ActionMap is cached in method BasicTextUI.getActionMap() // the property 'mapName' is set to null to force new actionMap creation UIManager.getLookAndFeelDefaults().put(mapName, null); UIManager.getDefaults().put(mapName, null); //#45678 super.installKeyboardActions(); } /** Installs the UI for a component. */ public void installUI(JComponent c) { super.installUI(c); if (!(c instanceof JTextComponent)) { return; } JTextComponent component = getComponent(); // set margin Object value = Settings.getValue(Utilities.getKitClass(component), SettingsNames.MARGIN); Insets margin = (value instanceof Insets) ? (Insets)value : null; component.setMargin(margin); getEditorUI().installUI(component); Boolean foldingEnabledBoolean = (Boolean)Settings.getValue(Utilities.getKitClass(component), SettingsNames.CODE_FOLDING_ENABLE); foldingEnabled = foldingEnabledBoolean.booleanValue(); component.putClientProperty(SettingsNames.CODE_FOLDING_ENABLE, foldingEnabledBoolean); Settings.addSettingsChangeListener(this); // attach to the model and component //component.addPropertyChangeListener(this); already done in super class if (component.getClientProperty(UIWatcher.class) == null) { component.addPropertyChangeListener(new UIWatcher(this.getClass())); component.putClientProperty(UIWatcher.class, UIWatcher.class); } BaseKit kit = (BaseKit)getEditorKit(component); ViewFactory vf = kit.getViewFactory(); // Create and attach caret Caret caret = kit.createCaret(); component.setCaretColor(Color.black); // will be changed by settings later component.setCaret(caret); // assign blink rate int br = SettingsUtil.getInteger(Utilities.getKitClass(component), SettingsNames.CARET_BLINK_RATE, SettingsDefaults.defaultCaretBlinkRate.intValue()); caret.setBlinkRate(br); // Create document /* BaseDocument doc = Utilities.getDocument(component); if (doc != null) { modelChanged(null, doc); } */ SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED, null); Registry.addComponent(component); Registry.activate(component); component.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); } /** Deinstalls the UI for a component */ public void uninstallUI(JComponent c) { super.uninstallUI(c); Settings.removeSettingsChangeListener(this); //c.removePropertyChangeListener(this); if (c instanceof JTextComponent){ JTextComponent comp = (JTextComponent)c; BaseDocument doc = Utilities.getDocument(comp); if (doc != null) { doc.removeDocumentListener(this); } comp.setKeymap(null); comp.setCaret(null); getEditorUI().uninstallUI(comp); Registry.removeComponent(comp); } // Clear the editorUI so it will be recreated according to the kit // of the component for which the installUI() is called editorUI = null; } public int getYFromPos(int pos) throws BadLocationException { Rectangle ret = modelToView(getComponent(), pos); return (ret == null) ? 0 : ret.y; /* BaseDocument doc = Utilities.getDocument(getComponent()); if (doc!=null){ int ret = (Utilities.getLineOffset(doc, pos)) * getEditorUI().getLineHeight(); return ret; } return 0; */ } public int getPosFromY(int y) throws BadLocationException { return viewToModel(getComponent(), 0, y); } public int getBaseX(int y) { return getEditorUI().getTextMargin().left; } public int viewToModel(JTextComponent c, int x, int y) { return viewToModel(c, new Point(x, y)); } /** Next visually represented model location where caret can be placed. * This version works without placing read lock on the document. */ public int getNextVisualPositionFrom(JTextComponent t, int pos, Position.Bias b, int direction, Position.Bias[] biasRet) throws BadLocationException{ if (biasRet == null) { biasRet = new Position.Bias[1]; biasRet[0] = Position.Bias.Forward; } return super.getNextVisualPositionFrom(t, pos, b, direction, biasRet); } /** Fetches the EditorKit for the UI. * * @return the component capabilities */ public EditorKit getEditorKit(JTextComponent c) { JEditorPane pane = (JEditorPane)getComponent(); return (pane==null) ? null : pane.getEditorKit(); } /** Get extended UI. This is called from views to get correct extended UI. */ public EditorUI getEditorUI() { if (editorUI == null) { BaseKit kit = (BaseKit)getEditorKit(getComponent()); editorUI = kit.createEditorUI(); } return editorUI; } /** * This method gets called when a bound property is changed. * We are looking for document changes on the component. */ public void propertyChange(PropertyChangeEvent evt) { String propName = evt.getPropertyName(); if ("document".equals(propName)) { // NOI18N BaseDocument oldDoc = (evt.getOldValue() instanceof BaseDocument) ? (BaseDocument)evt.getOldValue() : null; if (oldDoc != null) { oldDoc.removeDocumentListener(this); } BaseDocument newDoc = (evt.getNewValue() instanceof BaseDocument) ? (BaseDocument)evt.getNewValue() : null; if (newDoc != null) { newDoc.addDocumentListener(this); Registry.activate(newDoc); // Activate the new document } } else if ("ancestor".equals(propName)) { // NOI18N JTextComponent comp = (JTextComponent)evt.getSource(); if (comp.isDisplayable() && editorUI != null && editorUI.hasExtComponent()) { // #41209: In case extComponent was retrieved set the ancestorOverride // to true and expect that the editor kit that installed // this UI will be deinstalled explicitly. if (!Boolean.TRUE.equals(comp.getClientProperty("ancestorOverride"))) { // NOI18N comp.putClientProperty("ancestorOverride", Boolean.TRUE); // NOI18N } } } } /** Insert to document notification. */ public void insertUpdate(DocumentEvent evt) { try { BaseDocumentEvent bevt = (BaseDocumentEvent)evt; EditorUI editorUI = getEditorUI(); int y = getYFromPos(evt.getOffset()); int lineHeight = editorUI.getLineHeight(); int syntaxY = getYFromPos(bevt.getSyntaxUpdateOffset()); // !!! patch for case when DocMarksOp.eolMark is at the end of document if (bevt.getSyntaxUpdateOffset() == evt.getDocument().getLength()) { syntaxY += lineHeight; } if (getComponent().isShowing()) { editorUI.repaint(y, Math.max(lineHeight, syntaxY - y)); } } catch (BadLocationException ex) { Utilities.annotateLoggable(ex); } } /** Remove from document notification. */ public void removeUpdate(DocumentEvent evt) { try { BaseDocumentEvent bevt = (BaseDocumentEvent)evt; EditorUI editorUI = getEditorUI(); int y = getYFromPos(evt.getOffset()); int lineHeight = editorUI.getLineHeight(); int syntaxY = getYFromPos(bevt.getSyntaxUpdateOffset()); // !!! patch for case when DocMarksOp.eolMark is at the end of document if (bevt.getSyntaxUpdateOffset() == evt.getDocument().getLength()) { syntaxY += lineHeight; } if (getComponent().isShowing()) { editorUI.repaint(y, Math.max(lineHeight, syntaxY - y)); } } catch (BadLocationException ex) { Utilities.annotateLoggable(ex); } } /** The change in document notification. * * @param evt The change notification from the currently associated document. */ public void changedUpdate(DocumentEvent evt) { if (evt instanceof BaseDocumentEvent) { BaseDocumentEvent bdevt = (BaseDocumentEvent)evt; BaseDocument doc = (BaseDocument)bdevt.getDocument(); String layerName = bdevt.getDrawLayerName(); if (layerName != null) { getEditorUI().addLayer(doc.findLayer(layerName), bdevt.getDrawLayerVisibility()); }else{ //temp try { JTextComponent comp = getComponent(); if (comp!=null && comp.isShowing()) { getEditorUI().repaintBlock(evt.getOffset(), evt.getOffset() + evt.getLength()); } } catch (BadLocationException ex) { Utilities.annotateLoggable(ex); } } } } /** Creates a view for an element. * * @param elem the element * @return the newly created view or null */ public View create(Element elem) { String kind = elem.getName(); /* if (foldingEnabled){ Element parent = elem.getParentElement(); if (parent!=null){ int index = parent.getElementIndex(elem.getStartOffset()); if (index >=3 && index <=6){ return new CollapsedView(parent.getElement(3), parent.getElement(6)); } } } */ if (kind != null) { if (kind.equals(AbstractDocument.ContentElementName)) { return new LabelView(elem); } else if (kind.equals(AbstractDocument.ParagraphElementName)) { // System.out.println("creating DrawEngineLineView for elem=" + elem); return new DrawEngineLineView(elem);//.createFragment(elem.getStartOffset()+10,elem.getStartOffset()+30); } else if (kind.equals(AbstractDocument.SectionElementName)) { // return new LockView(new EditorUIBoxView(elem, View.Y_AXIS)); // System.out.println("creating DrawEngineDocView for elem=" + elem); // return new DrawEngineDocView(getComponent()); // EditorUIBoxView(elem, View.Y_AXIS); return new LockView(new DrawEngineDocView(elem)); // EditorUIBoxView(elem, View.Y_AXIS); } else if (kind.equals(StyleConstants.ComponentElementName)) { return new ComponentView(elem); } else if (kind.equals(StyleConstants.IconElementName)) { return new IconView(elem); } } // default to text display return new DrawEngineLineView(elem); } /** Creates a view for an element. * @param elem the element * @param p0 the starting offset >= 0 * @param p1 the ending offset >= p0 * @return the view */ public View create(Element elem, int p0, int p1) { return null; } /** Specifies that some preference has changed. */ public void preferenceChanged(boolean width, boolean height) { modelChanged(); } /** Update height of the views */ void updateHeight() { } public void invalidateStartY() { // no longer available } public void settingsChange(SettingsChangeEvent evt) { JTextComponent component = getComponent(); if (component == null) return; if (evt == null || Utilities.getKitClass(component) != evt.getKitClass()) return; if (SettingsNames.CODE_FOLDING_ENABLE.equals(evt.getSettingName())){ Boolean foldingEnabledBoolean =(Boolean)Settings.getValue(evt.getKitClass(), SettingsNames.CODE_FOLDING_ENABLE); foldingEnabled = foldingEnabledBoolean.booleanValue(); component.putClientProperty(SettingsNames.CODE_FOLDING_ENABLE, foldingEnabledBoolean); needsRefresh = true; refresh(); } } boolean isFoldingEnabled() { return foldingEnabled; } protected void refresh(){ if (getComponent().isShowing() && needsRefresh){ modelChanged(); needsRefresh = false; } } private static class GetFocusedComponentAction extends TextAction { private GetFocusedComponentAction() { super("get-focused-component"); // NOI18N } public void actionPerformed(ActionEvent evt) { } JTextComponent getFocusedComponent2() { return super.getFocusedComponent(); } } class EditorUIBoxView extends BoxView{ public EditorUIBoxView(Element elem, int axis){ super(elem, axis); } private DrawEngine.PreinitializedDrawEngine getPreinitializedDrawEngine(Graphics g){ DrawEngine.PreinitializedDrawEngine drawEngine = null; Rectangle clip = g.getClipBounds(); if (clip.height <= 0 || clip.width < 0) { return null; } int clipY = clip.y; int clipHeight = clip.height; int paintY = Math.max(clipY, 0); // relative start of area to paint BaseDocument doc = (BaseDocument)getEditorUI().getDocument(); try { int startPos = getPosFromY(paintY); int pos = getPosFromY(clipY + clipHeight - 1); int endPos = Utilities.getRowEnd(doc, pos); int startOffset = startPos; int endOffset = endPos; int y = getYFromPos(startOffset); if (endOffset > startOffset){ drawEngine = DrawEngine.getDrawEngine().getDrawEngine( this, new DrawGraphics.GraphicsDG(g), getEditorUI(), startOffset, endOffset, getBaseX(y), y, Integer.MAX_VALUE ); } }catch(BadLocationException ble){ ble.printStackTrace(); } return drawEngine; } public void paint(Graphics g, Shape allocation) { super.paint(g, allocation); DrawEngine.PreinitializedDrawEngine pde = null; JTextComponent component = getComponent(); try{ pde = getPreinitializedDrawEngine(g); // share the instance of PreinitializedDrawEngine among children views if (component!=null){ component.putClientProperty(DrawEngine.PreinitializedDrawEngine.class, pde); //NOI18N } getEditorUI().paint(g); }finally{ // release created preinitialized instance if (pde!=null) pde.release(); if (component!=null){ component.putClientProperty(DrawEngine.PreinitializedDrawEngine.class, null); } } } } /** Class that returns back BaseTextUI after its change * by changing look-and-feel. */ static class UIWatcher implements PropertyChangeListener { private Class uiClass; UIWatcher(Class uiClass) { this.uiClass = uiClass; } public void propertyChange(PropertyChangeEvent evt) { Object newValue = evt.getNewValue(); if ("UI".equals(evt.getPropertyName()) && (newValue != null) && !(newValue instanceof BaseTextUI) ) { JTextComponent c = (JTextComponent)evt.getSource(); EditorKit kit = ((TextUI)newValue).getEditorKit(c); if (kit instanceof BaseKit) { // BaseKit but not BaseTextUI -> restore BaseTextUI try { c.setUI((BaseTextUI)uiClass.newInstance()); } catch (InstantiationException e) { } catch (IllegalAccessException e) { } } } } } } |
... 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.