1. Christian Fischer
  2. nbandroid

Commits

radim  committed bad7d9e

Add customizer panel for JAR libraries location. Model in JarLibsModel and UI as a simple view.

Comments (0)

Files changed (14)

File project/src/org/netbeans/modules/android/project/AndroidProjectImpl.java Modified

View file
  • Ignore whitespace
  • Hide word diff
             new AndroidProjectEncodingQueryImpl(),
             new AndroidTemplateAttributesProvider(this),
             new AndroidLauncherImpl(),
-            new AuxiliaryPropertiesImpl(this)
+            new AuxiliaryPropertiesImpl(this),
+            propertyHelper
         );
         return LookupProviderSupport.createCompositeLookup(base, "Projects/org-netbeans-modules-android-project/Lookup"); //NOI18N
     }

File project/src/org/netbeans/modules/android/project/JarLibsModel.java Added

View file
  • Ignore whitespace
  • Hide word diff
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.netbeans.modules.android.project;
+
+import com.android.sdklib.internal.project.ProjectProperties;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import java.io.File;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.netbeans.api.project.ProjectManager;
+import org.netbeans.spi.project.support.ant.PropertyUtils;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.Mutex;
+
+/**
+ * Project updater that modifies properties related to locations of project libraries.
+ * @author radim
+ */
+public class JarLibsModel implements ProjectUpdater {
+
+  private boolean useDefaultLocation;
+  private FileObject libsFO;
+  private String libsDir;
+  private final AndroidProject project;
+
+  public JarLibsModel(AndroidProject project) {
+    this.project = Preconditions.checkNotNull(project);
+    libsDir = project.evaluator().getProperty(PropertyName.JAR_LIBS_DIR.getName());
+    if (libsDir == null) {
+      useDefaultLocation = true;
+      libsDir = "libs";
+      libsFO = project.getProjectDirectory().getFileObject(libsDir);
+    } else {
+      useDefaultLocation = false;
+      File libs = new File(project.getProjectDirectoryFile(), libsDir);
+      libsFO = FileUtil.toFileObject(libs);
+    }
+
+  }
+
+  public void setUseDefaultLocation(boolean useDefaultLocation) {
+    this.useDefaultLocation = useDefaultLocation;
+    updateData();
+  }
+
+  public boolean isUseDefaultLocation() {
+    return useDefaultLocation;
+  }
+
+  public String getLibsDir() {
+    return libsDir;
+  }
+
+  public void setLibsDir(String libsDir) {
+    this.libsDir = libsDir;
+    updateData();
+  }
+
+  public Iterable<String> getLibNames() {
+    List<String> names = Lists.newArrayList();
+    if (libsFO != null) {
+      for (FileObject library : libsFO.getChildren()) {
+        if (library.hasExt("jar")) {
+          names.add(library.getNameExt());
+        }
+      }
+    }
+    return names;
+  }
+
+  private void updateData() {
+    if (useDefaultLocation) {
+      libsDir = "libs";
+    }
+    if (libsDir == null) {
+      libsFO = null;
+    } else {
+      File f = new File(project.getProjectDirectoryFile(), libsDir);
+      libsFO = FileUtil.toFileObject(FileUtil.normalizeFile(f));
+    }
+  }
+
+  @Override
+  public boolean apply(final AndroidProject project) {
+    Logger.getLogger(JarLibsModel.class.getName()).log(
+        Level.FINE, "Udpating libs information {0} for project {1}", new Object[] {this, project});
+    assert this.project == project;
+    return ProjectManager.mutex().readAccess(new Mutex.Action<Boolean>() {
+
+      @Override
+      public Boolean run() {
+        PropertiesHelper propertyHelper = project.getLookup().lookup(PropertiesHelper.class);
+        if (useDefaultLocation) {
+          for (ProjectProperties.PropertyType type : ProjectProperties.PropertyType.values()) {
+            propertyHelper.setProperty(type, PropertyName.JAR_LIBS_DIR.getName(), null);
+          }
+        } else {
+          String relativePath = PropertyUtils.relativizeFile(
+              project.getProjectDirectoryFile(),
+              FileUtil.normalizeFile(new File(project.getProjectDirectoryFile(), libsDir)));
+          propertyHelper.setProperty(ProjectProperties.PropertyType.BUILD,
+              PropertyName.JAR_LIBS_DIR.getName(), relativePath);
+        }
+        return true;
+      }
+
+    });
+  }
+
+  @Override
+  public String toString() {
+    return "JarLibsModel{" +
+        "useDefaultLocation=" + useDefaultLocation +
+        ", libsDir=" + libsDir + '}';
+  }
+}

File project/src/org/netbeans/modules/android/project/ProjectUpdater.java Added

View file
  • Ignore whitespace
  • Hide word diff
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.netbeans.modules.android.project;
+
+import com.google.common.base.Predicate;
+
+/**
+ *
+ * @author radim
+ */
+public interface ProjectUpdater extends Predicate<AndroidProject> {
+
+}

File project/src/org/netbeans/modules/android/project/PropertiesHelper.java Modified

View file
  • Ignore whitespace
  • Hide word diff
 import com.android.sdklib.internal.project.ProjectProperties;
 import com.android.sdklib.internal.project.ProjectPropertiesWorkingCopy;
 import com.android.sdklib.io.StreamException;
+import com.google.common.collect.Sets;
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.Collections;
 import java.util.Map;
 import java.util.Properties;
