2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
42
package org.netbeans.core;
44
import java.beans.PropertyChangeEvent;
45
import java.beans.PropertyChangeListener;
47
import java.net.MalformedURLException;
49
import java.util.ArrayList;
50
import java.util.Collection;
51
import java.util.Enumeration;
52
import java.util.Iterator;
53
import java.util.LinkedHashSet;
55
import java.util.logging.Level;
56
import java.util.logging.Logger;
57
import javax.swing.Action;
58
import org.openide.filesystems.FileObject;
59
import org.openide.filesystems.FileStateInvalidException;
60
import org.openide.filesystems.FileSystem;
61
import org.openide.filesystems.Repository;
62
import org.openide.filesystems.RepositoryEvent;
63
import org.openide.filesystems.RepositoryListener;
64
import org.openide.filesystems.RepositoryReorderedEvent;
65
import org.openide.filesystems.URLMapper;
66
import org.openide.loaders.DataFilter;
67
import org.openide.loaders.DataFolder;
68
import org.openide.loaders.DataObject;
69
import org.openide.loaders.DataObjectNotFoundException;
70
import org.openide.loaders.InstanceSupport;
71
import org.openide.loaders.RepositoryNodeFactory;
72
import org.openide.nodes.AbstractNode;
73
import org.openide.nodes.Children;
74
import org.openide.nodes.FilterNode;
75
import org.openide.nodes.Node;
76
import org.openide.util.HelpCtx;
77
import org.openide.util.Lookup;
78
import org.openide.util.NbBundle;
79
import org.openide.util.WeakListeners;
80
import org.openide.util.actions.SystemAction;
82
/** Data system encapsulates logical structure of more file systems.
83
* It also allows filtering of content of DataFolders
85
* @author Jaroslav Tulach, Petr Hamernik
87
public final class DataSystem extends AbstractNode
88
implements RepositoryListener {
89
/** default instance */
90
private static DataSystem def;
92
/** the file system pool to work with */
93
private transient Repository fileSystemPool;
95
/** filter for the data system */
99
* @param fsp file system pool
100
* @param filter the filter for filtering files
102
private DataSystem(Children ch, Repository fsp, DataFilter filter) {
104
fileSystemPool = fsp;
105
this.filter = filter;
107
setIconBaseWithExtension ("org/netbeans/core/resources/repository.gif"); // NOI18N
108
setName (NbBundle.getBundle (DataSystem.class).getString ("dataSystemName"));
109
setShortDescription (NbBundle.getBundle (DataSystem.class).getString ("CTL_Repository_Hint"));
110
getCookieSet ().add (new InstanceSupport.Instance (fsp));
113
/** Constructor. Uses default file system pool.
114
* @param filter the filter to use
116
private DataSystem(Children ch, DataFilter filter) {
117
this (ch, Repository.getDefault(), filter);
120
public HelpCtx getHelpCtx () {
121
return new HelpCtx (DataSystem.class);
124
/** Factory for DataSystem instances */
125
public static Node getDataSystem(DataFilter filter) {
126
if (filter == null) {
130
return def = new DataSystem(new DSMap (), DataFilter.ALL);
132
return new DataSystem(new DSMap (), filter);
136
/** Gets a DataSystem */
137
public static Node getDataSystem() {
138
return getDataSystem(null);
142
fileSystemPool.addRepositoryListener(WeakListeners.create(RepositoryListener.class,
145
Enumeration en = fileSystemPool.getFileSystems ();
146
while (en.hasMoreElements ()) {
147
FileSystem fs = (FileSystem)en.nextElement ();
148
fs.addPropertyChangeListener (org.openide.util.WeakListeners.propertyChange ((DSMap)getChildren (), fs));
153
/** writes this node to ObjectOutputStream and its display name
155
public Node.Handle getHandle() {
156
return filter == DataFilter.ALL ? new DSHandle (null) : new DSHandle(filter);
160
public Action[] getActions(boolean context) {
161
return new Action[] {
162
SystemAction.get (org.openide.actions.FindAction.class),
163
//Problem with ToolsAction as last item and separator. When ToolsAction
164
//is empty separator is displayed as last item.
166
SystemAction.get (org.openide.actions.ToolsAction.class),
167
//SystemAction.get (org.openide.actions.PropertiesAction.class), // #12072
168
//SystemAction.get (org.openide.actions.CustomizeAction.class),
172
/** Called when new file system is added to the pool.
173
* @param ev event describing the action
175
public void fileSystemAdded (RepositoryEvent ev) {
176
ev.getFileSystem ().addPropertyChangeListener (
177
org.openide.util.WeakListeners.propertyChange ((DSMap)getChildren (), ev.getFileSystem ())
182
/** Called when a file system is deleted from the pool.
183
* @param ev event describing the action
185
public void fileSystemRemoved (RepositoryEvent ev) {
188
/** Called when the fsp is reordered */
189
public void fileSystemPoolReordered(RepositoryReorderedEvent ev) {
193
/** Refreshes the pool.
199
/** Refreshes the pool.
200
* @param fs file system to remove
202
void refresh (FileSystem fs) {
203
// XXX hack to show only masterfs and no other filesystems
204
// should later be solved better
205
// XXX should check if fs.root.url.protocol is not 'file' or 'jar', and if so, show it also
206
// (to display network mounts)
207
URLMapper mapper = getMasterFsURLMapper();
208
if (mapper == null) {
209
//original solution based on Repository
210
((DSMap)getChildren ()).refresh (fileSystemPool, fs);
212
((DSMap)getChildren ()).refreshListRoots(mapper);
216
private static URLMapper getMasterFsURLMapper() {
217
URLMapper retVal = null;
218
Lookup.Result result = Lookup.getDefault().lookupResult(URLMapper.class);
219
Collection c = result.allInstances();
220
for (Iterator iterator = c.iterator(); iterator.hasNext();) {
221
URLMapper mapper = (URLMapper) iterator.next();
222
if (mapper != null && "org.netbeans.modules.masterfs.MasterURLMapper".equals(mapper.getClass().getName())) {//NOI18N
230
/** We have customizer */
231
public boolean hasCustomizer() {
235
/** Children that listens to changes in filesystem pool.
237
static class DSMap extends Children.Keys implements PropertyChangeListener {
239
public void propertyChange (PropertyChangeEvent ev) {
240
//System.out.println ("Property change"); // NOI18N
241
DataSystem ds = getDS ();
242
if (ds == null) return;
244
if ("root".equals(ev.getPropertyName())) {
245
FileSystem fs = (FileSystem)ev.getSource ();
252
private DataSystem getDS() {
253
return (DataSystem)getNode ();
256
protected Node[] createNodes (Object key) {
257
DataFolder df = (DataFolder)key;
258
Node n = new FilterNode(df.getNodeDelegate(), df.createNodeChildren (getDS ().filter));
259
return new Node[] {n};
262
/** Refreshes the pool.
263
* @param fileSystemPool the pool
264
* @param fs file system to remove
266
public void refresh(Repository fileSystemPool, FileSystem fs) {
267
@SuppressWarnings("unchecked") Enumeration<FileSystem> en = (Enumeration<FileSystem>)fileSystemPool.getFileSystems();
268
ArrayList<DataFolder> list = new ArrayList<DataFolder>();
269
while (en.hasMoreElements()) {
270
FileSystem fsystem = en.nextElement();
271
DataObject root = null;
273
root = DataObject.find(fsystem.getRoot());
275
catch (DataObjectNotFoundException e) {
276
Logger.getLogger(DataSystem.class.getName()).log(Level.WARNING, null, e);
277
// root will remain null and will be accepted
278
// (as that seems safer than not accepting it)
280
if ((root instanceof DataFolder) && getDS().filter.acceptDataObject(root)) {
281
list.add((DataFolder)root);
287
private void refreshListRoots(URLMapper mapper) {
288
File[] files = File.listRoots();
289
Set<DataFolder> rootSet = new LinkedHashSet<DataFolder>();
291
for (int i = 0; i < files.length; i++) {
292
File file = files[i];
293
FileObject fo = fetchFileObject(file, mapper);
297
fo = fo.getFileSystem().getRoot();
299
catch (FileStateInvalidException e) {
302
DataObject root = null;
305
root = DataObject.find(fo);
307
catch (DataObjectNotFoundException e) {
308
Logger.getLogger(DataSystem.class.getName()).log(Level.WARNING, null, e);
310
if ((root instanceof DataFolder) &&
311
getDS().filter.acceptDataObject(root)) {
312
rootSet.add((DataFolder) root);
320
private FileObject fetchFileObject(File file, URLMapper mapper) {
321
/*intentiionally isn't used FileUtil.toFileObject because here can't be
322
called method normalizeFile which causes problems with removeable drives
324
FileObject retVal = null;
326
FileObject[] all = mapper.getFileObjects(toUrl(file));//NOI18N
327
if (all != null && all.length > 0) {
330
} catch (MalformedURLException e) {
336
private URL toUrl(File file) throws MalformedURLException {
337
return (org.openide.util.Utilities.isWindows()) ? new URL ("file:/"+file.getAbsolutePath ()) : file.toURI().toURL();//NOI18N
344
/** Serialization. */
345
private static class DSHandle implements Node.Handle {
348
static final long serialVersionUID =-2266375092419944364L;
349
public DSHandle(DataFilter f) {
353
public Node getNode() {
354
return getDataSystem (filter);
358
/** @deprecated No longer useful in the UI. */
359
public static final class NbRepositoryNodeFactory extends RepositoryNodeFactory {
361
public Node repository(DataFilter f) {
362
return DataSystem.getDataSystem(f == DataFilter.ALL ? null : f);