# This patch file was generated by NetBeans IDE # Following Index: paths are relative to: /doma/jarda/netbeans-src/openide/text # This patch can be applied using context Tools: Patch action on respective folder. # It uses platform neutral UTF-8 encoding and \n newlines. # Above lines and this line are ignored by the patching process. Index: src/org/openide/text/CloneableEditorSupportRedirector.java *** /doma/jarda/netbeans-src/openide/text/src/org/openide/text/CloneableEditorSupportRedirector.java No Base Revision --- /doma/jarda/netbeans-src/openide/text/src/org/openide/text/CloneableEditorSupportRedirector.java Locally New *************** *** 1,0 **** --- 1,55 ---- + /* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. + * Portions Copyrighted 2007 Sun Microsystems, Inc. + */ + package org.openide.text; + + import org.openide.util.Lookup; + + /** + * Allows to find another {@link CloneableEditorSupport} that all the + * requests passed to given one should be redirected to. This is useful + * for redirecting operation on + * FileObject to another one in cases when two FileObjects + * represent the same physical file. + * + * @author Jaroslav Tulach + * @since 6.13 + */ + public abstract class CloneableEditorSupportRedirector { + /** Find a delegate for given {@link CloneableEditorSupport}'s {@link Lookup}. + * The common code can be to extract for example a + * + * FileObject from the lookup and use its location to find another + * CloneableEditorSupport to delegate to. + * + * @param env the environment associated with current CloneableEditorSupport + * @return null or another CloneableEditorSupport to use as a replacement + */ + protected abstract CloneableEditorSupport redirect(Lookup env); + + static CloneableEditorSupport findRedirect(CloneableEditorSupport one) { + for (CloneableEditorSupportRedirector r : Lookup.getDefault().lookupAll(CloneableEditorSupportRedirector.class)) { + CloneableEditorSupport ces = r.redirect(one.getLookup()); + if (ces != null && ces != one) { + return ces; + } + } + return null; + } + } + + Index: test/unit/src/org/openide/text/CloneableEditorSupportRedirectorTest.java *** /doma/jarda/netbeans-src/openide/text/test/unit/src/org/openide/text/CloneableEditorSupportRedirectorTest.java No Base Revision --- /doma/jarda/netbeans-src/openide/text/test/unit/src/org/openide/text/CloneableEditorSupportRedirectorTest.java Locally New *************** *** 1,0 **** --- 1,334 ---- + /* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. + * Portions Copyrighted 2007 Sun Microsystems, Inc. + */ + package org.openide.text; + + import java.beans.PropertyChangeListener; + import java.io.ByteArrayOutputStream; + import java.io.IOException; + import java.io.InputStream; + import java.lang.ref.WeakReference; + import java.util.Arrays; + import javax.swing.SwingUtilities; + import javax.swing.text.Document; + import javax.swing.text.EditorKit; + import junit.framework.Test; + import junit.framework.TestSuite; + import org.netbeans.junit.MockServices; + import org.netbeans.junit.NbTestCase; + import org.netbeans.junit.NbTestSuite; + import org.openide.util.Exceptions; + import org.openide.util.Lookup; + import org.openide.util.lookup.AbstractLookup; + import org.openide.util.lookup.InstanceContent; + + /** + * + * @author Jaroslav Tulach + */ + public class CloneableEditorSupportRedirectorTest extends NbTestCase + implements CloneableEditorSupport.Env { + /** the content of lookup of support */ + private InstanceContent ic; + Redirector red; + + + // Env variables + private String content = ""; + private boolean valid = true; + private boolean modified = false; + /** if not null contains message why this document cannot be modified */ + private String cannotBeModified; + private java.util.Date date = new java.util.Date (); + private java.util.List propL = new java.util.ArrayList(); + private java.beans.VetoableChangeListener vetoL; + + + + public CloneableEditorSupportRedirectorTest(String testName) { + super(testName); + } + + public static Test suite() { + TestSuite suite = new NbTestSuite(CloneableEditorSupportRedirectorTest.class); + + return suite; + } + + + protected void setUp () { + ic = new InstanceContent (); + CES support = new CES (this, new AbstractLookup(ic)); + + MockServices.setServices(Redirector.class); + red = Lookup.getDefault().lookup(Redirector.class); + assertNotNull(red); + + CloneableEditorSupportRedirectorTest t = new CloneableEditorSupportRedirectorTest(""); + red.master = support; + InstanceContent slave = new InstanceContent(); + red.slave = new CES(t, new AbstractLookup (slave)); + slave.add(red.master); + } + + public void testSameDocument() throws Exception { + javax.swing.text.Document doc = red.slave.openDocument (); + assertNotNull (doc); + + assertSame(doc, red.master.getDocument()); + + String s = doc.getText (0, doc.getLength ()); + assertEquals ("Same text as in the stream", content, s); + + assertFalse ("No redo", red.slave.getUndoRedo ().canRedo ()); + assertFalse ("No undo", red.slave.getUndoRedo ().canUndo ()); + } + + public void testLineLookupIsPropagated () throws Exception { + content = "Line1\nLine2\n"; + Integer template = new Integer (1); + ic.add (template); // put anything into the lookup + + // in order to set.getLines() work correctly, the document has to be loaded + red.master.openDocument(); + + Line.Set set = red.master.getLineSet(); + assertSame("Same lines", set, red.slave.getLineSet()); + java.util.List list = set.getLines(); + assertEquals ("Three lines", 3, list.size ()); + + Line l = (Line)list.get (0); + Integer i = l.getLookup ().lookup (Integer.class); + assertEquals ("The original integer", template, i); + ic.remove (template); + i = l.getLookup ().lookup (Integer.class); + assertNull ("Lookup is dynamic, so now there is nothing", i); + } + + + public void testGetInputStream () throws Exception { + content = "goes\nto\nInputStream"; + String added = "added before\n"; + javax.swing.text.Document doc = red.master.openDocument (); + assertNotNull (doc); + + // modify the document + doc.insertString(0, added, null); + compareStreamWithString(red.master.getInputStream(), added + content); + compareStreamWithString(red.slave.getInputStream(), added + content); + } + + public void testGetInputStreamWhenClosed () throws Exception { + content = "basic\ncontent"; + compareStreamWithString(red.master.getInputStream(), content); + compareStreamWithString(red.slave.getInputStream(), content); + // we should be doing this with the document still closed + assertNull("The document is supposed to be still closed", red.master.getDocument ()); + } + + public void testDocumentCannotBeModified () throws Exception { + content = "Ahoj\nMyDoc"; + cannotBeModified = "No, you cannot modify this document in this test"; + + javax.swing.text.Document doc = red.master.openDocument (); + assertNotNull (doc); + + assertFalse ("Nothing to undo", red.master.getUndoRedo ().canUndo ()); + + // this should not be allowed + doc.insertString (0, "Kuk", null); + + String modifiedForAWhile = doc.getText (0, 3); + //assertEquals ("For a while the test really starts with Kuk", "Kuk", doc.getText (0, 3)); + + assertFalse ("The document cannot be modified", red.master.getUndoRedo ().canUndo ()); + + String s = doc.getText (0, doc.getLength ()); + assertEquals ("The document is now the same as at the begining", content, s); + + assertEquals ("Message has been shown to user in status bar", cannotBeModified, org.openide.awt.StatusDisplayer.getDefault ().getStatusText ()); + } + + public void testDocumentCanBeGarbageCollectedWhenClosed () throws Exception { + content = "Ahoj\nMyDoc"; + javax.swing.text.Document doc = red.master.openDocument (); + assertNotNull (doc); + + assertTrue ("Document is loaded", red.master.isDocumentLoaded ()); + assertTrue ("Document is loaded", red.slave.isDocumentLoaded ()); + assertTrue ("Can be closed without problems", red.slave.close ()); + assertFalse ("Document is not loaded", red.master.isDocumentLoaded ()); + assertFalse ("Document is not loaded", red.slave.isDocumentLoaded ()); + + WeakReference ref = new WeakReference(doc); + doc = null; + + assertGC ("Document can dissapear", ref); + } + + /** + * Tests that the wrapEditorComponent() method returns the passed + * parameter (doesn't wrap the passed component in some additional UI). + */ + public void testWrapEditorComponent() { + javax.swing.JPanel panel = new javax.swing.JPanel(); + assertSame(red.master.wrapEditorComponent(panel), panel); + assertSame(red.slave.wrapEditorComponent(panel), panel); + } + + public void testAfterOpenOfSlaveThereAreMasterPanes() throws Exception { + red.slave.open(); + + class Check implements Runnable { + public void run() { + assertTrue("Some panes are now open", red.master.getOpenedPanes() != null); + } + } + Check check = new Check(); + + SwingUtilities.invokeAndWait(check); + } + + public void testGetEditorKit() { + EditorKit kit = CloneableEditorSupport.getEditorKit("text/plain"); + assertNotNull("EditorKit should never be null", kit); + // There shouldn't be any EK registered and we should get the default one + assertEquals("Wrong default EditorKit", "org.openide.text.CloneableEditorSupport$PlainEditorKit", kit.getClass().getName()); + } + + private void compareStreamWithString(InputStream is, String s) throws Exception{ + int i; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + while ((i = is.read()) != -1) { + baos.write(i); + } + byte b1[] = baos.toByteArray(); + byte b2[] = s.getBytes(); + assertTrue("Same bytes as would result from the string: " + s, Arrays.equals(b1, b2)); + } + + // + // Implementation of the CloneableEditorred.master.Env + // + + public synchronized void addPropertyChangeListener(java.beans.PropertyChangeListener l) { + propL.add (l); + } + public synchronized void removePropertyChangeListener(java.beans.PropertyChangeListener l) { + propL.remove (l); + } + + public synchronized void addVetoableChangeListener(java.beans.VetoableChangeListener l) { + assertNull ("This is the first veto listener", vetoL); + vetoL = l; + } + public void removeVetoableChangeListener(java.beans.VetoableChangeListener l) { + assertEquals ("Removing the right veto one", vetoL, l); + vetoL = null; + } + + public org.openide.windows.CloneableOpenSupport findCloneableOpenSupport() { + return red.master; + } + + public String getMimeType() { + return "text/plain"; + } + + public java.util.Date getTime() { + return date; + } + + public java.io.InputStream inputStream() throws java.io.IOException { + return new java.io.ByteArrayInputStream (content.getBytes ()); + } + public java.io.OutputStream outputStream() throws java.io.IOException { + class ContentStream extends java.io.ByteArrayOutputStream { + public void close () throws java.io.IOException { + super.close (); + content = new String (toByteArray ()); + } + } + + return new ContentStream (); + } + + public boolean isValid() { + return valid; + } + + public boolean isModified() { + return modified; + } + + public void markModified() throws java.io.IOException { + if (cannotBeModified != null) { + final String notify = cannotBeModified; + IOException e = new IOException () { + public String getLocalizedMessage () { + return notify; + } + }; + Exceptions.attachLocalizedMessage(e, cannotBeModified); + throw e; + } + + modified = true; + } + + public void unmarkModified() { + modified = false; + } + + /** Implementation of the CES */ + private static final class CES extends CloneableEditorSupport { + public CES (Env env, Lookup l) { + super (env, l); + } + + protected String messageName() { + return "Name"; + } + + protected String messageOpened() { + return "Opened"; + } + + protected String messageOpening() { + return "Opening"; + } + + protected String messageSave() { + return "Save"; + } + + protected String messageToolTip() { + return "ToolTip"; + } + + } + + + public static final class Redirector extends CloneableEditorSupportRedirector { + CES master; + CES slave; + + protected CloneableEditorSupport redirect(Lookup ces) { + return ces.lookup(CloneableEditorSupport.class); + } + } + } Index: apichanges.xml *** /doma/jarda/netbeans-src/openide/text/apichanges.xml Base (1.16) --- /doma/jarda/netbeans-src/openide/text/apichanges.xml Locally Modified (Based On 1.16) *************** *** 23,28 **** --- 23,47 ---- Text API + + + CloneableEditorSupportRedirector + + + + + +