+import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import org.netbeans.modules.android.core.sdk.DalvikPlatformManager;
 class PropertiesHelper {
   private static final Logger LOG = Logger.getLogger(PropertiesHelper.class.getName());
 
+  static {
+    try {
+      // patch PropertyType enum(s) to enable property removals
+      Field mKnownPropsFld = ProjectProperties.PropertyType.class.getDeclaredField("mKnownProps");
+      mKnownPropsFld.setAccessible(true);
+      Set<String> mKnownProps = (Set) mKnownPropsFld.get(ProjectProperties.PropertyType.BUILD);
+      Set<String> mMoreKnownProps = Sets.newHashSet(mKnownProps);
+      mMoreKnownProps.add(PropertyName.JAR_LIBS_DIR.getName());
+      mKnownPropsFld.set(
+          ProjectProperties.PropertyType.BUILD, Collections.unmodifiableSet(mMoreKnownProps));
+    } catch (IllegalArgumentException ex) {
+      Exceptions.printStackTrace(ex);
+    } catch (IllegalAccessException ex) {
+      Exceptions.printStackTrace(ex);
+    } catch (NoSuchFieldException ex) {
+      Exceptions.printStackTrace(ex);
+    } catch (SecurityException ex) {
+      Exceptions.printStackTrace(ex);
+    }
+  }
+
   private final PropertyEvaluator eval;
   private final PropertyProvider localProps;
 //  private final PropertyProvider buildProps;
         m = NbCollections.checkedMapByCopy(p, String.class, String.class, false);
       }
       m.put("basedir", dirF.getAbsolutePath()); // NOI18N
-      File antJar = InstalledFileLocator.getDefault().locate("ant/lib/ant.jar", "org.apache.tools.ant.module", false); // NOI18N
+      File antJar = InstalledFileLocator.getDefault().locate(
+          "ant/lib/ant.jar", "org.apache.tools.ant.module", false); // NOI18N
       if (antJar != null) {
         File antHome = antJar.getParentFile().getParentFile();
         m.put("ant.home", antHome.getAbsolutePath()); // NOI18N

File project/src/org/netbeans/modules/android/project/queries/ClassPathProviderImpl.java Modified

View file
  • Ignore whitespace
  • Hide word diff
   }
     
     private ClassPath createCompile() {
-        FileObject basedir = project.getProjectDirectory();
-        PropertyEvaluator propEvaluator = project.evaluator();
-        String mainPrjPath = project.evaluator().getProperty(PropertyName.TEST_PROJECT_DIR.getName());
-        
-        List<PathResourceBase> pathResources = Lists.newArrayList();
-        if (mainPrjPath != null) {
-          // test project: ${main.project}/bin/classes 
-          //               + libs/*.jar (jar.libs.dir property is ignored) 
-          //               + ${jar.libs.dir}/libs/*.jar
-          File mainPrjDir = new File(project.getProjectDirectoryFile(), mainPrjPath);
-          FileObject mainPrjFO = FileUtil.toFileObject(FileUtil.normalizeFile(mainPrjDir));
-          if (mainPrjDir != null) {
-            pathResources.add(new LibPathResources(mainPrjFO, mainPrjFO.getFileObject("libs"), true));
-          }
-        }
-        String libsDir = propEvaluator.getProperty(PropertyName.JAR_LIBS_DIR.getName());
-        FileObject libsFO;
-        if (libsDir == null) {
-          libsDir = "libs";
-          libsFO = basedir.getFileObject(libsDir);
-        } else {
-          File libs = new File(project.getProjectDirectoryFile(), libsDir);
-          libsFO = FileUtil.toFileObject(libs);
-        }
-        pathResources.add(new LibPathResources(basedir, libsFO, false));
-        return ClassPathSupport.createClassPath(pathResources);
+      List<PathResourceBase> pathResources = Lists.newArrayList();
+      pathResources.add(new LibPathResources(project));
+      return ClassPathSupport.createClassPath(pathResources);
     }
     
