--- a/masterfs/nbproject/project.xml Sun Nov 20 00:28:39 2011 +0100 +++ a/masterfs/nbproject/project.xml Mon Nov 21 11:35:59 2011 +0100 @@ -72,7 +72,7 @@ - 7.37 + 7.54 --- a/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/BaseFileObj.java Sun Nov 20 00:28:39 2011 +0100 +++ a/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/BaseFileObj.java Mon Nov 21 11:35:59 2011 +0100 @@ -603,14 +603,14 @@ FileEventImpl parentFe = null; if (parent != null && pListeners != null) { - parentFe = new FileEventImpl(parent, this, expected); + parentFe = new FileEventImpl(parent, this, expected, 0); } if (parentFe != null) { final FileEventImpl fe = new FileEventImpl(this, parentFe); fireFileDataCreatedEvent(getListeners(), fe); parent.fireFileDataCreatedEvent(pListeners, parentFe); } else { - final FileEventImpl fe = new FileEventImpl(this, this, expected); + final FileEventImpl fe = new FileEventImpl(this, this, expected, 0); fireFileDataCreatedEvent(getListeners(), fe); } stopWatch.stop(); @@ -627,14 +627,14 @@ FileEventImpl parentFe = null; if (parent != null && pListeners != null) { - parentFe = new FileEventImpl(parent, this, expected); + parentFe = new FileEventImpl(parent, this, expected, 0); } if (parentFe != null) { final FileEventImpl fe = new FileEventImpl(this, parentFe); fireFileFolderCreatedEvent(getListeners(), fe); parent.fireFileFolderCreatedEvent(pListeners, parentFe); } else { - final FileEventImpl fe = new FileEventImpl(this, this, expected); + final FileEventImpl fe = new FileEventImpl(this, this, expected, 0); fireFileFolderCreatedEvent(getListeners(), fe); } stopWatch.stop(); @@ -652,14 +652,14 @@ FileEventImpl parentFe = null; if (parent != null && pListeners != null) { - parentFe = new FileEventImpl(parent, this, expected); + parentFe = new FileEventImpl(parent, this, expected, lastModified().getTime()); } if (parentFe != null) { final FileEventImpl fe = new FileEventImpl(this, parentFe); fireFileChangedEvent(getListeners(), fe); parent.fireFileChangedEvent(pListeners, parentFe); } else { - final FileEventImpl fe = new FileEventImpl(this, this, expected); + final FileEventImpl fe = new FileEventImpl(this, this, expected, lastModified().getTime()); fireFileChangedEvent(getListeners(), fe); } stopWatch.stop(); @@ -675,14 +675,14 @@ FileEventImpl parentFe = null; if (parent != null && pListeners != null) { - parentFe = new FileEventImpl(parent, this, expected); + parentFe = new FileEventImpl(parent, this, expected, 0); } if (parentFe != null) { final FileEventImpl fe = new FileEventImpl(this, parentFe); fireFileDeletedEvent(getListeners(), fe); parent.fireFileDeletedEvent(pListeners, parentFe); } else { - final FileEventImpl fe = new FileEventImpl(this, this, expected); + final FileEventImpl fe = new FileEventImpl(this, this, expected, 0); fireFileDeletedEvent(getListeners(), fe); } stopWatch.stop(); @@ -1025,12 +1025,12 @@ return next; } - public FileEventImpl(FileObject src, FileObject file, boolean expected) { - super(src, file, expected); + public FileEventImpl(FileObject src, FileObject file, boolean expected, long time) { + super(src, file, expected, time); } public FileEventImpl(FileObject src, FileEventImpl next) { - super(src, next.getFile(), next.isExpected()); + super(src, next.getFile(), next.isExpected(), next.getTime()); this.next = next; } } --- a/openide.filesystems/apichanges.xml Sun Nov 20 00:28:39 2011 +0100 +++ a/openide.filesystems/apichanges.xml Mon Nov 21 11:35:59 2011 +0100 @@ -49,6 +49,21 @@ Filesystems API + + + Detailed FileEvent constructor + + + + + +

