This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 44035
Collapse All | Expand All

(-)a/project.libraries/apichanges.xml (-2 / +56 lines)
Lines 40-47 Link Here
40
Version 2 license, then the option applies only if the new code is
40
Version 2 license, then the option applies only if the new code is
41
made subject to such option by the copyright holder.
41
made subject to such option by the copyright holder.
42
-->
42
-->
43
<?xml-stylesheet type="text/xml" href="../../nbbuild/javadoctools/apichanges.xsl"?>
43
<?xml-stylesheet type="text/xml" href="../nbbuild/javadoctools/apichanges.xsl"?>
44
<!DOCTYPE apichanges PUBLIC "-//NetBeans//DTD API changes list 1.0//EN" "../../nbbuild/javadoctools/apichanges.dtd">
44
<!DOCTYPE apichanges PUBLIC "-//NetBeans//DTD API changes list 1.0//EN" "../nbbuild/javadoctools/apichanges.dtd">
45
45
46
<!--
46
<!--
47
47
Lines 103-108 Link Here
103
103
104
    <!-- ACTUAL CHANGES BEGIN HERE: -->
104
    <!-- ACTUAL CHANGES BEGIN HERE: -->
105
    <changes>
105
    <changes>
106
107
    <change id="project-libraries">
108
        <api name="general"/>
109
        <summary>Support for project libraries</summary>
110
        <version major="1" minor="17"/>
111
        <date day="22" month="1" year="2008"/>
112
        <author login="jglick"/>
113
        <compatibility addition="yes" deprecation="yes">
114
            <p>
115
                <code>LibraryManager.addLibrary</code> will not work with areas,
116
                so it was deprecated in favor of the new <code>createLibrary</code>.
117
            </p>
118
            <p>
119
                Code which obtained a <code>Library</code> of arbitrary origin,
120
                and then assumed it could refer to that library henceforth by name only,
121
                will not work with project libraries.
122
                The simplest persistent identifier for a new-style library is pair of name
123
                and URL of manager (null for the default manager).
124
            </p>
125
        </compatibility>
126
        <description>
127
            <p>
128
                There is a new API and SPI for project libraries
129
                (or, more generally, libraries with specific storage locations).
130
                <code>ArealLibraryProvider</code>,
131
                and <code>LibraryStorageArea</code> are new, as are methods
132
                <code>Library.getManager</code>,
133
                <code>Library.getRawContent(String)</code>
134
                <code>LibraryManager.getDisplayName</code>,
135
                <code>LibraryManager.getLocation</code>,
136
                <code>LibraryManager.createLibrary</code>,
137
                <code>LibraryManager.forLocation</code>, and
138
                <code>LibraryManager.getOpenManagers</code>.
139
                (<code>LibraryProvider</code> was also generified.)
140
                <code>LibrariesSupport</code> has few additional helper methods.
141
            </p>
142
            <p>
143
                There's also new methods and classes for UI customizations of Libraries, eg.
144
                <code>LibrariesCustomizer.showCreateNewLibraryCustomizer(LibraryManager)</code>,
145
                <code>LibrariesCustomizer.showCustomizer(Library, LibraryManager)</code>,
146
                <code>LibrariesCustomizer.showSingleLibraryCustomizer(Library)</code>,
147
                and <code>LibraryChooser</code> class.
148
            </p>
149
        </description>
150
        <class package="org.netbeans.api.project.libraries" name="LibraryManager"/>
151
        <class package="org.netbeans.api.project.libraries" name="Library"/>
152
        <class package="org.netbeans.api.project.libraries" name="LibraryChooser"/>
153
        <class package="org.netbeans.api.project.libraries" name="LibrariesCustomizer"/>
154
        <class package="org.netbeans.spi.project.libraries" name="LibraryProvider"/>
155
        <class package="org.netbeans.spi.project.libraries" name="ArealLibraryProvider"/>
156
        <class package="org.netbeans.spi.project.libraries" name="LibraryStorageArea"/>
157
        <class package="org.netbeans.spi.project.libraries.support" name="LibrariesSupport"/>
158
        <issue number="44035"/>
159
    </change>
106
    
160
    
107
    <change id="Customizer-can-be-null">
161
    <change id="Customizer-can-be-null">
108
            <api name="general"/>
162
            <api name="general"/>
(-)a/project.libraries/src/org/netbeans/api/project/libraries/LibrariesCustomizer.java (-14 / +105 lines)
Lines 45-50 Link Here
45
import org.openide.DialogDisplayer;
45
import org.openide.DialogDisplayer;
46
import org.openide.util.NbBundle;
46
import org.openide.util.NbBundle;
47
import java.awt.Dialog;
47
import java.awt.Dialog;
48
import javax.swing.border.EmptyBorder;
49
import org.netbeans.modules.project.libraries.LibraryTypeRegistry;
50
import org.netbeans.modules.project.libraries.ui.LibrariesModel;
51
import org.netbeans.modules.project.libraries.ui.NewLibraryPanel;
52
import org.netbeans.spi.project.libraries.LibraryImplementation;
53
import org.netbeans.spi.project.libraries.LibraryStorageArea;
54
import org.netbeans.spi.project.libraries.LibraryTypeProvider;
48
55
49
/** Provides method for opening Libraries customizer
56
/** Provides method for opening Libraries customizer
50
 *
57
 *
Lines 55-86 Link Here
55
    }
62
    }
56
63
57
    /**
64
    /**
58
     * Shows libraries customizer
65
     * Shows libraries customizer for given library manager.
66
     * @param activeLibrary if not null the activeLibrary is selected in the opened customizer
67
     * @return true if user pressed OK and libraries were sucessfully modified
68
     */
69
    public static boolean showCustomizer (Library activeLibrary, LibraryManager libraryManager) {
70
        org.netbeans.modules.project.libraries.ui.LibrariesCustomizer  customizer =
71
                new org.netbeans.modules.project.libraries.ui.LibrariesCustomizer (libraryManager.getArea());
72
        customizer.setBorder(new EmptyBorder(12, 12, 0, 12));
73
        if (activeLibrary != null)
74
            customizer.setSelectedLibrary (activeLibrary.getLibraryImplementation ());
75
        DialogDescriptor descriptor = new DialogDescriptor (customizer,NbBundle.getMessage(LibrariesCustomizer.class,
76
                "TXT_LibrariesManager"));
77
        Dialog dlg = DialogDisplayer.getDefault().createDialog(descriptor);
78
        try {
79
            dlg.setVisible(true);
80
            if (descriptor.getValue() == DialogDescriptor.OK_OPTION) {
81
                return customizer.apply();
82
            } else {
83
                return false;
84
            }
85
        } finally {
86
            dlg.dispose();
87
        }
88
    }
89
90
    /**
91
     * Shows libraries customizer for global libraries.
59
     * @param activeLibrary if not null the activeLibrary is selected in the opened customizer
92
     * @param activeLibrary if not null the activeLibrary is selected in the opened customizer
60
     * @return true if user pressed OK and libraries were sucessfully modified
93
     * @return true if user pressed OK and libraries were sucessfully modified
61
     */
94
     */