-    private static class LibPathResources extends PathResourceBase implements FileChangeListener {
+    private static class LibPathResources extends PathResourceBase 
+        implements FileChangeListener, PropertyChangeListener {
+      private AndroidProject project;
       private FileObject libsDir;
       private FileObject prjDir;
       private boolean includeClassesDir;
 
-      public LibPathResources(FileObject prjDir, FileObject libsDir, boolean includeClassesDir) {
-        this.prjDir = prjDir;
-        this.libsDir = libsDir;
-        this.includeClassesDir = includeClassesDir;
+      public LibPathResources(AndroidProject project) {
+        this.project = project;
+        setup();
+        PropertyEvaluator propEvaluator = project.evaluator();
+        propEvaluator.addPropertyChangeListener(this);
+      }
+
+      private void setup() {
+        if (libsDir != null) {
+          libsDir.removeFileChangeListener(this);
+        }
+        if (prjDir != null) {
+          prjDir.removeFileChangeListener(this);
+        }
+        FileObject basedir = project.getProjectDirectory();
+        PropertyEvaluator propEvaluator = project.evaluator();
+        String mainPrjPath = project.evaluator().getProperty(PropertyName.TEST_PROJECT_DIR.getName());
+
+        if (mainPrjPath != null) {
+          // test project: ${main.project}/bin/classes
+          //               + libs/*.jar (jar.libs.dir property is ignored)
+          //               + ${jar.libs.dir}/libs/*.jar
+          File mainPrjDir = new File(project.getProjectDirectoryFile(), mainPrjPath);
+          FileObject mainPrjFO = FileUtil.toFileObject(FileUtil.normalizeFile(mainPrjDir));
+          prjDir = mainPrjFO;
+          libsDir = mainPrjFO.getFileObject("libs");
+          includeClassesDir = true;
+        } else {
+          String libsDirValue = propEvaluator.getProperty(PropertyName.JAR_LIBS_DIR.getName());
+          FileObject libsFO;
+          if (libsDirValue == null) {
+            libsDirValue = "libs";
+            libsFO = basedir.getFileObject(libsDirValue);
+          } else {
+            File libs = new File(project.getProjectDirectoryFile(), libsDirValue);
+            libsFO = FileUtil.toFileObject(libs);
+          }
+          prjDir = basedir;
+          libsDir = libsFO;
+          includeClassesDir = false;
+        }
         if (libsDir != null) {
           libsDir.addFileChangeListener(this);
         } else {
-          prjDir.addFileChangeListener(this);
+          if (prjDir != null) {
+            prjDir.addFileChangeListener(this);
+          }
         }
       }
 
       }
 
       @Override
+      public void propertyChange(PropertyChangeEvent evt) {
+        setup();
+        updateCP();
+      }
+
+      @Override
       public void fileFolderCreated(FileEvent fe) {
         // TODO wrong if there is a property that points to a different folder
         if (libsDir == null && "libs".equals(fe.getFile().getName())) {

File project/src/org/netbeans/modules/android/project/ui/customizer/AndroidCompositePanelProvider.java Modified

View file
  • Ignore whitespace
  • Hide word diff
 import org.netbeans.modules.android.core.sdk.DalvikPlatformManager;
 import org.netbeans.modules.android.project.AndroidProject;
 import org.netbeans.modules.android.project.AndroidProjectInfo;
+import org.netbeans.modules.android.project.JarLibsModel;
 import org.netbeans.modules.android.project.launch.LaunchConfiguration;
 import org.netbeans.spi.project.ui.support.ProjectCustomizer;
 import org.openide.util.Lookup;
 import org.openide.util.NbBundle;
 
 /**
- *
+ * Provider for Android project specific panel in project customizer.
  */
 public class AndroidCompositePanelProvider implements ProjectCustomizer.CompositeCategoryProvider {
-    /** General category in project customizer. */
-    static final String GENERAL = "General"; // NOI18N
-    static final String LIBRARIES = "Libraries";
-    
-    public static final String RUN = "Run";
+  /** General category in project customizer. */
+  static final String GENERAL = "General"; // NOI18N
+  /** Android libraries category in project customizer. */
+  static final String LIBRARIES = "Libraries";
+  /** JAR libraries category in project customizer. */
+  static final String JARS = "JARs";
+  /** Run category in project customizer. */
+  public static final String RUN = "Run";
 
-    private String name;
-    
-    public AndroidCompositePanelProvider(String name) {
-        this.name = name;
-    }
+  private String name;
+
+  public AndroidCompositePanelProvider(String name) {
+    this.name = name;
+  }
 
   @Override
     public ProjectCustomizer.Category createCategory(Lookup context) {
                     LIBRARIES,
                     bundle.getString( "LBL_Config_Libraries" ), // NOI18N
                     null);
+        } else if (JARS.equals(name)) {
+            toReturn = ProjectCustomizer.Category.create(
+                    JARS,
+                    bundle.getString( "LBL_Config_JARs" ), // NOI18N
+                    null);
         } else if (GENERAL.equals(name)) {
             toReturn = ProjectCustomizer.Category.create(
                     GENERAL,
         AndroidProject project = context.lookup(AndroidProject.class);
         AndroidGeneralData data = context.lookup(AndroidGeneralData.class);
         AndroidProjectInfo info = context.lookup(AndroidProjectInfo.class);
+        JarLibsModel jarLibs = context.lookup(JarLibsModel.class);
         if (LIBRARIES.equals(nm)) {
             return new CustomizerLibraries(data, project);
+        } else if (JARS.equals(nm)) {
+            return new CustomizerJARs(jarLibs);
         } else if (GENERAL.equals(nm)) {
             return new CustomizerGeneral(data, info, DalvikPlatformManager.getDefault());
         } else if (RUN.equals(nm)) {
 
     }
 
-    public static AndroidCompositePanelProvider createLibraries() {
-        return new AndroidCompositePanelProvider(LIBRARIES);
-    }
+  public static AndroidCompositePanelProvider createLibraries() {
+    return new AndroidCompositePanelProvider(LIBRARIES);
+  }
+
+  public static AndroidCompositePanelProvider createJARs() {
+    return new AndroidCompositePanelProvider(JARS);
+  }
 
     public static AndroidCompositePanelProvider createRun() {
         return new AndroidCompositePanelProvider(RUN);

File project/src/org/netbeans/modules/android/project/ui/customizer/Bundle.properties Modified

View file
  • Ignore whitespace
  • Hide word diff
 LBL_Customizer_Title=Project Properties - {0}
 
 # Configuration node labels
-Projects/org-netbeans-modules-java-j2seproject/Customizer/BuildCategory=Build
-Projects/org-netbeans-modules-java-j2seproject/Customizer/WebServiceCategory=Web Services
-Projects/org-netbeans-modules-java-j2seproject/Customizer/Application=Application
-#LBL_Config_RunCategory=Run X
-#LBL_Config_ProjectDependencies=Required Projects X
 LBL_Config_General=General
 LBL_Config_Libraries=Libraries
+LBL_Config_JARs=JAR Libraries
 # LBL_Config_Sources=Sources
 LBL_Config_Build=Compiling
 #LBL_Config_BuildTests=Compiling Tests X
 LBL_CustomizeGeneral_Platform_JButton=&Manage Platforms...
 
 #  Customize compilation
-LBL_CustomizeCompile_Compiler_Src14_JCheckBox=Accept Assertions (JDK 1.4 Sources)
 LBL_CustomizeCompile_Compiler_Deprecation_JCheckBox=Report Uses of &Deprecated APIs
 LBL_CustomizeCompile_Compiler_DebugInfo_JCheckBox=&Generate Debugging Info
 LBL_CustomizeCompile_Classpath_JLabel=&Classpath for Compiling Sources\:

File project/src/org/netbeans/modules/android/project/ui/customizer/CustomizerJARs.form Added

View file
  • Ignore whitespace
  • Hide word diff
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.6" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <NonVisualComponents>
+    <Component class="javax.swing.ButtonGroup" name="buttonGroupJARs">
+    </Component>
+  </NonVisualComponents>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="jLabelLibsFolder" alignment="0" min="-2" max="-2" attributes="0"/>
+                  <Component id="jLabelReferrencedJARs" alignment="0" min="-2" max="-2" attributes="0"/>
+                  <Component id="jScrollPane1" alignment="0" pref="430" max="32767" attributes="2"/>
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
+                      <Component id="jRadioButtonCustom" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace type="separate" min="-2" max="-2" attributes="0"/>
+                      <Component id="jTextFieldLibsFolder" pref="190" max="32767" attributes="0"/>
+                      <EmptySpace min="-2" max="-2" attributes="0"/>
+                      <Component id="jButtonLibsFolderBrowse" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
+                      <Component id="jRadioButtonDefault" min="-2" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="jLabelLibsFolder" min="-2" max="-2" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="jRadioButtonDefault" min="-2" max="-2" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jTextFieldLibsFolder" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jRadioButtonCustom" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButtonLibsFolderBrowse" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="jLabelReferrencedJARs" min="-2" max="-2" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="jScrollPane1" pref="176" max="32767" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="jLabelReferrencedJARs">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Referenced JRA libraries:"/>
+      </Properties>
+    </Component>
+    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JTable" name="jTableLibs">
+          <Properties>
+            <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+              <Connection code="libsTableModel" type="code"/>
+            </Property>
+            <Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor">
+              <TableColumnModel selectionModel="0"/>
+            </Property>
+            <Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
+              <JTableSelectionModel selectionMode="0"/>
+            </Property>
+            <Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
+              <TableHeader reorderingAllowed="false" resizingAllowed="true"/>
+            </Property>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JRadioButton" name="jRadioButtonDefault">
+      <Properties>
+        <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+          <ComponentRef name="buttonGroupJARs"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Default location (libs folder in your project)"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jRadioButtonDefaultActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JRadioButton" name="jRadioButtonCustom">
+      <Properties>
+        <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+          <ComponentRef name="buttonGroupJARs"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Custom location"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jRadioButtonCustomActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabelLibsFolder">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Location of JAR libraries"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="jTextFieldLibsFolder">
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonLibsFolderBrowse">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Browse"/>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>

File project/src/org/netbeans/modules/android/project/ui/customizer/CustomizerJARs.java Added

View file
  • Ignore whitespace
  • Hide word diff
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.netbeans.modules.android.project.ui.customizer;
+
+import org.netbeans.modules.android.project.JarLibsModel;
+import java.util.logging.Logger;
+import javax.swing.JPanel;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.table.DefaultTableModel;
+
+/** 
+ * Customizer for Android libraries.
+ */
+public class CustomizerJARs extends JPanel {
+  private static final Logger LOG = Logger.getLogger(CustomizerJARs.class.getName());
+    
+  private final DefaultTableModel libsTableModel;
+  private final JarLibsModel jarLibsModel;
+
+  public CustomizerJARs(JarLibsModel jarLibsModel) {
+    this.jarLibsModel = jarLibsModel;
+
+    libsTableModel = new javax.swing.table.DefaultTableModel(
+        new String[0][],
+        new String [] {"JAR"}) {
+      Class[] types = new Class [] {String.class};
+      boolean[] canEdit = new boolean [] {false};
+
+      @Override
+      public Class getColumnClass(int columnIndex) {
+        return types[columnIndex];
+      }
+
+      @Override
+      public boolean isCellEditable(int rowIndex, int columnIndex) {
+        return canEdit[columnIndex];
+      }
+    };
+    initComponents(); 
+    initFromProject();
+    jTextFieldLibsFolder.getDocument().addDocumentListener(new DocumentListener() {
+
+      @Override
+      public void insertUpdate(DocumentEvent e) {
+        updateData();
+      }
+
+      @Override
+      public void removeUpdate(DocumentEvent e) {
+        updateData();
+      }
+
+      @Override
+      public void changedUpdate(DocumentEvent e) {
+        updateData();
+      }
+    });
+  }
+        
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+  private void initComponents() {
+
+    buttonGroupJARs = new javax.swing.ButtonGroup();
+    jLabelReferrencedJARs = new javax.swing.JLabel();
+    jScrollPane1 = new javax.swing.JScrollPane();
+    jTableLibs = new javax.swing.JTable();
+    jRadioButtonDefault = new javax.swing.JRadioButton();
+    jRadioButtonCustom = new javax.swing.JRadioButton();
+    jLabelLibsFolder = new javax.swing.JLabel();
+    jTextFieldLibsFolder = new javax.swing.JTextField();
+    jButtonLibsFolderBrowse = new javax.swing.JButton();
+
+    org.openide.awt.Mnemonics.setLocalizedText(jLabelReferrencedJARs, "Referenced JRA libraries:");
+
+    jTableLibs.setModel(libsTableModel);
+    jTableLibs.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
+    jTableLibs.getTableHeader().setReorderingAllowed(false);
+    jScrollPane1.setViewportView(jTableLibs);
+
+    buttonGroupJARs.add(jRadioButtonDefault);
+    org.openide.awt.Mnemonics.setLocalizedText(jRadioButtonDefault, "Default location (libs folder in your project)");
+    jRadioButtonDefault.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(java.awt.event.ActionEvent evt) {
+        jRadioButtonDefaultActionPerformed(evt);
+      }
+    });
+
+    buttonGroupJARs.add(jRadioButtonCustom);
+    org.openide.awt.Mnemonics.setLocalizedText(jRadioButtonCustom, "Custom location");
+    jRadioButtonCustom.addActionListener(new java.awt.event.ActionListener() {
+      public void actionPerformed(java.awt.event.ActionEvent evt) {
+        jRadioButtonCustomActionPerformed(evt);
+      }
+    });
+
+    org.openide.awt.Mnemonics.setLocalizedText(jLabelLibsFolder, "Location of JAR libraries");
+
+    org.openide.awt.Mnemonics.setLocalizedText(jButtonLibsFolderBrowse, "Browse");
+
+    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+    this.setLayout(layout);
+    layout.setHorizontalGroup(
+      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+      .addGroup(layout.createSequentialGroup()
+        .addContainerGap()
+        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+          .addComponent(jLabelLibsFolder)
+          .addComponent(jLabelReferrencedJARs)
+          .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 430, Short.MAX_VALUE)
+          .addGroup(layout.createSequentialGroup()
+            .addGap(12, 12, 12)
+            .addComponent(jRadioButtonCustom)
+            .addGap(18, 18, 18)
+            .addComponent(jTextFieldLibsFolder, javax.swing.GroupLayout.DEFAULT_SIZE, 190, Short.MAX_VALUE)
+            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+            .addComponent(jButtonLibsFolderBrowse))
+          .addGroup(layout.createSequentialGroup()
+            .addGap(12, 12, 12)
+            .addComponent(jRadioButtonDefault)))
+        .addContainerGap())
+    );
+    layout.setVerticalGroup(
+      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+      .addGroup(layout.createSequentialGroup()
+        .addContainerGap()
+        .addComponent(jLabelLibsFolder)
+        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+        .addComponent(jRadioButtonDefault)
+        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+          .addComponent(jTextFieldLibsFolder, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+          .addComponent(jRadioButtonCustom)
+          .addComponent(jButtonLibsFolderBrowse))
+        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+        .addComponent(jLabelReferrencedJARs)
+        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+        .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 176, Short.MAX_VALUE)
+        .addContainerGap())
+    );
+  }// </editor-fold>//GEN-END:initComponents
+
+  private void jRadioButtonDefaultActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonDefaultActionPerformed
+    updateData();
+  }//GEN-LAST:event_jRadioButtonDefaultActionPerformed
+
+  private void jRadioButtonCustomActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonCustomActionPerformed
+    updateData();
+  }//GEN-LAST:event_jRadioButtonCustomActionPerformed
+    
+  // Variables declaration - do not modify//GEN-BEGIN:variables
+  private javax.swing.ButtonGroup buttonGroupJARs;
+  private javax.swing.JButton jButtonLibsFolderBrowse;
+  private javax.swing.JLabel jLabelLibsFolder;
+  private javax.swing.JLabel jLabelReferrencedJARs;
+  private javax.swing.JRadioButton jRadioButtonCustom;
+  private javax.swing.JRadioButton jRadioButtonDefault;
+  private javax.swing.JScrollPane jScrollPane1;
+  private javax.swing.JTable jTableLibs;
+  private javax.swing.JTextField jTextFieldLibsFolder;
+  // End of variables declaration//GEN-END:variables
+        
+  private void initFromProject() {
+    jRadioButtonDefault.setSelected(jarLibsModel.isUseDefaultLocation());
+    jRadioButtonCustom.setSelected(!jarLibsModel.isUseDefaultLocation());
+    jTextFieldLibsFolder.setText(
+        jarLibsModel.isUseDefaultLocation() ? "" : jarLibsModel.getLibsDir());
+    updateData();
+  }
+
+  private void updateData() {
+    jarLibsModel.setUseDefaultLocation(jRadioButtonDefault.isSelected());
+    jarLibsModel.setLibsDir(jTextFieldLibsFolder.getText());
+
+    jTextFieldLibsFolder.setEnabled(!jarLibsModel.isUseDefaultLocation());
+
+    libsTableModel.setRowCount(0);
+    for (String library : jarLibsModel.getLibNames()) {
+      libsTableModel.addRow(new String[] {library});
+    }
+  }
+}

