From d12a40744f7c49bb99fc7d3248655c95ce0bc858 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 4 Apr 2014 12:47:21 +0200 Subject: [PATCH 01/11] Add Library.isProperLibrary() to check for non-legacy libraries This shouldn't change any behaviour, just restructures the code to prepare for upcoming changes. --- app/src/processing/app/packages/Library.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/src/processing/app/packages/Library.java b/app/src/processing/app/packages/Library.java index 9c505fe4e41..73df883b160 100644 --- a/app/src/processing/app/packages/Library.java +++ b/app/src/processing/app/packages/Library.java @@ -36,6 +36,16 @@ public class Library { "Device Control", "Timing", "Data Storage", "Data Processing", "Other", "Uncategorized" }); + /** + * Check a folder to see if it contains a proper (non-legacy) library. + */ + public static boolean isProperLibrary(File libFolder) throws IOException { + // A library is considered "new" if it contains a file called + // "library.properties" + File check = new File(libFolder, "library.properties"); + return check.exists() && check.isFile(); + } + /** * Scans inside a folder and create a Library object out of it. Automatically * detects legacy libraries. Automatically fills metadata from @@ -45,10 +55,7 @@ public class Library { * @return */ static public Library create(File libFolder) throws IOException { - // A library is considered "new" if it contains a file called - // "library.properties" - File check = new File(libFolder, "library.properties"); - if (!check.exists() || !check.isFile()) + if (!isProperLibrary(libFolder)) return createLegacyLibrary(libFolder); else return createLibrary(libFolder); From 454db63ad4ab5d3e492d9d714ba39694f2f8d7a9 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 4 Apr 2014 16:59:12 +0200 Subject: [PATCH 02/11] Add Library.isLibrary() method This allows checking a folder on disk to see if it looks like a library. --- app/src/processing/app/packages/Library.java | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/src/processing/app/packages/Library.java b/app/src/processing/app/packages/Library.java index 73df883b160..b4c28587b7e 100644 --- a/app/src/processing/app/packages/Library.java +++ b/app/src/processing/app/packages/Library.java @@ -9,6 +9,7 @@ import processing.app.helpers.FileUtils; import processing.app.helpers.PreferencesMap; +import processing.app.helpers.filefilters.OnlyFilesWithExtension; public class Library { @@ -46,6 +47,26 @@ public static boolean isProperLibrary(File libFolder) throws IOException { return check.exists() && check.isFile(); } + /** + * Check a folder to see if it is a proper library, or looks like a + * legacy library (we can never tell for sure, though). + */ + public static boolean isLibrary(File libFolder) throws IOException { + if (isProperLibrary(libFolder)) + return true; + + // If it has a utility folder, then it's probably a legacy library + File utilFolder = new File(libFolder, "utility"); + if (utilFolder.exists() && utilFolder.isDirectory()) + return true; + + // If it his some .h files, it's probably a legacy library + if (libFolder.list(new OnlyFilesWithExtension(".h")).length > 0) + return true; + + return false; + } + /** * Scans inside a folder and create a Library object out of it. Automatically * detects legacy libraries. Automatically fills metadata from From 8ea0cae8b89e09ea6f42cdbb749348360cf7b45b Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 4 Apr 2014 12:49:34 +0200 Subject: [PATCH 03/11] Move the library name check into Library.create This prepares for a next change by making it easier to call Library.create from multiple places without having to copy the name check to every invocation. The name check is still performed in the same code paths. However, previously it would display a warning dialog, now it just prints a warning message in the text area (just like with other library loading failures). --- app/src/processing/app/Base.java | 8 -------- app/src/processing/app/packages/Library.java | 12 ++++++++++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index dee3103de6d..94f2cbdaa10 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1381,14 +1381,6 @@ public LibraryList scanLibraries(File folder) throws IOException { for (String libName : list) { File subfolder = new File(folder, libName); - if (!Sketch.isSanitaryName(libName)) { - String mess = I18n.format(_("The library \"{0}\" cannot be used.\n" - + "Library names must contain only basic letters and numbers.\n" - + "(ASCII only and no spaces, and it cannot start with a number)"), - libName); - Base.showMessage(_("Ignoring bad library name"), mess); - continue; - } try { Library lib = Library.create(subfolder); diff --git a/app/src/processing/app/packages/Library.java b/app/src/processing/app/packages/Library.java index b4c28587b7e..f1fb9bcd83c 100644 --- a/app/src/processing/app/packages/Library.java +++ b/app/src/processing/app/packages/Library.java @@ -10,6 +10,10 @@ import processing.app.helpers.FileUtils; import processing.app.helpers.PreferencesMap; import processing.app.helpers.filefilters.OnlyFilesWithExtension; +import processing.app.Sketch; + +import static processing.app.I18n._; +import processing.app.I18n; public class Library { @@ -76,6 +80,14 @@ public static boolean isLibrary(File libFolder) throws IOException { * @return */ static public Library create(File libFolder) throws IOException { + if (!Sketch.isSanitaryName(libFolder.getName())) { + String mess = I18n.format(_("The library \"{0}\" cannot be used.\n" + + "Library names must contain only basic letters and numbers.\n" + + "(ASCII only and no spaces, and it cannot start with a number)"), + libFolder.getName()); + throw new IOException(mess); + } + if (!isProperLibrary(libFolder)) return createLegacyLibrary(libFolder); else From eeb7dfa0ed33a02fc8b393759138e21bf5c64f1d Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 4 Apr 2014 14:18:34 +0200 Subject: [PATCH 04/11] Fix indentation error --- app/src/processing/app/Base.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 94f2cbdaa10..191f9337c55 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1412,7 +1412,7 @@ public void onBoardOrPortChange() { String referencedCore = core.split(":")[0]; TargetPlatform referencedPlatform = Base.getTargetPlatform(referencedCore, targetPlatform.getId()); if (referencedPlatform != null) { - File referencedPlatformFolder = referencedPlatform.getFolder(); + File referencedPlatformFolder = referencedPlatform.getFolder(); librariesFolders.add(new File(referencedPlatformFolder, "libraries")); } } From 0cc95ce9f5eabd82df68d1cb735d2bd685e024cf Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 4 Apr 2014 14:19:43 +0200 Subject: [PATCH 05/11] Slightly improve error message --- app/src/processing/app/Base.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 191f9337c55..01b114ab299 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1891,7 +1891,7 @@ protected void loadHardware(File folder) { try { packages.put(target, new TargetPackage(target, subfolder)); } catch (TargetPlatformException e) { - System.out.println("WARNING: Error loading hardware folder " + target); + System.out.println("WARNING: Error loading hardware folder " + target + " from " + subfolder); System.out.println(" " + e.getMessage()); } } From 3f29d0c6a3bd4a1d97fa1ac9094982f37b7d51e3 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 4 Apr 2014 16:12:58 +0200 Subject: [PATCH 06/11] Add TargetPlatform.getName() This simplifies some other code. --- app/src/processing/app/Base.java | 17 +++++------------ .../processing/app/debug/TargetPlatform.java | 7 +++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 01b114ab299..74cd4536608 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1315,15 +1315,9 @@ public void actionPerformed(ActionEvent e) { try { // Find the current target. Get the platform, and then select the // correct name and core path. - PreferencesMap prefs = targetPlatform.getPreferences(); - if (prefs != null) { - String platformName = prefs.get("name"); - if (platformName != null) { - JMenuItem platformItem = new JMenuItem(_(platformName)); - platformItem.setEnabled(false); - importMenu.add(platformItem); - } - } + JMenuItem platformItem = new JMenuItem(_(targetPlatform.getName())); + platformItem.setEnabled(false); + importMenu.add(platformItem); if (ideLibs.size() > 0) { importMenu.addSeparator(); addLibraries(importMenu, ideLibs); @@ -1485,9 +1479,8 @@ public void rebuildBoardsMenu(JMenu toolsMenu, Editor editor) throws Exception { first = false; // Add a title for each platform - String platformLabel = targetPlatform.getPreferences().get("name"); - if (platformLabel != null && !targetPlatform.getBoards().isEmpty()) { - JMenuItem menuLabel = new JMenuItem(_(platformLabel)); + if (!targetPlatform.getBoards().isEmpty()) { + JMenuItem menuLabel = new JMenuItem(_(targetPlatform.getName())); menuLabel.setEnabled(false); boardsMenu.add(menuLabel); } diff --git a/app/src/processing/app/debug/TargetPlatform.java b/app/src/processing/app/debug/TargetPlatform.java index 2666347fac4..9a715e4cfbd 100644 --- a/app/src/processing/app/debug/TargetPlatform.java +++ b/app/src/processing/app/debug/TargetPlatform.java @@ -141,6 +141,13 @@ public String getId() { return id; } + public String getName() { + String name = preferences.get("name"); + if (name == null) + return containerPackage.getId() + ":" + id; + return name; + } + public File getFolder() { return folder; } From cfb8156339cedbffc84e99bf58d8262d2342dfc8 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 4 Apr 2014 16:35:35 +0200 Subject: [PATCH 07/11] Make Sketch.importedLibraries an ArrayList Previously, it was a LibraryList, but since it was only iterated, there is no real need. This should not change any behaviour, but prepares for an upcoming change. --- app/src/processing/app/Sketch.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 4b2c6b44b4c..56fff7f8f16 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -33,7 +33,6 @@ import processing.app.helpers.PreferencesMap; import processing.app.helpers.FileUtils; import processing.app.packages.Library; -import processing.app.packages.LibraryList; import processing.app.preproc.*; import processing.core.*; import static processing.app.I18n._; @@ -94,7 +93,7 @@ public class Sketch { /** * List of library folders. */ - private LibraryList importedLibraries; + private ArrayList importedLibraries; /** * File inside the build directory that contains the build options @@ -1386,7 +1385,7 @@ public void preprocess(String buildPath, PdePreprocessor preprocessor) throws Ru // grab the imports from the code just preproc'd - importedLibraries = new LibraryList(); + importedLibraries = new ArrayList(); for (String item : preprocessor.getExtraImports()) { Library lib = Base.importToLibraryTable.get(item); if (lib != null && !importedLibraries.contains(lib)) { @@ -1419,7 +1418,7 @@ public void preprocess(String buildPath, PdePreprocessor preprocessor) throws Ru } - public LibraryList getImportedLibraries() { + public List getImportedLibraries() { return importedLibraries; } From 0a1266d62de6038784730d2b9bdf038a8a045d56 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 4 Apr 2014 16:44:10 +0200 Subject: [PATCH 08/11] Remove separation between IDE and user libraries In a subsequent commit, we'll reintroduce this distinction in a more flexible way, but for now just treat all libraries equal in the import and examples menus. --- app/src/processing/app/Base.java | 52 +++++--------------------------- 1 file changed, 7 insertions(+), 45 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 74cd4536608..c21a7fa0f21 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1277,20 +1277,6 @@ protected void rebuildSketchbookMenu(JMenu menu) { } } - public LibraryList getIDELibs() { - if (libraries == null) - return new LibraryList(); - LibraryList res = new LibraryList(libraries); - res.removeAll(getUserLibs()); - return res; - } - - public LibraryList getUserLibs() { - if (libraries == null) - return new LibraryList(); - return libraries.filterLibrariesInSubfolder(getSketchbookFolder()); - } - public void rebuildImportMenu(JMenu importMenu) { importMenu.removeAll(); @@ -1304,28 +1290,11 @@ public void actionPerformed(ActionEvent e) { } }); importMenu.add(addLibraryMenuItem); - importMenu.addSeparator(); - // Split between user supplied libraries and IDE libraries - TargetPlatform targetPlatform = getTargetPlatform(); - - if (targetPlatform != null) { - LibraryList ideLibs = getIDELibs(); - LibraryList userLibs = getUserLibs(); + if (libraries != null) { + importMenu.addSeparator(); try { - // Find the current target. Get the platform, and then select the - // correct name and core path. - JMenuItem platformItem = new JMenuItem(_(targetPlatform.getName())); - platformItem.setEnabled(false); - importMenu.add(platformItem); - if (ideLibs.size() > 0) { - importMenu.addSeparator(); - addLibraries(importMenu, ideLibs); - } - if (userLibs.size() > 0) { - importMenu.addSeparator(); - addLibraries(importMenu, userLibs); - } + addLibraries(importMenu, libraries); } catch (IOException e) { e.printStackTrace(); } @@ -1338,19 +1307,12 @@ public void rebuildExamplesMenu(JMenu menu) { // Add examples from distribution "example" folder boolean found = addSketches(menu, examplesFolder, false); - if (found) menu.addSeparator(); // Add examples from libraries - LibraryList ideLibs = getIDELibs(); - ideLibs.sort(); - for (Library lib : ideLibs) - addSketchesSubmenu(menu, lib, false); - - LibraryList userLibs = getUserLibs(); - if (userLibs.size()>0) { - menu.addSeparator(); - userLibs.sort(); - for (Library lib : userLibs) + if (libraries != null && !libraries.isEmpty()) { + if (found) + menu.addSeparator(); + for (Library lib : libraries) addSketchesSubmenu(menu, lib, false); } } catch (IOException e) { From 0e2d2eddce28ca16f31ea293c52226deed9ccd26 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 4 Apr 2014 16:52:34 +0200 Subject: [PATCH 09/11] Allow libraries to live in subdirectories Before, libraries could only be stored directly under e.g. Sketchbook/libraries. When a lot of libraries were present, this could lead to an unwieldy list in the import menu and a mess on disk. This commit changes the library scanning code to recursively scan the contents of the various libraries directories. Each directory is scanned for signs of a library (library.properties file, utility folder, any .h files). If the directory doesn't look like a library, any subdirectories are recursively scanned. This commit updates the scanning code and the modifies the LibraryList class so it can store a tree of libraries instead of just a flat list. In the GUI all libraries are still shown in a flat list. --- app/src/processing/app/Base.java | 120 ++++++++++-------- .../processing/app/packages/LibraryList.java | 78 ++++++++---- 2 files changed, 122 insertions(+), 76 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index c21a7fa0f21..a7ee2e42623 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1312,7 +1312,7 @@ public void rebuildExamplesMenu(JMenu menu) { if (libraries != null && !libraries.isEmpty()) { if (found) menu.addSeparator(); - for (Library lib : libraries) + for (Library lib : getLibraries()) addSketchesSubmenu(menu, lib, false); } } catch (IOException e) { @@ -1320,73 +1320,91 @@ public void rebuildExamplesMenu(JMenu menu) { } } - public LibraryList scanLibraries(List folders) throws IOException { - LibraryList res = new LibraryList(); - for (File folder : folders) - res.addOrReplaceAll(scanLibraries(folder)); - return res; + public void updateLibraries() throws IOException { + // Calculate paths for libraries and examples + examplesFolder = getContentFile("examples"); + toolsFolder = getContentFile("tools"); + + libraries = new LibraryList(null); + librariesFolders = new ArrayList(); + + File ideLibs = getContentFile("libraries"); + libraries.addSub(scanLibraries(ideLibs, _("Libraries for all boards"), true)); + librariesFolders.add(ideLibs); + + TargetPlatform targetPlatform = getTargetPlatform(); + if (targetPlatform != null) { + File platformFolder = targetPlatform.getFolder(); + File platformLibs = new File(platformFolder, "libraries"); + librariesFolders.add(platformLibs); + libraries.addSub(scanLibraries(platformLibs, I18n.format(_("Libraries for {0}"), targetPlatform.getName()), true)); + + String core = getBoardPreferences().get("build.core"); + TargetPlatform referencedPlatform = null; + if (core.contains(":")) { + String referencedCore = core.split(":")[0]; + referencedPlatform = Base.getTargetPlatform(referencedCore, targetPlatform.getId()); + if (referencedPlatform != null) { + File referencedPlatformFolder = referencedPlatform.getFolder(); + File referencedLibs = new File(referencedPlatformFolder, "libraries"); + librariesFolders.add(referencedLibs); + libraries.addSub(scanLibraries(referencedLibs, I18n.format(_("Libraries for {0}"), referencedPlatform.getName()), true)); + } + } + } + + File sketchbookLibs = getSketchbookLibrariesFolder(); + librariesFolders.add(sketchbookLibs); + libraries.addSub(scanLibraries(sketchbookLibs, _("Libraries from your sketchbook"), true)); } - public LibraryList scanLibraries(File folder) throws IOException { - LibraryList res = new LibraryList(); + public LibraryList scanLibraries(File folder, String name, boolean allow_legacy) throws IOException { + LibraryList res = new LibraryList(name != null ? name : folder.getName()); - String list[] = folder.list(new OnlyDirs()); - // if a bad folder or something like that, this might come back null - if (list == null) - return res; + File[] subfolders = folder.listFiles(new OnlyDirs()); + if (subfolders != null) { + for (File subfolder : subfolders) + scanLibraryFolder(res, subfolder, allow_legacy); + } - for (String libName : list) { - File subfolder = new File(folder, libName); + res.sort(); + return res; + } + + public void scanLibraryFolder(LibraryList list, File folder, boolean allow_legacy) throws IOException { + if (Library.isLibrary(folder)) { + // This looks like a library, add it try { - Library lib = Library.create(subfolder); + Library lib = Library.create(folder); // (also replace previously found libs with the same name) if (lib != null) - res.addOrReplace(lib); + list.addOrReplace(lib); } catch (IOException e) { System.out.println(I18n.format(_("Invalid library found in {0}: {1}"), - subfolder, e.getMessage())); + folder, e.getMessage())); } + } else { + // This didn't look like a library, see if we can find libraries + // in the subdirectories + LibraryList sub = scanLibraries(folder, null, false); + + if (!sub.isEmpty()) + list.addSub(sub); } - return res; } public void onBoardOrPortChange() { - TargetPlatform targetPlatform = getTargetPlatform(); - if (targetPlatform == null) - return; - - // Calculate paths for libraries and examples - examplesFolder = getContentFile("examples"); - toolsFolder = getContentFile("tools"); - - File platformFolder = targetPlatform.getFolder(); - librariesFolders = new ArrayList(); - librariesFolders.add(getContentFile("libraries")); - String core = getBoardPreferences().get("build.core"); - if (core.contains(":")) { - String referencedCore = core.split(":")[0]; - TargetPlatform referencedPlatform = Base.getTargetPlatform(referencedCore, targetPlatform.getId()); - if (referencedPlatform != null) { - File referencedPlatformFolder = referencedPlatform.getFolder(); - librariesFolders.add(new File(referencedPlatformFolder, "libraries")); - } - } - librariesFolders.add(new File(platformFolder, "libraries")); - librariesFolders.add(getSketchbookLibrariesFolder()); - - // Scan for libraries in each library folder. - // Libraries located in the latest folders on the list can override - // other libraries with the same name. + // Scan for libraries try { - libraries = scanLibraries(librariesFolders); + updateLibraries(); } catch (IOException e) { showWarning(_("Error"), _("Error loading libraries"), e); } // Populate importToLibraryTable importToLibraryTable = new HashMap(); - for (Library lib : libraries) { + for (Library lib : getLibraries()) { try { String headers[] = headerListFromIncludePath(lib.getSrcFolder()); for (String header : headers) { @@ -1785,11 +1803,7 @@ public void actionPerformed(ActionEvent e) { } protected void addLibraries(JMenu menu, LibraryList libs) throws IOException { - - LibraryList list = new LibraryList(libs); - list.sort(); - - for (Library lib : list) { + for (Library lib : libs.getAll()) { @SuppressWarnings("serial") AbstractAction action = new AbstractAction(lib.getName()) { public void actionPerformed(ActionEvent event) { @@ -2084,8 +2098,8 @@ static public File createTempFolder(String name) { } - static public LibraryList getLibraries() { - return libraries; + static public List getLibraries() { + return libraries.getAll(); } diff --git a/app/src/processing/app/packages/LibraryList.java b/app/src/processing/app/packages/LibraryList.java index 343ff4bde6a..ad6ab9f14d0 100644 --- a/app/src/processing/app/packages/LibraryList.java +++ b/app/src/processing/app/packages/LibraryList.java @@ -2,24 +2,28 @@ import java.io.File; import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; import java.util.Collection; import java.util.Collections; import processing.app.helpers.FileUtils; @SuppressWarnings("serial") -public class LibraryList extends ArrayList { +public class LibraryList { + protected ArrayList subs; + protected ArrayList libs; + protected String name; - public LibraryList(LibraryList libs) { - super(libs); - } - - public LibraryList() { + public LibraryList(String name) { super(); + this.name = name; + this.subs = new ArrayList(); + this.libs = new ArrayList(); } public Library getByName(String name) { - for (Library l : this) + for (Library l : libs) if (l.getName().equals(name)) return l; return null; @@ -28,8 +32,8 @@ public Library getByName(String name) { public void addOrReplace(Library lib) { Library l = getByName(lib.getName()); if (l != null) - remove(l); - add(lib); + libs.remove(l); + libs.add(lib); } public void addOrReplaceAll(Collection c) { @@ -37,34 +41,62 @@ public void addOrReplaceAll(Collection c) { addOrReplace(l); } + public void addSub(LibraryList sub) { + subs.add(sub); + } + + public List getSubs() { + return subs; + } + + public List getLibs() { + return libs; + } + + public List getAll() { + ArrayList list = new ArrayList(); + + for (LibraryList sub : subs) + list.addAll(sub.getAll()); + + list.addAll(libs); + + return list; + } + public void sort() { - Collections.sort(this, Library.CASE_INSENSITIVE_ORDER); + Collections.sort(libs, Library.CASE_INSENSITIVE_ORDER); + Collections.sort(subs, LibraryList.CASE_INSENSITIVE_ORDER); } public Library search(String name, String arch) { - for (Library lib : this) { + for (Library lib : libs) { if (!lib.getName().equals(name)) continue; if (!lib.supportsArchitecture(arch)) continue; return lib; } + for (LibraryList sub : subs) { + Library lib = sub.search(name, arch); + if (lib != null) + return lib; + } return null; } - public LibraryList filterByArchitecture(String reqArch) { - LibraryList res = new LibraryList(); - for (Library lib : this) - if (lib.supportsArchitecture(reqArch)) - res.add(lib); - return res; + public static final Comparator CASE_INSENSITIVE_ORDER = new Comparator() { + @Override + public int compare(LibraryList o1, LibraryList o2) { + return o1.getName().compareToIgnoreCase(o2.getName()); + } + }; + + public String getName() { + return name; } - public LibraryList filterLibrariesInSubfolder(File subFolder) { - LibraryList res = new LibraryList(); - for (Library lib : this) - if (FileUtils.isSubDirectory(subFolder, lib.getFolder())) - res.add(lib); - return res; + public boolean isEmpty() { + return libs.isEmpty() && subs.isEmpty(); } } From e7f6fba6ecf64e7aaf60054dd0bb6b020919022d Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 4 Apr 2014 17:18:46 +0200 Subject: [PATCH 10/11] Make the library (examples) menu nested Previously, the library scanning code started supported subfolders inside the libraries folders. Now, the import library and library examples menus also reflect this nested structure. In addition to the on-disk nesting, this also shows a top-level structure (which was already added by the scanning code), dividing the libraries into "Libraries for all boards", "Libraries for Arduino AVR Boards" (or whatever core is being used) and "Libraries from your sketchbook". --- app/src/processing/app/Base.java | 36 +++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index a7ee2e42623..4855557bac3 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1312,14 +1312,31 @@ public void rebuildExamplesMenu(JMenu menu) { if (libraries != null && !libraries.isEmpty()) { if (found) menu.addSeparator(); - for (Library lib : getLibraries()) - addSketchesSubmenu(menu, lib, false); + addLibraryExamples(menu, libraries); } } catch (IOException e) { e.printStackTrace(); } } + protected void addLibraryExamples(JMenu menu, LibraryList libs) throws IOException { + // Add any subdirectories first + for (LibraryList sub : libs.getSubs()) { + if (sub.isEmpty()) + continue; + + JMenu submenu = new JMenu(sub.getName()); + addLibraryExamples(submenu, sub); + menu.add(submenu); + MenuScroller.setScrollerFor(submenu); + } + + // Then add the libraries directly in this folder + for (Library lib : libs.getLibs()) { + addSketchesSubmenu(menu, lib, false); + } + } + public void updateLibraries() throws IOException { // Calculate paths for libraries and examples examplesFolder = getContentFile("examples"); @@ -1803,7 +1820,18 @@ public void actionPerformed(ActionEvent e) { } protected void addLibraries(JMenu menu, LibraryList libs) throws IOException { - for (Library lib : libs.getAll()) { + // Add any subdirectories first + for (LibraryList sub : libs.getSubs()) { + if (sub.isEmpty()) + continue; + + JMenu submenu = new JMenu(sub.getName()); + addLibraries(submenu, sub); + menu.add(submenu); + MenuScroller.setScrollerFor(submenu); + } + // Then add the libraries directly in this folder + for (Library lib : libs.getLibs()) { @SuppressWarnings("serial") AbstractAction action = new AbstractAction(lib.getName()) { public void actionPerformed(ActionEvent event) { @@ -1821,8 +1849,6 @@ public void actionPerformed(ActionEvent event) { JMenuItem item = new JMenuItem(action); item.putClientProperty("library", lib); menu.add(item); - - // XXX: DAM: should recurse here so that library folders can be nested } } From 1abd31a8f1b2f3a165f86db3feee1277ea53c3d8 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 24 Apr 2014 21:56:21 +0200 Subject: [PATCH 11/11] Don't show the top-level library categories as submenus In the previous commit, the import library and example menus were made recursive. The top level submenus here were the different kinds of library (hardware-independent libraries, hardware-specific libraries and sketchbook libraries). With this commit, these different kinds of libraries are all put together at the top level, with (unselectable) headers in between (like the boards menu, which already head these headers for the different platforms). --- app/src/processing/app/Base.java | 38 +++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 4855557bac3..6545b6ed222 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1292,7 +1292,6 @@ public void actionPerformed(ActionEvent e) { importMenu.add(addLibraryMenuItem); if (libraries != null) { - importMenu.addSeparator(); try { addLibraries(importMenu, libraries); } catch (IOException e) { @@ -1307,12 +1306,28 @@ public void rebuildExamplesMenu(JMenu menu) { // Add examples from distribution "example" folder boolean found = addSketches(menu, examplesFolder, false); + if (found) { + // Prepend a label + JMenuItem label = new JMenuItem(_("Core examples")); + label.setEnabled(false); + menu.add(label, 0); + } // Add examples from libraries if (libraries != null && !libraries.isEmpty()) { - if (found) - menu.addSeparator(); - addLibraryExamples(menu, libraries); + for (LibraryList sub : libraries.getSubs()) { + if (found) + menu.addSeparator(); + + // Prepend a label + JMenuItem label = new JMenuItem(sub.getName()); + label.setEnabled(false); + menu.add(label); + + addLibraryExamples(menu, sub); + + found = true; + } } } catch (IOException e) { e.printStackTrace(); @@ -1820,13 +1835,26 @@ public void actionPerformed(ActionEvent e) { } protected void addLibraries(JMenu menu, LibraryList libs) throws IOException { + for (LibraryList sub : libs.getSubs()) { + menu.addSeparator(); + + // Prepend a label + JMenuItem label = new JMenuItem(sub.getName()); + label.setEnabled(false); + menu.add(label); + + addLibrariesRecursive(menu, sub); + } + } + + protected void addLibrariesRecursive(JMenu menu, LibraryList libs) throws IOException { // Add any subdirectories first for (LibraryList sub : libs.getSubs()) { if (sub.isEmpty()) continue; JMenu submenu = new JMenu(sub.getName()); - addLibraries(submenu, sub); + addLibrariesRecursive(submenu, sub); menu.add(submenu); MenuScroller.setScrollerFor(submenu); }