blob: f8ec17a61ae7184045e608fe24d9ab1578614cf3 [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
= DevFaqNonSingletonTopComponents
:jbake-type: wiki
:jbake-tags: wiki, devfaq, needsreview
:jbake-status: published
:keywords: Apache NetBeans wiki DevFaqNonSingletonTopComponents
:description: Apache NetBeans wiki DevFaqNonSingletonTopComponents
:toc: left
:toc-title:
:syntax: true
=== How can I change my TopComponent to not be a singleton (NB version up to 6.9)?
The "New Window Component" wizard in the NetBeans IDE generates a link:http://en.wikipedia.org/wiki/Singleton_pattern[singleton] TopComponent. That's fine for windows that there should only be one of. Particularly if you are link:DevFaqEditorTopComponent.asciidoc[creating some kind of editor], you will want to create multiple instances of your TopComponent.
==== The really easy way
If you have not already used the *New Window* template to create your TopComponent subclass, don't.
Instead, use _New > JPanel Form_. Once the new JPanel is created, switch to the Code tab, and replace `extends javax.swing.JPanel` with `extends TopComponent`. Then do the following things:
* Override `getPersistenceType()`.
* If you _do not_ want your components reopened on restart
* return `PERSISTENCE_NEVER`—that is all you need to do to make sure they are not preserved across restarts.
* If you _do_ want your components reopened on restart, then
* return `PERSISTENCE_ONLY_OPENED` from `getPersistenceType()`
* Add the following slightly-cryptic annotation to the class: `@ConvertAsProperties(dtd = "-//com.yourmodule.yourpackage//YourTopComponent//EN", autostore = false)`, replacing the package and class name with your own. This identifies a DTD. You do not need to define the DTD. You just need to give it a unique namespace that nothing else is using. Package and class name work well for that.
* Add two additional methods (you are not overriding anything and they can be package-private, like serialization methods):
* `void writeProperties(Properties p)` - here we will call `p.put()` passing enough information to reconstruct your component on restart. If we are editing a file, we might save the path to the file. If we are viewing a URL, we might save the URL. If we want to be particularly fastidious, we might save the scroll position, or what line the editor caret was on , or anything else useful to restore the state of our component.
* `void readProperties(Properties p)` - here we will reading whatever keys we wrote out in `writeProperties` and (re)initializing the component to its pre-shutdown state. This method will be called on startup to restore our component to its pre-shutdown state as best can be done. If we were, say, editing a file that no longer exists, the appropriate thing to do is throw an exception.
==== If you already have a generated singleton TopComponent subclass
The good news is that you won't have to write any code -- you'll just have to delete some of the code that was generated for you.
In your TopComponent's .java source file:
* Delete the static `instance` variable, which ought to be declared a few lines above the constructor.
* Make sure your TopComponent class is `public`
* Make sure your TopComponent has a no-argument constructor which is `public`
* Delete the `getDefault()` method (typically somewhere around the middle of the file)
* Delete the `findInstance()` method (which typically follows the `getDefault()` method)
* Update the persistence code which saves your component's state on shutdown and restores it on restart to reopen your component as follows
* Locate the `getPersistenceType` method and change its return value to either `link:http://bits.netbeans.org/dev/javadoc/org-openide-windows/org/openide/windows/TopComponent.html#PERSISTENCE_NEVER[TopComponent.PERSISTENCE_NEVER]` or `link:http://bits.netbeans.org/dev/javadoc/org-openide-windows/org/openide/windows/TopComponent.html#PERSISTENCE_ONLY_OPENED[TopComponent.PERSISTENCE_ONLY_OPENED]` (see below for why).
* If you have methods called `writeReplace()`and an inner class called `ResolvableHelper` (NetBeans 6.8 and earlier):
* Delete the `writeReplace()` method (typically towards the end of the file)
* Delete the `ResolvableHelper` inner class (typically towards the end of the file)
* If you _do not want persistence across restarts_ — you are returning PERSISTENCE_NEVER from `getPersistenceType()`
* If you have a `@ConvertAsProperties` annotation and `readProperties(Properties)` and `writeProperties(Properties)` methods, delete the annotation and both methods
* If _do want persistence across restarts_ — you are returning `PERSISTENCE_ONLY_OPENED` from`getPersistenceType()`
* If you already have the `@ConvertAsProperties` annotation and `readProperties(Properties)` and `writeProperties(Properties)` methods just leave them there
* If you do not have the annotation and those methods, implement them as described in the previous section
Next we will need to delete the metadata that registers the component:
* For version 6.9 of NetBeans:
* Delete the settings XML file for your component. If your component class is `MyWindow` then that file will be in the same folder and will be called `MyWindowSettings.xml`.
* Delete the link:DevFaqWindowsWstcrefAndFriends.asciidoc[wstcrf] ("window system TopComponent reference") XML file in that folder. If your component class is `MyWindow` then that file will be named `MyWindowWstcrf.xml`
* Edit your module's [DevFaqModulesLayerFile| layer.xml file] to
* Remove any references to either of these files (just use Ctrl-F to search for e.g. `MyWindowSettings.xml` and `MyWindowWstcrf.xml`). They will be in `<file>` tags.
* If you have removed a `<file>` entry, and it was the only entry in that folder, you can remove the XML for parent folder (and its parent if it is now empty, and so forth)
* Find where an Action is registered for to open your (formerly) singleton TopComponent
* _NetBeans 6.9 and later:_
* Look for an `<file>` registered in `Actions/Window`in the XML file. It will have an `<attr>` element that refers to your TopComponent class, e.g. `<attr name=&quot;component&quot; methodvalue=&quot;com.foo.MyWindow.findInstance&quot;/>`. Delete the entire `<file>` entry.
* Look for `<file>` entry for a `.shadow` file in `Actions/Menu` in the XML, with its `originalFile` pointing to the file entry you just deleted. Delete the `.shadow` `<file>` too.
* _NetBeans 6.8 and earlier:_
* There will be an `Action` class in your sources which is registered, e.g. `MyWindowAction.java`. Delete the java source file.
* Look for an `<file>` registered in `Actions/Window`in the XML file. It will be a `<file>` whose name is the munged fully-qualified class name of the `Action` you just deleted, e.g. `com-foo-MyWindowAction.instance`. Delete the `<file>` entry for it
* Look for `<file>` entry for a `.shadow` file in `Actions/Menu` in the XML, with its `originalFile` pointing to the file entry you just deleted. Delete the `.shadow` `<file>` too.
==== Creating And Opening Your TopComponents
Now that you have deleted the actions for your TopComponent, presumably they will be created some other way (for example, from a file's popup menu). You can create new instances of your TopComponent, open them and give them focus as follows:
[source,java]
----
TopComponent win = new MyTopComponent();
win.open();
win.requestActive();
----
If you wrote your persistence code correctly, your components will magically reopen on restart with no further work.
==== What About PERSISTENCE_ALWAYS?
There is one other value you can return from `link:http://bits.netbeans.org/dev/javadoc/org-openide-windows/org/openide/windows/TopComponent.html#getPersistenceType()[TopComponent.getPersistenceType()]`. That value is `TopComponent.PERSISTENCE_ALWAYS`.
While it is _legal_ to return this value from a non-singleton TopComponent, it is almost never what you want to do. What will happen if you do this is:
* Every instance of your component that is *ever created* will be persisted on shutdown, _forever_
* Even if it is closed
* Even if nothing can use it, or it represents a file that was deleted, or is in some other way invalid
* Even if no code will ever be able to find it and open it again
* One every restart, _forever_
* Every instance of your component that has _ever existed_ will be read back from disk
* Each one will slow down startup a little bit
* Each one will be wasting disk space
`PERSISTENCE_ALWAYS` is for singleton components that need to be remembered forever across restarts. Don't use it for non-singletons.
==== If you do not have any persistence code, but your components are reopening on restart...
You are returning either `PERSISTENCE_ONLY_OPENED` or `PERSISTENCE_ALWAYS` from `getPersistenceType()`. If there is no persistence code, but you _are_ returning one of these values, NetBeans will use plain old Java serialization to store and reload your component.
Either use `PERSISTENCE_NEVER` or write persistence code as described above. Serialization is slower and more fragile than proper persistence, and is never a good option for production code.
=== Apache Migration Information
The content in this page was kindly donated by Oracle Corp. to the
Apache Software Foundation.
This page was exported from link:http://wiki.netbeans.org/DevFaqNonSingletonTopComponents[http://wiki.netbeans.org/DevFaqNonSingletonTopComponents] ,
that was last modified by NetBeans user Cvdenzen
on 2012-09-18T10:54:57Z.
*NOTE:* This document was automatically converted to the AsciiDoc format on 2018-02-07, and needs to be reviewed.