File project/src/org/netbeans/modules/android/project/ui/customizer/CustomizerProviderImpl.java Modified

View file
  • Ignore whitespace
  • Hide word diff
 import org.netbeans.api.project.ProjectUtils;
 import org.netbeans.modules.android.project.AndroidProject;
 import org.netbeans.modules.android.project.AndroidProjectInfo;
+import org.netbeans.modules.android.project.JarLibsModel;
 import org.netbeans.modules.android.project.launch.LaunchConfiguration;
 import org.netbeans.modules.android.project.launch.Launches;
 import org.netbeans.spi.project.ui.CustomizerProvider;
  */
 public class CustomizerProviderImpl implements CustomizerProvider {
     
-  public static final String CUSTOMIZER_FOLDER_PATH = "Projects/org-netbeans-modules-android-project/Customizer"; //NO18N
+  public static final String CUSTOMIZER_FOLDER_PATH =
+      "Projects/org-netbeans-modules-android-project/Customizer"; //NO18N
 
   private final AndroidProject project;
     
     final AndroidGeneralData data = AndroidGeneralData.fromProject(project);
     final LaunchConfiguration launchConfig = Launches.forProject(project);
     final AndroidProjectInfo info = project.info();
+    final JarLibsModel jarLibs = new JarLibsModel(project);
 
     Lookup context = Lookups.fixed(new Object[] {
         project,
         data,
         launchConfig,
         info,
+        jarLibs,
         new SubCategoryProvider(preselectedCategory, preselectedSubCategory)
     });
 
-    OptionListener listener = new OptionListener(project, data, launchConfig);
+    OptionListener listener = new OptionListener(project, data, launchConfig, jarLibs);
     Dialog dialog = ProjectCustomizer.createCustomizerDialog(
-        CUSTOMIZER_FOLDER_PATH, context, preselectedCategory, listener, null );
+        CUSTOMIZER_FOLDER_PATH, context, preselectedCategory, listener, null);
     listener.attachDialog(dialog);
     dialog.setTitle( MessageFormat.format(
             NbBundle.getMessage( CustomizerProviderImpl.class, "LBL_Customizer_Title" ), // NOI18N
     private final AndroidProject project;
     private final LaunchConfiguration launchConfig;
     private final AndroidGeneralData data;
+    private final JarLibsModel jarLibs;
     private Dialog dialog;
 
     private OptionListener(AndroidProject project, AndroidGeneralData data,
-        LaunchConfiguration launchConfig) {
+        LaunchConfiguration launchConfig, JarLibsModel jarLibs) {
       this.project = project;
       this.data = data;
       this.launchConfig = launchConfig;
+      this.jarLibs = jarLibs;
     }
 
     private void attachDialog(Dialog dialog) {
       // XXX save modified properties
       project.update(data);
       project.update(launchConfig);
+      // TODO(radim) handle errors / return value
+      jarLibs.apply(project);
       // Close & dispose the the dialog
       if (dialog != null) {
         dialog.setVisible(false);

File project/src/org/netbeans/modules/android/project/ui/resources/layer.xml Modified

View file
  • Ignore whitespace
  • Hide word diff
                     <attr name="instanceCreate" methodvalue="org.netbeans.modules.android.project.ui.customizer.AndroidCompositePanelProvider.createLibraries"/>
                     <attr name="position" intvalue="200"/>
                 </file>
+                <file name="JARs.instance">
+                    <attr name="instanceCreate" methodvalue="org.netbeans.modules.android.project.ui.customizer.AndroidCompositePanelProvider.createJARs"/>
+                    <attr name="position" intvalue="300"/>
+                </file>
                 <!--
                 <folder name="BuildCategory">
                     <attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.android.project.ui.customizer.Bundle"/>

File project/test/unit/src/org/netbeans/modules/android/project/JarLibsModelTest.java Added

View file
  • Ignore whitespace
  • Hide word diff
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+package org.netbeans.modules.android.project;
+
+import java.util.List;
+import com.android.sdklib.SdkManager;
+import com.android.sdklib.internal.project.ProjectCreator;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Properties;
+import org.junit.After;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.project.ProjectManager;
+import org.netbeans.modules.android.core.sdk.DalvikPlatform;
+import org.netbeans.modules.android.core.sdk.DalvikPlatformManager;
+import org.netbeans.modules.android.core.sdk.SdkLogProvider;
+import org.netbeans.modules.android.core.sdk.Utils;
+import org.netbeans.spi.java.classpath.ClassPathProvider;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author radim, Baldur
+ */
+public class JarLibsModelTest {
+  
+  private static final String SDK_DIR = System.getProperty("test.all.android.sdks.home");
+  
+  private static DalvikPlatformManager platformManager;
+  
+  private static File tempFolder;
+  
+  
+  
+  @BeforeClass
+  public static void setUpClass() throws Exception {
+    platformManager = DalvikPlatformManager.getDefault();
+    platformManager.setSdkLocation(SDK_DIR);
+  }
+  
+  
+  @After
+  public void clear() {
+    FileUtilities.recursiveDelete(tempFolder);
+  }
+  
+  private static FileObject createProject(Utils.TestPlatform p, FileObject root, String name,
+      boolean isLibrary, String ... usedLib) 
+      throws IOException {
+    // get platform manager & project creator for the current target
+    DalvikPlatform platform = platformManager.findPlatformForTarget(p.getTarget());
+    assertNotNull("missing platform for target " + p.getTarget(), platform);
+
+    SdkManager sdkManager = platform.getSdkManager();
+    assertNotNull("missing sdk manager for target " + p.getTarget(), sdkManager);
+
+    ProjectCreator prjCreator = new ProjectCreator(
+              sdkManager,
+              sdkManager.getLocation(),
+              ProjectCreator.OutputLevel.NORMAL,
+              SdkLogProvider.createSdkLogger(true)
+    );
+
+    FileObject foProject   = root.createFolder(name);
+    prjCreator.createProject(
+              FileUtil.toFile(foProject).getAbsolutePath(),
+              name,
+              "com.android.test." + name,
+              "MainActivity",
+              platform.getAndroidTarget(),
+              isLibrary,
+              /*main project*/null
+    );
+    
+    if (usedLib.length > 0) {
+
+      // write project properties
+      FileObject foProjectProps = foProject.getFileObject("default", "properties");
+      Properties propProject = new Properties();
+      InputStream in = foProjectProps.getInputStream();
+      propProject.load(in);
+      in.close();
+      int i = 1;
+      for (String lib : usedLib) {
+        propProject.setProperty("android.library.reference." + String.valueOf(i), 
+            ".." + File.separatorChar + lib);
+      }
+      OutputStream out = foProjectProps.getOutputStream();
+      propProject.store(out, "");  
+      out.close();
+    }
+    return foProject;
+  }
+  
+  @Test
+  public void testFindClassPathWithLib() throws IOException, InterruptedException {
+
+    for (Utils.TestPlatform p : Utils.purePlatforms()) {
+      tempFolder = File.createTempFile("junit", "");
+      tempFolder.delete();
+      tempFolder.mkdirs();
+      
+      // file object for the temp dir
+      FileObject root = FileUtil.toFileObject(tempFolder);
+      FileObject foProject = createProject(p, root, "TestProject", false);
+      
+      // create the project
+      AndroidProject project = (AndroidProject)ProjectManager.getDefault().findProject(foProject);
+      ClassPathProvider cpp = project.getLookup().lookup(ClassPathProvider.class);
+      // expected paths
+      FileObject foProjectSrc   = foProject.getFileObject("src");
+      // library in main project
+      FileObject libs = foProject.getFileObject("libs");
+      FileObject myLib = libs.createData("myLib.jar");
+      
+      ClassPath classpath = cpp.findClassPath(foProjectSrc, ClassPath.COMPILE);
+      assertNotNull(classpath);
+      checkLib(classpath, true, myLib.getPath());
+
+      FileObject libs2 = foProject.createFolder("libs2");
+      FileObject myLib2 = libs2.createData("myLib.jar");
+      JarLibsModel model = new JarLibsModel(project);
+      model.setUseDefaultLocation(false);
+      model.setLibsDir("libs2");
+      assertTrue(model.apply(project));
+      checkLib(classpath, false, myLib.getPath());
+      checkLib(classpath, true, myLib2.getPath());
+
+      model.setUseDefaultLocation(true);
+      assertTrue(model.apply(project));
+      checkLib(classpath, true, myLib.getPath());
+      checkLib(classpath, false, myLib2.getPath());
+
+    }
+  }
+
+  private void checkLib(ClassPath classpath, boolean contains, String path) {
+      List<String> cpEntries = Lists.newArrayList(
+          Splitter.on(':').split(classpath.toString(ClassPath.PathConversionMode.PRINT)));
+      System.err.println(cpEntries);
+      assertEquals("Classpath " + classpath + " has sources", contains, cpEntries.contains(path));
+  }
+  
+}

File project/test/unit/src/org/netbeans/modules/android/project/TestUtils.java Added

View file
  • Ignore whitespace
  • Hide word diff
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+package org.netbeans.modules.android.project;
+
+import com.android.sdklib.SdkManager;
+import com.android.sdklib.internal.project.ProjectCreator;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Properties;
+import org.netbeans.modules.android.core.sdk.DalvikPlatform;
+import org.netbeans.modules.android.core.sdk.DalvikPlatformManager;
+import org.netbeans.modules.android.core.sdk.SdkLogProvider;
+import org.netbeans.modules.android.core.sdk.Utils;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author radim
+ */
+public class TestUtils {
+  
+  /**
+   * Creates an android project.
+   * Expects that DalvikPlatformManager is already configured.
+   *
+   * @return file object of a project root directory
+   */
+  public static FileObject createProject(Utils.TestPlatform p, FileObject root, String name,
+      boolean isLibrary, String ... usedLib) 
+      throws IOException {
+    DalvikPlatformManager platformManager = DalvikPlatformManager.getDefault();
+    // get platform manager & project creator for the current target
+    DalvikPlatform platform = platformManager.findPlatformForTarget(p.getTarget());
+    assertNotNull("missing platform for target " + p.getTarget(), platform);
+
+    SdkManager sdkManager = platform.getSdkManager();
+    assertNotNull("missing sdk manager for target " + p.getTarget(), sdkManager);
+
+    ProjectCreator prjCreator = new ProjectCreator(
+              sdkManager,
+              sdkManager.getLocation(),
+              ProjectCreator.OutputLevel.NORMAL,
+              SdkLogProvider.createSdkLogger(true)
+    );
+
+    FileObject foProject   = root.createFolder(name);
+    prjCreator.createProject(
+              FileUtil.toFile(foProject).getAbsolutePath(),
+              name,
+              "com.android.test." + name,
+              "MainActivity",
+              platform.getAndroidTarget(),
+              isLibrary,
+              /*main project*/null
+    );
+    
+    if (usedLib.length > 0) {
+
+      // write project properties
+      FileObject foProjectProps = foProject.getFileObject("default", "properties");
+      Properties propProject = new Properties();
+      InputStream in = foProjectProps.getInputStream();
+      propProject.load(in);
+      in.close();
+      int i = 1;
+      for (String lib : usedLib) {
+        propProject.setProperty("android.library.reference." + String.valueOf(i), 
+            ".." + File.separatorChar + lib);
+      }
+      OutputStream out = foProjectProps.getOutputStream();
+      propProject.store(out, "");  
+      out.close();
+    }
+    return foProject;
+  }
+}

File project/test/unit/src/org/netbeans/modules/android/project/queries/ClassPathProviderImplTest.java Modified

View file
  • Ignore whitespace
  • Hide word diff
  */
 package org.netbeans.modules.android.project.queries;
 
+import org.netbeans.modules.android.project.TestUtils;
 import java.util.List;
 import java.net.URL;
-import com.android.sdklib.SdkManager;
-import com.android.sdklib.internal.project.ProjectCreator;
 import com.google.common.base.Splitter;
 import com.google.common.collect.Lists;
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Properties;
 import org.junit.After;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.netbeans.api.java.classpath.ClassPath;
 import org.netbeans.api.project.ProjectManager;
-import org.netbeans.modules.android.core.sdk.DalvikPlatform;
 import org.netbeans.modules.android.core.sdk.DalvikPlatformManager;
-import org.netbeans.modules.android.core.sdk.SdkLogProvider;
 import org.netbeans.modules.android.core.sdk.Utils;
 import org.netbeans.modules.android.project.AndroidProject;
 import org.netbeans.modules.android.project.FileUtilities;
     FileUtilities.recursiveDelete(tempFolder);
   }
   
-  private FileObject createProject(Utils.TestPlatform p, FileObject root, String name, 
-      boolean isLibrary, String ... usedLib) 
-      throws IOException {
-    // get platform manager & project creator for the current target
-    DalvikPlatform platform = platformManager.findPlatformForTarget(p.getTarget());
-    assertNotNull("missing platform for target " + p.getTarget(), platform);
-
-    SdkManager sdkManager = platform.getSdkManager();
-    assertNotNull("missing sdk manager for target " + p.getTarget(), sdkManager);
-
-    ProjectCreator prjCreator = new ProjectCreator(
-              sdkManager,
-              sdkManager.getLocation(),
-              ProjectCreator.OutputLevel.NORMAL,
-              SdkLogProvider.createSdkLogger(true)
-    );
-
-    FileObject foProject   = root.createFolder(name);
-    prjCreator.createProject(
-              FileUtil.toFile(foProject).getAbsolutePath(),
-              name,
-              "com.android.test." + name,
-              "MainActivity",
-              platform.getAndroidTarget(),
-              isLibrary,
-              /*main project*/null
-    );
-    
-    if (usedLib.length > 0) {
-
-      // write project properties
-      FileObject foProjectProps = foProject.getFileObject("default", "properties");
-      Properties propProject = new Properties();
-      InputStream in = foProjectProps.getInputStream();
-      propProject.load(in);
-      in.close();
-      int i = 1;
-      for (String lib : usedLib) {
-        propProject.setProperty("android.library.reference." + String.valueOf(i), 
-            ".." + File.separatorChar + lib);
-      }
-      OutputStream out = foProjectProps.getOutputStream();
-      propProject.store(out, "");  
-      out.close();
-    }
-    return foProject;
-  }
-  
   @Test
   public void testNestedLibrariesClassPathProvider() throws IOException {
     for (Utils.TestPlatform p : Utils.purePlatforms()) {
       // file object for the temp dir
       FileObject root = FileUtil.toFileObject(tempFolder);
       
-      FileObject foProject   = createProject(p, root, "TestProject", false, "TestLibrary");
-      FileObject foFirstLib  = createProject(p, root, "TestLibrary", true, "NestedLibrary");
-      FileObject foNestedLib = createProject(p, root, "NestedLibrary", true);
+      FileObject foProject = TestUtils.createProject(p, root, "TestProject", false, "TestLibrary");
+      FileObject foFirstLib = TestUtils.createProject(p, root, "TestLibrary", true, "NestedLibrary");
+      FileObject foNestedLib = TestUtils.createProject(p, root, "NestedLibrary", true);
       
       // create the project
       AndroidProject project = (AndroidProject)ProjectManager.getDefault().findProject(foProject);
       // file object for the temp dir
       FileObject root = FileUtil.toFileObject(tempFolder);
       
-      FileObject foProject = createProject(p, root, "TestProject", false);
+      FileObject foProject = TestUtils.createProject(p, root, "TestProject", false);
       
       // create the project
       AndroidProject project = (AndroidProject)ProjectManager.getDefault().findProject(foProject);
       // file object for the temp dir
       FileObject root = FileUtil.toFileObject(tempFolder);
       
-      FileObject foProject   = createProject(p, root, "TestProject", false, "TestLibrary");
-      FileObject foFirstLib  = createProject(p, root, "TestLibrary", true);
+      FileObject foProject = TestUtils.createProject(p, root, "TestProject", false, "TestLibrary");
+      FileObject foFirstLib = TestUtils.createProject(p, root, "TestLibrary", true);
       
       // create the project
       AndroidProject project = (AndroidProject)ProjectManager.getDefault().findProject(foProject);