# HG changeset patch # Parent 871ef973c89964ca9583e9d80b8384af2c53eab3 #182538: getIO() not flexible enough in view of multiple impl's diff --git a/core.output2/nbproject/project.xml b/core.output2/nbproject/project.xml --- a/core.output2/nbproject/project.xml +++ b/core.output2/nbproject/project.xml @@ -94,7 +94,7 @@ - 1.23 + 1.33 diff --git a/core.output2/src/org/netbeans/core/output2/NbIOProvider.java b/core.output2/src/org/netbeans/core/output2/NbIOProvider.java --- a/core.output2/src/org/netbeans/core/output2/NbIOProvider.java +++ b/core.output2/src/org/netbeans/core/output2/NbIOProvider.java @@ -45,11 +45,12 @@ package org.netbeans.core.output2; import java.io.IOException; +import java.util.WeakHashMap; import javax.swing.Action; import org.openide.util.Exceptions; import org.openide.util.NbBundle; +import org.openide.windows.IOContainer; import org.openide.windows.IOProvider; -import org.openide.windows.IOContainer; import org.openide.windows.InputOutput; import org.openide.windows.OutputWriter; @@ -59,7 +60,8 @@ */ @org.openide.util.lookup.ServiceProvider(service=org.openide.windows.IOProvider.class, position=100) public final class NbIOProvider extends IOProvider { - private static final PairMap namesToIos = new PairMap(); + private static final WeakHashMap containerPairMaps = + new WeakHashMap(); private static final String STDOUT = NbBundle.getMessage(NbIOProvider.class, "LBL_STDOUT"); //NOI18N @@ -110,15 +112,29 @@ return NAME; } - private InputOutput getIO(String name, boolean newIO, Action[] toolbarActions, IOContainer ioContainer) { + @Override + public InputOutput getIO(String name, boolean newIO, + Action[] toolbarActions, IOContainer ioContainer) { if (Controller.LOG) { Controller.log("GETIO: " + name + " new:" + newIO); } - NbIO result = namesToIos.get(name); - + IOContainer realIoContainer = ioContainer == null + ? IOContainer.getDefault() : ioContainer; + NbIO result; + synchronized (containerPairMaps) { + PairMap namesToIos = containerPairMaps.get(realIoContainer); + result = namesToIos != null ? namesToIos.get(name) : null; + } if (result == null || newIO) { - result = new NbIO(name, toolbarActions, ioContainer); - namesToIos.add (name, result); + result = new NbIO(name, toolbarActions, realIoContainer); + synchronized (containerPairMaps) { + PairMap namesToIos = containerPairMaps.get(realIoContainer); + if (namesToIos == null) { + namesToIos = new PairMap(); + containerPairMaps.put(realIoContainer, namesToIos); + } + namesToIos.add(name, result); + } NbIO.post(new IOEvent(result, IOEvent.CMD_CREATE, newIO)); } return result; @@ -126,16 +142,19 @@ static void dispose (NbIO io) { - namesToIos.remove (io); - } - - /** - * Called when the output window is hidden. Switches the caching of IOs - * to weak references, so that only those still alive will be shown the - * next time the output window is opened. - */ - static void setWeak(boolean value) { - namesToIos.setWeak(value); + IOContainer ioContainer = io.getIOContainer(); + if (ioContainer == null) { + ioContainer = IOContainer.getDefault(); + } + synchronized (containerPairMaps) { + PairMap namesToIos = containerPairMaps.get(ioContainer); + if (namesToIos != null) { + namesToIos.remove(io); + if (namesToIos.isEmpty()) { + containerPairMaps.remove(ioContainer); + } + } + } } } diff --git a/core.output2/test/unit/src/org/netbeans/core/output2/NbIOProviderTest.java b/core.output2/test/unit/src/org/netbeans/core/output2/NbIOProviderTest.java new file mode 100644 --- /dev/null +++ b/core.output2/test/unit/src/org/netbeans/core/output2/NbIOProviderTest.java @@ -0,0 +1,148 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 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]" + * + * 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. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.core.output2; + +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.JComponent; +import static org.junit.Assert.*; +import org.junit.Test; +import org.openide.windows.IOContainer; +import org.openide.windows.IOContainer.CallBacks; +import org.openide.windows.IOProvider; +import org.openide.windows.InputOutput; + +/** + * + * @author jhavlin + */ +public class NbIOProviderTest { + + public NbIOProviderTest() { + } + + @Test + public void testGetIO_4args() { + + IOContainer def = IOContainer.getDefault(); + IOContainer cus = IOContainer.create(new MyContainerProvider()); + + InputOutput ioDef1 = IOProvider.getDefault().getIO("test1", true, null, def); + InputOutput ioCus1 = IOProvider.getDefault().getIO("test1", true, null, cus); + InputOutput ioDef2 = IOProvider.getDefault().getIO("test2", true, null, def); + InputOutput ioCus2 = IOProvider.getDefault().getIO("test2", true, null, cus); + + assertNotSame(ioDef1, ioCus1); + assertNotSame(ioDef2, ioCus2); + assertNotSame(ioDef1, ioDef2); + assertNotSame(ioCus1, ioCus2); + + InputOutput ioDef1b = IOProvider.getDefault().getIO("test1", false, null, def); + InputOutput ioCus1b = IOProvider.getDefault().getIO("test1", false, null, cus); + + assertSame(ioDef1, ioDef1b); + assertSame(ioCus1, ioCus1b); + + ioDef1.closeInputOutput(); + ioDef2.closeInputOutput(); + ioCus1.closeInputOutput(); + ioCus2.closeInputOutput(); + } + + public static class MyContainerProvider implements IOContainer.Provider { + + @Override + public void open() { + } + + @Override + public void requestActive() { + } + + @Override + public void requestVisible() { + } + + @Override + public boolean isActivated() { + return true; + } + + @Override + public void add(JComponent comp, CallBacks cb) { + } + + @Override + public void remove(JComponent comp) { + } + + @Override + public void select(JComponent comp) { + } + + @Override + public JComponent getSelected() { + return null; + } + + @Override + public void setTitle(JComponent comp, String name) { + } + + @Override + public void setToolTipText(JComponent comp, String text) { + } + + @Override + public void setIcon(JComponent comp, Icon icon) { + } + + @Override + public void setToolbarActions(JComponent comp, Action[] toolbarActions) { + } + + @Override + public boolean isCloseable(JComponent comp) { + return true; + } + } +} diff --git a/openide.io/apichanges.xml b/openide.io/apichanges.xml --- a/openide.io/apichanges.xml +++ b/openide.io/apichanges.xml @@ -107,6 +107,30 @@ + + + Added IOProvider.getIO variant that takes all 4 possible parameters. + + + + + +

