/** * Make sure the sketch hasn't been moved or deleted by some nefarious user. If they did, try to * re-create it and save. Only checks to see if the main folder is still around, but not its * contents. */ protected void ensureExistence() { if (folder.exists()) return; Base.showWarning( "Sketch Disappeared", "The sketch folder has disappeared.\n " + "Will attempt to re-save in the same location,\n" + "but anything besides the code will be lost.", null); try { folder.mkdirs(); modified = true; for (int i = 0; i < codeCount; i++) { code[i].save(); // this will force a save } for (int i = 0; i < hiddenCount; i++) { hidden[i].save(); // this will force a save } calcModified(); } catch (Exception e) { Base.showWarning( "Could not re-save sketch", "Could not properly re-save the sketch. " + "You may be in trouble at this point,\n" + "and it might be time to copy and paste " + "your code to another text editor.", e); } }
/** * Add a file to the sketch. * * <p>.gcode files will be added to the sketch folder. <br> * All other files will be added to the "data" folder. * * <p>If they don't exist already, the "code" or "data" folder will be created. * * <p> * * @return true if successful. */ public boolean addFile(File sourceFile) { String filename = sourceFile.getName(); File destFile = null; boolean addingCode = false; destFile = new File(this.folder, filename); addingCode = true; // make sure they aren't the same file if (!addingCode && sourceFile.equals(destFile)) { Base.showWarning( "You can't fool me", "This file has already been copied to the\n" + "location where you're trying to add it.\n" + "I ain't not doin nuthin'.", null); return false; } // in case the user is "adding" the code in an attempt // to update the sketch's tabs if (!sourceFile.equals(destFile)) { try { Base.copyFile(sourceFile, destFile); } catch (IOException e) { Base.showWarning("Error adding file", "Could not add '" + filename + "' to the sketch.", e); return false; } } // make the tabs update after this guy is added if (addingCode) { String newName = destFile.getName(); int newFlavor = -1; if (newName.toLowerCase().endsWith(".gcode")) { newName = newName.substring(0, newName.length() - 6); newFlavor = GCODE; } // see also "nameCode" for identical situation SketchCode newCode = new SketchCode(newName, destFile, newFlavor); insertCode(newCode); sortCode(); setCurrent(newName); editor.header.repaint(); } return true; }
public void hideCode() { // make sure the user didn't hide the sketch folder ensureExistence(); // if read-only, give an error if (isReadOnly()) { // if the files are read-only, need to first do a "save as". Base.showMessage( "Sketch is Read-Only", "Some files are marked \"read-only\", so you'll\n" + "need to re-save the sketch in another location,\n" + "and try again."); return; } // don't allow hide of the main code // TODO maybe gray out the menu on setCurrent(0) if (currentIndex == 0) { Base.showMessage( "Can't do that", "You cannot hide the main " + ".gcode file from a sketch\n"); return; } // rename the file File newFile = new File(current.file.getAbsolutePath() + ".x"); if (!current.file.renameTo(newFile)) { Base.showWarning("Error", "Could not hide " + "\"" + current.file.getName() + "\".", null); return; } current.file = newFile; // move it to the hidden list if (hiddenCount == hidden.length) { SketchCode temp[] = new SketchCode[hiddenCount + 1]; System.arraycopy(hidden, 0, temp, 0, hiddenCount); hidden = temp; } hidden[hiddenCount++] = current; // remove it from the main list removeCode(current); // update the tabs setCurrent(0); editor.header.repaint(); }
/** * Implements the cross-platform headache of opening URLs TODO This code should be replaced by * PApplet.link(), however that's not a static method (because it requires an AppletContext when * used as an applet), so it's mildly trickier than just removing this method. */ public static void openURL(String url) { // System.out.println("opening url " + url); try { if (Base.isWindows()) { // this is not guaranteed to work, because who knows if the // path will always be c:\progra~1 et al. also if the user has // a different browser set as their default (which would // include me) it'd be annoying to be dropped into ie. // Runtime.getRuntime().exec("c:\\progra~1\\intern~1\\iexplore " // + currentDir // the following uses a shell execute to launch the .html file // note that under cygwin, the .html files have to be chmodded // +x // after they're unpacked from the zip file. i don't know why, // and don't understand what this does in terms of windows // permissions. without the chmod, the command prompt says // "Access is denied" in both cygwin and the "dos" prompt. // Runtime.getRuntime().exec("cmd /c " + currentDir + // "\\reference\\" + // referenceFile + ".html"); if (url.startsWith("http://")) { // open dos prompt, give it 'start' command, which will // open the url properly. start by itself won't work since // it appears to need cmd Runtime.getRuntime().exec("cmd /c start " + url); } else { // just launching the .html file via the shell works // but make sure to chmod +x the .html files first // also place quotes around it in case there's a space // in the user.dir part of the url Runtime.getRuntime().exec("cmd /c \"" + url + "\""); } } else if (Base.isMacOS()) { // com.apple.eio.FileManager.openURL(url); if (!url.startsWith("http://")) { // prepend file:// on this guy since it's a file url = "file://" + url; // replace spaces with %20 for the file url // otherwise the mac doesn't like to open it // can't just use URLEncoder, since that makes slashes into // %2F characters, which is no good. some might say // "useless" if (url.indexOf(' ') != -1) { StringBuffer sb = new StringBuffer(); char c[] = url.toCharArray(); for (int i = 0; i < c.length; i++) { if (c[i] == ' ') { sb.append("%20"); } else { sb.append(c[i]); } } url = sb.toString(); } } com.apple.mrj.MRJFileUtils.openURL(url); } else if (Base.isLinux()) { String launcher = preferences.get("launcher.linux", "gnome-open"); if (launcher != null) { Runtime.getRuntime().exec(new String[] {launcher, url}); } } else { String launcher = preferences.get("launcher", null); if (launcher != null) { Runtime.getRuntime().exec(new String[] {launcher, url}); } else { Base.logger.warning("Unspecified platform, no launcher available."); } } } catch (IOException e) { Base.showWarning("Could not open URL", "An error occurred while trying to open\n" + url, e); } }
/** * This is called upon return from entering a new file name. (that is, from either newCode or * renameCode after the prompt) This code is almost identical for both the newCode and renameCode * cases, so they're kept merged except for right in the middle where they diverge. */ public void nameCode(String newName) { // make sure the user didn't hide the sketch folder ensureExistence(); // 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 && newName.equalsIgnoreCase(current.name)) { // exit quietly for the 'rename' case. // if it's a 'new' then an error will occur down below return; } // don't allow blank names if (newName.trim().equals("")) { return; } if (newName.trim().equals(".gcode")) { return; } String newFilename = null; int newFlavor = 0; // separate into newName (no extension) and newFilename (with ext) // add .gcode to file if it has no extension if (newName.endsWith(".gcode")) { newFilename = newName; newName = newName.substring(0, newName.length() - 6); newFlavor = GCODE; } else { newFilename = newName + ".gcode"; newFlavor = GCODE; } // dots are allowed for the .gcode and .java, but not in the name // make sure the user didn't name things poo.time.gcode // or something like that (nothing against poo time) if (newName.indexOf('.') != -1) { newFilename = newName + ".gcode"; } // create the new file, new SketchCode object and load it File newFile = new File(folder, newFilename); if (newFile.exists()) { // yay! users will try anything Base.showMessage( "Nope", "A file named \"" + newFile + "\" already exists\n" + "in \"" + folder.getAbsolutePath() + "\""); return; } File newFileHidden = new File(folder, newFilename + ".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 (currentIndex == 0) { // get the new folder name/location File newFolder = new File(folder.getParentFile(), newName); if (newFolder.exists()) { Base.showWarning( "Cannot Rename", "Sorry, a sketch (or folder) named " + "\"" + newName + "\" already exists.", null); return; } // unfortunately this can't be a "save as" because that // only copies the sketch files and the data folder // however this *will* first save the sketch, then rename // first get the contents of the editor text area if (current.modified) { current.program = editor.getText(); try { // save this new SketchCode current.save(); } catch (Exception e) { Base.showWarning("Error", "Could not rename the sketch. (0)", e); return; } } if (!current.file.renameTo(newFile)) { Base.showWarning( "Error", "Could not rename \"" + current.file.getName() + "\" to \"" + newFile.getName() + "\"", null); return; } // save each of the other tabs because this is gonna be // re-opened try { for (int i = 1; i < codeCount; i++) { // if (code[i].modified) code[i].save(); code[i].save(); } } catch (Exception e) { Base.showWarning("Error", "Could not rename the sketch. (1)", e); return; } // now rename the sketch folder and re-open boolean success = folder.renameTo(newFolder); if (!success) { Base.showWarning("Error", "Could not rename the sketch. (2)", null); return; } // if successful, set base properties for the sketch File mainFile = new File(newFolder, newName + ".gcode"); mainFilename = mainFile.getAbsolutePath(); // having saved everything and renamed the folder and the main // .gcode, // use the editor to re-open the sketch to re-init state // (unfortunately this will kill positions for carets etc) editor.handleOpenUnchecked( mainFilename, currentIndex, editor.textarea.getSelectionStart(), editor.textarea.getSelectionEnd(), editor.textarea.getScrollPosition()); // get the changes into the sketchbook menu // (re-enabled in 0115 to fix bug #332) // editor.sketchbook.rebuildMenus(); } else { // else if something besides code[0] if (!current.file.renameTo(newFile)) { Base.showWarning( "Error", "Could not rename \"" + current.file.getName() + "\" to \"" + newFile.getName() + "\"", null); return; } // just reopen the class itself current.name = newName; current.file = newFile; current.flavor = newFlavor; } } else { // creating a new file try { newFile.createNewFile(); // TODO returns a boolean } catch (IOException e) { Base.showWarning( "Error", "Could not create the file \"" + newFile + "\"\n" + "in \"" + folder.getAbsolutePath() + "\"", e); return; } SketchCode newCode = new SketchCode(newName, newFile, newFlavor); insertCode(newCode); } // sort the entries sortCode(); // set the new guy as current setCurrent(newName + flavorExtensionsShown[newFlavor]); // update the tabs // editor.header.repaint(); editor.header.rebuild(); // force the update on the mac? Toolkit.getDefaultToolkit().sync(); // editor.header.getToolkit().sync(); }