62
    public static boolean showCustomizer (Library activeLibrary) {
95
    public static boolean showCustomizer (Library activeLibrary) {
96
        return showCustomizer(activeLibrary, LibraryManager.getDefault());
97
    }
98
    
99
    /**
100
     * Show customizer for creating new library in the given library manager.
101
     * @param manager manager
102
     * @return created persisted library or null if user cancelled operation
103
     * @since org.netbeans.modules.project.libraries/1 1.16
104
     */
105
    public static Library showCreateNewLibraryCustomizer(LibraryManager manager) {                                             
106
        if (manager == null) {
107
            manager = LibraryManager.getDefault();
108
        }
109
        LibraryStorageArea area = manager.getArea();
110
        if (area == null) {
111
            area = LibrariesModel.GLOBAL_AREA;
112
        }
63
        org.netbeans.modules.project.libraries.ui.LibrariesCustomizer  customizer =
113
        org.netbeans.modules.project.libraries.ui.LibrariesCustomizer  customizer =
64
                new org.netbeans.modules.project.libraries.ui.LibrariesCustomizer ();
114
                new org.netbeans.modules.project.libraries.ui.LibrariesCustomizer (area);
65
        if (activeLibrary != null)
115
        NewLibraryPanel p = new NewLibraryPanel(customizer.getModel(), null, area);
66
            customizer.setSelectedLibrary (activeLibrary.getLibraryImplementation ());
116
        DialogDescriptor dd = new DialogDescriptor (p, 
117
                NbBundle.getMessage(LibrariesCustomizer.class,"LibrariesCustomizer.createLibrary.title"),
118
                true, DialogDescriptor.OK_CANCEL_OPTION, null, null);
119
        p.setDialogDescriptor(dd);
120
        Dialog dlg = DialogDisplayer.getDefault().createDialog (dd);
121
        dlg.setVisible(true);
122
        if (dd.getValue() == DialogDescriptor.OK_OPTION) {
123
            LibraryImplementation impl;
124
            if (area != LibrariesModel.GLOBAL_AREA) {
125
                impl = customizer.getModel().createArealLibrary(p.getLibraryType(), p.getLibraryName(), manager.getArea());
126
            } else {
127
                LibraryTypeProvider provider = LibraryTypeRegistry.getDefault().getLibraryTypeProvider(p.getLibraryType());
128
                if (provider == null) {
129
                    return null;
130
                }
131
                impl = provider.createLibrary();
132
                impl.setName(p.getLibraryName());
133
            }
134
            customizer.getModel().addLibrary(impl);
135
            customizer.forceTreeRecreation();
136
            if (customizeLibrary(customizer, impl)) {
137
                return manager.getLibrary(impl.getName());
138
            }
139
        }
140
        return null;
141
    }                                            
142
143
    /**
144
     * Show library customizer for the given library.
145
     * @param library library
146
     * @return true if library was modified or not
147
     * @since org.netbeans.modules.project.libraries/1 1.16
148
     */
149
    public static boolean showSingleLibraryCustomizer(Library library) {                                             
150
        org.netbeans.modules.project.libraries.ui.LibrariesCustomizer  customizer =
151
                new org.netbeans.modules.project.libraries.ui.LibrariesCustomizer (library.getManager().getArea());
152
        return customizeLibrary(customizer, library.getLibraryImplementation());
153
    }
154
    
155
    private static boolean customizeLibrary(org.netbeans.modules.project.libraries.ui.LibrariesCustomizer customizer, 
156
            LibraryImplementation activeLibrary) {
157
        customizer.hideLibrariesList();
158
        customizer.setBorder(new EmptyBorder(12, 8, 0, 10));
159
        customizer.setSelectedLibrary (activeLibrary);
67
        DialogDescriptor descriptor = new DialogDescriptor (customizer,NbBundle.getMessage(LibrariesCustomizer.class,
160
        DialogDescriptor descriptor = new DialogDescriptor (customizer,NbBundle.getMessage(LibrariesCustomizer.class,
68
                "TXT_LibrariesManager"));
161
                "LibrariesCustomizer.customizeLibrary.title"));
69
        Dialog dlg = null;
162
        Dialog dlg = DialogDisplayer.getDefault().createDialog(descriptor);
70
        try {
163
        try {
71
            dlg = DialogDisplayer.getDefault().createDialog (descriptor);
72
            dlg.setVisible(true);
164
            dlg.setVisible(true);
73
            if (descriptor.getValue() == DialogDescriptor.OK_OPTION) {
165
            if (descriptor.getValue() == DialogDescriptor.OK_OPTION) {
74
                return customizer.apply();
166
                customizer.apply();
75
            }
167
                return true;
76
            else {
168
            } else {
77
                customizer.cancel();
169
                return false;
78
            }
170
            }
79
        } finally {
171
        } finally {
80
            if (dlg != null)
172
            dlg.dispose();
81
                dlg.dispose();
82
        }
173
        }
83
        return false;
84
    }
174
    }
175
    
85
}
176
}
86
177
(-)a/project.libraries/src/org/netbeans/api/project/libraries/Library.java (-14 / +43 lines)
Lines 45-56 Link Here
45
import java.beans.PropertyChangeEvent;
45
import java.beans.PropertyChangeEvent;
46
import java.net.URL;
46
import java.net.URL;
47
import java.util.ArrayList;
47
import java.util.ArrayList;
48
import java.util.Iterator;
49
import java.util.List;
48
import java.util.List;
50
import java.util.MissingResourceException;
49
import java.util.MissingResourceException;
51
import java.util.ResourceBundle;
50
import java.util.ResourceBundle;
52
import org.netbeans.modules.project.libraries.LibraryAccessor;
51
import org.netbeans.modules.project.libraries.LibraryAccessor;
53
import org.netbeans.spi.project.libraries.LibraryImplementation;
52
import org.netbeans.spi.project.libraries.LibraryImplementation;
53
import org.netbeans.spi.project.libraries.support.LibrariesSupport;
54
import org.openide.ErrorManager;
54
import org.openide.ErrorManager;
55
import org.openide.util.NbBundle;
55
import org.openide.util.NbBundle;
56
56
Lines 76-86 Link Here
76
76
77
    private List<PropertyChangeListener> listeners;
77
    private List<PropertyChangeListener> listeners;
78
78
79
    /**
79
    private final LibraryManager manager;
80
     * Creates new library instance
80
81
     *
81
    Library(LibraryImplementation impl, LibraryManager manager) {
82
     */
83
    private Library (LibraryImplementation impl) {
84
        this.impl = impl;
82
        this.impl = impl;
85
        this.impl.addPropertyChangeListener (new PropertyChangeListener () {
83
        this.impl.addPropertyChangeListener (new PropertyChangeListener () {
86
            public void propertyChange(PropertyChangeEvent evt) {
84
            public void propertyChange(PropertyChangeEvent evt) {
Lines 88-94 Link Here
88
                Library.this.fireChange (propName,evt.getOldValue(),evt.getNewValue());
86
                Library.this.fireChange (propName,evt.getOldValue(),evt.getNewValue());
89
            }
87
            }
90
        });
88
        });
89
        this.manager = manager;
91
    } // end create
90
    } // end create
91
92
    /**
93
     * Gets the associated library manager.
94
     * @return the manager (may be the "default" global manager, or a local manager)
95
     * @since org.netbeans.modules.project.libraries/1 1.15
96
     */
97
    public LibraryManager getManager() {
98
        return manager;
99
    }
100
101
    /**
102
     * Access typed library data. Any relative URL provided by SPI is made absolute
103
     * before being passed to client. See {@link #getRawContent} if you need raw library data.
104
     * <p>
105
     * The contents are defined by SPI providers and identified
106
     * by the <a href="package-summary.html#volumeType">volume types</a>. For example the j2se library supports the following
107
     * volume types: classpath - the library classpath roots, src - the library sources, javadoc - the library javadoc.
108
     * Your module must have contract with a particular provider's module to be able to query it effectively.
109
     * </p>
110
     *
111
     * @param volumeType which resources to return.
112
     * @return path of URLs of given type (possibly empty but never <code>null</code>)
113
     */
114
    public List<URL> getContent(final String volumeType) {
115
        List<URL> urls = this.impl.getContent (volumeType);
116
        List<URL> resolvedUrls = new ArrayList<URL>(urls.size());
117
        for (URL u : urls) {
118
            resolvedUrls.add(LibrariesSupport.resolveLibraryEntryURL(manager.getLocation(), u));
119
        }
120
        return resolvedUrls;
121
    } // end getContent
92
122
93
    /**
123
    /**
94
     * Access typed but raw library data.
124
     * Access typed but raw library data.
Lines 102-111 Link Here
102
     * @param volumeType which resources to return.
132
     * @param volumeType which resources to return.
103
     * @return path of URLs of given type (possibly empty but never <code>null</code>)
133
     * @return path of URLs of given type (possibly empty but never <code>null</code>)
104
     */
134
     */
105
    public List<URL> getContent(final String volumeType) {
135
    public List<URL> getRawContent(final String volumeType) {
106
        return this.impl.getContent (volumeType);
136
        return this.impl.getContent (volumeType);
107
    } // end getContent
137
    } // end getContent
108
109
138
110
139
111
    /**
140
    /**
Lines 169-179 Link Here
169
        return impl.hashCode();
198
        return impl.hashCode();
170
    }
199
    }
171
    
200
    
172
    @Override
173
    public String toString () {
174
        return this.getName();
175
    }
176
177
    /**
201
    /**
178
     * Adds PropertyChangeListener
202
     * Adds PropertyChangeListener
179
     * @param listener
203
     * @param listener
Lines 235-245 Link Here
235
            return key;
259
            return key;
236
        }
260
        }
237
    }
261
    }
262
263
    @Override
264
    public String toString() {
265
        return "Library[" + getName() + "]"; // NOI18N
266
    }
238
    
267
    
239
    static {
268
    static {
240
        LibraryAccessor.DEFAULT = new LibraryAccessor () {
269
        LibraryAccessor.DEFAULT = new LibraryAccessor () {
241
            public Library createLibrary (LibraryImplementation impl) {
270
            public Library createLibrary (LibraryImplementation impl) {
242
                return new Library (impl);
271
                return new Library(impl, LibraryManager.getDefault());
243
            }
272
            }
244
        };
273
        };
245
    }
274
    }
(-)ffef4cca2ff4 (+140 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.api.project.libraries;
21
22
import java.awt.Component;
23
import java.beans.PropertyChangeListener;
24
import java.io.File;
25
import java.io.IOException;
26
import java.util.Set;
27
import javax.swing.JFileChooser;
28
import org.openide.filesystems.FileUtil;
29
import org.openide.util.Exceptions;
30
import org.openide.util.NbBundle;
31
32
/**
33
 * Visual picker for libraries.
34
 * @since org.netbeans.modules.project.libraries/1 1.16
35
 */
