mirror of
https://github.com/arduino/Arduino.git
synced 2024-11-29 10:24:12 +01:00
Refactor file adding and renaming, and save as handling
This commits replaces a significant part of the code handling these
features. A lot of responsibilities are moved from SketchController to
Sketch, though the code involved is rewritten mostly.
Most of the handling now happens inside Sketch, including various checks
against the new filename. Basically SketchController processes the user
input to decide what needs to be done, and Sketch checks if it can be
done and does it.
If problems occur, an IOException is thrown, using a translated error
message that is shown by SketchController as-is. This might not be the
best way to transfer error messages (regular IOExceptions might contain
less-friendly messages), so this might need further improvement later.
In addition to moving around code and responsibilities, this code also
changes behaviour in some places:
- Because Sketch and SketchFile are now in control of renames and
saves, they can update their internal state after a rename. This
removes the need for reloading the entire sketch after a rename or
save as and allows `Editor.handleOpenUnchecked()` to be removed.
- When renaming the entire sketch, all files used to be saved before
renaming, since the sketch would be re-opened after renaming. Since
the re-opening no longer happens, there is no longer a need to save
the sketch, so any unsaved changes remain unsaved in the editor after
renaming the sketch.
- When renaming or adding new files, duplicate filenames are detected.
Initially, this happened case sensitively, but it was later changed to
use case insensitive matching to prevent problems on Windows (where
filenames cannot differ in just case). To prevent complexity, this
did not distinguish between systems. In commit 5fbf9621f6
(Sketch
rename: allowig a case change rename if NOT on windows), the
intention was to only do case insensitive checking on Windows, but it
effectively disabled all checking on other systems, making the check
not catch duplicate filenames at all.
With this commit, all these checks are done using `File.equals()`
instead of comparing strings, which is already aware of the case
sensitivity of the platform and should act accordingly.
- Some error messages were changed.
- When adding a file, an empty file is not created directly, but only a
SketchFile and EditorTab is added. When the sketch is saved, the file
is created.
- When importing a file that already exists (thus overwriting it),
instead of replacing the SketchFile instance, this just lets the
EditorTab reload its contents. This was broken since the introduction
of EditorTab. The file would be replaced, but not this was not
reflected in the editor, which is now fixed. This change allows
`Sketch.replaceFile()` to be removed.
- When importing a file that does not exist yet (thus adding it), a tab
is now also added for it (in addition to a SketchFile). This was
broken since the introduction of EditorTab, and would result in the
file being added, but not shown in the editor.
This commit adds a `Sketch.renameFileTo()` method, to rename a single
file within the sketch. It would be better to integrate its contents
into `Sketch.renameTo()`, but that does not have access to the `Sketch`
instance it is contained in. This will be changed in a future commit.
This commit is contained in:
parent
9705e1e734
commit
72f815bcf9
@ -1642,6 +1642,13 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
return tabs.get(findTabIndex(file));
|
return tabs.get(findTabIndex(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the index of the tab showing the given file. Matches the file against
|
||||||
|
* EditorTab.getSketchFile() using ==.
|
||||||
|
*
|
||||||
|
* @returns The index of the tab for the given file, or -1 if no such tab was
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
public int findTabIndex(final SketchFile file) {
|
public int findTabIndex(final SketchFile file) {
|
||||||
for (int i = 0; i < tabs.size(); ++i) {
|
for (int i = 0; i < tabs.size(); ++i) {
|
||||||
if (tabs.get(i).getSketchFile() == file)
|
if (tabs.get(i).getSketchFile() == file)
|
||||||
@ -1650,6 +1657,21 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the index of the tab showing the given file. Matches the file against
|
||||||
|
* EditorTab.getSketchFile().getFile() using equals.
|
||||||
|
*
|
||||||
|
* @returns The index of the tab for the given file, or -1 if no such tab was
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
|
public int findTabIndex(final File file) {
|
||||||
|
for (int i = 0; i < tabs.size(); ++i) {
|
||||||
|
if (tabs.get(i).getSketchFile().getFile().equals(file))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create tabs for each of the current sketch's files, removing any existing
|
* Create tabs for each of the current sketch's files, removing any existing
|
||||||
* tabs.
|
* tabs.
|
||||||
@ -1872,23 +1894,6 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a sketch from a particular path, but don't check to save changes.
|
|
||||||
* Used by Sketch.saveAs() to re-open a sketch after the "Save As"
|
|
||||||
*/
|
|
||||||
protected void handleOpenUnchecked(File file, int codeIndex,
|
|
||||||
int selStart, int selStop, int scrollPos) {
|
|
||||||
handleOpenInternal(file);
|
|
||||||
// Replacing a document that may be untitled. If this is an actual
|
|
||||||
// untitled document, then editor.untitled will be set by Base.
|
|
||||||
untitled = false;
|
|
||||||
|
|
||||||
selectTab(codeIndex);
|
|
||||||
getCurrentTab().setSelection(selStart, selStop);
|
|
||||||
getCurrentTab().setScrollPosition(scrollPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Second stage of open, occurs after having checked to see if the
|
* Second stage of open, occurs after having checked to see if the
|
||||||
* modifications (if any) to the previous sketch need to be saved.
|
* modifications (if any) to the previous sketch need to be saved.
|
||||||
|
@ -334,7 +334,7 @@ public class EditorTab extends JPanel implements SketchFile.TextStorage {
|
|||||||
/**
|
/**
|
||||||
* Reload the contents of our file.
|
* Reload the contents of our file.
|
||||||
*/
|
*/
|
||||||
private void reload() {
|
public void reload() {
|
||||||
String text;
|
String text;
|
||||||
try {
|
try {
|
||||||
text = file.load();
|
text = file.load();
|
||||||
|
@ -133,213 +133,79 @@ public class SketchController {
|
|||||||
* where they diverge.
|
* where they diverge.
|
||||||
*/
|
*/
|
||||||
protected void nameCode(String newName) {
|
protected void nameCode(String newName) {
|
||||||
SketchFile current = editor.getCurrentTab().getSketchFile();
|
|
||||||
int currentIndex = editor.getCurrentTabIndex();
|
|
||||||
|
|
||||||
// make sure the user didn't hide the sketch folder
|
// make sure the user didn't hide the sketch folder
|
||||||
ensureExistence();
|
ensureExistence();
|
||||||
|
|
||||||
// Add the extension here, this simplifies some of the logic below.
|
|
||||||
if (newName.indexOf('.') == -1) {
|
|
||||||
newName += "." + Sketch.DEFAULT_SKETCH_EXTENSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if renaming to the same thing as before, just ignore.
|
|
||||||
// also ignoring case here, because i don't want to write
|
|
||||||
// a bunch of special stuff for each platform
|
|
||||||
// (osx is case insensitive but preserving, windows insensitive,
|
|
||||||
// *nix is sensitive and preserving.. argh)
|
|
||||||
if (renamingCode) {
|
|
||||||
if (newName.equalsIgnoreCase(current.getFileName())
|
|
||||||
&& OSUtils.isWindows()) {
|
|
||||||
// exit quietly for the 'rename' case.
|
|
||||||
// if it's a 'new' then an error will occur down below
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newName = newName.trim();
|
newName = newName.trim();
|
||||||
if (newName.equals("")) return;
|
if (newName.equals("")) return;
|
||||||
|
|
||||||
int dot = newName.indexOf('.');
|
if (newName.charAt(0) == '.') {
|
||||||
if (dot == 0) {
|
|
||||||
Base.showWarning(tr("Problem with rename"),
|
Base.showWarning(tr("Problem with rename"),
|
||||||
tr("The name cannot start with a period."), null);
|
tr("The name cannot start with a period."), null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileUtils.SplitFile split = FileUtils.splitFilename(newName);
|
FileUtils.SplitFile split = FileUtils.splitFilename(newName);
|
||||||
|
if (split.extension.equals(""))
|
||||||
|
split.extension = Sketch.DEFAULT_SKETCH_EXTENSION;
|
||||||
|
|
||||||
if (!Sketch.EXTENSIONS.contains(split.extension)) {
|
if (!Sketch.EXTENSIONS.contains(split.extension)) {
|
||||||
Base.showWarning(tr("Problem with rename"),
|
String msg = I18n.format(tr("\".{0}\" is not a valid extension."),
|
||||||
I18n.format(tr("\".{0}\" is not a valid extension."),
|
split.extension);
|
||||||
split.extension),
|
Base.showWarning(tr("Problem with rename"), msg, null);
|
||||||
null);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't let the user create the main tab as a .java file instead of .pde
|
|
||||||
if (!split.extension.equals(Sketch.DEFAULT_SKETCH_EXTENSION)) {
|
|
||||||
if (renamingCode) { // If creating a new tab, don't show this error
|
|
||||||
if (current.isPrimary()) { // If this is the main tab, disallow
|
|
||||||
Base.showWarning(tr("Problem with rename"),
|
|
||||||
tr("The main file can't use an extension.\n" +
|
|
||||||
"(It may be time for your to graduate to a\n" +
|
|
||||||
"\"real\" programming environment)"), null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sanitize name
|
// Sanitize name
|
||||||
String sanitaryName = BaseNoGui.sanitizeName(split.basename);
|
split.basename = BaseNoGui.sanitizeName(split.basename);
|
||||||
newName = sanitaryName + "." + split.extension;
|
newName = split.join();
|
||||||
|
|
||||||
// In Arduino, we want to allow files with the same name but different
|
|
||||||
// extensions, so compare the full names (including extensions). This
|
|
||||||
// might cause problems: http://dev.processing.org/bugs/show_bug.cgi?id=543
|
|
||||||
for (SketchFile file : sketch.getFiles()) {
|
|
||||||
if (newName.equalsIgnoreCase(file.getFileName()) && OSUtils.isWindows()) {
|
|
||||||
Base.showMessage(tr("Error"),
|
|
||||||
I18n.format(
|
|
||||||
tr("A file named \"{0}\" already exists in \"{1}\""),
|
|
||||||
file.getFileName(),
|
|
||||||
sketch.getFolder().getAbsolutePath()
|
|
||||||
));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
File newFile = new File(sketch.getFolder(), newName);
|
|
||||||
// if (newFile.exists()) { // yay! users will try anything
|
|
||||||
// Base.showMessage("Error",
|
|
||||||
// "A file named \"" + newFile + "\" already exists\n" +
|
|
||||||
// "in \"" + folder.getAbsolutePath() + "\"");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// File newFileHidden = new File(folder, newName + ".x");
|
|
||||||
// if (newFileHidden.exists()) {
|
|
||||||
// // don't let them get away with it if they try to create something
|
|
||||||
// // with the same name as something hidden
|
|
||||||
// Base.showMessage("No Way",
|
|
||||||
// "A hidden tab with the same name already exists.\n" +
|
|
||||||
// "Use \"Unhide\" to bring it back.");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (renamingCode) {
|
if (renamingCode) {
|
||||||
|
SketchFile current = editor.getCurrentTab().getSketchFile();
|
||||||
|
|
||||||
if (current.isPrimary()) {
|
if (current.isPrimary()) {
|
||||||
// get the new folder name/location
|
if (!split.extension.equals(Sketch.DEFAULT_SKETCH_EXTENSION)) {
|
||||||
String folderName = newName.substring(0, newName.indexOf('.'));
|
Base.showWarning(tr("Problem with rename"),
|
||||||
File newFolder = new File(sketch.getFolder().getParentFile(), folderName);
|
tr("The main file cannot use an extension"), null);
|
||||||
if (newFolder.exists()) {
|
|
||||||
Base.showWarning(tr("Cannot Rename"),
|
|
||||||
I18n.format(
|
|
||||||
tr("Sorry, a sketch (or folder) named " +
|
|
||||||
"\"{0}\" already exists."),
|
|
||||||
newName
|
|
||||||
), null);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// unfortunately this can't be a "save as" because that
|
// Primary file, rename the entire sketch
|
||||||
// only copies the sketch files and the data folder
|
final File parent = sketch.getFolder().getParentFile();
|
||||||
// however this *will* first save the sketch, then rename
|
File newFolder = new File(parent, split.basename);
|
||||||
|
|
||||||
// first get the contents of the editor text area
|
|
||||||
if (current.isModified()) {
|
|
||||||
try {
|
|
||||||
// save this new SketchFile
|
|
||||||
current.save();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Base.showWarning(tr("Error"), tr("Could not rename the sketch. (0)"), e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!current.renameTo(newFile)) {
|
|
||||||
Base.showWarning(tr("Error"),
|
|
||||||
I18n.format(
|
|
||||||
tr("Could not rename \"{0}\" to \"{1}\""),
|
|
||||||
current.getFileName(),
|
|
||||||
newFile.getName()
|
|
||||||
), null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// save each of the other tabs because this is gonna be re-opened
|
|
||||||
try {
|
try {
|
||||||
for (SketchFile file : sketch.getFiles()) {
|
sketch.renameTo(newFolder);
|
||||||
file.save();
|
} catch (IOException e) {
|
||||||
}
|
// This does not pass on e, to prevent showing a backtrace for
|
||||||
} catch (Exception e) {
|
// "normal" errors.
|
||||||
Base.showWarning(tr("Error"), tr("Could not rename the sketch. (1)"), e);
|
Base.showWarning(tr("Error"), e.getMessage(), null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now rename the sketch folder and re-open
|
|
||||||
boolean success = sketch.getFolder().renameTo(newFolder);
|
|
||||||
if (!success) {
|
|
||||||
Base.showWarning(tr("Error"), tr("Could not rename the sketch. (2)"), null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// if successful, set base properties for the sketch
|
|
||||||
|
|
||||||
File newMainFile = new File(newFolder, newName + ".ino");
|
|
||||||
|
|
||||||
// having saved everything and renamed the folder and the main .pde,
|
|
||||||
// use the editor to re-open the sketch to re-init state
|
|
||||||
// (unfortunately this will kill positions for carets etc)
|
|
||||||
editor.handleOpenUnchecked(newMainFile,
|
|
||||||
currentIndex,
|
|
||||||
editor.getCurrentTab().getSelectionStart(),
|
|
||||||
editor.getCurrentTab().getSelectionStop(),
|
|
||||||
editor.getCurrentTab().getScrollPosition());
|
|
||||||
|
|
||||||
// get the changes into the sketchbook menu
|
|
||||||
// (re-enabled in 0115 to fix bug #332)
|
|
||||||
editor.base.rebuildSketchbookMenus();
|
editor.base.rebuildSketchbookMenus();
|
||||||
|
} else {
|
||||||
} else { // else if something besides code[0]
|
// Non-primary file, rename just that file
|
||||||
if (!current.renameTo(newFile)) {
|
try {
|
||||||
Base.showWarning(tr("Error"),
|
sketch.renameFileTo(current, newName);
|
||||||
I18n.format(
|
} catch (IOException e) {
|
||||||
tr("Could not rename \"{0}\" to \"{1}\""),
|
// This does not pass on e, to prevent showing a backtrace for
|
||||||
current.getFileName(),
|
// "normal" errors.
|
||||||
newFile.getName()
|
Base.showWarning(tr("Error"), e.getMessage(), null);
|
||||||
), null);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else { // creating a new file
|
} else { // creating a new file
|
||||||
|
SketchFile file;
|
||||||
try {
|
try {
|
||||||
if (!newFile.createNewFile()) {
|
file = sketch.addFile(newName);
|
||||||
// Already checking for IOException, so make our own.
|
|
||||||
throw new IOException(tr("createNewFile() returned false"));
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Base.showWarning(tr("Error"),
|
|
||||||
I18n.format(
|
|
||||||
"Could not create the file \"{0}\" in \"{1}\"",
|
|
||||||
newFile,
|
|
||||||
sketch.getFolder().getAbsolutePath()
|
|
||||||
), e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ensureExistence();
|
|
||||||
SketchFile file = new SketchFile(newFile, false);
|
|
||||||
try {
|
|
||||||
editor.addTab(file, "");
|
editor.addTab(file, "");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Base.showWarning(tr("Error"),
|
// This does not pass on e, to prevent showing a backtrace for
|
||||||
I18n.format(
|
// "normal" errors.
|
||||||
"Failed to open tab for new file"
|
Base.showWarning(tr("Error"), e.getMessage(), null);
|
||||||
), e);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sketch.addFile(file);
|
|
||||||
editor.selectTab(editor.findTabIndex(file));
|
editor.selectTab(editor.findTabIndex(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,35 +424,17 @@ public class SketchController {
|
|||||||
// in fact, you can't do this on windows because the file dialog
|
// in fact, you can't do this on windows because the file dialog
|
||||||
// will instead put you inside the folder, but it happens on osx a lot.
|
// will instead put you inside the folder, but it happens on osx a lot.
|
||||||
|
|
||||||
// now make a fresh copy of the folder
|
try {
|
||||||
newFolder.mkdirs();
|
sketch.saveAs(newFolder);
|
||||||
|
} catch (IOException e) {
|
||||||
// save the other tabs to their new location
|
// This does not pass on e, to prevent showing a backtrace for "normal"
|
||||||
for (SketchFile file : sketch.getFiles()) {
|
// errors.
|
||||||
if (file.isPrimary()) continue;
|
Base.showWarning(tr("Error"), e.getMessage(), null);
|
||||||
File newFile = new File(newFolder, file.getFileName());
|
|
||||||
file.saveAs(newFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// re-copy the data folder (this may take a while.. add progress bar?)
|
|
||||||
if (sketch.getDataFolder().exists()) {
|
|
||||||
File newDataFolder = new File(newFolder, "data");
|
|
||||||
FileUtils.copy(sketch.getDataFolder(), newDataFolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// save the main tab with its new name
|
|
||||||
File newFile = new File(newFolder, newName + ".ino");
|
|
||||||
sketch.getFile(0).saveAs(newFile);
|
|
||||||
|
|
||||||
editor.handleOpenUnchecked(newFile,
|
|
||||||
editor.getCurrentTabIndex(),
|
|
||||||
editor.getCurrentTab().getSelectionStart(),
|
|
||||||
editor.getCurrentTab().getSelectionStop(),
|
|
||||||
editor.getCurrentTab().getScrollPosition());
|
|
||||||
|
|
||||||
// Name changed, rebuild the sketch menus
|
// Name changed, rebuild the sketch menus
|
||||||
//editor.sketchbook.rebuildMenusAsync();
|
//editor.sketchbook.rebuildMenusAsync();
|
||||||
editor.base.rebuildSketchbookMenus();
|
editor.base.rebuildSketchbookMenus();
|
||||||
|
editor.header.rebuild();
|
||||||
|
|
||||||
// Make sure that it's not an untitled sketch
|
// Make sure that it's not an untitled sketch
|
||||||
setUntitled(false);
|
setUntitled(false);
|
||||||
@ -719,16 +567,24 @@ public class SketchController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isData) {
|
if (!isData) {
|
||||||
SketchFile newFile = new SketchFile(destFile, false);
|
int tabIndex;
|
||||||
|
|
||||||
if (replacement) {
|
if (replacement) {
|
||||||
sketch.replaceFile(newFile);
|
tabIndex = editor.findTabIndex(destFile);
|
||||||
|
editor.getTabs().get(tabIndex).reload();
|
||||||
} else {
|
} else {
|
||||||
ensureExistence();
|
SketchFile sketchFile;
|
||||||
sketch.addFile(newFile);
|
try {
|
||||||
|
sketchFile = sketch.addFile(destFile.getName());
|
||||||
|
editor.addTab(sketchFile, null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// This does not pass on e, to prevent showing a backtrace for
|
||||||
|
// "normal" errors.
|
||||||
|
Base.showWarning(tr("Error"), e.getMessage(), null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tabIndex = editor.findTabIndex(sketchFile);
|
||||||
}
|
}
|
||||||
editor.selectTab(editor.findTabIndex(newFile));
|
editor.selectTab(tabIndex);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -159,20 +159,6 @@ public class Sketch {
|
|||||||
return getPrimaryFile().getFile().getAbsolutePath();
|
return getPrimaryFile().getFile().getAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addFile(SketchFile file) {
|
|
||||||
files.add(file);
|
|
||||||
Collections.sort(files, CODE_DOCS_COMPARATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void replaceFile(SketchFile newCode) {
|
|
||||||
for (SketchFile file : files) {
|
|
||||||
if (file.getFileName().equals(newCode.getFileName())) {
|
|
||||||
files.set(files.indexOf(file), newCode);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public SketchFile getFile(int i) {
|
public SketchFile getFile(int i) {
|
||||||
return files.get(i);
|
return files.get(i);
|
||||||
}
|
}
|
||||||
@ -204,4 +190,164 @@ public class Sketch {
|
|||||||
}
|
}
|
||||||
return false;
|
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
|
||||||
|
if (!getPrimaryFile().renameTo(newPrimary))
|
||||||
|
throw new IOException(tr("Failed to rename primary sketch file"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename the given file to get the given name.
|
||||||
|
*
|
||||||
|
* @param sketchfile
|
||||||
|
* The SketchFile to be renamed.
|
||||||
|
* @param newName
|
||||||
|
* The new name, including extension, excluding directory
|
||||||
|
* name.
|
||||||
|
* @throws IOException
|
||||||
|
* When a problem occurs, or is expected to occur. The error
|
||||||
|
* message should be already translated.
|
||||||
|
*/
|
||||||
|
public void renameFileTo(SketchFile sketchfile, String newName) throws IOException {
|
||||||
|
File newFile = new File(folder, newName);
|
||||||
|
checkNewFilename(newFile);
|
||||||
|
sketchfile.renameTo(newFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,12 +154,18 @@ public class SketchFile {
|
|||||||
|
|
||||||
protected boolean renameTo(File what) {
|
protected boolean renameTo(File what) {
|
||||||
boolean success = file.renameTo(what);
|
boolean success = file.renameTo(what);
|
||||||
if (success) {
|
if (success)
|
||||||
file = what;
|
renamedTo(what);
|
||||||
}
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be called when this file was renamed and renameTo could not
|
||||||
|
* be used (e.g. when renaming the entire sketch directory).
|
||||||
|
*/
|
||||||
|
protected void renamedTo(File what) {
|
||||||
|
file = what;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the filename include extension.
|
* Returns the filename include extension.
|
||||||
@ -264,5 +270,6 @@ public class SketchFile {
|
|||||||
return; /* Nothing to do */
|
return; /* Nothing to do */
|
||||||
|
|
||||||
BaseNoGui.saveFile(storage.getText(), newFile);
|
BaseNoGui.saveFile(storage.getText(), newFile);
|
||||||
|
renamedTo(newFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,6 +265,24 @@ public class FileUtils {
|
|||||||
return new File(file.getParentFile(), replaceExtension(file.getName(), extension));
|
return new File(file.getParentFile(), replaceExtension(file.getName(), extension));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an extension to the given filename. If it already contains
|
||||||
|
* one, an additional extension is added. If the extension is the
|
||||||
|
* empty string, the file is returned unmodified.
|
||||||
|
*/
|
||||||
|
public static String addExtension(String filename, String extension) {
|
||||||
|
return extension.equals("") ? filename : (filename + "." + extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an extension to the given filename. If it already contains
|
||||||
|
* one, an additional extension is added. If the extension is the
|
||||||
|
* empty string, the file is returned unmodified.
|
||||||
|
*/
|
||||||
|
public static File addExtension(File file, String extension) {
|
||||||
|
return new File(file.getParentFile(), addExtension(file.getName(), extension));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The result of a splitFilename call.
|
* The result of a splitFilename call.
|
||||||
*/
|
*/
|
||||||
@ -278,10 +296,7 @@ public class FileUtils {
|
|||||||
public String extension;
|
public String extension;
|
||||||
|
|
||||||
public String join() {
|
public String join() {
|
||||||
if (extension.equals(""))
|
return addExtension(basename, extension);
|
||||||
return basename;
|
|
||||||
else
|
|
||||||
return basename + "." + extension;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user