Skip to content

Commit bd24067

Browse files
committed
Merge branch 'master' of github.com:arduino/Arduino
2 parents 2387046 + 296bdac commit bd24067

File tree

6 files changed

+247
-41
lines changed

6 files changed

+247
-41
lines changed

app/src/processing/app/Base.java

+64-14
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@
2828
import java.util.*;
2929

3030
import javax.swing.*;
31+
import javax.swing.filechooser.FileNameExtensionFilter;
3132

3233
import processing.app.debug.Compiler;
3334
import processing.app.debug.Target;
35+
import processing.app.helpers.FileUtils;
36+
import processing.app.helpers.filefilters.OnlyDirs;
3437
import processing.app.tools.ZipDeflater;
3538
import processing.core.*;
3639
import static processing.app.I18n._;
@@ -949,9 +952,10 @@ public void rebuildImportMenu(JMenu importMenu, final Editor editor) {
949952
JMenuItem addLibraryMenuItem = new JMenuItem(_("Add Library..."));
950953
addLibraryMenuItem.addActionListener(new ActionListener() {
951954
public void actionPerformed(ActionEvent e) {
952-
Base.this.handleAddZipLibrary(editor);
955+
Base.this.handleAddLibrary(editor);
953956
Base.this.onBoardOrPortChange();
954957
Base.this.rebuildImportMenu(Editor.importMenu, editor);
958+
Base.this.rebuildExamplesMenu(Editor.examplesMenu);
955959
}
956960
});
957961
importMenu.add(addLibraryMenuItem);
@@ -2374,24 +2378,70 @@ static protected void listFiles(String basePath,
23742378
}
23752379
}
23762380

2381+
public void handleAddLibrary(Editor editor) {
2382+
JFileChooser fileChooser = new JFileChooser(System.getProperty("user.home"));
2383+
fileChooser.setDialogTitle(_("Select a zip file or a folder containing the library you'd like to add"));
2384+
fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
2385+
fileChooser.setFileFilter(new FileNameExtensionFilter(_("ZIP files or folders"), "zip"));
23772386

2378-
public void handleAddZipLibrary(Editor editor) {
2379-
String prompt = _("Select a zip file containing the library you'd like to add");
2380-
FileDialog fd = new FileDialog(editor, prompt, FileDialog.LOAD);
2381-
fd.setDirectory(System.getProperty("user.home"));
2382-
fd.setVisible(true);
2387+
Dimension preferredSize = fileChooser.getPreferredSize();
2388+
fileChooser.setPreferredSize(new Dimension(preferredSize.width + 200, preferredSize.height + 200));
23832389

2384-
String directory = fd.getDirectory();
2385-
String filename = fd.getFile();
2386-
if (filename == null) return;
2390+
int returnVal = fileChooser.showOpenDialog(editor);
2391+
2392+
if (returnVal != JFileChooser.APPROVE_OPTION) {
2393+
return;
2394+
}
2395+
2396+
File sourceFile = fileChooser.getSelectedFile();
2397+
File tmpFolder = null;
23872398

2388-
File sourceFile = new File(directory, filename);
23892399
try {
2390-
ZipDeflater zipDeflater = new ZipDeflater(sourceFile, getSketchbookLibrariesFolder());
2391-
zipDeflater.deflate();
2400+
// unpack ZIP
2401+
if (!sourceFile.isDirectory()) {
2402+
try {
2403+
tmpFolder = FileUtils.createTempFolder();
2404+
ZipDeflater zipDeflater = new ZipDeflater(sourceFile, tmpFolder);
2405+
zipDeflater.deflate();
2406+
File[] foldersInTmpFolder = tmpFolder.listFiles(new OnlyDirs());
2407+
if (foldersInTmpFolder.length != 1) {
2408+
throw new IOException(_("Zip doesn't contain a library"));
2409+
}
2410+
sourceFile = foldersInTmpFolder[0];
2411+
} catch (IOException e) {
2412+
editor.statusError(e);
2413+
return;
2414+
}
2415+
}
2416+
2417+
// is there a valid library?
2418+
File libFolder = sourceFile;
2419+
String libName = libFolder.getName();
2420+
if (!Sketch.isSanitaryName(libName)) {
2421+
String mess = I18n.format(_("The library \"{0}\" cannot be used.\n"
2422+
+ "Library names must contain only basic letters and numbers.\n"
2423+
+ "(ASCII only and no spaces, and it cannot start with a number)"),
2424+
libName);
2425+
editor.statusError(mess);
2426+
return;
2427+
}
2428+
2429+
// copy folder
2430+
File destinationFolder = new File(getSketchbookLibrariesFolder(), sourceFile.getName());
2431+
if (!destinationFolder.mkdir()) {
2432+
editor.statusError(I18n.format(_("A library named {0} already exists"), sourceFile.getName()));
2433+
return;
2434+
}
2435+
try {
2436+
FileUtils.copy(sourceFile, destinationFolder);
2437+
} catch (IOException e) {
2438+
editor.statusError(e);
2439+
return;
2440+
}
23922441
editor.statusNotice(_("Library added to your libraries. Check \"Import library\" menu"));
2393-
} catch (IOException e) {
2394-
editor.statusError(e);
2442+
} finally {
2443+
// delete zip created temp folder, if exists
2444+
FileUtils.recursiveDelete(tmpFolder);
23952445
}
23962446
}
23972447
}