36
public final class LibraryChooser {
37
38
    private LibraryChooser() {
39
    }
40
    
41
    /**
42
     * Create a chooser showing libraries from given library manager and let the
43
     * user to pick some.
44
     * @param manager manager; can be null in which case global libraries are listed
45
     * @param filter optional libraries filter; null for no filtering
46
     * @param handler handler to perform library importing; can be null in which case
47
     *  import will not be allowed in UI
48
     * @return a nonempty set of libraries that were selected, or null if the dialog was cancelled
49
     */
50
    public static Set<Library> showDialog(LibraryManager manager, Filter filter, LibraryImportHandler handler) {
51
        return LibraryChooserGUI.showChooser(manager, filter, handler, true);
52
    }
53
54
    /**
55
     * Create a picker as an embeddable panel.
56
     * Might be used in a wizard, for example.
57
     * @param manager library manager to use or null for global libraries
58
     * @param filter optional libraries filter; null for no filtering
59
     * @return a panel controller
60
     */
61
    public static Panel createPanel(LibraryManager manager, Filter filter) {
62
        return LibraryChooserGUI.createPanel(manager, filter);
63
    }
64
65
    /**
66
     * Filter for use by {@link LibraryChooser#createPanel()} or 
67
     * {@link LibraryChooser#showDialog()}.
68
     */
69
    public interface Filter {
70
71
        /**
72
         * Accepts or rejects a library.
73
         * @param library a library found in one of the managers
74
         * @return true to display, false to hide
75
         */
76
        boolean accept(Library library);
77
78
    }
79
80
    /**
81
     * Represents operations permitted by {@link #createPanel}.
82
     * Not to be implemented by foreign code (methods may be added in the future).
83
     */
84
    public interface Panel {
85
86
        /**
87
         * Produces the actual component you can display.
88
         * @return an embeddable GUI component
89
         */
90
        Component getVisualComponent();
91
92
        /**
93
         * Gets the set of libraries which are currently selected.
94
         * @return a (possibly empty) set of libraries
95
         */
96
        Set<Library> getSelectedLibraries();
97
98
        /**
99
         * Property fired when {@link #getSelectedLibraries} changes.
100
         * Do not expect the old and new values to be non-null.
101
         */
102
        String PROP_SELECTED_LIBRARIES = "selectedLibraries"; // NOI18N
103
104
        /**
105
         * Add a listener for {@link #PROP_SELECTED_LIBRARIES}.
106
         * @param listener the listener to add
107
         */
108
        void addPropertyChangeListener(PropertyChangeListener listener);
109
110
        /**
111
         * Remove a listener.
112
         * @param listener the listener to remove
113
         */
114
        void removePropertyChangeListener(PropertyChangeListener listener);
115
116
    }
117
118
    /**
119
     * Handler for library importing. The handler is used from library chooser
120
     * UI in order to import global library to sharable libraries location. A 
121
     * library is only imported if there is no library with the same library
122
     * name in destination library manager.
123
     */
124
    public interface LibraryImportHandler {
125
        
126
        /**
127
         * Implementation is expected to copy given global library to 
128
         * sharable libraries location, that is to library manager the library
129
         * chooser was created for.
130
         * 
131
         * @param library library to copy
132
         * @return newly created library
133
         * @throws java.io.IOException any IO failure
134
         * @throws IllegalArgumentException if there already exists library 
135
         *  with this name
136
         */
137
        Library importLibrary(Library library) throws IOException;
138
    }
139
    
140
}
(-)ffef4cca2ff4 (+382 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.api.project.libraries;
21
22
import java.awt.BorderLayout;
23
import java.awt.Component;
24
import java.awt.Image;
25
import java.beans.PropertyChangeEvent;
26
import java.beans.PropertyChangeListener;
27
import java.beans.PropertyVetoException;
28
import java.io.IOException;
29
import java.text.Collator;
30
import java.util.ArrayList;
31
import java.util.Collection;
32
import java.util.Collections;
33
import java.util.Comparator;
34
import java.util.HashSet;
35
import java.util.List;
36
import java.util.Set;
37
import javax.swing.JButton;
38
import javax.swing.JPanel;
39
import javax.swing.border.EmptyBorder;
40
import org.openide.DialogDescriptor;
41
import org.openide.DialogDisplayer;
42
import org.openide.NotifyDescriptor;
43
import org.openide.explorer.ExplorerManager;
44
import org.openide.filesystems.Repository;
45
import org.openide.loaders.DataFolder;
46
import org.openide.nodes.AbstractNode;
47
import org.openide.nodes.Children;
48
import org.openide.nodes.Node;
49
import org.openide.nodes.NodeNotFoundException;
50
import org.openide.nodes.NodeOp;
51
import org.openide.util.Exceptions;
52
import org.openide.util.HelpCtx;
53
import org.openide.util.NbBundle;
54
import org.openide.util.lookup.Lookups;
55
56
class LibraryChooserGUI extends JPanel implements ExplorerManager.Provider, HelpCtx.Provider, LibraryChooser.Panel {
57
58
    private final LibraryManager manager;
59
    private final LibraryChooser.Filter filter;
60
    private final ExplorerManager explorer;
61
    private LibraryChooser.LibraryImportHandler importHandler;
62
63
    private LibraryChooserGUI(LibraryManager manager, LibraryChooser.Filter filter, 
64
            LibraryChooser.LibraryImportHandler importHandler) {
65
        if (manager == null) {
66
            manager = LibraryManager.getDefault();
67
        }
68
        this.manager = manager;
69
        this.filter = filter;
70
        this.importHandler = importHandler;
71
        explorer = new ExplorerManager();
72
        initComponents();
73
        tree.setDefaultActionAllowed(false);
74
    }
75
    
76
    public static LibraryChooser.Panel createPanel(LibraryManager manager, 
77
            LibraryChooser.Filter filter) {
78
        LibraryChooserGUI l = new LibraryChooserGUI(manager, filter, null);
79
        l.configureForEmbedded();
80
        return l;
81
    }
82
83
    public static Set<Library> showChooser(LibraryManager manager, LibraryChooser.Filter filter, 
84
            LibraryChooser.LibraryImportHandler handler, boolean addOperation) {
85
        LibraryChooserGUI l = new LibraryChooserGUI(manager, filter, handler);
86
        return l.showDialog(addOperation);
87
    }
88
89
    private Set<Library> showDialog(boolean addOperatation) {
90
        // show manage button only in embedded panel:
91
        manageLibrariesButton.setVisible(false);
92
        // import enabled only for non-global library manager
93
        importButton.setVisible(manager.getLocation() != null && importHandler != null);
94
        JPanel inset = new JPanel(new BorderLayout());
95
        inset.setBorder(new EmptyBorder(12,12,0,12));
96
        inset.add(this);
97
        String title;
98
        String buttonLabel;
99
        if (addOperatation) {
100
            title = NbBundle.getMessage(LibraryChooserGUI.class, "LibraryChooserGUI.add.title");
101
            buttonLabel = NbBundle.getMessage(LibraryChooserGUI.class, "LibraryChooserGUI.add.button");
102
        } else {
103
            title = NbBundle.getMessage(LibraryChooserGUI.class, "LibraryChooserGUI.import.title");
104
            buttonLabel = NbBundle.getMessage(LibraryChooserGUI.class, "LibraryChooserGUI.import.button");
105
            createButton.setVisible(false);
106
        }
107
        DialogDescriptor dd = new DialogDescriptor(inset, title);
108
        dd.setModal(true);
109
        final JButton add = new JButton(buttonLabel);
110
        add.setEnabled(false);
111
        add.setDefaultCapable(true);
112
        explorer.addPropertyChangeListener(new PropertyChangeListener() {
113
           public void propertyChange(PropertyChangeEvent evt) {
114
               add.setEnabled(!getSelectedLibraries().isEmpty());
115
           }
116
        });
117
        dd.setOptions(new Object[] {add, NotifyDescriptor.CANCEL_OPTION});
118
        dd.setClosingOptions(new Object[] {add, NotifyDescriptor.CANCEL_OPTION});
119
        if (DialogDisplayer.getDefault().notify(dd) == add) {
120
            Set<Library> selection = getSelectedLibraries();
121
            assert !selection.isEmpty();
122
            return selection;
123
        } else {
124
            return null;
125
        }
126
    }
127
128
    private void configureForEmbedded() {
129
        explorer.addPropertyChangeListener(new PropertyChangeListener() {
130
           public void propertyChange(PropertyChangeEvent evt) {
131
               firePropertyChange(PROP_SELECTED_LIBRARIES, null, null);
132
           }
133
        });
134
        createButton.setVisible(false);
135
        importButton.setVisible(false);
136
    }
137
138
    public Set<Library> getSelectedLibraries() {
139
        Set<Library> s = new HashSet<Library>();
140
        for (Node n : explorer.getSelectedNodes()) {
141
            Library l = n.getLookup().lookup(Library.class);
142
            if (l != null) {
143
                s.add(l);
144
            } else {
145
                return Collections.emptySet();
146
            }
147
        }
148
        return s;
149
    }
150
151
    public Component getVisualComponent() {
152
        return this;
153
    }
154
155
    public ExplorerManager getExplorerManager() {
156
        return explorer;
157
    }
158
159
    public HelpCtx getHelpCtx() {
160
        return new HelpCtx(LibraryChooserGUI.class);
161
    }
162
163
    private void setRootNode() {
164
        explorer.setRootContext(new AbstractNode(new LibraryManagerChildren()));
165
        tree.expandAll();
166
        try {
167
            if (explorer.getRootContext().getChildren().getNodes(true).length > 0) {
168
                explorer.setSelectedNodes(new Node[] {explorer.getRootContext().getChildren().getNodes(true)[0]});
169
            }
170
        } catch (PropertyVetoException x) {
171
            Exceptions.printStackTrace(x);
172
        }
173
        /* XXX Nothing seems to work to scroll to top; how is it done?
174
        tree.getViewport().setViewPosition(new Point());
175
        tree.getViewport().scrollRectToVisible(new Rectangle(0, 0, 1, 1));
176
         */
177
        tree.requestFocus();
178
    }
179
180
    @Override
181
    public void addNotify() {
182
        super.addNotify();
183
        setRootNode();
184
    }
185
186
    private class LibraryManagerChildren extends Children.Keys<LibraryManager> {
187
188
        @Override
189
        protected void addNotify() {
190
            super.addNotify();
191
            if (manager != null) {
192
                setKeys(Collections.singleton(manager));
193
            }
194
        }
195
196
        protected Node[] createNodes(LibraryManager mgr) {
197
            List<Library> libs = new ArrayList<Library>();
198
            for (Library lib : mgr.getLibraries()) {
199
                if (filter == null || filter.accept(lib)) {
200
                    libs.add(lib);
201
                }
202
            }
203
            if (libs.isEmpty()) {
204
                return new Node[0];
205
            } else {
206
                Collections.sort(libs,new Comparator<Library>() {
207
                    Collator COLL = Collator.getInstance();
208
                    public int compare(Library lib1, Library lib2) {
209
                        return COLL.compare(lib1.getDisplayName(), lib2.getDisplayName());
210
                    }
211
                });
212
                Node n = new AbstractNode(new LibraryChildren(libs)) {
213
                    Node iconDelegate = DataFolder.findFolder(Repository.getDefault().getDefaultFileSystem().getRoot()).getNodeDelegate();
214
                    public Image getIcon(int type) {
215
                        return iconDelegate.getIcon(type);
216
                    }
217
                    public Image getOpenedIcon(int type) {
218
                        return iconDelegate.getOpenedIcon(type);
219
                    }
220
                };
221
                n.setName(mgr.getDisplayName());
222
                n.setDisplayName(mgr.getDisplayName());
223
                return new Node[] {n};
224
            }
225
        }
226
227
    }
228
229
    private class LibraryChildren extends Children.Keys<Library> {
230
231
        LibraryChildren(List<Library> libs) {
232
            setKeys(libs);
233
        }
234
235
        protected Node[] createNodes(Library lib) {
236
            AbstractNode n = new AbstractNode(Children.LEAF, Lookups.singleton(lib));
237
            n.setName(lib.getName());
238
            n.setDisplayName(lib.getDisplayName());
239
            n.setShortDescription(lib.getDescription());
240
            n.setIconBaseWithExtension("org/netbeans/modules/project/libraries/resources/libraries.gif"); // NOI18N
241
            return new Node[] {n};
242
        }
243
244
    }
245
246
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
247
    private void initComponents() {
248
249
        librariesLabel = new javax.swing.JLabel();
250
        tree = new org.openide.explorer.view.BeanTreeView();
251
        createButton = new javax.swing.JButton();
252
        importButton = new javax.swing.JButton();
253
        manageLibrariesButton = new javax.swing.JButton();
254
255
        librariesLabel.setLabelFor(tree);
256
        org.openide.awt.Mnemonics.setLocalizedText(librariesLabel, org.openide.util.NbBundle.getMessage(LibraryChooserGUI.class, "LibraryChooserGUI.librariesLabel")); // NOI18N
257
258
        tree.setBorder(javax.swing.BorderFactory.createEtchedBorder());
259
        tree.setPopupAllowed(false);
260
        tree.setRootVisible(false);
261
262
        createButton.setText(org.openide.util.NbBundle.getMessage(LibraryChooserGUI.class, "LibraryChooserGUI.createButton.text")); // NOI18N
263
        createButton.addActionListener(new java.awt.event.ActionListener() {
264
            public void actionPerformed(java.awt.event.ActionEvent evt) {
265
                createButtonActionPerformed(evt);
266
            }
267
        });
268
269
        importButton.setText(org.openide.util.NbBundle.getMessage(LibraryChooserGUI.class, "LibraryChooserGUI.importButton.text")); // NOI18N
270
        importButton.addActionListener(new java.awt.event.ActionListener() {
271
            public void actionPerformed(java.awt.event.ActionEvent evt) {
272
                importButtonActionPerformed(evt);
273
            }
274
        });
275
276
        manageLibrariesButton.setText(org.openide.util.NbBundle.getMessage(LibraryChooserGUI.class, "LibraryChooserGUI.manageLibrariesButton.text")); // NOI18N
277
        manageLibrariesButton.addActionListener(new java.awt.event.ActionListener() {
278
            public void actionPerformed(java.awt.event.ActionEvent evt) {
279
                manageLibrariesButtonActionPerformed(evt);
280
            }
281
        });
282
283
        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
284
        this.setLayout(layout);
285
        layout.setHorizontalGroup(
286
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
287
            .add(librariesLabel)
288
            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
289
                .add(tree, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 257, Short.MAX_VALUE)
290
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
291
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
292
                    .add(createButton)
293
                    .add(importButton)))
294
            .add(layout.createSequentialGroup()
295
                .add(manageLibrariesButton)
296
                .addContainerGap())
297
        );
298
        layout.setVerticalGroup(
299
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
300
            .add(layout.createSequentialGroup()
301
                .add(librariesLabel)
302
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
303
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
304
                    .add(layout.createSequentialGroup()
305
                        .add(createButton)
306
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
307
                        .add(importButton))
308
                    .add(tree, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 284, Short.MAX_VALUE))
309
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
310
                .add(manageLibrariesButton))
311
        );