New FileEvent constructor allowing specification + of expected state as well as time. +

+
+ + +
FileObject.getMIMEType(String... withinMIMETypes) --- a/openide.filesystems/manifest.mf Sun Nov 20 00:28:39 2011 +0100 +++ a/openide.filesystems/manifest.mf Mon Nov 21 11:35:59 2011 +0100 @@ -2,5 +2,5 @@ OpenIDE-Module: org.openide.filesystems OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties OpenIDE-Module-Layer: org/openide/filesystems/resources/layer.xml -OpenIDE-Module-Specification-Version: 7.53 +OpenIDE-Module-Specification-Version: 7.54 --- a/openide.filesystems/src/org/openide/filesystems/AbstractFolder.java Sun Nov 20 00:28:39 2011 +0100 +++ a/openide.filesystems/src/org/openide/filesystems/AbstractFolder.java Mon Nov 21 11:35:59 2011 +0100 @@ -571,7 +571,7 @@ super.fireFileChangedEvent(listeners(), fileevent); if (fileevent.getFile().equals(this) && (parent != null)) { - FileEvent ev = new FileEvent(parent, fileevent.getFile(), fileevent.isExpected()); + FileEvent ev = new FileEvent(parent, fileevent.getFile(), fileevent.isExpected(), fileevent.getTime()); try { ev.inheritPostNotify(fileevent); parent.fileChanged0(ev); @@ -956,7 +956,7 @@ */ protected void outputStreamClosed(boolean fireFileChanged) { if (fireFileChanged) { - fileChanged0(new FileEvent(AbstractFolder.this)); + fileChanged0(new FileEvent(AbstractFolder.this, AbstractFolder.this, lastModified().getTime())); } } --- a/openide.filesystems/src/org/openide/filesystems/FileEvent.java Sun Nov 20 00:28:39 2011 +0100 +++ a/openide.filesystems/src/org/openide/filesystems/FileEvent.java Mon Nov 21 11:35:59 2011 +0100 @@ -74,52 +74,66 @@ /** Creates new FileEvent. The FileObject where the action occurred * is assumed to be the same as the source object. + * Delegates to {@link #FileEvent(org.openide.filesystems.FileObject, org.openide.filesystems.FileObject, boolean, long) + * FileEvent(src, src, false, -1)}. * @param src source file which sent this event */ public FileEvent(FileObject src) { - this(src, src); + this(src, src, false, -1); } /** Creates new FileEvent, specifying the action object. - *

- * Note that the two arguments of this method need not be identical - * in cases where it is reasonable that a different file object from - * the one affected would be listened to by other components. E.g., - * in the case of a file creation event, the event source (which - * listeners are attached to) would be the containing folder, while - * the action object would be the newly created file object. + * Delegates to {@link #FileEvent(org.openide.filesystems.FileObject, org.openide.filesystems.FileObject, boolean, long) + * FileEvent(src, file, false, -1)}. + * * @param src source file which sent this event * @param file FileObject where the action occurred */ public FileEvent(FileObject src, FileObject file) { - super(src); - this.file = file; - this.time = System.currentTimeMillis(); - MIMESupport.freeCaches(); + this(src, file, false, -1); } - /** Creates new FileEvent. The FileObject where the action occurred - * is assumed to be the same as the source object. Important if FileEvent is created according to - * existing FileEvent but with another source and file but with the same time. + /** Creates new FileEvent. + * Delegates to {@link #FileEvent(org.openide.filesystems.FileObject, org.openide.filesystems.FileObject, boolean, long) + * FileEvent(src, file, false, time)}. */ FileEvent(FileObject src, FileObject file, long time) { - this(src, file); - this.time = time; + this(src, file, false, time); } /** Creates new FileEvent, specifying the action object. - *

- * Note that the two arguments of this method need not be identical - * in cases where it is reasonable that a different file object from - * the one affected would be listened to by other components. E.g., - * in the case of a file creation event, the event source (which - * listeners are attached to) would be the containing folder, while - * the action object would be the newly created file object. + * Delegates to {@link #FileEvent(org.openide.filesystems.FileObject, org.openide.filesystems.FileObject, boolean, long) + * FileEvent(src, file, expected, -1)}. + * * @param src source file which sent this event * @param file FileObject where the action occurred * @param expected sets flag whether the value was expected*/ public FileEvent(FileObject src, FileObject file, boolean expected) { - this(src, file); + this(src, file, expected, -1); + } + + + /** Creates new FileEvent, specifying all its details. + *

+ * Note that the two arguments of this method need not be identical + * in cases where it is reasonable that a different file object from + * the one affected would be listened to by other components. E.g., + * in the case of a file creation event, the event source (which + * listeners are attached to) would be the containing folder, while + * the action object would be the newly created file object. + * + * @param src source file which sends this event + * @param file {@link FileObject} where the action occured + * @param expected whether the change has been expected or not + * @param time time time when the change happened + * @since 7.54 + */ + public FileEvent(FileObject src, FileObject file, boolean expected, long time) { + super(src); + this.file = file; + this.time = time <= 0L ? System.currentTimeMillis() : time; this.expected = expected; + this.time = time; + MIMESupport.freeCaches(); } /** @return the original file where action occurred --- a/openide.filesystems/test/unit/src/org/openide/filesystems/FileObjectTestHid.java Sun Nov 20 00:28:39 2011 +0100 +++ a/openide.filesystems/test/unit/src/org/openide/filesystems/FileObjectTestHid.java Mon Nov 21 11:35:59 2011 +0100 @@ -385,6 +385,10 @@ assertNotNull("Child found", ch); changed = ch.asText(); + long delta = fe.getTime() - ch.lastModified().getTime(); + if (delta > 0) { + fail("File event should always have a lower time stamp than the created file. The diff: " + delta); + } notifyAll(); } catch (IOException ex) { throw new IllegalStateException(ex); @@ -419,6 +423,44 @@ assertEquals("Right content when created", "Ahoj", l.dataCreated); } + public void testLastModifiedAndEventGetTime() throws Exception { + checkSetUp(); + FileObject f; + try { + f = getTestFolder1(root).createFolder("EventGetTime"); + } catch (IOException iex) { + fsAssert("If read only FS, then OK to fail", + fs.isReadOnly()); + return; + } + final FileObject fold = f; + + class L extends FileChangeAdapter { + Long time; + @Override + public void fileChanged(FileEvent fe) { + assertNull("Only one event expected", time); + time = fe.getTime(); + } + } + + FileObject ch = fold.createData("child.txt"); + L l = new L(); + fold.addFileChangeListener(l); + assertEquals("One child", 1, fold.getChildren().length); + + OutputStream os = ch.getOutputStream(); + os.write("Ahoj".getBytes()); + os.close(); + + assertNotNull("Event has been delivered", l.time); + long delta = ch.lastModified().getTime() - l.time; + + if (delta < 0) { + fail("Event creation time should be lower or equal than actual file time stamp: " + delta); + } + } + /** Test of copy method, of class org.openide.filesystems.FileObject. */ public void testCopy1_FS() throws IOException { checkSetUp(); --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ d687683b8aa7 Mon Nov 21 11:35:59 2011 +0100 @@ -0,0 +1,220 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, 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-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.openide.text; + +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.Frame; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicReference; +import javax.swing.JEditorPane; +import javax.swing.text.StyledDocument; +import org.netbeans.junit.NbTestCase; +import org.openide.DialogDescriptor; +import org.openide.DialogDisplayer; +import org.openide.NotifyDescriptor; +import org.openide.cookies.EditorCookie; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataFolder; +import org.openide.loaders.DataLoader; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectExistsException; +import org.openide.loaders.FileEntry; +import org.openide.loaders.MultiDataObject; +import org.openide.loaders.MultiFileLoader; +import org.openide.loaders.UniFileLoader; +import org.openide.util.test.MockLookup; + +public class DataEditorSupportMoveTest extends NbTestCase { + + static { + System.setProperty("org.openide.windows.DummyWindowManager.VISIBLE", "false"); + } + + public DataEditorSupportMoveTest(String s) { + super(s); + } + + @Override + protected void setUp() throws Exception { + clearWorkDir(); + MockLookup.setInstances(new Pool(), new DD()); + } + + public void testModifiedMove() throws Exception { + FileObject root = FileUtil.toFileObject(getWorkDir()); + FileObject data = FileUtil.createData(root, "someFolder/someFile.obj"); + + DataObject obj = DataObject.find(data); + assertEquals( MyDataObject.class, obj.getClass()); + assertEquals(MyLoader.class, obj.getLoader().getClass()); + + EditorCookie ec = obj.getLookup().lookup(EditorCookie.class); + assertNotNull("Editor cookie found", ec); + ec.open(); + JEditorPane[] arr = openedPanes(ec); + assertEquals("One pane is opened", 1, arr.length); + + StyledDocument doc = ec.openDocument(); + doc.insertString(0, "Ahoj", null); + assertTrue("Modified", obj.isModified()); + Thread.sleep(100); + + FileObject newFolder = FileUtil.createFolder(root, "otherFolder"); + DataFolder df = DataFolder.findFolder(newFolder); + + obj.move(df); + + assertEquals(newFolder, obj.getPrimaryFile().getParent()); + + assertEquals("Still one editor", 1, openedPanes(ec).length); + DD.assertNoCalls(); + } + + private JEditorPane[] openedPanes(final EditorCookie ec) throws Exception { + final AtomicReference ref = new AtomicReference(); + EventQueue.invokeAndWait(new Runnable() { + @Override + public void run() { + ref.set(ec.getOpenedPanes()); + } + }); + return ref.get(); + } + + private static final class Pool extends org.openide.loaders.DataLoaderPool { + @Override + protected java.util.Enumeration loaders() { + return org.openide.util.Enumerations.array(DataLoader.getLoader(MyLoader.class), + DataLoader.getLoader(MyMultiFileLoader.class)); + } + } + + public static final class MyLoader extends UniFileLoader { + + public MyLoader() { + super(MyDataObject.class.getName ()); + getExtensions ().addExtension ("obj"); + getExtensions ().addExtension ("newExt"); + } + @Override + protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException { + return new MyDataObject(this, primaryFile); + } + } + + public static final class MyDataObject extends MultiDataObject { + public MyDataObject(MyLoader l, FileObject folder) throws DataObjectExistsException { + super(folder, l); + registerEditor("text/plain", false); + } + + } + + private static class MyMultiFileLoader extends MultiFileLoader { + public MyMultiFileLoader () { + super(MyMultiFileDataObject.class.getName()); + } + + @Override + protected MultiDataObject createMultiObject (FileObject primaryFile) throws DataObjectExistsException, IOException { + return new MyMultiFileDataObject( primaryFile, this ); + } + + @Override + protected FileObject findPrimaryFile(FileObject fo) { + if (!fo.isFolder()) { + // here is the common code for the worse behaviour + if (fo.hasExt("prima")) { + return FileUtil.findBrother(fo, "seconda") != null ? fo : null; + } + + if (fo.hasExt("seconda")) { + return FileUtil.findBrother(fo, "prima"); + } + } + return null; + } + + @Override + protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) { + return new FileEntry (obj, primaryFile); + } + + @Override + protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) { + return new FileEntry (obj, secondaryFile); + } + } // end of MyDL3 + + private static class MyMultiFileDataObject extends MultiDataObject { + public MyMultiFileDataObject( FileObject primaryFile, MultiFileLoader loader ) throws DataObjectExistsException { + super( primaryFile, loader ); + } + } + + public static final class DD extends DialogDisplayer { + static Exception called; + + @Override + public Object notify(NotifyDescriptor descriptor) { + called = new Exception("Notify called"); + return NotifyDescriptor.CANCEL_OPTION; + } + + @Override + public Dialog createDialog(DialogDescriptor descriptor) { + called = new Exception("Dialog created"); + return new Dialog((Frame)null); + } + + public static void assertNoCalls() throws Exception { + if (called != null) { + throw called; + } + } + } +}