app/src/processing/app/Editor.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ public void windowActivated(WindowEvent e) {
177177
// re-add the sub-menus that are shared by all windows
178178
fileMenu.insert(sketchbookMenu, 2);
179179
fileMenu.insert(examplesMenu, 3);
180-
//sketchMenu.insert(importMenu, 4);
180+
sketchMenu.insert(importMenu, 4);
181181
toolsMenu.insert(boardsMenu, numTools);
182182
toolsMenu.insert(serialMenu, numTools + 1);
183183
}
@@ -188,7 +188,7 @@ public void windowDeactivated(WindowEvent e) {
188188
// System.err.println("deactivate"); // not coming through
189189
fileMenu.remove(sketchbookMenu);
190190
fileMenu.remove(examplesMenu);
191-
//sketchMenu.remove(importMenu);
191+
sketchMenu.remove(importMenu);
192192
toolsMenu.remove(boardsMenu);
193193
toolsMenu.remove(serialMenu);
194194
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package processing.app.helpers;
2+
3+
import java.io.File;
4+
import java.io.FileInputStream;
5+
import java.io.FileOutputStream;
6+
import java.io.IOException;
7+
import java.util.Random;
8+
9+
public class FileUtils {
10+
11+
/**
12+
* Checks, whether the child directory is a subdirectory of the base directory.
13+
*
14+
* @param base
15+
* the base directory.
16+
* @param child
17+
* the suspected child directory.
18+
* @return true, if the child is a subdirectory of the base directory.
19+
*/
20+
public static boolean isSubDirectory(File base, File child) {
21+
try {
22+
base = base.getCanonicalFile();
23+
child = child.getCanonicalFile();
24+
} catch (IOException e) {
25+
return false;
26+
}
27+
28+
File parentFile = child;
29+
while (parentFile != null) {
30+
if (base.equals(parentFile)) {
31+
return true;
32+
}
33+
parentFile = parentFile.getParentFile();
34+
}
35+
return false;
36+
}
37+
38+
public static void copy(File sourceFolder, File destFolder) throws IOException {
39+
for (File file : sourceFolder.listFiles()) {
40+
File destFile = new File(destFolder, file.getName());
41+
if (file.isDirectory()) {
42+
if (!destFile.mkdir()) {
43+
throw new IOException("Unable to create folder: " + destFile);
44+
}
45+
copy(file, destFile);
46+
} else {
47+
FileInputStream fis = null;
48+
FileOutputStream fos = null;
49+
try {
50+
fis = new FileInputStream(file);
51+
fos = new FileOutputStream(destFile);
52+
byte[] buf = new byte[4096];
53+
int readBytes = -1;
54+
while ((readBytes = fis.read(buf, 0, buf.length)) != -1) {
55+
fos.write(buf, 0, readBytes);
56+
}
57+
} finally {
58+
if (fis != null) {
59+
fis.close();
60+
}
61+
if (fos != null) {
62+
fos.close();
63+
}
64+
}
65+
}
66+
}
67+
}
68+
69+
public static void recursiveDelete(File file) {
70+
if (file == null) {
71+
return;
72+
}
73+
if (file.isDirectory()) {
74+
for (File current : file.listFiles()) {
75+
if (current.isDirectory()) {
76+
recursiveDelete(current);
77+
} else {
78+
current.delete();
79+
}
80+
}
81+
}
82+
file.delete();
83+
}
84+
85+
public static File createTempFolder() throws IOException {
86+
File tmpFolder = new File(System.getProperty("java.io.tmpdir"), "arduino_" + new Random().nextInt(1000000));
87+
if (!tmpFolder.mkdir()) {
88+
throw new IOException("Unable to create temp folder " + tmpFolder);
89+
}
90+
return tmpFolder;
91+
}
92+
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
OnlyDirs - FilenameFilter that accepts only directories (CVS, .svn,
3+
.DS_Store files are excluded as well)
4+
Part of the Arduino project - http://www.arduino.cc/
5+
6+
Copyright (c) 2011 Cristian Maglie
7+
8+
This program is free software; you can redistribute it and/or modify
9+
it under the terms of the GNU General Public License as published by
10+
the Free Software Foundation; either version 2 of the License, or
11+
(at your option) any later version.
12+
13+
This program is distributed in the hope that it will be useful,
14+
but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
GNU General Public License for more details.
17+
18+
You should have received a copy of the GNU General Public License
19+
along with this program; if not, write to the Free Software Foundation,
20+
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21+
*/
22+
package processing.app.helpers.filefilters;
23+
24+
import java.io.File;
25+
import java.io.FilenameFilter;
26+
27+
/**
28+
* This filter accepts only directories (excluding .DS_Store files, .svn
29+
* folders, etc)
30+
*
31+
* @author Cristian Maglie
32+
*/
33+
public class OnlyDirs implements FilenameFilter {
34+
35+
public boolean accept(File dir, String name) {
36+
if (name.charAt(0) == '.')
37+
return false;
38+
if (name.equals("CVS"))
39+
return false;
40+
return new File(dir, name).isDirectory();
41+
}
42+
}

app/src/processing/app/tools/ZipDeflater.java

+38-23
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,36 @@
1010
import java.util.zip.ZipException;
1111
import java.util.zip.ZipFile;
1212

13+
import processing.app.helpers.FileUtils;
14+
1315
public class ZipDeflater {
1416

1517
private final ZipFile zipFile;
1618
private final File destFolder;
19+
private final Random random;
20+
private final File file;
1721

1822
public ZipDeflater(File file, File destFolder) throws ZipException, IOException {
23+
this.file = file;
1924
this.destFolder = destFolder;
2025
this.zipFile = new ZipFile(file);
26+
this.random = new Random();
2127
}
2228

2329
public void deflate() throws IOException {
24-
String folderName = tempFolderNameFromZip();
30+
String tmpFolderName = folderNameFromZip() + random.nextInt(1000000);
2531

26-
File folder = new File(destFolder, folderName);
32+
File tmpFolder = new File(destFolder, tmpFolderName);
2733

28-
if (!folder.mkdir()) {
29-
throw new IOException("Unable to create folder " + folderName);
34+
if (!tmpFolder.mkdir()) {
35+
throw new IOException("Unable to create folder " + tmpFolderName);
3036
}
3137

3238
Enumeration<? extends ZipEntry> entries = zipFile.entries();
3339
while (entries.hasMoreElements()) {
3440
ZipEntry entry = entries.nextElement();
35-
ensureFoldersOfEntryExist(folder, entry);
36-
File entryFile = new File(folder, entry.getName());
41+
ensureFoldersOfEntryExist(tmpFolder, entry);
42+
File entryFile = new File(tmpFolder, entry.getName());
3743
if (entry.isDirectory()) {
3844
entryFile.mkdir();
3945
} else {
@@ -58,8 +64,20 @@ public void deflate() throws IOException {
5864
}
5965
}
6066

61-
// Test.zip may or may not contain Test folder. We use zip name to create libraries folder. Therefore, a contained Test folder is useless and must be removed
62-
ensureOneLevelFolder(folder);
67+
deleteUndesiredFoldersAndFiles(tmpFolder);
68+
69+
// Test.zip may or may not contain Test folder. If it does, we keep it. If not, we use zip name.
70+
ensureOneLevelFolder(tmpFolder);
71+
}
72+
73+
private void deleteUndesiredFoldersAndFiles(File folder) {
74+
for (File file : folder.listFiles()) {
75+
if (file.isDirectory() && "__MACOSX".equals(file.getName())) {
76+
FileUtils.recursiveDelete(file);
77+
} else if (file.getName().startsWith(".")) {
78+
FileUtils.recursiveDelete(file);
79+
}
80+
}
6381
}
6482

6583
private void ensureFoldersOfEntryExist(File folder, ZipEntry entry) {
@@ -73,25 +91,22 @@ private void ensureFoldersOfEntryExist(File folder, ZipEntry entry) {
7391

7492
private void ensureOneLevelFolder(File folder) {
7593
File[] files = folder.listFiles();
76-
if (files.length == 1 && files[0].isDirectory()) {
77-
File tempFile = new File(files[0].getPath() + new Random().nextInt(1000));
78-
files[0].renameTo(tempFile);
79-
for (File file : tempFile.listFiles()) {
80-
file.renameTo(new File(folder, file.getName()));
81-
}
82-
tempFile.delete();
94+
95+
if (files.length != 1) {
96+
folder.renameTo(new File(folder.getParentFile(), folderNameFromZip()));
97+
return;
8398
}
99+
100+
files[0].renameTo(new File(folder.getParentFile(), files[0].getName()));
101+
FileUtils.recursiveDelete(folder);
84102
}
85103

86-
private String tempFolderNameFromZip() {
87-
String folderName = zipFile.getName();
88-
if (folderName.lastIndexOf(".") != -1) {
89-
folderName = folderName.substring(0, folderName.lastIndexOf("."));
90-
}
91-
if (folderName.lastIndexOf(File.separator) != -1) {
92-
folderName = folderName.substring(folderName.lastIndexOf(File.separator) + 1);
104+
private String folderNameFromZip() {
105+
String filename = file.getName();
106+
if (filename.lastIndexOf(".") != -1) {
107+
filename = filename.substring(0, filename.lastIndexOf("."));
93108
}
94-
return folderName;
109+
return filename;
95110
}
96111

97112
}

build/shared/revisions.txt

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,29 @@
11

2-
ARDUINO 1.0.5 - 2013.04.08
2+
ARDUINO 1.0.5 - 2013.05.15
33

44
[core]
55

66
* [avr] malloc bug: backported avr-libc 1.8.0 implementation
77
* [avr] removed deprecated interrupt handlers causing compiler issues
88
with newer avr-gcc.
9+
* [avr] added c_str() method to String
10+
* [avr] Stream "_timeout" field and related methods are now protected
911

1012
[libraries]
1113

1214
* Upgrades to WiFi library
15+
* Fixed a bunch of examples
1316

1417
[firmwares]
1518

1619
* Upgrades to WiFi firmwares
1720

1821
[ide]
1922

20-
* Backport from 1.5: install Library from file
23+
* Backport from 1.5: install Library from .zip file or folder
24+
* Added button "Copy error to clipboard" (Paul Stoffregen)
25+
* Updated windows drivers
26+
* Added Windows installer
2127

2228
ARDUINO 1.0.4 - 2013.03.11
2329

0 commit comments

Comments
 (0)