312
313
        getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(LibraryChooserGUI.class, "LibraryChooserGUI.accessibleDescription")); // NOI18N
314
    }// </editor-fold>//GEN-END:initComponents
315
316
    private void manageLibrariesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_manageLibrariesButtonActionPerformed
317
        if (LibrariesCustomizer.showCustomizer(null, manager)) {
318
            setRootNode();
319
        }
320
    }//GEN-LAST:event_manageLibrariesButtonActionPerformed
321
322
    private void createButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createButtonActionPerformed
323
        Library l = LibrariesCustomizer.showCreateNewLibraryCustomizer(manager);
324
        if (l != null) {
325
            setRootNode();
326
            selectLibrary(Collections.singleton(l));
327
        }
328
    }//GEN-LAST:event_createButtonActionPerformed
329
330
    private void selectLibrary(Collection<Library> libraries) {
331
        Node root = explorer.getRootContext();
332
        List<Node> selection = new ArrayList<Node>();
333
        for (Library lib : libraries) {
334
            String[] path = {lib.getManager().getDisplayName(), lib.getName()};
335
            try {
336
                Node node = NodeOp.findPath(root, path);
337
                if (node != null) {
338
                    selection.add(node);
339
                }
340
            } catch (NodeNotFoundException e) {
341
                //Ignore it
342
            }
343
        }
344
        try {
345
            explorer.setSelectedNodes(selection.toArray(new Node[selection.size()]));
346
        } catch (PropertyVetoException e) {
347
            //Ignore it
348
        }
349
    }
350
    
351
    private void importButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importButtonActionPerformed
352
        Set<Library> libs = showChooser(LibraryManager.getDefault(), 
353
                new IgnoreAlreadyImportedLibrariesFilter(), null, false);
354
        if (libs != null) {
355
            Set<Library> importedLibs = new HashSet<Library>();
356
            try {
357
                for (Library lib : libs) {
358
                    importedLibs.add(importHandler.importLibrary(lib));
359
                }
360
            } catch (IOException ex) {
361
                Exceptions.printStackTrace(ex);
362
            }
363
            setRootNode();        
364
            selectLibrary(importedLibs);
365
        }
366
    }//GEN-LAST:event_importButtonActionPerformed
367
368
    private class IgnoreAlreadyImportedLibrariesFilter implements LibraryChooser.Filter {
369
        public boolean accept(Library library) {
370
            return manager.getLibrary(library.getName()) == null;
371
        }
372
    }
373
374
    // Variables declaration - do not modify//GEN-BEGIN:variables
375
    private javax.swing.JButton createButton;
376
    private javax.swing.JButton importButton;
377
    private javax.swing.JLabel librariesLabel;
378
    private javax.swing.JButton manageLibrariesButton;
379
    private org.openide.explorer.view.BeanTreeView tree;
380
    // End of variables declaration//GEN-END:variables
