1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-02-13 07:54:20 +01:00
Matthijs Kooijman 85d48394a4 Merge Sketch.renameFileTo() into SketchFile.renameTo()
Now that SketchFile keeps a reference to its Sketch,
`SketchFile.renameTo()` can call `Sketch.checkNewFilename()`, so there
is no need for the renaming itself to go through Sketch.

This changes the parameter for `SketchFile.renameTo()` from File to
String, to enforce that only the filename is changed, not the directory
name.
2016-08-26 16:42:44 +02:00

336 lines
10 KiB
Java

package processing.app;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import processing.app.helpers.FileUtils;
import static processing.app.I18n.tr;
/**
* This represents a single sketch, consisting of one or more files.
*/
public class Sketch {
public static final String DEFAULT_SKETCH_EXTENSION = "ino";
public static final List<String> OLD_SKETCH_EXTENSIONS = Arrays.asList("pde");
public static final List<String> SKETCH_EXTENSIONS = Stream.concat(Stream.of(DEFAULT_SKETCH_EXTENSION), OLD_SKETCH_EXTENSIONS.stream()).collect(Collectors.toList());
public static final List<String> OTHER_ALLOWED_EXTENSIONS = Arrays.asList("c", "cpp", "h", "hh", "hpp", "s");
public static final List<String> EXTENSIONS = Stream.concat(SKETCH_EXTENSIONS.stream(), OTHER_ALLOWED_EXTENSIONS.stream()).collect(Collectors.toList());
/**
* folder that contains this sketch
*/
private File folder;
private List<SketchFile> files = new ArrayList<SketchFile>();
private static final Comparator<SketchFile> CODE_DOCS_COMPARATOR = new Comparator<SketchFile>() {
@Override
public int compare(SketchFile x, SketchFile y) {
if (x.isPrimary() && !y.isPrimary())
return -1;
if (y.isPrimary() && !x.isPrimary())
return 1;
return x.getFileName().compareTo(y.getFileName());
}
};
/**
* Create a new SketchData object, and looks at the sketch directory
* on disk to get populate the list of files in this sketch.
*
* @param file
* Any file inside the sketch directory.
*/
Sketch(File file) throws IOException {
folder = file.getParentFile();
files = listSketchFiles(true);
}
static public File checkSketchFile(File file) {
// check to make sure that this .pde file is
// in a folder of the same name
String fileName = file.getName();
File parent = file.getParentFile();
String parentName = parent.getName();
String pdeName = parentName + ".pde";
File altPdeFile = new File(parent, pdeName);
String inoName = parentName + ".ino";
File altInoFile = new File(parent, inoName);
if (pdeName.equals(fileName) || inoName.equals(fileName))
return file;
if (altPdeFile.exists())
return altPdeFile;
if (altInoFile.exists())
return altInoFile;
return null;
}
/**
* Reload the list of files. This checks the sketch directory on disk,
* to see if any files were added or removed. This does *not* check
* the contents of the files, just their presence.
*
* @return true when the list of files was changed, false when it was
* not.
*/
public boolean reload() throws IOException {
List<SketchFile> reloaded = listSketchFiles(false);
if (!reloaded.equals(files)) {
files = reloaded;
return true;
}
return false;
}
/**
* Scan this sketch's directory for files that should be loaded as
* part of this sketch. Doesn't modify this SketchData instance, just
* returns a filtered and sorted list of File objects ready to be
* passed to the SketchFile constructor.
*
* @param showWarnings
* When true, any invalid filenames will show a warning.
*/
private List<SketchFile> listSketchFiles(boolean showWarnings) throws IOException {
Set<SketchFile> result = new TreeSet<>(CODE_DOCS_COMPARATOR);
for (File file : FileUtils.listFiles(folder, false, EXTENSIONS)) {
if (BaseNoGui.isSanitaryName(file.getName())) {
FileUtils.SplitFile split = FileUtils.splitFilename(file);
boolean isPrimary = split.basename.equals(folder.getName()) && SKETCH_EXTENSIONS.contains(split.extension);
result.add(new SketchFile(this, file, isPrimary));
} else if (showWarnings) {
System.err.println(I18n.format(tr("File name {0} is invalid: ignored"), file.getName()));
}
}
if (result.size() == 0)
throw new IOException(tr("No valid code files found"));
return new ArrayList<>(result);
}
/**
* Create the data folder if it does not exist already. As a
* convenience, it also returns the data folder, since it's likely
* about to be used.
*/
public File prepareDataFolder() {
File dataFolder = getDataFolder();
if (!dataFolder.exists()) {
dataFolder.mkdirs();
}
return dataFolder;
}
public void save() throws IOException {
for (SketchFile file : getFiles()) {
if (file.isModified())
file.save();
}
}
public int getCodeCount() {
return files.size();
}
public SketchFile[] getFiles() {
return files.toArray(new SketchFile[0]);
}
/**
* Returns a file object for the primary .pde of this sketch.
*/
public SketchFile getPrimaryFile() {
return files.get(0);
}
/**
* Returns path to the main .pde file for this sketch.
*/
public String getMainFilePath() {
return getPrimaryFile().getFile().getAbsolutePath();
}
public SketchFile getFile(int i) {
return files.get(i);
}
protected void removeFile(SketchFile which) {
if (!files.remove(which))
System.err.println("removeCode: internal error.. could not find code");
}
public String getName() {
return folder.getName();
}
public File getFolder() {
return folder;
}
public File getDataFolder() {
return new File(folder, "data");
}
/**
* Is any of the files in this sketch modified?
*/
public boolean isModified() {
for (SketchFile file : files) {
if (file.isModified())
return true;
}
return false;
}
/**
* Finds the file with the given filename and returns its index.
* Returns -1 when the file was not found.
*/
public int findFileIndex(File filename) {
int i = 0;
for (SketchFile file : files) {
if (file.getFile().equals(filename))
return i;
i++;
}
return -1;
}
/**
* Check if renaming/saving this sketch to the given folder would
* cause a problem because: 1. The new folder already exists 2.
* Renaming the primary file would cause a conflict with an existing
* file. If so, an IOEXception is thrown. If not, the name of the new
* primary file is returned.
*/
protected File checkNewFoldername(File newFolder) throws IOException {
String newPrimary = FileUtils.addExtension(newFolder.getName(), DEFAULT_SKETCH_EXTENSION);
// Verify the new folder does not exist yet
if (newFolder.exists()) {
String msg = I18n.format(tr("Sorry, the folder \"{0}\" already exists."), newFolder.getAbsoluteFile());
throw new IOException(msg);
}
// If the folder is actually renamed (as opposed to moved somewhere
// else), check for conflicts using the new filename, but the
// existing folder name.
if(newFolder.getName() != folder.getName())
checkNewFilename(new File(folder, newPrimary));
return new File(newFolder, newPrimary);
}
/**
* Check if renaming or adding a file would cause a problem because
* the file already exists in this sketch. If so, an IOEXception is
* thrown.
*
* @param newFile
* The filename of the new file, or the new name for an
* existing file.
*/
protected void checkNewFilename(File newFile) throws IOException {
// Verify that the sketch doesn't have a filem with the new name
// already, other than the current primary (index 0)
if (findFileIndex(newFile) >= 0) {
String msg = I18n.format(tr("The sketch already contains a file named \"{0}\""), newFile.getName());
throw new IOException(msg);
}
}
/**
* Rename this sketch' folder to the given name. Unlike saveAs(), this
* moves the sketch directory, not leaving anything in the old place.
* This operation does not *save* the sketch, so the files on disk are
* moved, but not modified.
*
* @param newFolder
* The new folder name for this sketch. The new primary
* file's name will be derived from this.
*
* @throws IOException
* When a problem occurs. The error message should be
* already translated.
*/
public void renameTo(File newFolder) throws IOException {
// Check intended rename (throws if there is a problem)
File newPrimary = checkNewFoldername(newFolder);
// Rename the sketch folder
if (!getFolder().renameTo(newFolder))
throw new IOException(tr("Failed to rename sketch folder"));
folder = newFolder;
// Tell each file about its new name
for (SketchFile file : files)
file.renamedTo(new File(newFolder, file.getFileName()));
// And finally, rename the primary file
getPrimaryFile().renameTo(newPrimary.getName());
}
public SketchFile addFile(String newName) throws IOException {
// Check the name will not cause any conflicts
File newFile = new File(folder, newName);
checkNewFilename(newFile);
// Add a new sketchFile
SketchFile sketchFile = new SketchFile(this, newFile, false);
files.add(sketchFile);
Collections.sort(files, CODE_DOCS_COMPARATOR);
return sketchFile;
}
/**
* Save this sketch under the new name given. Unlike renameTo(), this
* leaves the existing sketch in place.
*
* @param newFolder
* The new folder name for this sketch. The new primary
* file's name will be derived from this.
*
* @throws IOException
* When a problem occurs. The error message should be
* already translated.
*/
public void saveAs(File newFolder) throws IOException {
// Check intented rename (throws if there is a problem)
File newPrimary = checkNewFoldername(newFolder);
// Create the folder
if (!newFolder.mkdirs()) {
String msg = I18n.format(tr("Could not create directory \"{0}\""), newFolder.getAbsolutePath());
throw new IOException(msg);
}
// Save the files to their new location
for (SketchFile file : files) {
if (file.isPrimary())
file.saveAs(newPrimary);
else
file.saveAs(new File(newFolder, file.getFileName()));
}
folder = newFolder;
// Copy the data folder (this may take a while.. add progress bar?)
if (getDataFolder().exists()) {
File newDataFolder = new File(newFolder, "data");
FileUtils.copy(getDataFolder(), newDataFolder);
}
}
}