+ Added method IOProvider.getIO that takes all + 4 supported parameters and that complements other + getIO methods. See + + IOProvider +

+

+ The original mapping from IO name to IO object has been replaced + with mapping from pair [IO container, IO name] to IO object. + This mapping is used for reusing of IO objects. +

+
+ + +
Added API for fine grain control over IO select operation diff --git a/openide.io/manifest.mf b/openide.io/manifest.mf --- a/openide.io/manifest.mf +++ b/openide.io/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.openide.io -OpenIDE-Module-Specification-Version: 1.32 +OpenIDE-Module-Specification-Version: 1.33 OpenIDE-Module-Localizing-Bundle: org/openide/io/Bundle.properties OpenIDE-Module-Recommends: org.openide.windows.IOProvider, org.openide.windows.IOContainer$Provider AutoUpdate-Essential-Module: true diff --git a/openide.io/nbproject/project.xml b/openide.io/nbproject/project.xml --- a/openide.io/nbproject/project.xml +++ b/openide.io/nbproject/project.xml @@ -50,6 +50,15 @@ org.openide.io + org.netbeans.api.annotations.common + + + + 1 + 1.15 + + + org.openide.util diff --git a/openide.io/src/org/openide/windows/IOProvider.java b/openide.io/src/org/openide/windows/IOProvider.java --- a/openide.io/src/org/openide/windows/IOProvider.java +++ b/openide.io/src/org/openide/windows/IOProvider.java @@ -52,6 +52,8 @@ import java.io.StringWriter; import java.util.Collection; import javax.swing.Action; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.annotations.common.NullAllowed; import org.openide.util.Lookup; /** A factory for IO tabs shown in the output window. To create a new tab to @@ -156,6 +158,30 @@ } /** + * Gets a named instance of {@link InputOutput}. Corresponding IO tab will be placed + * in parent container corresponding to provided {@link IOContainer}. + * @param name A localized display name for the tab + * @param newIO if true, a new InputOutput is returned, else an existing InputOutput of the same name may be returned + * @param actions array of actions that are added to the toolbar, Can be empty array, but not null. + * The number of actions should not exceed 5 and each should have the Action.SMALL_ICON property defined. + * @param ioContainer parent container accessor + * @return an InputOutput instance for accessing the new tab + *
Note: Please remember that {@link InputOutput} objects need to be + * properly closed. Ensure that {@link InputOutput#closeInputOutput()} is + * called when returned object is no longer needed, otherwise allocated + * memory and other resources will not be freed. + * @see InputOutput + * @since 1.33 + *
Note: The method is non-abstract for backward compatibility reasons only. If you are + * extending IOProvider and implementing its abstract classes, you are encouraged to override + * this method as well. The default implementation falls back to the getIO(name, actions) method, ignoring the ioContainer and newIO passed. + */ + public @NonNull InputOutput getIO(@NonNull String name, boolean newIO, + @NonNull Action[] actions, @NullAllowed IOContainer ioContainer) { + return getIO(name, actions); + } + + /** * Gets name (ID) of provider * @return name of provider * @since 1.15