381
382
}
(-)a/project.libraries/src/org/netbeans/api/project/libraries/LibraryManager.java (-54 / +261 lines)
Lines 41-64 Link Here
41
41
42
package org.netbeans.api.project.libraries;
42
package org.netbeans.api.project.libraries;
43
43
44
45
import org.netbeans.api.project.libraries.Library;
46
import org.netbeans.spi.project.libraries.LibraryImplementation;
47
import org.netbeans.spi.project.libraries.LibraryProvider;
48
import org.openide.util.Lookup;
49
import org.openide.util.LookupListener;
50
import org.openide.util.LookupEvent;
51
52
import java.beans.PropertyChangeSupport;
44
import java.beans.PropertyChangeSupport;
53
import java.beans.PropertyChangeListener;
45
import java.beans.PropertyChangeListener;
54
import java.beans.PropertyChangeEvent;
46
import java.beans.PropertyChangeEvent;
55
import java.io.IOException;
47
import java.io.IOException;
56
import java.util.*;
48
import java.net.URL;
49
import java.util.ArrayList;
50
import java.util.Collection;
51
import java.util.HashSet;
52
import java.util.List;
53
import java.util.Map;
54
import java.util.Set;
55
import org.netbeans.modules.project.libraries.LibraryAccessor;
57
import org.netbeans.modules.project.libraries.WritableLibraryProvider;
56
import org.netbeans.modules.project.libraries.WritableLibraryProvider;
58
import org.netbeans.spi.project.libraries.LibraryFactory;
57
import org.netbeans.modules.project.libraries.ui.LibrariesModel;
58
import org.netbeans.spi.project.libraries.ArealLibraryProvider;
59
import org.netbeans.spi.project.libraries.LibraryImplementation;
60
import org.netbeans.spi.project.libraries.LibraryProvider;
61
import org.netbeans.spi.project.libraries.LibraryStorageArea;
62
import org.netbeans.spi.project.libraries.LibraryTypeProvider;
59
import org.netbeans.spi.project.libraries.support.LibrariesSupport;
63
import org.netbeans.spi.project.libraries.support.LibrariesSupport;
60
64
import org.openide.util.Lookup;
61
// XXX make getLibraries return Set not array
65
import org.openide.util.LookupListener;
66
import org.openide.util.LookupEvent;
62
67
63
/**
68
/**
64
 * LibraryManager provides registry of the installed libraries.
69
 * LibraryManager provides registry of the installed libraries.
Lines 67-85 Link Here
67
 */
72
 */
