UI for Cordova Plugins phonegap30
authorJan Becicka <jbecicka@netbeans.org>
Wed, 14 Aug 2013 14:46:35 +0200
branchphonegap30
changeset 269598a46e7b1ec157
parent 269596 dc6b8a616fbe
child 269599 578899fe5956
UI for Cordova Plugins
cordova/cordovaprojectupdate/src/org/netbeans/modules/cordova/updatetask/CordovaPlugin.java
cordova/cordovaprojectupdate/src/org/netbeans/modules/cordova/updatetask/PluginTask.java
cordova/nbproject/project.properties
cordova/nbproject/project.xml
cordova/src/org/netbeans/modules/cordova/project/Bundle.properties
cordova/src/org/netbeans/modules/cordova/project/CordovaCustomizerPanel.form
cordova/src/org/netbeans/modules/cordova/project/CordovaCustomizerPanel.java
cordova/src/org/netbeans/modules/cordova/project/PluginsPanel.form
cordova/src/org/netbeans/modules/cordova/project/PluginsPanel.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/cordova/cordovaprojectupdate/src/org/netbeans/modules/cordova/updatetask/CordovaPlugin.java	Wed Aug 14 14:46:35 2013 +0200
     1.3 @@ -0,0 +1,84 @@
     1.4 +/*
     1.5 + * To change this template, choose Tools | Templates
     1.6 + * and open the template in the editor.
     1.7 + */
     1.8 +package org.netbeans.modules.cordova.updatetask;
     1.9 +
    1.10 +import java.util.HashMap;
    1.11 +import java.util.Map;
    1.12 +
    1.13 +/**
    1.14 + *
    1.15 + * @author Jan Becicka
    1.16 + */
    1.17 +public class CordovaPlugin {
    1.18 +    private String id;
    1.19 +    private String url;
    1.20 +    
    1.21 +    private static final Map<String, String> wellKnowNames = new HashMap<String, String>();
    1.22 +    
    1.23 +    static {
    1.24 +        wellKnowNames.put("org.apache.cordova.core.device", "Device API");
    1.25 +        wellKnowNames.put("org.apache.cordova.core.network-information", "Network Connection");
    1.26 +        wellKnowNames.put("org.apache.cordova.core.battery-status", "Battery Events");
    1.27 +        wellKnowNames.put("org.apache.cordova.core.device-motion", "Acceleromatter");
    1.28 +        wellKnowNames.put("org.apache.cordova.core.device-orientation", "Compass");
    1.29 +        wellKnowNames.put("org.apache.cordova.core.geolocation", "Geolocation");
    1.30 +        wellKnowNames.put("org.apache.cordova.core.camera", "Camera");
    1.31 +        wellKnowNames.put("org.apache.cordova.core.media-capture", "Media Capture");
    1.32 +        wellKnowNames.put("org.apache.cordova.core.AudioHandler", "Media Playback");
    1.33 +        wellKnowNames.put("org.apache.cordova.core.file", "File API");
    1.34 +        wellKnowNames.put("org.apache.cordova.core.file-transfer", "File Transfer");
    1.35 +        wellKnowNames.put("org.apache.cordova.core.dialogs", "Dialogs (Notifications)");
    1.36 +        wellKnowNames.put("org.apache.cordova.core.vibration", "Vibration");
    1.37 +        wellKnowNames.put("org.apache.cordova.core.contacts", "Contacts");
    1.38 +        wellKnowNames.put("org.apache.cordova.core.globalization", "Globalization");
    1.39 +        wellKnowNames.put("org.apache.cordova.core.splashscreen", "Splashscreen");
    1.40 +        wellKnowNames.put("org.apache.cordova.core.console", "Debugger Console");
    1.41 +   }
    1.42 +
    1.43 +    public CordovaPlugin(String id, String url) {
    1.44 +        this.id = id;
    1.45 +        this.url = url;
    1.46 +    }
    1.47 +
    1.48 +    public String getId() {
    1.49 +        return id;
    1.50 +    }
    1.51 +
    1.52 +    public String getUrl() {
    1.53 +        return url;
    1.54 +    }
    1.55 +    
    1.56 +    public String getName() {
    1.57 +        String name = wellKnowNames.get(id);
    1.58 +        return name!=null?name:getId();
    1.59 +    }
    1.60 +
    1.61 +    @Override
    1.62 +    public int hashCode() {
    1.63 +        int hash = 5;
    1.64 +        hash = 29 * hash + (this.id != null ? this.id.hashCode() : 0);
    1.65 +        return hash;
    1.66 +    }
    1.67 +
    1.68 +    @Override
    1.69 +    public boolean equals(Object obj) {
    1.70 +        if (obj == null) {
    1.71 +            return false;
    1.72 +        }
    1.73 +        if (getClass() != obj.getClass()) {
    1.74 +            return false;
    1.75 +        }
    1.76 +        final CordovaPlugin other = (CordovaPlugin) obj;
    1.77 +        if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) {
    1.78 +            return false;
    1.79 +        }
    1.80 +        return true;
    1.81 +    }
    1.82 +
    1.83 +    @Override
    1.84 +    public String toString() {
    1.85 +        return getName();
    1.86 +    }
    1.87 +}
     2.1 --- a/cordova/cordovaprojectupdate/src/org/netbeans/modules/cordova/updatetask/PluginTask.java	Tue Aug 13 16:18:48 2013 +0200
     2.2 +++ b/cordova/cordovaprojectupdate/src/org/netbeans/modules/cordova/updatetask/PluginTask.java	Wed Aug 14 14:46:35 2013 +0200
     2.3 @@ -159,47 +159,4 @@
     2.4              exec.execute();
     2.5          }
     2.6      }
     2.7 -    
     2.8 -    
     2.9 -    private class CordovaPlugin {
    2.10 -        private String id;
    2.11 -        private String url;
    2.12 -
    2.13 -        public CordovaPlugin(String id, String url) {
    2.14 -            this.id = id;
    2.15 -            this.url = url;
    2.16 -        }
    2.17 -
    2.18 -        public String getId() {
    2.19 -            return id;
    2.20 -        }
    2.21 -
    2.22 -        public String getUrl() {
    2.23 -            return url;
    2.24 -        }
    2.25 -
    2.26 -        @Override
    2.27 -        public int hashCode() {
    2.28 -            int hash = 5;
    2.29 -            hash = 29 * hash + (this.id != null ? this.id.hashCode() : 0);
    2.30 -            return hash;
    2.31 -        }
    2.32 -
    2.33 -        @Override
    2.34 -        public boolean equals(Object obj) {
    2.35 -            if (obj == null) {
    2.36 -                return false;
    2.37 -            }
    2.38 -            if (getClass() != obj.getClass()) {
    2.39 -                return false;
    2.40 -            }
    2.41 -            final CordovaPlugin other = (CordovaPlugin) obj;
    2.42 -            if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) {
    2.43 -                return false;
    2.44 -            }
    2.45 -            return true;
    2.46 -        }
    2.47 -        
    2.48 -        
    2.49 -    }
    2.50  }
     3.1 --- a/cordova/nbproject/project.properties	Tue Aug 13 16:18:48 2013 +0200
     3.2 +++ b/cordova/nbproject/project.properties	Wed Aug 14 14:46:35 2013 +0200
     3.3 @@ -1,4 +1,4 @@
     3.4 -javac.source=1.6
     3.5 +javac.source=1.7
     3.6  javac.compilerargs=-Xlint -Xlint:-serial
     3.7  # masterfs needed for the usual reasons; tools.jar needed for Ant's <javac> to work
     3.8  test.unit.run.cp.extra=${tools.jar}
     4.1 --- a/cordova/nbproject/project.xml	Tue Aug 13 16:18:48 2013 +0200
     4.2 +++ b/cordova/nbproject/project.xml	Wed Aug 14 14:46:35 2013 +0200
     4.3 @@ -261,6 +261,14 @@
     4.4                          <specification-version>8.12</specification-version>
     4.5                      </run-dependency>
     4.6                  </dependency>
     4.7 +                <dependency>
     4.8 +                    <code-name-base>org.openide.windows</code-name-base>
     4.9 +                    <build-prerequisite/>
    4.10 +                    <compile-dependency/>
    4.11 +                    <run-dependency>
    4.12 +                        <specification-version>6.64</specification-version>
    4.13 +                    </run-dependency>
    4.14 +                </dependency>
    4.15              </module-dependencies>
    4.16              <test-dependencies>
    4.17                  <test-type>
     5.1 --- a/cordova/src/org/netbeans/modules/cordova/project/Bundle.properties	Tue Aug 13 16:18:48 2013 +0200
     5.2 +++ b/cordova/src/org/netbeans/modules/cordova/project/Bundle.properties	Wed Aug 14 14:46:35 2013 +0200
     5.3 @@ -68,9 +68,15 @@
     5.4  CordovaPanel.labiPadSplashPortrait.text=Splash (iPad, Portrait):
     5.5  CordovaPanel.labiPadSplashRetLandscape.text=Splash (iPad, Retina, Landscape):
     5.6  CordovaPanel.labiPadSplashRetPortrait.text=Splash (iPad, Retina, Portrait):
     5.7 -CordovaCustomizerPanel.editPlugins.text=Edit List of Plugins...
     5.8  CordovaCustomizerPanel.mobilePlatformsSetup.text=Mobile Platforms Setup...
     5.9  CordovaPanel.platformSetup.text=Setup Mobile Platforms...
    5.10  CordovaCustomizerPanel.createConfigsLabel.text=Cordova Resources not created.
    5.11  CordovaNotFound.jLabel2.text=<html><body><a href="">Install Cordova</a></body></html>
    5.12  CordovaNotFound.jLabel1.text=<html><body>\nNetBeans cannot find <b>cordova</b> or <b>git</b> on your PATH. Please install <b>cordova</b> and <b>git</b>.<br>\nNetBeans might require restart for changes to take effect.\n</body>\n</html>\n
    5.13 +CordovaCustomizerPanel.cordovaPanel.TabConstraints.tabTitle=Application
    5.14 +PluginsPanel.selectSelectedButton.text=>
    5.15 +PluginsPanel.deselectSelectedButton.text=<
    5.16 +PluginsPanel.generalInfoLabel.text=<html>Choose a cordova plugin and shuttle it the Selected list to add it to your project.</html>
    5.17 +PluginsPanel.selectedLabel.text=&Selected:
    5.18 +PluginsPanel.librariesLabel.text=A&vailable:
    5.19 +CordovaCustomizerPanel.pluginsPanel1.TabConstraints.tabTitle=Plugins
     6.1 --- a/cordova/src/org/netbeans/modules/cordova/project/CordovaCustomizerPanel.form	Tue Aug 13 16:18:48 2013 +0200
     6.2 +++ b/cordova/src/org/netbeans/modules/cordova/project/CordovaCustomizerPanel.form	Wed Aug 14 14:46:35 2013 +0200
     6.3 @@ -20,12 +20,11 @@
     6.4                <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
     6.5                <Component id="mobilePlatformsSetup" min="-2" max="-2" attributes="0"/>
     6.6            </Group>
     6.7 -          <Group type="102" attributes="0">
     6.8 -              <Component id="editPlugins" min="-2" max="-2" attributes="0"/>
     6.9 -              <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
    6.10 +          <Component id="generatePanel" alignment="0" max="32767" attributes="0"/>
    6.11 +          <Group type="102" alignment="0" attributes="0">
    6.12 +              <Component id="jTabbedPane1" pref="516" max="32767" attributes="0"/>
    6.13 +              <EmptySpace max="-2" attributes="0"/>
    6.14            </Group>
    6.15 -          <Component id="generatePanel" alignment="0" max="32767" attributes="0"/>
    6.16 -          <Component id="cordovaPanel" pref="486" max="32767" attributes="0"/>
    6.17        </Group>
    6.18      </DimensionLayout>
    6.19      <DimensionLayout dim="1">
    6.20 @@ -33,18 +32,14 @@
    6.21            <Group type="102" attributes="0">
    6.22                <Component id="generatePanel" min="-2" max="-2" attributes="0"/>
    6.23                <EmptySpace max="-2" attributes="0"/>
    6.24 -              <Component id="cordovaPanel" min="-2" max="-2" attributes="0"/>
    6.25 +              <Component id="jTabbedPane1" pref="209" max="32767" attributes="0"/>
    6.26                <EmptySpace max="-2" attributes="0"/>
    6.27 -              <Component id="editPlugins" min="-2" max="-2" attributes="0"/>
    6.28 -              <EmptySpace max="32767" attributes="0"/>
    6.29                <Component id="mobilePlatformsSetup" min="-2" max="-2" attributes="0"/>
    6.30            </Group>
    6.31        </Group>
    6.32      </DimensionLayout>
    6.33    </Layout>
    6.34    <SubComponents>
    6.35 -    <Component class="org.netbeans.modules.cordova.project.CordovaPanel" name="cordovaPanel">
    6.36 -    </Component>
    6.37      <Container class="javax.swing.JPanel" name="generatePanel">
    6.38  
    6.39        <Layout>
    6.40 @@ -52,7 +47,7 @@
    6.41            <Group type="103" groupAlignment="0" attributes="0">
    6.42                <Group type="102" attributes="0">
    6.43                    <Component id="createConfigs" min="-2" max="-2" attributes="0"/>
    6.44 -                  <EmptySpace pref="314" max="32767" attributes="0"/>
    6.45 +                  <EmptySpace max="32767" attributes="0"/>
    6.46                </Group>
    6.47                <Group type="102" alignment="0" attributes="0">
    6.48                    <Component id="createConfigsLabel" min="-2" max="-2" attributes="0"/>
    6.49 @@ -101,15 +96,33 @@
    6.50          <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="mobilePlatformsSetupActionPerformed"/>
    6.51        </Events>
    6.52      </Component>
    6.53 -    <Component class="javax.swing.JButton" name="editPlugins">
    6.54 -      <Properties>
    6.55 -        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
    6.56 -          <ResourceString bundle="org/netbeans/modules/cordova/project/Bundle.properties" key="CordovaCustomizerPanel.editPlugins.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
    6.57 -        </Property>
    6.58 -      </Properties>
    6.59 -      <Events>
    6.60 -        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="editPluginsActionPerformed"/>
    6.61 -      </Events>
    6.62 -    </Component>
    6.63 +    <Container class="javax.swing.JTabbedPane" name="jTabbedPane1">
    6.64 +
    6.65 +      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
    6.66 +      <SubComponents>
    6.67 +        <Component class="org.netbeans.modules.cordova.project.CordovaPanel" name="cordovaPanel">
    6.68 +          <Constraints>
    6.69 +            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
    6.70 +              <JTabbedPaneConstraints tabName="Application">
    6.71 +                <Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
    6.72 +                  <ResourceString bundle="org/netbeans/modules/cordova/project/Bundle.properties" key="CordovaCustomizerPanel.cordovaPanel.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
    6.73 +                </Property>
    6.74 +              </JTabbedPaneConstraints>
    6.75 +            </Constraint>
    6.76 +          </Constraints>
    6.77 +        </Component>
    6.78 +        <Component class="org.netbeans.modules.cordova.project.PluginsPanel" name="pluginsPanel1">
    6.79 +          <Constraints>
    6.80 +            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
    6.81 +              <JTabbedPaneConstraints tabName="Plugins">
    6.82 +                <Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
    6.83 +                  <ResourceString bundle="org/netbeans/modules/cordova/project/Bundle.properties" key="CordovaCustomizerPanel.pluginsPanel1.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
    6.84 +                </Property>
    6.85 +              </JTabbedPaneConstraints>
    6.86 +            </Constraint>
    6.87 +          </Constraints>
    6.88 +        </Component>
    6.89 +      </SubComponents>
    6.90 +    </Container>
    6.91    </SubComponents>
    6.92  </Form>
     7.1 --- a/cordova/src/org/netbeans/modules/cordova/project/CordovaCustomizerPanel.java	Tue Aug 13 16:18:48 2013 +0200
     7.2 +++ b/cordova/src/org/netbeans/modules/cordova/project/CordovaCustomizerPanel.java	Wed Aug 14 14:46:35 2013 +0200
     7.3 @@ -47,6 +47,13 @@
     7.4  import java.beans.PropertyChangeEvent;
     7.5  import java.beans.PropertyChangeListener;
     7.6  import java.io.IOException;
     7.7 +import java.io.InputStream;
     7.8 +import java.io.OutputStream;
     7.9 +import java.util.ArrayList;
    7.10 +import java.util.Collections;
    7.11 +import java.util.HashSet;
    7.12 +import java.util.List;
    7.13 +import java.util.Properties;
    7.14  import java.util.prefs.Preferences;
    7.15  import org.netbeans.api.options.OptionsDisplayer;
    7.16  import org.netbeans.api.progress.ProgressUtils;
    7.17 @@ -54,13 +61,13 @@
    7.18  import org.netbeans.api.project.ProjectUtils;
    7.19  import org.netbeans.modules.cordova.CordovaPerformer;
    7.20  import org.netbeans.modules.cordova.CordovaPlatform;
    7.21 +import org.netbeans.modules.cordova.updatetask.CordovaPlugin;
    7.22  import org.netbeans.modules.cordova.wizard.CordovaProjectExtender;
    7.23  import org.netbeans.modules.cordova.updatetask.SourceConfig;
    7.24  import org.netbeans.modules.cordova.wizard.CordovaTemplate;
    7.25  import org.netbeans.spi.project.ui.support.ProjectCustomizer.Category;
    7.26 -import org.openide.cookies.EditCookie;
    7.27  import org.openide.filesystems.FileObject;
    7.28 -import org.openide.loaders.DataObject;
    7.29 +import org.openide.util.EditableProperties;
    7.30  import org.openide.util.Exceptions;
    7.31  import org.openide.util.HelpCtx;
    7.32  import org.openide.util.NbBundle;
    7.33 @@ -128,12 +135,13 @@
    7.34      // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    7.35      private void initComponents() {
    7.36  
    7.37 -        cordovaPanel = new org.netbeans.modules.cordova.project.CordovaPanel();
    7.38          generatePanel = new javax.swing.JPanel();
    7.39          createConfigs = new javax.swing.JButton();
    7.40          createConfigsLabel = new javax.swing.JLabel();
    7.41          mobilePlatformsSetup = new javax.swing.JButton();
    7.42 -        editPlugins = new javax.swing.JButton();
    7.43 +        jTabbedPane1 = new javax.swing.JTabbedPane();
    7.44 +        cordovaPanel = new org.netbeans.modules.cordova.project.CordovaPanel();
    7.45 +        pluginsPanel1 = new org.netbeans.modules.cordova.project.PluginsPanel();
    7.46  
    7.47          org.openide.awt.Mnemonics.setLocalizedText(createConfigs, org.openide.util.NbBundle.getMessage(CordovaCustomizerPanel.class, "CordovaPanel.createConfigs.text")); // NOI18N
    7.48          createConfigs.addActionListener(new java.awt.event.ActionListener() {
    7.49 @@ -150,7 +158,7 @@
    7.50              generatePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
    7.51              .addGroup(generatePanelLayout.createSequentialGroup()
    7.52                  .addComponent(createConfigs)
    7.53 -                .addContainerGap(314, Short.MAX_VALUE))
    7.54 +                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
    7.55              .addGroup(generatePanelLayout.createSequentialGroup()
    7.56                  .addComponent(createConfigsLabel)
    7.57                  .addGap(0, 0, Short.MAX_VALUE))
    7.58 @@ -171,12 +179,8 @@
    7.59              }
    7.60          });
    7.61  
    7.62 -        org.openide.awt.Mnemonics.setLocalizedText(editPlugins, org.openide.util.NbBundle.getMessage(CordovaCustomizerPanel.class, "CordovaCustomizerPanel.editPlugins.text")); // NOI18N
    7.63 -        editPlugins.addActionListener(new java.awt.event.ActionListener() {
    7.64 -            public void actionPerformed(java.awt.event.ActionEvent evt) {
    7.65 -                editPluginsActionPerformed(evt);
    7.66 -            }
    7.67 -        });
    7.68 +        jTabbedPane1.addTab(org.openide.util.NbBundle.getMessage(CordovaCustomizerPanel.class, "CordovaCustomizerPanel.cordovaPanel.TabConstraints.tabTitle"), cordovaPanel); // NOI18N
    7.69 +        jTabbedPane1.addTab(org.openide.util.NbBundle.getMessage(CordovaCustomizerPanel.class, "CordovaCustomizerPanel.pluginsPanel1.TabConstraints.tabTitle"), pluginsPanel1); // NOI18N
    7.70  
    7.71          javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
    7.72          this.setLayout(layout);
    7.73 @@ -185,21 +189,18 @@
    7.74              .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
    7.75                  .addGap(0, 0, Short.MAX_VALUE)
    7.76                  .addComponent(mobilePlatformsSetup))
    7.77 +            .addComponent(generatePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
    7.78              .addGroup(layout.createSequentialGroup()
    7.79 -                .addComponent(editPlugins)
    7.80 -                .addGap(0, 0, Short.MAX_VALUE))
    7.81 -            .addComponent(generatePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
    7.82 -            .addComponent(cordovaPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 486, Short.MAX_VALUE)
    7.83 +                .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 516, Short.MAX_VALUE)
    7.84 +                .addContainerGap())
    7.85          );
    7.86          layout.setVerticalGroup(
    7.87              layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
    7.88              .addGroup(layout.createSequentialGroup()
    7.89                  .addComponent(generatePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
    7.90                  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
    7.91 -                .addComponent(cordovaPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
    7.92 +                .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 209, Short.MAX_VALUE)
    7.93                  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
    7.94 -                .addComponent(editPlugins)
    7.95 -                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
    7.96                  .addComponent(mobilePlatformsSetup))
    7.97          );
    7.98      }// </editor-fold>//GEN-END:initComponents
    7.99 @@ -207,9 +208,8 @@
   7.100      private void createConfigsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createConfigsActionPerformed
   7.101          createConfigs.setVisible(false);
   7.102          createConfigsLabel.setVisible(false);
   7.103 -        editPlugins.setVisible(true);
   7.104          mobilePlatformsSetup.setVisible(true);
   7.105 -        cordovaPanel.setVisible(true);
   7.106 +        jTabbedPane1.setVisible(true);
   7.107          ProgressUtils.showProgressDialogAndRun(new Runnable() {
   7.108  
   7.109              @Override
   7.110 @@ -224,24 +224,14 @@
   7.111          OptionsDisplayer.getDefault().open("Advanced/MobilePlatforms");//NOI18N
   7.112      }//GEN-LAST:event_mobilePlatformsSetupActionPerformed
   7.113  
   7.114 -    private void editPluginsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editPluginsActionPerformed
   7.115 -        try {
   7.116 -            CordovaPerformer.createScript(project, "plugins.properties", "nbproject/plugins.properties", false);
   7.117 -            FileObject fileObject = this.project.getProjectDirectory().getFileObject("nbproject/plugins.properties");
   7.118 -            DataObject dob = DataObject.find(fileObject);
   7.119 -            dob.getCookie(EditCookie.class).edit();
   7.120 -        } catch (IOException ex) {
   7.121 -            Exceptions.printStackTrace(ex);
   7.122 -        }
   7.123 -    }//GEN-LAST:event_editPluginsActionPerformed
   7.124 -
   7.125      // Variables declaration - do not modify//GEN-BEGIN:variables
   7.126      private org.netbeans.modules.cordova.project.CordovaPanel cordovaPanel;
   7.127      private javax.swing.JButton createConfigs;
   7.128      private javax.swing.JLabel createConfigsLabel;
   7.129 -    private javax.swing.JButton editPlugins;
   7.130      private javax.swing.JPanel generatePanel;
   7.131 +    private javax.swing.JTabbedPane jTabbedPane1;
   7.132      private javax.swing.JButton mobilePlatformsSetup;
   7.133 +    private org.netbeans.modules.cordova.project.PluginsPanel pluginsPanel1;
   7.134      // End of variables declaration//GEN-END:variables
   7.135  
   7.136      private void initControls() {
   7.137 @@ -252,9 +242,41 @@
   7.138                  checkIdValid(cordovaPanel.getPackageName());
   7.139              }
   7.140          });
   7.141 +        try {
   7.142 +            pluginsPanel1.init(getCurrent(), getAll());
   7.143 +        } catch (IOException ex) {
   7.144 +            Exceptions.printStackTrace(ex);
   7.145 +        }
   7.146          setVisibility();
   7.147      }
   7.148      
   7.149 +    private List<CordovaPlugin> getCurrent() throws IOException {
   7.150 +        List<CordovaPlugin> requestedPlugins = new ArrayList<CordovaPlugin>();
   7.151 +        FileObject fileObject = project.getProjectDirectory().getFileObject("nbproject/plugins.properties");
   7.152 +
   7.153 +        if (fileObject == null) {
   7.154 +            return Collections.EMPTY_LIST;
   7.155 +        }
   7.156 +        Properties props = new Properties();
   7.157 +        try (InputStream inputStream = fileObject.getInputStream()) {
   7.158 +            props.load(inputStream);
   7.159 +        }
   7.160 +        for (String name : props.stringPropertyNames()) {
   7.161 +            requestedPlugins.add(new CordovaPlugin(name, props.getProperty(name)));
   7.162 +        }
   7.163 +        requestedPlugins.retainAll(getAll());
   7.164 +        return requestedPlugins;
   7.165 +    }
   7.166 +    private List<CordovaPlugin> getAll() throws IOException {
   7.167 +        List<CordovaPlugin> requestedPlugins = new ArrayList<CordovaPlugin>();
   7.168 +
   7.169 +        Properties props = new Properties();
   7.170 +        props.load(CordovaPerformer.class.getResourceAsStream("plugins.properties"));
   7.171 +        for (String name : props.stringPropertyNames()) {
   7.172 +            requestedPlugins.add(new CordovaPlugin(name, props.getProperty(name)));
   7.173 +        }
   7.174 +        return requestedPlugins;
   7.175 +    }
   7.176      
   7.177      @NbBundle.Messages({
   7.178              "ERR_InvalidAppId={0} is not a valid Application ID"
   7.179 @@ -274,18 +296,57 @@
   7.180       * Store listener
   7.181       */
   7.182      public void actionPerformed(ActionEvent e) {
   7.183 -        if (cordovaPanel == null) {
   7.184 -            return;
   7.185 +
   7.186 +        try {
   7.187 +            if (cordovaPanel == null) {
   7.188 +                return;
   7.189 +            }
   7.190 +            Preferences preferences = ProjectUtils.getPreferences(project, CordovaPlatform.class, true);
   7.191 +            preferences.put("phonegap", Boolean.toString(cordovaPanel.isPanelEnabled())); // NOI18N
   7.192 +
   7.193 +            List<CordovaPlugin> selected = pluginsPanel1.getSelectedPlugins();
   7.194 +            
   7.195 +            EditableProperties props = new EditableProperties(false);
   7.196 +            FileObject fileObject = project.getProjectDirectory().getFileObject("nbproject/plugins.properties");
   7.197 +
   7.198 +            if (fileObject != null) {
   7.199 +                try (InputStream inputStream = fileObject.getInputStream()) {
   7.200 +                    props.load(inputStream);
   7.201 +                }
   7.202 +            }
   7.203 +
   7.204 +
   7.205 +            HashSet<CordovaPlugin> pluginsToAdd = new HashSet();
   7.206 +            pluginsToAdd.addAll(selected);
   7.207 +
   7.208 +            //plugins to install
   7.209 +            pluginsToAdd.removeAll(getCurrent());
   7.210 +
   7.211 +            //plugins to remove
   7.212 +            HashSet<CordovaPlugin> pluginsToRemove = new HashSet();
   7.213 +            pluginsToRemove.addAll(getCurrent());
   7.214 +            pluginsToRemove.removeAll(selected);
   7.215 +
   7.216 +            for (CordovaPlugin plugin : pluginsToAdd) {
   7.217 +                props.put(plugin.getId(), plugin.getUrl());
   7.218 +            }
   7.219 +
   7.220 +            for (CordovaPlugin plugin : pluginsToRemove) {
   7.221 +                props.remove(plugin.getId());
   7.222 +            }
   7.223 +            
   7.224 +            try (OutputStream outputStream = fileObject.getOutputStream()) {
   7.225 +                props.store(outputStream);
   7.226 +            }
   7.227 +            try {
   7.228 +                cordovaPanel.save(config);
   7.229 +            } catch (IOException iOException) {
   7.230 +                Exceptions.printStackTrace(iOException);
   7.231 +            }
   7.232 +        } catch (IOException ex) {
   7.233 +            Exceptions.printStackTrace(ex);
   7.234          }
   7.235 -        Preferences preferences = ProjectUtils.getPreferences(project, CordovaPlatform.class, true);
   7.236 -        preferences.put("phonegap", Boolean.toString(cordovaPanel.isPanelEnabled())); // NOI18N
   7.237 -        
   7.238 -        try {
   7.239 -            cordovaPanel.save(config);
   7.240 -        } catch (IOException iOException) {
   7.241 -            Exceptions.printStackTrace(iOException);
   7.242 -        }
   7.243 -   }
   7.244 +    }
   7.245  
   7.246      public void setVisibility() {
   7.247          boolean platformsReady = CordovaPlatform.getDefault().isReady();
   7.248 @@ -293,8 +354,7 @@
   7.249          
   7.250          createConfigs.setVisible(!isCordovaProject && platformsReady);
   7.251          createConfigsLabel.setVisible(!isCordovaProject && platformsReady);
   7.252 -        cordovaPanel.setVisible(isCordovaProject && platformsReady);
   7.253 -        editPlugins.setVisible(isCordovaProject && platformsReady);
   7.254 +        jTabbedPane1.setVisible(isCordovaProject && platformsReady);
   7.255          mobilePlatformsSetup.setVisible(isCordovaProject && platformsReady);
   7.256  
   7.257          cordovaPanel.update();
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/cordova/src/org/netbeans/modules/cordova/project/PluginsPanel.form	Wed Aug 14 14:46:35 2013 +0200
     8.3 @@ -0,0 +1,149 @@
     8.4 +<?xml version="1.0" encoding="UTF-8" ?>
     8.5 +
     8.6 +<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
     8.7 +  <AuxValues>
     8.8 +    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
     8.9 +    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
    8.10 +    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
    8.11 +    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
    8.12 +    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
    8.13 +    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
    8.14 +    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
    8.15 +    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
    8.16 +    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
    8.17 +  </AuxValues>
    8.18 +
    8.19 +  <Layout>
    8.20 +    <DimensionLayout dim="0">
    8.21 +      <Group type="103" groupAlignment="0" attributes="0">
    8.22 +          <Group type="102" attributes="0">
    8.23 +              <Group type="103" groupAlignment="0" attributes="0">
    8.24 +                  <Component id="generalInfoLabel" alignment="0" pref="0" max="32767" attributes="0"/>
    8.25 +                  <Group type="102" attributes="0">
    8.26 +                      <Group type="103" groupAlignment="0" attributes="0">
    8.27 +                          <Group type="102" attributes="0">
    8.28 +                              <Component id="librariesLabel" min="-2" max="-2" attributes="0"/>
    8.29 +                              <EmptySpace max="-2" attributes="0"/>
    8.30 +                              <Component id="pluginsFilterTextField" max="32767" attributes="0"/>
    8.31 +                          </Group>
    8.32 +                          <Group type="102" attributes="0">
    8.33 +                              <EmptySpace min="-2" max="-2" attributes="0"/>
    8.34 +                              <Component id="pluginsScrollPane" max="32767" attributes="0"/>
    8.35 +                          </Group>
    8.36 +                      </Group>
    8.37 +                      <EmptySpace min="-2" max="-2" attributes="0"/>
    8.38 +                      <Group type="103" groupAlignment="0" attributes="0">
    8.39 +                          <Component id="selectSelectedButton" linkSize="2" min="-2" max="-2" attributes="0"/>
    8.40 +                          <Component id="deselectSelectedButton" linkSize="2" min="-2" max="-2" attributes="0"/>
    8.41 +                      </Group>
    8.42 +                      <EmptySpace min="-2" max="-2" attributes="0"/>
    8.43 +                      <Group type="103" groupAlignment="0" attributes="0">
    8.44 +                          <Component id="selectedLabel" min="-2" max="-2" attributes="0"/>
    8.45 +                          <Component id="selectedLibrariesScrollPane" max="32767" attributes="0"/>
    8.46 +                      </Group>
    8.47 +                  </Group>
    8.48 +              </Group>
    8.49 +              <EmptySpace min="-2" max="-2" attributes="0"/>
    8.50 +          </Group>
    8.51 +      </Group>
    8.52 +    </DimensionLayout>
    8.53 +    <DimensionLayout dim="1">
    8.54 +      <Group type="103" groupAlignment="0" attributes="0">
    8.55 +          <Group type="102" alignment="0" attributes="0">
    8.56 +              <Component id="generalInfoLabel" min="-2" max="-2" attributes="0"/>
    8.57 +              <EmptySpace max="-2" attributes="0"/>
    8.58 +              <Group type="103" groupAlignment="3" attributes="0">
    8.59 +                  <Component id="librariesLabel" alignment="3" min="-2" max="-2" attributes="0"/>
    8.60 +                  <Component id="selectedLabel" alignment="3" min="-2" max="-2" attributes="0"/>
    8.61 +                  <Component id="pluginsFilterTextField" alignment="3" min="-2" max="-2" attributes="0"/>
    8.62 +              </Group>
    8.63 +              <EmptySpace max="-2" attributes="0"/>
    8.64 +              <Group type="103" groupAlignment="0" attributes="0">
    8.65 +                  <Component id="selectedLibrariesScrollPane" pref="301" max="32767" attributes="0"/>
    8.66 +                  <Group type="102" attributes="0">
    8.67 +                      <Component id="selectSelectedButton" min="-2" max="-2" attributes="0"/>
    8.68 +                      <EmptySpace max="-2" attributes="0"/>
    8.69 +                      <Component id="deselectSelectedButton" min="-2" max="-2" attributes="0"/>
    8.70 +                      <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
    8.71 +                  </Group>
    8.72 +                  <Component id="pluginsScrollPane" max="32767" attributes="0"/>
    8.73 +              </Group>
    8.74 +              <EmptySpace max="-2" attributes="0"/>
    8.75 +          </Group>
    8.76 +      </Group>
    8.77 +    </DimensionLayout>
    8.78 +  </Layout>
    8.79 +  <SubComponents>
    8.80 +    <Component class="javax.swing.JLabel" name="generalInfoLabel">
    8.81 +      <Properties>
    8.82 +        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
    8.83 +          <ResourceString bundle="org/netbeans/modules/cordova/project/Bundle.properties" key="PluginsPanel.generalInfoLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
    8.84 +        </Property>
    8.85 +      </Properties>
    8.86 +    </Component>
    8.87 +    <Component class="javax.swing.JLabel" name="librariesLabel">
    8.88 +      <Properties>
    8.89 +        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
    8.90 +          <ResourceString bundle="org/netbeans/modules/cordova/project/Bundle.properties" key="PluginsPanel.librariesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
    8.91 +        </Property>
    8.92 +      </Properties>
    8.93 +    </Component>
    8.94 +    <Component class="javax.swing.JTextField" name="pluginsFilterTextField">
    8.95 +    </Component>
    8.96 +    <Component class="javax.swing.JButton" name="selectSelectedButton">
    8.97 +      <Properties>
    8.98 +        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
    8.99 +          <ResourceString bundle="org/netbeans/modules/cordova/project/Bundle.properties" key="PluginsPanel.selectSelectedButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
   8.100 +        </Property>
   8.101 +      </Properties>
   8.102 +      <Events>
   8.103 +        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="selectSelectedButtonActionPerformed"/>
   8.104 +      </Events>
   8.105 +    </Component>
   8.106 +    <Component class="javax.swing.JButton" name="deselectSelectedButton">
   8.107 +      <Properties>
   8.108 +        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
   8.109 +          <ResourceString bundle="org/netbeans/modules/cordova/project/Bundle.properties" key="PluginsPanel.deselectSelectedButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
   8.110 +        </Property>
   8.111 +      </Properties>
   8.112 +      <Events>
   8.113 +        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deselectSelectedButtonActionPerformed"/>
   8.114 +      </Events>
   8.115 +    </Component>
   8.116 +    <Component class="javax.swing.JLabel" name="selectedLabel">
   8.117 +      <Properties>
   8.118 +        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
   8.119 +          <ResourceString bundle="org/netbeans/modules/cordova/project/Bundle.properties" key="PluginsPanel.selectedLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
   8.120 +        </Property>
   8.121 +      </Properties>
   8.122 +    </Component>
   8.123 +    <Container class="javax.swing.JScrollPane" name="selectedLibrariesScrollPane">
   8.124 +      <AuxValues>
   8.125 +        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
   8.126 +      </AuxValues>
   8.127 +
   8.128 +      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
   8.129 +      <SubComponents>
   8.130 +        <Component class="javax.swing.JList" name="selectedLibrariesList">
   8.131 +          <Events>
   8.132 +            <EventHandler event="valueChanged" listener="javax.swing.event.ListSelectionListener" parameters="javax.swing.event.ListSelectionEvent" handler="selectedLibrariesListValueChanged"/>
   8.133 +          </Events>
   8.134 +        </Component>
   8.135 +      </SubComponents>
   8.136 +    </Container>
   8.137 +    <Container class="javax.swing.JScrollPane" name="pluginsScrollPane">
   8.138 +      <AuxValues>
   8.139 +        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
   8.140 +      </AuxValues>
   8.141 +
   8.142 +      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
   8.143 +      <SubComponents>
   8.144 +        <Component class="javax.swing.JList" name="pluginsList">
   8.145 +          <Events>
   8.146 +            <EventHandler event="valueChanged" listener="javax.swing.event.ListSelectionListener" parameters="javax.swing.event.ListSelectionEvent" handler="pluginsListValueChanged"/>
   8.147 +          </Events>
   8.148 +        </Component>
   8.149 +      </SubComponents>
   8.150 +    </Container>
   8.151 +  </SubComponents>
   8.152 +</Form>
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/cordova/src/org/netbeans/modules/cordova/project/PluginsPanel.java	Wed Aug 14 14:46:35 2013 +0200
     9.3 @@ -0,0 +1,370 @@
     9.4 +/*
     9.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     9.6 + *
     9.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
     9.8 + *
     9.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    9.10 + * Other names may be trademarks of their respective owners.
    9.11 + *
    9.12 + * The contents of this file are subject to the terms of either the GNU
    9.13 + * General Public License Version 2 only ("GPL") or the Common
    9.14 + * Development and Distribution License("CDDL") (collectively, the
    9.15 + * "License"). You may not use this file except in compliance with the
    9.16 + * License. You can obtain a copy of the License at
    9.17 + * http://www.netbeans.org/cddl-gplv2.html
    9.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    9.19 + * specific language governing permissions and limitations under the
    9.20 + * License.  When distributing the software, include this License Header
    9.21 + * Notice in each file and include the License file at
    9.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    9.23 + * particular file as subject to the "Classpath" exception as provided
    9.24 + * by Oracle in the GPL Version 2 section of the License file that
    9.25 + * accompanied this code. If applicable, add the following below the
    9.26 + * License Header, with the fields enclosed by brackets [] replaced by
    9.27 + * your own identifying information:
    9.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    9.29 + *
    9.30 + * If you wish your version of this file to be governed by only the CDDL
    9.31 + * or only the GPL Version 2, indicate your decision by adding
    9.32 + * "[Contributor] elects to include this software in this distribution
    9.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    9.34 + * single choice of license, a recipient has the option to distribute
    9.35 + * your version of this file under either the CDDL, the GPL Version 2 or
    9.36 + * to extend the choice of license to its licensees as provided above.
    9.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    9.38 + * Version 2 license, then the option applies only if the new code is
    9.39 + * made subject to such option by the copyright holder.
    9.40 + *
    9.41 + * Contributor(s):
    9.42 + *
    9.43 + * Portions Copyrighted 2013 Sun Microsystems, Inc.
    9.44 + */
    9.45 +package org.netbeans.modules.cordova.project;
    9.46 +
    9.47 +import java.awt.EventQueue;
    9.48 +import java.util.Collections;
    9.49 +import java.util.Comparator;
    9.50 +import java.util.List;
    9.51 +import javax.swing.AbstractListModel;
    9.52 +import javax.swing.JPanel;
    9.53 +import javax.swing.event.DocumentEvent;
    9.54 +import javax.swing.event.DocumentListener;
    9.55 +import org.netbeans.modules.cordova.updatetask.CordovaPlugin;
    9.56 +
    9.57 +/**
    9.58 + * UI for selecting Cordova Plugins.
    9.59 + */
    9.60 +public final class PluginsPanel extends JPanel {
    9.61 +
    9.62 +    // folder path is accessed outside of EDT thread
    9.63 +    private volatile boolean panelEnabled = true;
    9.64 +
    9.65 +    private PluginsListModel selectedPluginsModel;
    9.66 +    private PluginsListModel allPluginsModel;
    9.67 +
    9.68 +    public PluginsPanel() {
    9.69 +        checkUiThread();
    9.70 +        initComponents();
    9.71 +    }
    9.72 +   
    9.73 +    public void init(List<CordovaPlugin> current, List<CordovaPlugin> all) {
    9.74 +        checkUiThread();
    9.75 +        initComponents();
    9.76 +        pluginsFilterTextField.setVisible(false);
    9.77 +        selectedPluginsModel = new PluginsListModel(current);
    9.78 +        selectedPluginsModel.sortLibraries();
    9.79 +        allPluginsModel = new PluginsListModel(all);
    9.80 +        allPluginsModel.sortLibraries();
    9.81 +        initPlugins();
    9.82 +    }
    9.83 +
    9.84 +    /**
    9.85 +     * Get the list of selected Plugins.
    9.86 +     * @return list of selected Plugins
    9.87 +     */
    9.88 +    public List<CordovaPlugin> getSelectedPlugins() {
    9.89 +        return selectedPluginsModel.plugins;
    9.90 +    }
    9.91 +
    9.92 +
    9.93 +    /**
    9.94 +     * Lock this panel, it means no user changes can be done.
    9.95 +     * <p>
    9.96 +     * This method must be run in the UI thread.
    9.97 +     * @see #unlockPanel()
    9.98 +     */
    9.99 +    public void lockPanel() {
   9.100 +        checkUiThread();
   9.101 +        enablePanel(false);
   9.102 +    }
   9.103 +
   9.104 +    /**
   9.105 +     * Unlock this panel, it means no user changes can be done.
   9.106 +     * <p>
   9.107 +     * This method must be run in the UI thread.
   9.108 +     * @see #lockPanel()
   9.109 +     */
   9.110 +    public void unlockPanel() {
   9.111 +        checkUiThread();
   9.112 +        enablePanel(true);
   9.113 +    }
   9.114 +
   9.115 +
   9.116 +    private void checkUiThread() {
   9.117 +        if (!EventQueue.isDispatchThread()) {
   9.118 +            throw new IllegalStateException("Must be run in UI thread");
   9.119 +        }
   9.120 +    }
   9.121 +
   9.122 +    private void initPlugins() {
   9.123 +        initAllPluginsList();
   9.124 +        initSelectedPluginsList();
   9.125 +    }
   9.126 +    
   9.127 +
   9.128 +    private void initAllPluginsList() {
   9.129 +        assert EventQueue.isDispatchThread();
   9.130 +        pluginsList.setModel(allPluginsModel);
   9.131 +
   9.132 +        pluginsFilterTextField.getDocument().addDocumentListener(new DocumentListener() {
   9.133 +            @Override
   9.134 +            public void insertUpdate(DocumentEvent e) {
   9.135 +                processChange();
   9.136 +            }
   9.137 +            @Override
   9.138 +            public void removeUpdate(DocumentEvent e) {
   9.139 +                processChange();
   9.140 +            }
   9.141 +            @Override
   9.142 +            public void changedUpdate(DocumentEvent e) {
   9.143 +                processChange();
   9.144 +            }
   9.145 +            private void processChange() {
   9.146 +                //filterLibrariesTable();
   9.147 +            }
   9.148 +        });
   9.149 +    }
   9.150 +
   9.151 +    private void initSelectedPluginsList() {
   9.152 +        assert EventQueue.isDispatchThread();
   9.153 +        selectedLibrariesList.setModel(selectedPluginsModel);
   9.154 +   }
   9.155 +
   9.156 +    private boolean isUpdateRunning() {
   9.157 +        return !panelEnabled;
   9.158 +    }
   9.159 +
   9.160 +    private void startUpdate() {
   9.161 +        lockPanel();
   9.162 +    }
   9.163 +
   9.164 +    void finishUpdate() {
   9.165 +        unlockPanel();
   9.166 +    }
   9.167 +
   9.168 +    private void enablePanel(boolean enabled) {
   9.169 +        assert EventQueue.isDispatchThread();
   9.170 +        panelEnabled = enabled;
   9.171 +        pluginsFilterTextField.setEnabled(enabled);
   9.172 +        pluginsList.setEnabled(enabled);
   9.173 +        selectSelectedButton.setEnabled(enabled);
   9.174 +        deselectSelectedButton.setEnabled(enabled);
   9.175 +        selectedLibrariesList.setEnabled(enabled);
   9.176 +    }
   9.177 +
   9.178 +
   9.179 +    /**
   9.180 +     * This method is called from within the constructor to initialize the form.
   9.181 +     * WARNING: Do NOT modify this code. The content of this method is always
   9.182 +     * regenerated by the Form Editor.
   9.183 +     */
   9.184 +    @SuppressWarnings("unchecked")
   9.185 +    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
   9.186 +    private void initComponents() {
   9.187 +
   9.188 +        generalInfoLabel = new javax.swing.JLabel();
   9.189 +        librariesLabel = new javax.swing.JLabel();
   9.190 +        pluginsFilterTextField = new javax.swing.JTextField();
   9.191 +        selectSelectedButton = new javax.swing.JButton();
   9.192 +        deselectSelectedButton = new javax.swing.JButton();
   9.193 +        selectedLabel = new javax.swing.JLabel();
   9.194 +        selectedLibrariesScrollPane = new javax.swing.JScrollPane();
   9.195 +        selectedLibrariesList = new javax.swing.JList();
   9.196 +        pluginsScrollPane = new javax.swing.JScrollPane();
   9.197 +        pluginsList = new javax.swing.JList();
   9.198 +
   9.199 +        org.openide.awt.Mnemonics.setLocalizedText(generalInfoLabel, org.openide.util.NbBundle.getMessage(PluginsPanel.class, "PluginsPanel.generalInfoLabel.text")); // NOI18N
   9.200 +
   9.201 +        org.openide.awt.Mnemonics.setLocalizedText(librariesLabel, org.openide.util.NbBundle.getMessage(PluginsPanel.class, "PluginsPanel.librariesLabel.text")); // NOI18N
   9.202 +
   9.203 +        org.openide.awt.Mnemonics.setLocalizedText(selectSelectedButton, org.openide.util.NbBundle.getMessage(PluginsPanel.class, "PluginsPanel.selectSelectedButton.text")); // NOI18N
   9.204 +        selectSelectedButton.addActionListener(new java.awt.event.ActionListener() {
   9.205 +            public void actionPerformed(java.awt.event.ActionEvent evt) {
   9.206 +                selectSelectedButtonActionPerformed(evt);
   9.207 +            }
   9.208 +        });
   9.209 +
   9.210 +        org.openide.awt.Mnemonics.setLocalizedText(deselectSelectedButton, org.openide.util.NbBundle.getMessage(PluginsPanel.class, "PluginsPanel.deselectSelectedButton.text")); // NOI18N
   9.211 +        deselectSelectedButton.addActionListener(new java.awt.event.ActionListener() {
   9.212 +            public void actionPerformed(java.awt.event.ActionEvent evt) {
   9.213 +                deselectSelectedButtonActionPerformed(evt);
   9.214 +            }
   9.215 +        });
   9.216 +
   9.217 +        org.openide.awt.Mnemonics.setLocalizedText(selectedLabel, org.openide.util.NbBundle.getMessage(PluginsPanel.class, "PluginsPanel.selectedLabel.text")); // NOI18N
   9.218 +
   9.219 +        selectedLibrariesList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
   9.220 +            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
   9.221 +                selectedLibrariesListValueChanged(evt);
   9.222 +            }
   9.223 +        });
   9.224 +        selectedLibrariesScrollPane.setViewportView(selectedLibrariesList);
   9.225 +
   9.226 +        pluginsList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
   9.227 +            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
   9.228 +                pluginsListValueChanged(evt);
   9.229 +            }
   9.230 +        });
   9.231 +        pluginsScrollPane.setViewportView(pluginsList);
   9.232 +
   9.233 +        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
   9.234 +        this.setLayout(layout);
   9.235 +        layout.setHorizontalGroup(
   9.236 +            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
   9.237 +            .addGroup(layout.createSequentialGroup()
   9.238 +                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
   9.239 +                    .addComponent(generalInfoLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
   9.240 +                    .addGroup(layout.createSequentialGroup()
   9.241 +                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
   9.242 +                            .addGroup(layout.createSequentialGroup()
   9.243 +                                .addComponent(librariesLabel)
   9.244 +                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
   9.245 +                                .addComponent(pluginsFilterTextField))
   9.246 +                            .addGroup(layout.createSequentialGroup()
   9.247 +                                .addContainerGap()
   9.248 +                                .addComponent(pluginsScrollPane)))
   9.249 +                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
   9.250 +                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
   9.251 +                            .addComponent(selectSelectedButton)
   9.252 +                            .addComponent(deselectSelectedButton))
   9.253 +                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
   9.254 +                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
   9.255 +                            .addComponent(selectedLabel)
   9.256 +                            .addComponent(selectedLibrariesScrollPane))))
   9.257 +                .addContainerGap())
   9.258 +        );
   9.259 +
   9.260 +        layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {deselectSelectedButton, selectSelectedButton});
   9.261 +
   9.262 +        layout.setVerticalGroup(
   9.263 +            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
   9.264 +            .addGroup(layout.createSequentialGroup()
   9.265 +                .addComponent(generalInfoLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
   9.266 +                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
   9.267 +                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
   9.268 +                    .addComponent(librariesLabel)
   9.269 +                    .addComponent(selectedLabel)
   9.270 +                    .addComponent(pluginsFilterTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
   9.271 +                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
   9.272 +                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
   9.273 +                    .addComponent(selectedLibrariesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 301, Short.MAX_VALUE)
   9.274 +                    .addGroup(layout.createSequentialGroup()
   9.275 +                        .addComponent(selectSelectedButton)
   9.276 +                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
   9.277 +                        .addComponent(deselectSelectedButton)
   9.278 +                        .addGap(0, 0, Short.MAX_VALUE))
   9.279 +                    .addComponent(pluginsScrollPane))
   9.280 +                .addContainerGap())
   9.281 +        );
   9.282 +    }// </editor-fold>//GEN-END:initComponents
   9.283 +
   9.284 +    private void selectSelectedButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSelectedButtonActionPerformed
   9.285 +        selectedPluginsModel.add(pluginsList.getSelectedValuesList());
   9.286 +    }//GEN-LAST:event_selectSelectedButtonActionPerformed
   9.287 +
   9.288 +    private void deselectSelectedButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deselectSelectedButtonActionPerformed
   9.289 +        selectedPluginsModel.remove(selectedLibrariesList.getSelectedValuesList());
   9.290 +    }//GEN-LAST:event_deselectSelectedButtonActionPerformed
   9.291 +
   9.292 +    private void pluginsListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_pluginsListValueChanged
   9.293 +        updateButtonsEnabled();
   9.294 +    }//GEN-LAST:event_pluginsListValueChanged
   9.295 +
   9.296 +    private void selectedLibrariesListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_selectedLibrariesListValueChanged
   9.297 +        updateButtonsEnabled();
   9.298 +    }//GEN-LAST:event_selectedLibrariesListValueChanged
   9.299 +
   9.300 +    // Variables declaration - do not modify//GEN-BEGIN:variables
   9.301 +    private javax.swing.JButton deselectSelectedButton;
   9.302 +    private javax.swing.JLabel generalInfoLabel;
   9.303 +    private javax.swing.JLabel librariesLabel;
   9.304 +    private javax.swing.JTextField pluginsFilterTextField;
   9.305 +    private javax.swing.JList pluginsList;
   9.306 +    private javax.swing.JScrollPane pluginsScrollPane;
   9.307 +    private javax.swing.JButton selectSelectedButton;
   9.308 +    private javax.swing.JLabel selectedLabel;
   9.309 +    private javax.swing.JList selectedLibrariesList;
   9.310 +    private javax.swing.JScrollPane selectedLibrariesScrollPane;
   9.311 +    // End of variables declaration//GEN-END:variables
   9.312 +
   9.313 +    private void updateButtonsEnabled() {
   9.314 +        selectSelectedButton.setEnabled(pluginsList.getSelectedIndex()!=-1);
   9.315 +        deselectSelectedButton.setEnabled(selectedLibrariesList.getSelectedIndex()!=-1);
   9.316 +    }
   9.317 +
   9.318 +    private static final class PluginsListModel extends AbstractListModel {
   9.319 +
   9.320 +        private static final Comparator<CordovaPlugin> SELECTED_PLUGINS_COMPARATOR = new Comparator<CordovaPlugin>() {
   9.321 +            @Override
   9.322 +            public int compare(CordovaPlugin left, CordovaPlugin right) {
   9.323 +                return left.getName().compareToIgnoreCase(right.getName());
   9.324 +            }
   9.325 +        };
   9.326 +
   9.327 +        private final List<CordovaPlugin> plugins;
   9.328 +
   9.329 +
   9.330 +        public PluginsListModel(List<CordovaPlugin> plugins) {
   9.331 +            this.plugins = plugins;
   9.332 +        }
   9.333 +
   9.334 +        @Override
   9.335 +        public int getSize() {
   9.336 +            return plugins.size();
   9.337 +        }
   9.338 +
   9.339 +        @Override
   9.340 +        public CordovaPlugin getElementAt(int index) {
   9.341 +            return plugins.get(index);
   9.342 +        }
   9.343 +
   9.344 +        public void fireContentsChanged() {
   9.345 +            sortLibraries();
   9.346 +            fireContentsChanged(this, 0, plugins.size() - 1);
   9.347 +        }
   9.348 +        
   9.349 +        public void add(List<CordovaPlugin> add) {
   9.350 +            for (CordovaPlugin p:add) {
   9.351 +                if (!plugins.contains(p)) {
   9.352 +                    plugins.add(p);
   9.353 +                }
   9.354 +            }
   9.355 +            sortLibraries();
   9.356 +            fireContentsChanged();
   9.357 +        }
   9.358 +        
   9.359 +        public void remove(List<CordovaPlugin> rem) {
   9.360 +            plugins.removeAll(rem);
   9.361 +            sortLibraries();
   9.362 +            fireContentsChanged();
   9.363 +        }
   9.364 +
   9.365 +        /**
   9.366 +         * Make selected plugins unique and sort them.
   9.367 +         */
   9.368 +        private void sortLibraries() {
   9.369 +            Collections.sort(plugins, SELECTED_PLUGINS_COMPARATOR);
   9.370 +        }
   9.371 +
   9.372 +    }
   9.373 +}