mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
trying to clear up the "Save As" progress frame and avoid bugs
This commit is contained in:
@@ -24,21 +24,25 @@
|
||||
package processing.app;
|
||||
|
||||
import processing.app.ui.Editor;
|
||||
import processing.app.ui.ProgressFrame;
|
||||
import processing.app.ui.Recent;
|
||||
import processing.app.ui.Toolkit;
|
||||
import processing.core.*;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.FileDialog;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
|
||||
/**
|
||||
@@ -792,7 +796,7 @@ public class Sketch {
|
||||
String newParentDir = null;
|
||||
String newName = null;
|
||||
|
||||
final String oldName2 = folder.getName();
|
||||
String oldName = folder.getName();
|
||||
// TODO rewrite this to use shared version from PApplet
|
||||
final String PROMPT = Language.text("save");
|
||||
if (Preferences.getBoolean("chooser.files.native")) {
|
||||
@@ -805,8 +809,8 @@ public class Sketch {
|
||||
// default to the parent folder of where this was
|
||||
fd.setDirectory(folder.getParent());
|
||||
}
|
||||
String oldName = folder.getName();
|
||||
fd.setFile(oldName);
|
||||
String oldFolderName = folder.getName();
|
||||
fd.setFile(oldFolderName);
|
||||
fd.setVisible(true);
|
||||
newParentDir = fd.getDirectory();
|
||||
newName = fd.getFile();
|
||||
@@ -868,7 +872,7 @@ public class Sketch {
|
||||
// just use "save" here instead, because the user will have received a
|
||||
// message (from the operating system) about "do you want to replace?"
|
||||
return save();
|
||||
}
|
||||
}
|
||||
|
||||
// check to see if the user is trying to save this sketch inside itself
|
||||
try {
|
||||
@@ -927,21 +931,21 @@ public class Sketch {
|
||||
}
|
||||
});
|
||||
|
||||
// Kick off a background thread to copy everything *but* the .pde files.
|
||||
// Due to the poor way (dating back to the late 90s with DBN) that our
|
||||
// save() and saveAs() methods have been implemented to return booleans,
|
||||
// there isn't a good way to return a value to the calling thread without
|
||||
// a good bit of refactoring (that should be done at some point).
|
||||
// As a result, this method will return 'true' before the full "Save As"
|
||||
// has completed, which will cause problems in weird cases.
|
||||
// For instance, saving an untitled sketch that has an enormous data
|
||||
// folder while quitting. The save thread to move those data folder files
|
||||
// won't have finished before this returns true, and the PDE may quit
|
||||
// before the SwingWorker completes its job.
|
||||
// https://github.com/processing/processing/issues/3843
|
||||
startSaveAsThread(oldName, newName, newFolder, copyItems);
|
||||
|
||||
final File newFolder2 = newFolder;
|
||||
final File[] copyItems2 = copyItems;
|
||||
final String newName2 = newName;
|
||||
|
||||
// Create a new event dispatch thread- to display ProgressBar
|
||||
// while Saving As
|
||||
javax.swing.SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new ProgressFrame(copyItems2, newFolder2, oldName2, newName2, editor);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// save the other tabs to their new location
|
||||
// save the other tabs to their new location (main tab saved below)
|
||||
for (int i = 1; i < codeCount; i++) {
|
||||
File newFile = new File(newFolder, code[i].getFileName());
|
||||
code[i].saveAs(newFile);
|
||||
@@ -971,6 +975,171 @@ public class Sketch {
|
||||
}
|
||||
|
||||
|
||||
void startSaveAsThread(final String oldName, final String newName,
|
||||
final File newFolder, final File[] copyItems) {
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
final JFrame frame = new JFrame("Saving \u201C" + newName + "\u201C...");
|
||||
// the UI of the progress bar follows
|
||||
frame.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
|
||||
// frame.setBounds(200, 200, 400, 140);
|
||||
// frame.setResizable(false);
|
||||
|
||||
Box box = Box.createVerticalBox();
|
||||
box.setBorder(new EmptyBorder(16, 16, 16, 16));
|
||||
// JPanel panel = new JPanel(null);
|
||||
// frame.add(panel);
|
||||
// frame.setContentPane(panel); // uh, both?
|
||||
|
||||
if (Platform.isMacOS()) {
|
||||
frame.setBackground(Color.WHITE);
|
||||
}
|
||||
|
||||
JLabel label = new JLabel("Saving additional files from the sketch folder...");
|
||||
// JLabel label = new JLabel("Saving " + oldName + " as " + newName + "...");
|
||||
// label.setBounds(40, 20, 300, 20);
|
||||
box.add(label);
|
||||
|
||||
final JProgressBar progressBar = new JProgressBar(0, 100);
|
||||
// no luck, stuck with ugly on OS X
|
||||
//progressBar.putClientProperty("JComponent.sizeVariant", "regular");
|
||||
progressBar.setValue(0);
|
||||
// progressBar.setBounds(40, 50, 300, 30);
|
||||
progressBar.setStringPainted(true);
|
||||
box.add(progressBar);
|
||||
|
||||
// panel.add(progressBar);
|
||||
// panel.add(label);
|
||||
|
||||
frame.getContentPane().add(box);
|
||||
frame.pack();
|
||||
frame.setLocationRelativeTo(editor);
|
||||
Toolkit.setIcon(frame);
|
||||
frame.setVisible(true);
|
||||
|
||||
new SwingWorker<Void, Void>() {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground() throws Exception {
|
||||
addPropertyChangeListener(new PropertyChangeListener() {
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if ("progress".equals(evt.getPropertyName())) {
|
||||
System.out.println(evt.getNewValue());
|
||||
progressBar.setValue((Integer) evt.getNewValue());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
long totalSize = 0;
|
||||
for (File copyable : copyItems) {
|
||||
totalSize += Util.calcSize(copyable);
|
||||
}
|
||||
|
||||
long progress = 0;
|
||||
setProgress(0);
|
||||
for (File copyable : copyItems) {
|
||||
if (copyable.isDirectory()) {
|
||||
copyDir(copyable,
|
||||
new File(newFolder, copyable.getName()),
|
||||
progress, totalSize);
|
||||
progress += Util.calcSize(copyable);
|
||||
} else {
|
||||
copyFile(copyable,
|
||||
new File(newFolder, copyable.getName()),
|
||||
progress, totalSize);
|
||||
if (Util.calcSize(copyable) < 512 * 1024) {
|
||||
// If the file length > 0.5MB, the copyFile() function has
|
||||
// been redesigned to change progress every 0.5MB so that
|
||||
// the progress bar doesn't stagnate during that time
|
||||
progress += Util.calcSize(copyable);
|
||||
setProgress((int) (progress * 100L / totalSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overloaded copyFile that is called whenever a Save As is being done,
|
||||
* so that the ProgressBar is updated for very large files as well.
|
||||
*/
|
||||
void copyFile(File sourceFile, File targetFile,
|
||||
long progress, long totalSize) throws IOException {
|
||||
BufferedInputStream from =
|
||||
new BufferedInputStream(new FileInputStream(sourceFile));
|
||||
BufferedOutputStream to =
|
||||
new BufferedOutputStream(new FileOutputStream(targetFile));
|
||||
byte[] buffer = new byte[16 * 1024];
|
||||
int bytesRead;
|
||||
int progRead = 0;
|
||||
while ((bytesRead = from.read(buffer)) != -1) {
|
||||
to.write(buffer, 0, bytesRead);
|
||||
progRead += bytesRead;
|
||||
if (progRead >= 512 * 1024) { // to update progress bar every 0.5MB
|
||||
progress += progRead;
|
||||
//progressBar.setValue((int) Math.min(Math.ceil(progress * 100.0 / totalSize), 100));
|
||||
setProgress((int) (100L * progress / totalSize));
|
||||
progRead = 0;
|
||||
}
|
||||
}
|
||||
// Final update to progress bar
|
||||
setProgress((int) (100L * progress / totalSize));
|
||||
|
||||
from.close();
|
||||
from = null;
|
||||
to.flush();
|
||||
to.close();
|
||||
to = null;
|
||||
|
||||
targetFile.setLastModified(sourceFile.lastModified());
|
||||
targetFile.setExecutable(sourceFile.canExecute());
|
||||
}
|
||||
|
||||
|
||||
long copyDir(File sourceDir, File targetDir,
|
||||
long progress, long totalSize) throws IOException {
|
||||
// Overloaded copyDir so that the Save As progress bar gets updated when the
|
||||
// files are in folders as well (like in the data folder)
|
||||
if (sourceDir.equals(targetDir)) {
|
||||
final String urDum = "source and target directories are identical";
|
||||
throw new IllegalArgumentException(urDum);
|
||||
}
|
||||
targetDir.mkdirs();
|
||||
String files[] = sourceDir.list();
|
||||
for (String filename : files) {
|
||||
// Ignore dot files (.DS_Store), dot folders (.svn) while copying
|
||||
if (filename.charAt(0) == '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
File source = new File(sourceDir, filename);
|
||||
File target = new File(targetDir, filename);
|
||||
if (source.isDirectory()) {
|
||||
progress = copyDir(source, target, progress, totalSize);
|
||||
//progressBar.setValue((int) Math.min(Math.ceil(progress * 100.0 / totalSize), 100));
|
||||
setProgress((int) (100L * progress / totalSize));
|
||||
target.setLastModified(source.lastModified());
|
||||
} else {
|
||||
copyFile(source, target, progress, totalSize);
|
||||
progress += source.length();
|
||||
//progressBar.setValue((int) Math.min(Math.ceil(progress * 100.0 / totalSize), 100));
|
||||
setProgress((int) (100L * progress / totalSize));
|
||||
}
|
||||
}
|
||||
return progress;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void done() {
|
||||
frame.dispose();
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update internal state for new sketch name or folder location.
|
||||
|
||||
@@ -340,12 +340,22 @@ public class Util {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to return the length of the file, or entire directory, including
|
||||
* the component files and sub-folders if passed.
|
||||
* @param file The file or folder to calculate
|
||||
*/
|
||||
static public long calcSize(File file) {
|
||||
return file.isFile() ? file.length() : Util.calcFolderSize(file);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the size of the contents of a folder.
|
||||
* Used to determine whether sketches are empty or not.
|
||||
* Note that the function calls itself recursively.
|
||||
*/
|
||||
static public int calcFolderSize(File folder) {
|
||||
static public long calcFolderSize(File folder) {
|
||||
int size = 0;
|
||||
|
||||
String files[] = folder.list();
|
||||
|
||||
@@ -2540,6 +2540,29 @@ public abstract class Editor extends JFrame implements RunnerListener {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public void handleSaveAs() {
|
||||
statusNotice(Language.text("editor.status.saving"));
|
||||
sketch.saveAs();
|
||||
}
|
||||
|
||||
|
||||
public void handleSaveAsSuccess() {
|
||||
statusNotice(Language.text("editor.status.saving.done"));
|
||||
}
|
||||
|
||||
|
||||
public void handleSaveAsCanceled() {
|
||||
statusNotice(Language.text("editor.status.saving.canceled"));
|
||||
}
|
||||
|
||||
|
||||
public void handleSaveAsError(Exception e) {
|
||||
statusError(e);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Handler for File → Page Setup.
|
||||
*/
|
||||
|
||||
@@ -15,9 +15,6 @@ import javax.swing.JPanel;
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import processing.app.Language;
|
||||
import processing.app.Util;
|
||||
|
||||
|
||||
// TODO This code was contributed and needs a lot of work. [fry]
|
||||
// + It probably shouldn't a "Frame" object at all.
|
||||
@@ -33,137 +30,7 @@ import processing.app.Util;
|
||||
public class ProgressFrame extends JFrame implements PropertyChangeListener {
|
||||
private JProgressBar progressBar;
|
||||
private JLabel label;
|
||||
private File[] copyItems;
|
||||
private File newFolder;
|
||||
private File addFile, sourceFile;
|
||||
private Editor editor;
|
||||
|
||||
|
||||
/** Create a new background thread to Save As */
|
||||
public class TaskSaveAs extends SwingWorker<Void, Void> {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground() throws Exception {
|
||||
// a large part of the file copying happens in this background
|
||||
// thread
|
||||
|
||||
long totalSize = 0;
|
||||
for (File copyable : copyItems) {
|
||||
totalSize += calcSize(copyable);
|
||||
}
|
||||
|
||||
long progress = 0;
|
||||
setProgress(0);
|
||||
for (File copyable : ProgressFrame.this.copyItems) {
|
||||
// loop to copy over the items that make sense, and to set the
|
||||
// current progress
|
||||
|
||||
if (copyable.isDirectory()) {
|
||||
copyDir(copyable,
|
||||
new File(ProgressFrame.this.newFolder, copyable.getName()),
|
||||
progress, totalSize);
|
||||
progress += calcSize(copyable);
|
||||
} else {
|
||||
copyFile(copyable,
|
||||
new File(ProgressFrame.this.newFolder, copyable.getName()),
|
||||
progress, totalSize);
|
||||
if (calcSize(copyable) < 524288) {
|
||||
// If the file length > 0.5MB, the copyFile() function has
|
||||
// been redesigned to change progress every 0.5MB so that
|
||||
// the progress bar doesn't stagnate during that time
|
||||
progress += calcSize(copyable);
|
||||
setProgress((int) (progress * 100L / totalSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overloaded copyFile that is called whenever a Save As is being done,
|
||||
* so that the ProgressBar is updated for very large files as well.
|
||||
*/
|
||||
private void copyFile(File sourceFile, File targetFile,
|
||||
double progress, long totalSize) throws IOException {
|
||||
BufferedInputStream from = new BufferedInputStream(new FileInputStream(sourceFile));
|
||||
BufferedOutputStream to = new BufferedOutputStream(new FileOutputStream(targetFile));
|
||||
byte[] buffer = new byte[16 * 1024];
|
||||
int bytesRead;
|
||||
int totalRead = 0;
|
||||
while ((bytesRead = from.read(buffer)) != -1) {
|
||||
to.write(buffer, 0, bytesRead);
|
||||
totalRead += bytesRead;
|
||||
if (totalRead >= 512 * 1024) { // to update progress bar every 0.5MB
|
||||
progress += totalRead;
|
||||
setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0 / totalSize), 100));
|
||||
totalRead = 0;
|
||||
}
|
||||
}
|
||||
if (sourceFile.length() > 512 * 1024) {
|
||||
// Update the progress bar one final time if file size is more than 0.5MB,
|
||||
// otherwise, the update is handled either by the copyDir function,
|
||||
// or directly by ProgressFrame.TaskSaveAs.doInBackground()
|
||||
progress += totalRead;
|
||||
setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0 / totalSize), 100));
|
||||
}
|
||||
from.close();
|
||||
from = null;
|
||||
to.flush();
|
||||
to.close();
|
||||
to = null;
|
||||
|
||||
targetFile.setLastModified(sourceFile.lastModified());
|
||||
targetFile.setExecutable(sourceFile.canExecute());
|
||||
}
|
||||
|
||||
|
||||
private double copyDir(File sourceDir, File targetDir,
|
||||
double progress, long totalSize) throws IOException {
|
||||
// Overloaded copyDir so that the Save As progress bar gets updated when the
|
||||
// files are in folders as well (like in the data folder)
|
||||
if (sourceDir.equals(targetDir)) {
|
||||
final String urDum = "source and target directories are identical";
|
||||
throw new IllegalArgumentException(urDum);
|
||||
}
|
||||
targetDir.mkdirs();
|
||||
String files[] = sourceDir.list();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
// Ignore dot files (.DS_Store), dot folders (.svn) while copying
|
||||
if (files[i].charAt(0) == '.')
|
||||
continue;
|
||||
//if (files[i].equals(".") || files[i].equals("..")) continue;
|
||||
File source = new File(sourceDir, files[i]);
|
||||
File target = new File(targetDir, files[i]);
|
||||
if (source.isDirectory()) {
|
||||
//target.mkdirs();
|
||||
progress = copyDir(source, target, progress, totalSize);
|
||||
setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0 / totalSize), 100));
|
||||
target.setLastModified(source.lastModified());
|
||||
} else {
|
||||
copyFile(source, target, progress, totalSize);
|
||||
// Update SaveAs progress bar
|
||||
progress += source.length();
|
||||
setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0 / totalSize), 100));
|
||||
}
|
||||
}
|
||||
return progress;
|
||||
}
|
||||
|
||||
|
||||
public void setProgressBarStatus(int status) {
|
||||
setProgress(status);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void done() {
|
||||
// to close the progress bar automatically when done, and to
|
||||
// print that Saving is done in Message Area
|
||||
editor.statusNotice(Language.text("editor.status.saving.done"));
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Create a new background thread to add a file. */
|
||||
@@ -245,49 +112,10 @@ public class ProgressFrame extends JFrame implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
|
||||
/** Use for Save As */
|
||||
public ProgressFrame(File[] c, File nf, String oldName, String newName,
|
||||
Editor editor) {
|
||||
// initialize a copyItems and newFolder, which are used for file
|
||||
// copying in the background thread
|
||||
copyItems = c;
|
||||
newFolder = nf;
|
||||
this.editor = editor;
|
||||
|
||||
// the UI of the progress bar follows
|
||||
setDefaultCloseOperation(HIDE_ON_CLOSE);
|
||||
setBounds(200, 200, 400, 140);
|
||||
setResizable(false);
|
||||
setTitle("Saving As...");
|
||||
JPanel panel = new JPanel(null);
|
||||
add(panel);
|
||||
setContentPane(panel);
|
||||
label = new JLabel("Saving " + oldName + " as " + newName + "...");
|
||||
label.setBounds(40, 20, 300, 20);
|
||||
|
||||
progressBar = new JProgressBar(0, 100);
|
||||
progressBar.setValue(0);
|
||||
progressBar.setBounds(40, 50, 300, 30);
|
||||
progressBar.setStringPainted(true);
|
||||
|
||||
panel.add(progressBar);
|
||||
panel.add(label);
|
||||
Toolkit.setIcon(this);
|
||||
this.setVisible(true);
|
||||
|
||||
// create an instance of TaskSaveAs and run execute() on this
|
||||
// instance to start background thread
|
||||
TaskSaveAs t = new TaskSaveAs();
|
||||
t.addPropertyChangeListener(this);
|
||||
t.execute();
|
||||
}
|
||||
|
||||
|
||||
/** Used for Add File */
|
||||
public ProgressFrame(File sf, File add, Editor editor) {
|
||||
addFile = add;
|
||||
sourceFile = sf;
|
||||
this.editor = editor;
|
||||
|
||||
// the UI of the progress bar follows
|
||||
setDefaultCloseOperation(HIDE_ON_CLOSE);
|
||||
@@ -319,15 +147,6 @@ public class ProgressFrame extends JFrame implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to return the length of the file, or entire directory, including
|
||||
* the component files and sub-folders if passed.
|
||||
*/
|
||||
long calcSize(File file) {
|
||||
return file.isFile() ? file.length() : Util.calcFolderSize(file);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detects a change in the property of the background task,
|
||||
* i.e., is called when the size of files already copied changes.
|
||||
|
||||
@@ -1730,39 +1730,6 @@ public class JavaEditor extends Editor {
|
||||
|
||||
@Override
|
||||
public boolean handleSave(boolean immediately) {
|
||||
//System.out.println("handleSave " + immediately);
|
||||
|
||||
//log("handleSave, viewing autosave? " + viewingAutosaveBackup);
|
||||
/* If user wants to save a backup, the backup sketch should get
|
||||
* copied to the main sketch directory, simply reload the main sketch.
|
||||
*/
|
||||
if(viewingAutosaveBackup){
|
||||
/*
|
||||
File files[] = autosaver.getSketchBackupFolder().listFiles();
|
||||
File src = autosaver.getSketchBackupFolder(), dst = autosaver
|
||||
.getActualSketchFolder();
|
||||
for (File f : files) {
|
||||
log("Copying " + f.getAbsolutePath() + " to " + dst.getAbsolutePath());
|
||||
try {
|
||||
if (f.isFile()) {
|
||||
f.delete();
|
||||
Base.copyFile(f, new File(dst + File.separator + f.getName()));
|
||||
} else {
|
||||
Base.removeDir(f);
|
||||
Base.copyDir(f, new File(dst + File.separator + f.getName()));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
File sk = autosaver.getActualSketchFolder();
|
||||
Base.removeDir(autosaver.getAutoSaveDir());
|
||||
//handleOpenInternal(sk.getAbsolutePath() + File.separator + sk.getName() + ".pde");
|
||||
getBase().handleOpen(sk.getAbsolutePath() + File.separator + sk.getName() + ".pde");
|
||||
//viewingAutosaveBackup = false;
|
||||
*/
|
||||
}
|
||||
|
||||
// note modified tabs
|
||||
final List<String> modified = new ArrayList<String>();
|
||||
for (int i = 0; i < getSketch().getCodeCount(); i++) {
|
||||
@@ -1795,9 +1762,6 @@ public class JavaEditor extends Editor {
|
||||
}
|
||||
|
||||
|
||||
private boolean viewingAutosaveBackup;
|
||||
|
||||
|
||||
/**
|
||||
* Set text contents of a specific tab. Updates underlying document and text
|
||||
* area. Clears Breakpoints.
|
||||
|
||||
@@ -73,10 +73,11 @@ X https://github.com/processing/processing/issues/3806
|
||||
X https://github.com/processing/processing/pull/3817
|
||||
X CM list should be sortable by status and author name
|
||||
X https://github.com/processing/processing/issues/3608
|
||||
X "update all" button appears to do nothing in library manager
|
||||
X https://github.com/processing/processing/issues/3837
|
||||
X https://github.com/processing/processing/pull/3842
|
||||
_ All contributions listed after install button is clicked
|
||||
_ https://github.com/processing/processing/issues/3826
|
||||
_ "update all" button appears to do nothing in library manager
|
||||
_ https://github.com/processing/processing/issues/3837
|
||||
|
||||
jakub
|
||||
X Make preprocessor scope-aware
|
||||
@@ -232,7 +233,8 @@ _ pass through the source to update licenses
|
||||
_ add Processing Foundation as 2012-15
|
||||
_ update license info to state gplv2 not v3
|
||||
_ run through that online license checker
|
||||
|
||||
_ save() and saveAs() need to be refactored
|
||||
_ https://github.com/processing/processing/issues/3843
|
||||
|
||||
|
||||
breakage
|
||||
@@ -962,6 +964,8 @@ _ this may already work with SingleInstance stuff
|
||||
DIST / Mac OS X
|
||||
|
||||
|
||||
_ client properties
|
||||
_ https://developer.apple.com/library/mac/technotes/tn2007/tn2196.html
|
||||
_ built-in images: http://nadeausoftware.com/articles/2008/12/mac_java_tip_how_access_mac_specific_nsimage_icons
|
||||
_ replace appbundler with the Java 8 packager
|
||||
_ https://github.com/processing/processing/issues/3071
|
||||
|
||||
Reference in New Issue
Block a user