68
public final class LibraryManager {
73
public final class LibraryManager {
69
74
75
    /**
76
     * Property fired when the set of libraries changes.
77
     */
70
    public static final String PROP_LIBRARIES = "libraries"; //NOI18N
78
    public static final String PROP_LIBRARIES = "libraries"; //NOI18N
71
79
72
    private static LibraryManager instance;
80
    private static LibraryManager instance;
73
81
74
    private Lookup.Result<LibraryProvider> result;
82
    private Lookup.Result<LibraryProvider> result;
75
    private Collection<LibraryProvider> currentStorages = new ArrayList<LibraryProvider>();
83
    private final Collection<LibraryProvider> currentStorages = new ArrayList<LibraryProvider>();
76
    private PropertyChangeListener plistener;
84
    private final PropertyChangeListener plistener = new PropertyChangeListener() {
77
    private PropertyChangeSupport listeners;
85
        public void propertyChange(PropertyChangeEvent evt) {
86
            if (LibraryProvider.PROP_LIBRARIES.equals(evt.getPropertyName())) {
87
                resetCache();
88
            }
89
        }
90
    };
91
    private final PropertyChangeSupport listeners = new PropertyChangeSupport(this);
92
    private static final PropertyChangeSupport openLibraryManagerListListeners = 
93
            new PropertyChangeSupport(LibraryManager.class);
94
    private static final PropertyChangeListener AREAL_LIBRARY_PROVIDER_LISTENER = new PropertyChangeListener() {
95
            public void propertyChange(PropertyChangeEvent evt) {
96
                openLibraryManagerListListeners.firePropertyChange(PROP_OPEN_LIBRARY_MANAGERS, null, null);
97
            }
98
        };
99
        
100
    /** Property fired when list of open library managers changes. */
101
    public static final String PROP_OPEN_LIBRARY_MANAGERS = "openManagers"; // NOI18N
102
    private static Lookup.Result<ArealLibraryProvider> areaProvidersLookupResult = null;
103
    private static Collection<? extends ArealLibraryProvider> currentAreaProviders = new ArrayList<ArealLibraryProvider>();
104
78
    private Collection<Library> cache;
105
    private Collection<Library> cache;
79
106
    /** null for default manager */
107
    private final ArealLibraryProvider alp;
108
    /** null for default manager */
109
    private final LibraryStorageArea area;
80
110
81
    private LibraryManager () {
111
    private LibraryManager () {
82
        this.listeners = new PropertyChangeSupport(this);
112
        alp = null;
113
        area = null;
114
    }
115
116
    private LibraryManager(ArealLibraryProvider alp, LibraryStorageArea area) {
117
        this.alp = alp;
118
        this.area = area;
119
        LibraryProvider lp = LibraryAccessor.getLibraries(alp, area);
120
        lp.addPropertyChangeListener(plistener);
121
        currentStorages.add(lp);
122
    }
123
124
    /**
125
     * Gets a human-readable description of this manager.
126
     * This may be used to visually differentiate the global manager from various local managers.
127
     * @return a localized display name
128
     * @see LibraryStorageArea#getDisplayName
129
     * @since org.netbeans.modules.project.libraries/1 1.15
130
     */
131
    public String getDisplayName() {
132
        if (area == null) {
133
            return LibrariesModel.GLOBAL_AREA.getDisplayName();
134
        } else {
135
            return area.getDisplayName();
136
        }
137
    }
138
139
    /**
140
     * Gets the location associated with this manager.
141
     * @return a location where library definitions are kept, or null in the case of {@link #getDefault}
142
     * @see LibraryStorageArea#getLocation
143
     * @see #forLocation
144
     * @since org.netbeans.modules.project.libraries/1 1.15
145
     */
146
    public URL getLocation() {
147
        return area != null ? area.getLocation() : null;
83
    }
148
    }
84
149
85
    /**
150
    /**
Lines 99-142 Link Here
99
    }
164
    }
100
165
101
    /**
166
    /**
102
     * List all library defined in the IDE.
167
     * Lists all libraries defined in this manager.
103
     *
168
     * @return library definitions (never <code>null</code>)
104
     * @return Library[] library definitions never <code>null</code>
105
     */
169
     */
106
    public synchronized Library[] getLibraries() {
170
    public synchronized Library[] getLibraries() {
107
        if (this.cache == null) {
171
        if (this.cache == null) {
108
            if (this.result == null) {
172
            List<Library> l = new ArrayList<Library>();
109
                plistener = new PropertyChangeListener() {
173
            if (area == null) {
110
                    public void propertyChange(PropertyChangeEvent evt) {
174
                if (result == null) {
111
                        resetCache ();
175
                    result = Lookup.getDefault().lookupResult(LibraryProvider.class);
176
                    result.addLookupListener(new LookupListener() {
177
                        public void resultChanged(LookupEvent ev) {
178
                            resetCache();
179
                        }
180
                    });
181
                }
182
                Collection<? extends LibraryProvider> instances = result.allInstances();
183
                Collection<LibraryProvider> added = new HashSet<LibraryProvider>(instances);
184
                added.removeAll(currentStorages);
185
                Collection<LibraryProvider> removed = new HashSet<LibraryProvider>(currentStorages);
186
                removed.removeAll(instances);
187
                currentStorages.clear();
188
                for (LibraryProvider storage : instances) {
189
                    this.currentStorages.add(storage);
190
                    for (LibraryImplementation impl : storage.getLibraries()) {
191
                        l.add(new Library(impl, this));
112
                    }
192
                    }
113
                };
193
                }
114
                result = Lookup.getDefault().lookupResult(LibraryProvider.class);
194
                for (LibraryProvider p : removed) {
115
                result.addLookupListener (new LookupListener() {
195
                    p.removePropertyChangeListener(this.plistener);
116
                    public void resultChanged(LookupEvent ev) {
196
                }
117
                            resetCache ();
197
                for (LibraryProvider p : added) {
118
                    }
198
                    p.addPropertyChangeListener(this.plistener);
119
                });
199
                }
120
            }
200
            } else {
121
            List<Library> l = new ArrayList<Library>();
201
                for (LibraryImplementation impl : currentStorages.iterator().next().getLibraries()) {
122
            Collection<? extends LibraryProvider> instances = result.allInstances();
202
                    l.add(new Library(impl, this));
123
            Collection<LibraryProvider> added = new HashSet<LibraryProvider>(instances);
124
            added.removeAll (currentStorages);
125
            Collection<LibraryProvider> removed = new HashSet<LibraryProvider>(currentStorages);
126
            removed.removeAll (instances);
127
            currentStorages.clear();
128
            for (LibraryProvider storage : instances) {
129
                this.currentStorages.add (storage);
130
                for (LibraryImplementation impl : storage.getLibraries()) {
131
                    l.add(LibraryFactory.createLibrary(impl));
132
                }
203
                }
133
            }
204
            }
134
            for (LibraryProvider p : removed) {
135
                p.removePropertyChangeListener(this.plistener);
136
            }
137
            for (LibraryProvider p : added) {
138
                p.addPropertyChangeListener(this.plistener);
139
            }            
140
            this.cache = l;
205
            this.cache = l;
141
        }
206
        }
142
        return this.cache.toArray(new Library[this.cache.size()]);
207
        return this.cache.toArray(new Library[this.cache.size()]);
Lines 160-168 Link Here
160
     * @throws IOException when the library cannot be stored
225
     * @throws IOException when the library cannot be stored
161
     * @throws IllegalArgumentException if the library is not recognized by any 
226
     * @throws IllegalArgumentException if the library is not recognized by any 
162
     * {@link org.netbeans.spi.project.libraries.LibraryTypeProvider} or the library
227
     * {@link org.netbeans.spi.project.libraries.LibraryTypeProvider} or the library
163
     * of the same name already exists.
228
     * of the same name already exists, or if this manager is not {@link #getDefault}.
164
     * @since org.netbeans.modules.project.libraries/1 1.14
229
     * @since org.netbeans.modules.project.libraries/1 1.14
230
     * @deprecated Use {@link #createLibrary} instead, as this properly supports local managers.
165
     */
231
     */
232
    @Deprecated
166
    public void addLibrary (final Library library) throws IOException, IllegalArgumentException {
233
    public void addLibrary (final Library library) throws IOException, IllegalArgumentException {
167
        assert library != null;
234
        assert library != null;
168
        if (LibrariesSupport.getLibraryTypeProvider(library.getType()) == null) {
235
        if (LibrariesSupport.getLibraryTypeProvider(library.getType()) == null) {
Lines 176-182 Link Here
176
        assert providers.size() == 1;        
243
        assert providers.size() == 1;        
177
        providers.iterator().next().addLibrary(library.getLibraryImplementation());
244
        providers.iterator().next().addLibrary(library.getLibraryImplementation());
178
    }
245
    }
179
    
246
247
    /**
248
     * Creates a new library definition and adds it to the list.
249
     * @param type the type of library, as in {@link LibraryTypeProvider#getLibraryType} or {@link LibraryImplementation#getType}
250
     * @param name the identifying name of the new library (must not duplicate a name already in use by a library in this manager)
251
     * @param contents the initial contents of the library's volumes, as a map from volume type to volume content
252
     * @return a newly created library
253
     * @throws IOException if the new definition could not be stored
254
     * @throws IllegalArgumentException if the library type or one of the content volume types is not supported,
255
     *                                  or if a library of the same name already exists in this manager
256
     * @see ArealLibraryProvider#createLibrary
257
     * @since org.netbeans.modules.project.libraries/1 1.15
258
     */
259
    public Library createLibrary(String type, String name, Map<String,List<URL>> contents) throws IOException {
260
        if (getLibrary(name) != null) {
261
            throw new IllegalArgumentException("Name already in use: " + name); // NOI18N
262
        }
263
        LibraryImplementation impl;
264
        if (area == null) {
265
            LibraryTypeProvider ltp = LibrariesSupport.getLibraryTypeProvider(type);
266
            if (ltp == null) {
267
                throw new IllegalArgumentException("Trying to add a library of unknown type: " + type); // NOI18N
268
            }
269
            impl = ltp.createLibrary();
270
            impl.setName(name);
271
            for (Map.Entry<String,List<URL>> entry : contents.entrySet()) {
272
                impl.setContent(entry.getKey(), entry.getValue());
273
            }
274
            Lookup.getDefault().lookup(WritableLibraryProvider.class).addLibrary(impl);
275
        } else {
276
            impl = LibraryAccessor.createLibrary(alp, type, name, area, contents);
277
        }
278
        return new Library(impl, this);
279
    }
280
180
    /**
281
    /**
181
     * Removes installed library 
282
     * Removes installed library 
182
     * @param library to be removed. 
283
     * @param library to be removed. 
Lines 187-195 Link Here
187
     */
288
     */
188
    public void removeLibrary (final Library library) throws IOException, IllegalArgumentException {
289
    public void removeLibrary (final Library library) throws IOException, IllegalArgumentException {
189
        assert library != null;
290
        assert library != null;
190
        final Collection<? extends WritableLibraryProvider> providers = Lookup.getDefault().lookupAll(WritableLibraryProvider.class);
291
        if (area == null) {
191
        assert providers.size() == 1;
292
            final Collection<? extends WritableLibraryProvider> providers = Lookup.getDefault().lookupAll(WritableLibraryProvider.class);
192
        providers.iterator().next().removeLibrary(library.getLibraryImplementation());
293
            assert providers.size() == 1;
294
            providers.iterator().next().removeLibrary(library.getLibraryImplementation());
295
        } else {
296
            LibraryAccessor.remove(alp, library.getLibraryImplementation());
297
        }
193
    }
298
    }
194
299
195
    /**
300
    /**
Lines 229-235 Link Here
229
        return instance;
334
        return instance;
230
    }
335
    }
231
336
337
    /**
338
     * Gets a library manager which loads library definitions from a particular location.
339
     * There is no guarantee that the return value is the same object from call to call with the same location.
340
     * @param location any storage location supported by an installed provider
341
     * @return a library manager whose {@link #getLocation} matches the supplied location
342
     * @throws IllegalArgumentException if no installed provider is able to manage locations of this kind
343
     * @see ArealLibraryProvider#loadArea
344
     * @see ArealLibraryProvider#getLibraries
345
     * @since org.netbeans.modules.project.libraries/1 1.15
346
     */
347
    public static LibraryManager forLocation(URL location) throws IllegalArgumentException {
348
        for (ArealLibraryProvider alp : Lookup.getDefault().lookupAll(ArealLibraryProvider.class)) {
349
            LibraryStorageArea area = alp.loadArea(location);
350
            if (area != null) {
351
                return new LibraryManager(alp, area);
352
            }
353
        }
354
        throw new IllegalArgumentException(location.toExternalForm());
355
    }
232
356
357
    /**
358
     * Gets an unspecified collection of managers which are somehow to be represented as open.
359
     * For example, library storages referred to from open projects might be returned.
360
     * You can listen on changes in list of open managers via {@link #addOpenManagersPropertyChangeListener}.
361
     * There is no guarantee that the non-default managers are the same objects from call to call
362
     * even if the locations remain the same.
363
     * @see ArealLibraryProvider#getOpenAreas
364
     * @return a set of managers, always including at least {@link #getDefault}
365
     * @since org.netbeans.modules.project.libraries/1 1.15
366
     */
367
    public static Collection<LibraryManager> getOpenManagers() {
368
        List<LibraryManager> managers = new ArrayList<LibraryManager>();
369
        managers.add(getDefault());
370
        Set<URL> locations = new HashSet<URL>();
371
        for (ArealLibraryProvider alp : Lookup.getDefault().lookupAll(ArealLibraryProvider.class)) {
372
            for (LibraryStorageArea area : LibraryAccessor.getOpenAreas(alp)) {
373
                if (locations.add(area.getLocation())) {
374
                    managers.add(new LibraryManager(alp, area));
375
                }
376
            }
377
        }
378
        for (ArealLibraryProvider alp : Lookup.getDefault().lookupAll(ArealLibraryProvider.class)) {
379
            for (URL location : LibrariesModel.createdAreas) {
380
                LibraryStorageArea area = alp.loadArea(location);
381
                if (area != null) {
382
                    assert area.getLocation().equals(location) : "Bad location " + area.getLocation() + " does not match " + location + " from " + alp.getClass().getName();
383
                    if (locations.add(location)) {
384
                        managers.add(new LibraryManager(alp, area));
385
                    }
386
                }
387
            }
388
        }
389
        return managers;
390
    }
391
392
    /**
393
     * Adds PropertyChangeListener on list of open library managers.
394
     * The listener is notified when list of open library managers changes via
395
     * {@link #PROP_OPEN_LIBRARY_MANAGERS}.
396
     * @param listener to be notified
397
     */
398
    public static synchronized void addOpenManagersPropertyChangeListener (PropertyChangeListener listener) {
399
        assert listener != null;
400
        if (areaProvidersLookupResult == null) {
401
            areaProvidersLookupResult = Lookup.getDefault().lookupResult(ArealLibraryProvider.class);
402
            attachListeners(areaProvidersLookupResult.allInstances());
403
            areaProvidersLookupResult.addLookupListener(new LookupListener() {
404
                public void resultChanged(LookupEvent ev) {
405
                    attachListeners(areaProvidersLookupResult.allInstances());
406
                }
407
            });
408
        }
409
        openLibraryManagerListListeners.addPropertyChangeListener (listener);
410
    }
411
    
412
    private static synchronized void attachListeners(Collection<? extends ArealLibraryProvider> currentProviders) {
413
        for (ArealLibraryProvider provider : currentAreaProviders) {
414
            provider.removePropertyChangeListener(AREAL_LIBRARY_PROVIDER_LISTENER);
415
        }
416
        for (ArealLibraryProvider provider : currentProviders) {
417
            provider.addPropertyChangeListener(AREAL_LIBRARY_PROVIDER_LISTENER);
418
        }
419
        currentAreaProviders = currentProviders;
420
    }
421
422
    /**
423
     * Removes PropertyChangeListener
424
     * @param listener
425
     */
426
    public static void removeOpenManagersPropertyChangeListener (PropertyChangeListener listener) {
427
        assert listener != null;
428
        openLibraryManagerListListeners.removePropertyChangeListener (listener);
429
    }
430
    
431
    @Override
432
    public String toString() {
433
        URL loc = getLocation();
434
        return "LibraryManager[" + (loc != null ? loc : "default") + "]"; // NOI18N
435
    }
436
437
    LibraryStorageArea getArea() {
438
        return area;
439
    }
233
440
234
} // end LibraryManager
441
} // end LibraryManager
235
442
(-)ffef4cca2ff4 (+124 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.spi.project.libraries;
21
22
import java.beans.PropertyChangeListener;
23
import java.io.IOException;
24
import java.net.URL;
25
import java.util.List;
26
import java.util.Map;
27
import java.util.Set;
28
29
/**
30
 * Library provider which can define libraries in particular areas.
31
 * There is no explicit method to save a library; setters on {@link LibraryImplementation} should do this.
32
 * @param A the type of storage area used by this provider
33
 * @param L the type of library created by this provider
34
 * @since org.netbeans.modules.project.libraries/1 1.15
35
 */
36
public interface ArealLibraryProvider<A extends LibraryStorageArea, L extends LibraryImplementation> {
37
38
    /**
39
     * Property to fire when {@link #getOpenAreas} might have changed.
40
     */
41
    String PROP_OPEN_AREAS = "openAreas"; // NOI18N
42
43
    /**
44
     * Adds a listener to {@link #PROP_OPEN_AREAS}.
45
     * @param listener a listener to add
46
     */
47
    void addPropertyChangeListener(PropertyChangeListener listener);
48
49
    /**
50
     * Removes a listener to {@link #PROP_OPEN_AREAS}.
51
     * @param listener a listener to remove
52
     */
53
    void removePropertyChangeListener(PropertyChangeListener listener);
54
55
    /**
56
     * Gets the runtime type of the area used by this provider.
57
     * @return the area type
58
     */
59
    Class<A> areaType();
60
61
    /**
62
     * Gets the runtime type of the libraries created by this provider.
63
     * @return the library type
64
     */
65
    Class<L> libraryType();
66
67
    /**
68
     * Creates or otherwise picks a storage area interactively.
69
     * This might actually create a fresh area, or just load an existing one,
70
     * or even do nothing (and return null).
71
     * The implementor is free to show a dialog here.
72
     * @return a new or existing storage area, or null
73
     */
74
    A createArea();
75
76
    /**
77
     * Loads a storage area (which may or may exist yet).
78
     * @param location an abstract storage location which may or may not be recognized by this provider
79
     * @return an area whose {@link LibraryStorageArea#getLocation} matches the provided location,
80
     *         or null if this type of location is not recognized by this provider
81
     */
82
    A loadArea(URL location);
83
84
    /**
85
     * Looks for areas which should be somehow listed as open.
86
     * For example, a provider which refers to library areas from project metadata
87
     * could list all areas referred to from currently open projects.
88
     * It is <em>not</em> necessary to include areas recently mentioned e.g. by {@link #createArea}.
89
     * @return a (possibly empty) collection of areas
90
     */
91
    Set<A> getOpenAreas();
92
93
    /**
94
     * Gets all libraries defined in a given area.
95
     * No two libraries in this area may share a given name (as in {@link LibraryImplementation#getName},
96
     * though it is permitted for libraries from different areas to have the same name.
97
     * Changes in the set of libraries defined in this area should be fired through {@link LibraryProvider#PROP_LIBRARIES}.
98
     * Since {@link IOException} is not thrown either from this method or from {@link LibraryProvider#getLibraries},
99
     * it is expected that any problems loading library definitions will be logged and that those libraries will be skipped.
100
     * @param area some storage area (which might not even exist yet, in which case the set of libraries will initially be empty)
101
     * @return a listenable set of libraries in this area
102
     *         (it is permitted to return distinct objects from call to call on the same area,
103
     *         i.e. no caching by the implementation is necessary)
104
     */
105
    LibraryProvider<L> getLibraries(A area);
106
107
    /**
108
     * Creates a new library.
109
     * @param type the kind of library to make, as in {@link LibraryTypeProvider#getLibraryType} or {@link LibraryImplementation#getType}
110
     * @param name the library name, as in {@link LibraryImplementation#getName}
111
     * @param area the location to define the library
112
     * @param contents initial volume contents (keys must be contained in the appropriate {@link LibraryTypeProvider#getSupportedVolumeTypes})
113
     * @return a new library with matching type, name, area, and contents
114
     * @throws IOException if an error occurs creating the library definition     */
115
    L createLibrary(String type, String name, A area, Map<String,List<URL>> contents) throws IOException;
116
117
    /**
118
     * Deletes an existing library.
119
     * @param library a library produced by this provider
120
     * @throws IOException if a problem can encountered deleting the library definition
121
     */
122
    void remove(L library) throws IOException;
123
124
}
(-)a/project.libraries/src/org/netbeans/spi/project/libraries/LibraryFactory.java (-2 / +1 lines)
Lines 58-68 Link Here
58
    private LibraryFactory() {
58
    private LibraryFactory() {
59
    }
59
    }
60
    
60
    
61
    
62
    /**
61
    /**
63
     * Creates Library for LibraryImplementation
62
     * Creates Library for LibraryImplementation
64
     * @param libraryImplementation the library SPI object
63
     * @param libraryImplementation the library SPI object
65
     * @return Library API instance
64
     * @return Library API instance, for which the {@link Library#getManager} will be {@link LibraryManager#getDefault}
66
     */
65
     */
67
    public static Library createLibrary (LibraryImplementation libraryImplementation) {
66
    public static Library createLibrary (LibraryImplementation libraryImplementation) {
68
        assert libraryImplementation != null;
67
        assert libraryImplementation != null;
(-)a/project.libraries/src/org/netbeans/spi/project/libraries/LibraryProvider.java (-6 / +9 lines)
Lines 38-43 Link Here
38
 * Version 2 license, then the option applies only if the new code is
38
 * Version 2 license, then the option applies only if the new code is
39
 * made subject to such option by the copyright holder.
39
 * made subject to such option by the copyright holder.
40
 */
40
 */
41
41
package org.netbeans.spi.project.libraries;
42
package org.netbeans.spi.project.libraries;
42
43
43
import java.beans.PropertyChangeListener;
44
import java.beans.PropertyChangeListener;
Lines 47-75 Link Here
47
 * Library storage is a source of libraries used by LibraryManager.
48
 * Library storage is a source of libraries used by LibraryManager.
48
 * LibraryManager allows existence of multiple LibraryProviders registered in
49
 * LibraryManager allows existence of multiple LibraryProviders registered in
49
 * the default lookup.
50
 * the default lookup.
51
 * @param L the type of implementation which will be produced by this provider
50
 */
52
 */
51
public interface LibraryProvider {
53
public interface LibraryProvider<L extends LibraryImplementation> {
52
54
53
    /**
55
    /**
54
     * Name of libraries property
56
     * Name of libraries property
55
     */
57
     */
56
    public static final String PROP_LIBRARIES = "libraries";        //NOI18N
58
    String PROP_LIBRARIES = "libraries"; // NOI18N
57
59
58
    /**
60
    /**
59
     * Returns libraries provided by the implemented provider.
61
     * Returns libraries provided by the implemented provider.
60
     * @return LibraryImplementation[] never return null, may return empty array.
62
     * @return (possibly empty but not null) list of libraries
61
     */
63
     */
62
    public LibraryImplementation[] getLibraries();
64
    L[] getLibraries();
63
65
64
    /**
66
    /**
65
     * Adds property change listener, the listener is notified when the libraries changed
67
     * Adds property change listener, the listener is notified when the libraries changed
66
     * @param listener
68
     * @param listener
67
     */
69
     */
68
    public void addPropertyChangeListener (PropertyChangeListener listener);
70
    void addPropertyChangeListener (PropertyChangeListener listener);
69
71
70
    /**
72
    /**
71
     * Removes property change listener
73
     * Removes property change listener
72
     * @param listener
74
     * @param listener
73
     */
75
     */
74
    public void removePropertyChangeListener (PropertyChangeListener listener);
76
    void removePropertyChangeListener (PropertyChangeListener listener);
77
75
}
78
}
(-)ffef4cca2ff4 (+46 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 * 
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 * 
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 * 
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.spi.project.libraries;
21
22
import java.net.URL;
23
24
/**
25
 * Abstract location where zero or more libraries are defined.
26
 * {@link Object#equals} and {@link Object#hashCode} are expected to be defined
27
 * such that object identity (within the implementing class) are driven by {@link #getLocation}.
28
 * @see ArealLibraryProvider
29
 * @since org.netbeans.modules.project.libraries/1 1.15
30
 */
31
public interface LibraryStorageArea {
32
33
    /**
34
     * Gets an associated storage location.
35
     * The contents of the URL (if it is even accessible) are unspecified.
36
     * @return an associated URL uniquely identifying this location
37
     */
38
    URL getLocation();
39
40
    /**
41
     * Gets a human-readable display label for this area.
42
     * @return a localized display name
43
     */
44
    String getDisplayName();
45
46
}
(-)a/project.libraries/src/org/netbeans/spi/project/libraries/LibraryTypeProvider.java (-2 / +5 lines)
Lines 75-80 Link Here
75
75
76
    /**
76
    /**
77
     * Creates a new empty library implementation.
77
     * Creates a new empty library implementation.
78
     * Generally will use {@link LibrariesSupport#createLibraryImplementation}.
79
     * This method is <strong>not</strong> used by {@link LibraryManager#createLibrary} except in the case of {@link LibraryManager#getDefault}.
78
     * @return the created library model, never null
80
     * @return the created library model, never null
79
     */
81
     */
80
    public LibraryImplementation createLibrary ();
82
    public LibraryImplementation createLibrary ();
Lines 85-90 Link Here
85
     * If the LibraryTypeProvider implementation requires clean of
87
     * If the LibraryTypeProvider implementation requires clean of
86
     * additional settings (e.g. remove properties in the build.properties)
88
     * additional settings (e.g. remove properties in the build.properties)
87
     * it should be done in this method.
89
     * it should be done in this method.
90
     * This method is <strong>not</strong> used by {@link LibraryManager#createLibrary} except in the case of {@link LibraryManager#getDefault}.
88
     * @param libraryImpl
91
     * @param libraryImpl
89
     */
92
     */
90
    public void libraryDeleted (LibraryImplementation libraryImpl);
93
    public void libraryDeleted (LibraryImplementation libraryImpl);
Lines 96-108 Link Here
96
     * If the LibraryTypeProvider implementation requires initialization of
99
     * If the LibraryTypeProvider implementation requires initialization of
97
     * additional settings (e.g. adding properties into the build.properties)
100
     * additional settings (e.g. adding properties into the build.properties)
98
     * it should be done in this method.
101
     * it should be done in this method.
99
     *
102
     * This method is <strong>not</strong> used by {@link LibraryManager#createLibrary} except in the case of {@link LibraryManager#getDefault}.
100
     */
103
     */
101
    public void libraryCreated (LibraryImplementation libraryImpl);
104
    public void libraryCreated (LibraryImplementation libraryImpl);
102
105
103
    /**
106
    /**
104
     * Returns customizer for given volume's type, or null if the volume is not customizable.
107
     * Returns customizer for given volume's type, or null if the volume is not customizable.
105
     * The object of the LibraryImplementation type is
108
     * The object of the LibraryImplementation type and optionally LibraryStorageArea type is
106
     * passed to the customizer's setObject method.
109
     * passed to the customizer's setObject method.
107
     * The customized object describes the library created by this
110
     * The customized object describes the library created by this
108
     * provider, but the customizer cannot assume that the customized
111
     * provider, but the customizer cannot assume that the customized
(-)a/project.libraries/src/org/netbeans/spi/project/libraries/support/LibrariesSupport.java (+147 lines)
Lines 40-49 Link Here
40
 */
40
 */
41
package org.netbeans.spi.project.libraries.support;
41
package org.netbeans.spi.project.libraries.support;
42
42
43
import java.io.File;
44
import java.net.MalformedURLException;
45
import java.net.URI;
46
import java.net.URISyntaxException;
47
import java.net.URL;
43
import org.netbeans.modules.project.libraries.LibraryTypeRegistry;
48
import org.netbeans.modules.project.libraries.LibraryTypeRegistry;
44
import org.netbeans.spi.project.libraries.LibraryImplementation;
49
import org.netbeans.spi.project.libraries.LibraryImplementation;
45
import org.netbeans.modules.project.libraries.DefaultLibraryImplementation;
50
import org.netbeans.modules.project.libraries.DefaultLibraryImplementation;
46
import org.netbeans.spi.project.libraries.LibraryTypeProvider;
51
import org.netbeans.spi.project.libraries.LibraryTypeProvider;
52
import org.openide.filesystems.FileObject;
53
import org.openide.filesystems.FileUtil;
54
import org.openide.filesystems.URLMapper;
55
import org.openide.util.Parameters;
47
56
48
/**
57
/**
49
 * SPI Support class.
58
 * SPI Support class.
Lines 85-88 Link Here
85
    public static LibraryTypeProvider[] getLibraryTypeProviders () {
94
    public static LibraryTypeProvider[] getLibraryTypeProviders () {
86
        return LibraryTypeRegistry.getDefault().getLibraryTypeProviders();
95
        return LibraryTypeRegistry.getDefault().getLibraryTypeProviders();
87
    }
96
    }
97
    
98
    /**
99
     * Properly converts possibly relative file to URL.
100
     * @param f file to convert; can be relative; cannot be null
101
     * @return url
102
     * @since org.netbeans.modules.project.libraries/1 1.17
103
     */
104
    public static URL convertFilePathToURL(String path) {
105
        try {
106
            File f = new File(path);
107
            if (f.isAbsolute()) {
108
                return f.toURI().toURL();
109
            } else {
110
                // create hierarchical relative URI (that is no schema)
111
                // to encode OS characters
112
                URI uri = new URI(null, null, path.replace('\\', '/'), null);
113
                return new URL("file", null, uri.getRawPath());
114
            }
115
116
        } catch (URISyntaxException ex) {
117
	    IllegalArgumentException y = new IllegalArgumentException();
118
	    y.initCause(ex);
119
	    throw y;
120
        } catch (MalformedURLException ex) {
121
	    IllegalArgumentException y = new IllegalArgumentException();
122
	    y.initCause(ex);
123
	    throw y;
124
        }
125
    }
126
    
127
    /**
128
     * Properly converts possibly relative URL to file.
129
     * @param url file URL to convert; can be relative; cannot be null
130
     * @return url
131
     * @since org.netbeans.modules.project.libraries/1 1.17
132
     */
133
    public static String convertURLToFilePath(URL url) {
134
        if (!"file".equals(url.getProtocol())) {
135
            throw new IllegalArgumentException("not file URL "+url); //NOI18N
136
        }
137
        try {
138
            if (isAbsoluteURL(url)) {
139
                return new File(new URI(url.toExternalForm())).getPath();
140
            } else {
141
                // workaround to decode URL path - created fake absolute URI 
142
                // just to construct File instance and properly decoded path:
143
                URI uri3 = new URI("file:/"+url.getPath());
144
                return new File(uri3).getPath().substring(1);
145
            }
146
        } catch (URISyntaxException ex) {
147
	    IllegalArgumentException y = new IllegalArgumentException();
148
	    y.initCause(ex);
149
	    throw y;
150
        }
151
    }
152
153
    /**
154
     * Is given URL absolute?
155
     * 
156
     * @param url url to test; cannot be null
157
     * @return is absolute
158
     * @since org.netbeans.modules.project.libraries/1 1.17
159
     */
160
    public static boolean isAbsoluteURL(URL url) {
161
        if ("jar".equals(url.getProtocol())) { // NOI18N
162
            url = FileUtil.getArchiveFile(url);
163
        }
164
        return url.getPath().startsWith("/");
165
    }
166
    
167
    /**
168
     * Helper method to resolve (possibly relative) library content URL to FileObject.
169
     * 
170
     * @param libraryLocation library location file; can be null for global libraries
171
     * @param libraryEntry library entry to resolve
172
     * @return file object
173
     * @since org.netbeans.modules.project.libraries/1 1.17
174
     */
175
    public static FileObject resolveLibraryEntryFileObject(URL libraryLocation, URL libraryEntry) {
176
        URL u = resolveLibraryEntryURL(libraryLocation, libraryEntry);
177
        return URLMapper.findFileObject(u);
178
    }
179
    
180
    /**
181
     * Helper method to resolve (possibly relative) library content URL.
182
     * 
183
     * @param libraryLocation library location file; can be null for global libraries
184
     * @param libraryEntry library entry to resolve
185
     * @return absolute URL
186
     * @since org.netbeans.modules.project.libraries/1 1.17
187
     */
188
    public static URL resolveLibraryEntryURL(URL libraryLocation, URL libraryEntry) {
189
        Parameters.notNull("libraryEntry", libraryEntry); //NOI18N
190
        if (isAbsoluteURL(libraryEntry)) {
191
            return libraryEntry;
192
        } else {
193
            if (libraryLocation == null) {
194
                throw new IllegalArgumentException("cannot resolve relative URL without library location"); //NOI18N
195
            }
196
            if (!"file".equals(libraryLocation.getProtocol())) { //NOI18N
197
                throw new IllegalArgumentException("not file: protocol - "+libraryLocation.toExternalForm()); //NOI18N
198
            }
199
            File libLocation = new File(URI.create(libraryLocation.toExternalForm()));
200
            if (!libLocation.getName().endsWith(".properties")) { //NOI18N
201
                throw new IllegalArgumentException("library location must be a file - "+libraryLocation.toExternalForm()); //NOI18N
202
            }
203
            File libBase = libLocation.getParentFile();
204
            String jarFolder = null;
205
            if ("jar".equals(libraryEntry.getProtocol())) {
206
                assert libraryEntry.toExternalForm().indexOf("!/") != -1 : libraryEntry.toExternalForm(); //NOI18N
207
                jarFolder = libraryEntry.toExternalForm().substring(libraryEntry.toExternalForm().indexOf("!/")+2); //NOI18N
208
                libraryEntry = FileUtil.getArchiveFile(libraryEntry);
209
            }
210
            String path = convertURLToFilePath(libraryEntry);
211
            File f = FileUtil.normalizeFile(new File(libBase, path));
212
            URL u;
213
            try {
214
                u = f.toURI().toURL();
215
            } catch (MalformedURLException ex) {
216
                IllegalArgumentException y = new IllegalArgumentException();
217
                y.initCause(ex);
218
                throw y;
219
            }
220
            if (jarFolder != null) {
221
                u = FileUtil.getArchiveRoot(u);
222
                try {
223
                    u = new URL(u + jarFolder.replace('\\', '/')); //NOI18N
224
                } catch (MalformedURLException e) {
225
                    throw new AssertionError(e);
226
                }
227
            }
228
            return u;
229
        }
230
    }
231
232
    // TODO: add method which compares two libraries: compare content and file sizes and ...
233
    
234
    // TODO: move some of these methods to openide.FileUtil
88
}
235
}

Return to bug 44035