| // |
| // 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="component" methodvalue="com.foo.MyWindow.findInstance"/>`. 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. |