The CloneableEditorSupportRedirector + class allows a redirection of operations on a CloneableEditorSupport + object to another one. This can be useful if there are two logical + files representing one physical and one wants to have just a single + editor for both files. In such case just implement the + CloneableEditorSupportRedirector. +

+
+ + +
Index: src/org/openide/text/CloneableEditorSupport.java *** /doma/jarda/netbeans-src/openide/text/src/org/openide/text/CloneableEditorSupport.java Base (1.28) --- /doma/jarda/netbeans-src/openide/text/src/org/openide/text/CloneableEditorSupport.java Locally Modified (Based On 1.28) *************** *** 305,310 **** --- 305,315 ---- * @return the manager */ protected final synchronized UndoRedo.Manager getUndoRedo() { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + return redirect.getUndoRedo(); + } + if (undoRedo == null) { undoRedo = createUndoRedoManager(); } *************** *** 381,386 **** --- 386,397 ---- /** Overrides superclass method, first processes document preparation. * @see #prepareDocument */ public void open() { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + redirect.open(); + return; + } + try { if (getListener().loadExc instanceof UserQuestionException) { getListener().loadExc = null; *************** *** 460,465 **** --- 471,480 ---- * @return task for control over loading */ public Task prepareDocument() { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + return redirect.prepareDocument(); + } synchronized (getLock()) { switch (documentStatus) { case DOCUMENT_NO: *************** *** 633,638 **** --- 648,657 ---- * @exception IOException if the document could not be loaded */ public StyledDocument openDocument() throws IOException { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + return redirect.openDocument(); + } synchronized (getLock()) { return openDocumentCheckIOE(); } *************** *** 695,700 **** --- 714,723 ---- * @return document or null if it is not yet loaded */ public StyledDocument getDocument() { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + return redirect.getDocument(); + } synchronized (getLock()) { while (true) { switch (documentStatus) { *************** *** 722,727 **** --- 745,754 ---- * otherwise false */ public boolean isModified() { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + return redirect.isModified(); + } return cesEnv().isModified(); } *************** *** 730,735 **** --- 757,767 ---- * @exception IOException on I/O error */ public void saveDocument() throws IOException { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + redirect.saveDocument(); + return; + } // #17714: Don't try to save unmodified doc. if (!cesEnv().isModified()) { return; *************** *** 834,839 **** --- 866,875 ---- public JEditorPane[] getOpenedPanes() { // expected in AWT only assert SwingUtilities.isEventDispatchThread(); // NOI18N + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + return redirect.getOpenedPanes(); + } LinkedList ll = new LinkedList(); Enumeration en = allEditors.getComponents(); *************** *** 888,893 **** --- 924,933 ---- * @return positions of all paragraphs on last save */ public Line.Set getLineSet() { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + return redirect.getLineSet(); + } return updateLineSet(false); } *************** *** 913,918 **** --- 953,963 ---- /** A printing implementation suitable for {@link org.openide.cookies.PrintCookie}. */ public void print() { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + redirect.print(); + return; + } // XXX should this run synch? can be slow for an enormous doc synchronized (LOCK_PRINTING) { if (printing) { *************** *** 1125,1130 **** --- 1170,1179 ---- * @return true if document is loaded */ public boolean isDocumentLoaded() { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + return redirect.isDocumentLoaded(); + } return documentStatus != DOCUMENT_NO; } *************** *** 1133,1138 **** --- 1182,1192 ---- * @param s the new MIME type */ public void setMIMEType(String s) { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + redirect.setMIMEType(s); + return; + } mimeType = s; } *************** *** 1227,1232 **** --- 1281,1290 ---- * @since 4.7 */ public InputStream getInputStream() throws IOException { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + return redirect.getInputStream(); + } // Implementation note // Piped stream will not work, as we are in the same thread // Doing this in a different thread would need to lock the document for *************** *** 1780,1785 **** --- 1838,1848 ---- * @return false if the operation is cancelled */ protected boolean close(boolean ask) { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + return redirect.close(ask); + } + if (!super.close(ask)) { // if not all editors has been closed return false; *************** *** 2054,2059 **** --- 2117,2126 ---- * @since 5.2 */ protected final Pane openAt(final PositionRef pos, final int column) { + CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this); + if (redirect != null) { + return redirect.openAt(pos, column); + } final Pane e = openPane(); final Task t = prepareDocument(); e.ensureVisible(); Index: manifest.mf *** /doma/jarda/netbeans-src/openide/text/manifest.mf Base (1.14) --- /doma/jarda/netbeans-src/openide/text/manifest.mf Locally Modified (Based On 1.14) *************** *** 1,5 **** Manifest-Version: 1.0 OpenIDE-Module: org.openide.text ! OpenIDE-Module-Specification-Version: 6.12 OpenIDE-Module-Localizing-Bundle: org/openide/text/Bundle.properties --- 1,5 ---- Manifest-Version: 1.0 OpenIDE-Module: org.openide.text ! OpenIDE-Module-Specification-Version: 6.13 OpenIDE-Module-Localizing-Bundle: org/openide/text/Bundle.properties