Skip to content

Commit 05a2d77

Browse files
committed
Merge remote-tracking branch 'origin/master' into merge-1.0.1
2 parents e6d5255 + a21c4e1 commit 05a2d77

File tree

25 files changed

+225
-144
lines changed

25 files changed

+225
-144
lines changed

app/src/processing/app/Base.java

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2596,24 +2596,43 @@ static protected void listFiles(String basePath,
25962596
}
25972597
}
25982598

2599+
public void handleAddLibrary(Editor editor) {
2600+
JFileChooser fileChooser = new JFileChooser(System.getProperty("user.home"));
2601+
fileChooser.setDialogTitle(_("Select a zip file or a folder containing the library you'd like to add"));
2602+
fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
25992603

2600-
public void handleAddZipLibrary(Editor editor) {
2601-
String prompt = _("Select a zip file containing the library you'd like to add");
2602-
FileDialog fd = new FileDialog(editor, prompt, FileDialog.LOAD);
2603-
fd.setDirectory(System.getProperty("user.home"));
2604-
fd.setVisible(true);
2604+
Dimension preferredSize = fileChooser.getPreferredSize();
2605+
fileChooser.setPreferredSize(new Dimension(preferredSize.width + 200, preferredSize.height + 200));
2606+
2607+
int returnVal = fileChooser.showOpenDialog(editor);
26052608

2606-
String directory = fd.getDirectory();
2607-
String filename = fd.getFile();
2608-
if (filename == null) return;
2609+
if (returnVal != JFileChooser.APPROVE_OPTION) {
2610+
return;
2611+
}
26092612

2610-
File sourceFile = new File(directory, filename);
2611-
try {
2612-
ZipDeflater zipDeflater = new ZipDeflater(sourceFile, getSketchbookLibrariesFolder());
2613-
zipDeflater.deflate();
2614-
editor.statusNotice(_("Library added to your libraries. Check \"Import library\" menu"));
2615-
} catch (IOException e) {
2616-
editor.statusError(e);
2613+
File sourceFile = fileChooser.getSelectedFile();
2614+
2615+
if (sourceFile.isDirectory()) {
2616+
File destinationFolder = new File(getSketchbookLibrariesFolder(), sourceFile.getName());
2617+
if (!destinationFolder.mkdir()) {
2618+
editor.statusError("Can't create folder: " + sourceFile.getName() + " into libraries folder");
2619+
return;
2620+
}
2621+
try {
2622+
FileUtils.copy(sourceFile, destinationFolder);
2623+
} catch (IOException e) {
2624+
editor.statusError(e);
2625+
return;
2626+
}
2627+
} else {
2628+
try {
2629+
ZipDeflater zipDeflater = new ZipDeflater(sourceFile, getSketchbookLibrariesFolder());
2630+
zipDeflater.deflate();
2631+
} catch (IOException e) {
2632+
editor.statusError(e);
2633+
return;
2634+
}
26172635
}
2636+
editor.statusNotice(_("Library added to your libraries. Check \"Import library\" menu"));
26182637
}
26192638
}

app/src/processing/app/Editor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -634,10 +634,10 @@ public void actionPerformed(ActionEvent e) {
634634
}
635635
sketchMenu.add(importMenu);
636636

637-
item = new JMenuItem(_("Add Library from ZIP"));
637+
item = new JMenuItem(_("Add Library..."));
638638
item.addActionListener(new ActionListener() {
639639
public void actionPerformed(ActionEvent e) {
640-
base.handleAddZipLibrary(Editor.this);
640+
base.handleAddLibrary(Editor.this);
641641
base.onBoardOrPortChange();
642642
base.rebuildImportMenu(Editor.importMenu);
643643
}
@@ -693,7 +693,7 @@ public void actionPerformed(ActionEvent e) {
693693

694694
if (boardsMenu == null) {
695695
boardsMenu = new JMenu(_("Board"));
696-
cpuTypeMenu = new JMenu(_("CPUType"));
696+
cpuTypeMenu = new JMenu(_("Processor"));
697697
base.rebuildBoardsMenu(boardsMenu, cpuTypeMenu);
698698
//Debug: rebuild imports
699699
importMenu.removeAll();

app/src/processing/app/helpers/FileUtils.java

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package processing.app.helpers;
22

33
import java.io.File;
4+
import java.io.FileInputStream;
5+
import java.io.FileOutputStream;
46
import java.io.IOException;
57

68
public class FileUtils {
7-
9+
810
/**
9-
* Checks, whether the child directory is a subdirectory of the base
10-
* directory.
11+
* Checks, whether the child directory is a subdirectory of the base directory.
1112
*
1213
* @param base
1314
* the base directory.
@@ -32,4 +33,49 @@ public static boolean isSubDirectory(File base, File child) {
3233
}
3334
return false;
3435
}
36+
37+
public static void copy(File sourceFolder, File destFolder) throws IOException {
38+
for (File file : sourceFolder.listFiles()) {
39+
File destFile = new File(destFolder, file.getName());
40+
if (file.isDirectory()) {
41+
if (!destFile.mkdir()) {
42+
throw new IOException("Unable to create folder: " + destFile);
43+
}
44+
copy(file, destFile);
45+
} else {
46+
FileInputStream fis = null;
47+
FileOutputStream fos = null;
48+
try {
49+
fis = new FileInputStream(file);
50+
fos = new FileOutputStream(destFile);
51+
byte[] buf = new byte[4096];
52+
int readBytes = -1;
53+
while ((readBytes = fis.read(buf, 0, buf.length)) != -1) {
54+
fos.write(buf, 0, readBytes);
55+
}
56+
} finally {
57+
if (fis != null) {
58+
fis.close();
59+
}
60+
if (fos != null) {
61+
fos.close();
62+
}
63+
}
64+
}
65+
}
66+
}
67+
68+
public static void recursiveDelete(File file) {
69+
if (file.isDirectory()) {
70+
for (File current : file.listFiles()) {
71+
if (current.isDirectory()) {
72+
recursiveDelete(current);
73+
} else {
74+
current.delete();
75+
}
76+
}
77+
}
78+
file.delete();
79+
}
80+
3581
}

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

Lines changed: 38 additions & 23 deletions
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
}

app/test/Keypad_mac.zip

16.9 KB
Binary file not shown.

app/test/Keypad_with_hidden_files.zip

11.9 KB
Binary file not shown.

app/test/processing/app/tools/ZipDeflaterTest.java

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import org.junit.Before;
1111
import org.junit.Test;
1212

13-
import processing.app.tools.ZipDeflater;
13+
import processing.app.helpers.FileUtils;
1414

1515
public class ZipDeflaterTest {
1616

@@ -62,20 +62,50 @@ public void shouldDeflateZipAndMoveContentsToParentFolder() throws Exception {
6262
assertEquals("readme.txt", files[4]);
6363
}
6464

65-
@After
66-
public void deleteTempFolder() {
67-
recursiveDelete(destFolder);
65+
@Test
66+
public void shouldDeflateMacZip() throws Exception {
67+
File file = new File(ZipDeflater.class.getResource("/Keypad_mac.zip").getFile());
68+
new ZipDeflater(file, destFolder).deflate();
69+
70+
String[] files = destFolder.list();
71+
assertEquals(1, files.length);
72+
assertEquals("Keypad", files[0]);
73+
74+
file = destFolder.listFiles()[0];
75+
files = file.list();
76+
assertEquals(4, files.length);
77+
Arrays.sort(files);
78+
assertEquals("Keypad.cpp", files[0]);
79+
assertEquals("Keypad.h", files[1]);
80+
assertEquals("examples", files[2]);
81+
assertEquals("keywords.txt", files[3]);
82+
83+
files = new File(file, "examples").list();
84+
assertEquals(4, files.length);
85+
Arrays.sort(files);
86+
assertEquals("CustomKeypad", files[0]);
87+
assertEquals("DynamicKeypad", files[1]);
88+
assertEquals("EventKeypad", files[2]);
89+
assertEquals("HelloKeypad", files[3]);
6890
}
6991

70-
private void recursiveDelete(File folder) {
71-
for (File file : folder.listFiles()) {
72-
if (file.isDirectory()) {
73-
recursiveDelete(file);
74-
} else {
75-
file.delete();
76-
}
77-
}
78-
folder.delete();
92+
@Test
93+
public void shouldDeleteHiddenFiles() throws Exception {
94+
File file = new File(ZipDeflater.class.getResource("/Keypad_with_hidden_files.zip").getFile());
95+
new ZipDeflater(file, destFolder).deflate();
96+
97+
String[] files = destFolder.list();
98+
assertEquals(1, files.length);
99+
assertEquals("Keypad_with_hidden_files", files[0]);
100+
101+
file = destFolder.listFiles()[0];
102+
files = file.list();
103+
assertEquals(4, files.length);
104+
}
105+
106+
@After
107+
public void deleteTempFolder() {
108+
FileUtils.recursiveDelete(destFolder);
79109
}
80110

81111
}

build/shared/examples/08.Strings/StringAppendOperator/StringAppendOperator.ino

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
1212
This example code is in the public domain.
1313
*/
14+
1415
String stringOne, stringTwo;
1516

1617
void setup() {

build/shared/examples/08.Strings/StringLength/StringLength.ino

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
1212
This example code is in the public domain.
1313
*/
14+
1415
String txtMsg = ""; // a string for incoming text
1516
int lastStringLength = txtMsg.length(); // previous length of the String
1617

hardware/arduino/avr/libraries/Ethernet/examples/CosmClient/CosmClient.ino

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,11 @@ EthernetClient client;
4949
//IPAddress server(216,52,233,121); // numeric IP for api.cosm.com
5050
char server[] = "api.cosm.com"; // name address for cosm API
5151

52-
unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
53-
boolean lastConnected = false; // state of the connection last time through the main loop
54-
const unsigned long postingInterval = 10*1000; //delay between updates to cosm.com
52+
unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
53+
boolean lastConnected = false; // state of the connection last time through the main loop
54+
const unsigned long postingInterval = 10L*1000L; // delay between updates to cosm.com
55+
// the "L" is needed to use long type numbers
56+
5557

5658
void setup() {
5759
// start serial port:

hardware/arduino/avr/libraries/Ethernet/examples/CosmClientString/CosmClientString.ino

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ EthernetClient client;
5151
//IPAddress server(216,52,233,121); // numeric IP for api.cosm.com
5252
char server[] = "api.cosm.com"; // name address for Cosm API
5353

54-
unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
55-
boolean lastConnected = false; // state of the connection last time through the main loop
56-
const unsigned long postingInterval = 10*1000; //delay between updates to Cosm.com
57-
54+
unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
55+
boolean lastConnected = false; // state of the connection last time through the main loop
56+
const unsigned long postingInterval = 10L*1000L; // delay between updates to Cosm.com
57+
// the "L" is needed to use long type numbers
5858
void setup() {
5959
// start serial port:
6060
Serial.begin(9600);

hardware/arduino/avr/libraries/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ EthernetClient client;
3939

4040
char server[] = "www.arduino.cc";
4141

42-
unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
43-
boolean lastConnected = false; // state of the connection last time through the main loop
44-
const unsigned long postingInterval = 60*1000; // delay between updates, in milliseconds
42+
unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
43+
boolean lastConnected = false; // state of the connection last time through the main loop
44+
const unsigned long postingInterval = 60L*1000L; // delay between updates, in milliseconds
45+
// the "L" is needed to use long type numbers
4546

4647
void setup() {
4748
// start serial port:

0 commit comments

Comments
 (0)