Photoshop scripting - Close all except first document - photoshop-script

I'm trying to make a photoshop script that closes all documents without saving except for the first document. The first document will be a psd/psdc, the rest will be images
Currently I have the below code, this closes all documents
while (app.documents.length > 0) {
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
}
I've tried modifying it the same way I've done with a previous script, but it closes random documents, and not even all of them, it can leave 5-6 documents open
for (var i = 1; i < app.documents.length; i++) {
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
}
Can anyone point me in the right direction

Just use the inverted loop (so the docs are closed from the last to the first) and address them by the reference from the documents array, not by active document:
for (var i = documents.length - 1; i >= 1; i--) {
documents[i].close(SaveOptions.DONOTSAVECHANGES)
}

Related

Indesign Script: Looping ALL paragraphs (including in overset)

Looking for a selector of ALL paragraphs in the selected TextFrame, including the "not visible ones" in the overset. Script is already working and looping through the visible paragraphs:
[...]
if(app.selection[0].constructor.name=="TextFrame") {
var myParagraphs = app.selection[0].paragraphs; // only visible ones?!
var myArray = myParagraphs.everyItem().contents;
for (var i=0; i<myArray.length; i++) {
// do some fancy styling - WORKING
myParagraphs[i].appliedParagraphStyle = app.activeDocument.paragraphStyles.item('Format XYZ');
}
}
myArray.length changes when I set another hight for the TextFrame. But how can I work with ALL paragraphs? Already tested .anyItem() with the same result :(
Well, the paragraphs in the overset are not paragraphs of the text frame, so it makes sense that they are skipped in your script. To access all the paragraphs of the text frames + those that are in the overset part, you will need to access all paragraphs of the parent story (a story is the text entity that describes all the text within linked text frames and the overset text) of the text frame.
You can do so like this:
if(app.selection[0].constructor.name === "TextFrame") {
var myParagraphs = app.selection[0].parentStory.paragraphs;
for (var i = 0; i < myParagraphs.length; i++) {
myParagraphs[i].appliedParagraphStyle = app.activeDocument.paragraphStyles.item("Format XYZ");
}
}
Be aware though that this will handle all paragraphs in all text frames that are linked to your text frame in case there are any of those.
Also, since it looks like you need to apply the paragraph style on each paragraph of the entire story, you might as well apply the paragraph style to the entire story directly instead of looping over the paragraphs:
app.selection[0].parentStory.appliedParagraphStyle = app.activeDocument.paragraphStyles.item("Format XYZ");

Iterating through controls on a form

I am using C++ Builder. I want to locate several string grids that I have located on different tab sheets of a page control. I know how to iterate through the child controls of a specific control. In my case, each string grid is contained under a separate tab sheet control. My question is, is there a list of all controls in an app, without regards to the hierarchy of where they are contained?
There is such a list: Application->Components, consider code below
for (int i = 0; i < Application->ComponentCount; i++) {
for (int j = 0; j < Application->Components[i]->ComponentCount; j++) {
if (dynamic_cast<TStringGrid*>(Application->Components[i]->Components[j])){
//there is your TStringGrid* regardless of a place in application
}
}
}
You may as well iterate through your tab controls children if you are sure that your string grids are only there.

For loop over a Google Sheets Range fails to change file owner

I need to transfer ownership of thousands of files I own to someone else with editing access, but I've learned that Google Drive requires you to do this one file at a time. With intermediate but growing JS experience I decided to write a script to change the owner from a list of file IDs in a spreadsheet, however I've run into trouble and I have no idea why. The debugger just runs through the script and everything looks sound for me. I'd greatly appreciate any help.
function changeOwner() {
var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/********/').getSheetByName('Sheet1');
var range = ss.getRange(1,1,2211);
for (i = 0; i < range.length; i++){
var file = range[i][0].getValue();
var fileid = DriveApp.getFileById(file);
fileid.setOwner('******#gmail.com');
}
}
Tested below code working fine with IDs,
function myFunction() {
var spreadsheet = SpreadsheetApp.openById('ID');
var range = spreadsheet.getDataRange().getValues();
for (i = 0; i < range.length; i++){
var file = range[i][0].toString();
var fileid = DriveApp.getFileById(file);
fileid.setOwner('***#gmail.com');
}
}
Your issue is that the Range class had no length property. Instead, perform a getValues() call on the range to efficiently create a JavaScript array, and iterate on it:
function changeOwner() {
var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/********/').getSheetByName('Sheet1');
var values = ss.getRange(1, 1, 2211).getValues();
for (i = 0; i < values.length; ++i){
var fileid = value[i][0];
var file = DriveApp.getFileById(fileid);
file.setOwner('******#gmail.com');
}
}
There are other improvements you can make, such as:
dynamic range read (rather than the fixed assumption of 2211 rows of data)
writing to a second array to keep track of which files you have yet to process
checks for if the file exists
checks for if the file is actually owned by you
checks for execution time remaining, to allow serializing any updates/tracking you do that prevents the next execution from repeating what you just did
and so on. I'll let you research those topics, and the methods available in Apps Script documentation for the DriveApp, SpreadsheetApp, Sheet, and Range classes. Note that you also have all features of Javascript 1.6 available, so many of the things you find on a Javascript Developer Reference (like MDN) are also available to you.

playing PDE files in a loop?

I'm still relatively new to Processing. We are thinking of showing our Processing work in a loop for a small exhibition. Is there a way to play multiple PDEs in a loop? I know I can export as frames and then assemble them as a longer loop-able Quicktime file, but I'm wondering if there's any way to play and loop the files themselves?
Also, for interactive PDEs, what's the best way to present them? We are thinking of having a couple of computers with PDEs running in Processing but it would be nice to have a file run for 20 minutes and then open another file for 20 minutes.
Thanks in advance!
You should be able to put together a shell/batch script that uses the processing-java command line executable.
You should be able to set that up via the Tools > Install "processing-java"
If you're not confortable with bash/batch scripting you could even write a Processing sketch that launches Processing sketches
Here's a very rough take on it using selectFolder() and exec():
final int SKETCH_RUN_TIME = 10000;//10 seconds for each sketch, feel free to change
ArrayList<File> sketches = new ArrayList<File>();
int sketchIndex = 0;
void setup(){
selectFolder("Select a folder containing Processing sketches:", "folderSelected");
}
void draw(){
}
void nextSketch(){
//run sketch
String sketchPath = sketches.get(sketchIndex).getAbsolutePath();
println("launching",sketchPath);
Process sketch = exec("/usr/local/bin/processing-java",
"--sketch="+sketchPath,
"--present");
//increment sketch index for next time around (checking the index is still valid, otherwise go back to 0)
sketchIndex++;
if(sketchIndex >= sketches.size()){
sketchIndex = 0;
}
//delay is deprecated so you shouldn't use this a lot, but as a proof concept this will do
delay(SKETCH_RUN_TIME);
nextSketch();
}
void folderSelected(File selection) {
if (selection == null) {
println("No folder ? Ok, maybe another time. Bye! :)");
exit();
} else {
File[] files = selection.listFiles();
//filter just Processing sketches
for(int i = 0; i < files.length; i++){
if(files[i].isDirectory()){
String folderName = files[i].getName();
File[] sketchFiles = files[i].listFiles();
boolean isValidSketch = false;
//search for a .pde file with the same folder name to check if it's a valid sketch
for(File f : sketchFiles){
if(f.getName().equals(folderName+".pde")){
isValidSketch = true;
break;
}
}
if(isValidSketch) {
sketches.add(files[i]);
}else{
System.out.println(files[i]+" is not a valid Processing sketch");
}
}
}
println("sketches found:",sketches);
nextSketch();
}
}
The code is commented so hopefully it should be easy to read and follow.
You will be prompted to select a folder containing sketches to run.
Note 1: I've used the processing-java path on my machine (/usr/local/bin/processing-java). If you're on Windows this may be different and you need to change this.
Note 2: The processing-java command launches another Process which makes it tricky to close the previous sketch before running the next one. As a workaround for you you could call exit() on each sketch after the amount of time you need.
Note 3: The code will not recursively traverse the selected folder containing sketches, so only the first level sketches will be executed, anything deeper should be ignored.

inDesign JSX scripted add of heading and content into textFrame

I'm attempting to use inDesign JSX scripts to insert the following data into a document:
data = [{heading:"Heading 1", content: ["Some content"]},
{heading:"Heading 2", content: ["Some other content with", "Multiple paragraphs"]}]
The data has to be placed into a single TextFrame, but have different styling on the heading and content.
The only way I can see to add the text is in one go via the textFrame.contents variable:
allContent = "";
headingParagraphs = []; // keep track of which paragraphs are headings
paragraph = 0;
for (var i = 0; i < data.length; i++) {
allContent += data.heading + "\r"; // Use a newline to split the paragraph
headingParagraphs.push(paragraph);
paragraph++;
for (var j = 0; j < data.content.length; j++) {
allContent += data.content[j] + "\r"; // Use a newline to split the paragraph
paragraph++;
}
}
textFrame.contents = allContent; // all data is in, but all text is styled the same
Then once the data is in, I iterate the paragraphs and add some style to the headings:
for (var i = 0; i < textFrame.paragraphs.count(); i++) {
if (headingParagraphs.indexOf(i) != -1) { // this is a heading paragraph
textFrame.paragraphs[i].pointSize = 20;
}
}
This works fine for small data sets that fit on one page, but once the contents gets bigger than the frame, paragraphs only returns visible paragraphs. And if I follow on to a new textFrame, paragraphs get split and the headingParagraphs[] array no longer lines up.
Ideally I'd like to append to the contents and set styles before I append the next content - but the API docs aren't very clear on how you might do that (if at all)
// Pseudo code:
for all sections:
append the heading to the frame, split to next page if needed
style all the *new* paragraphs as headings
for all section contents
append the content to the frame, split to next page if needed
style any *new* paragraphs as normal content
Is there a way to achieve this using either an append function or some other way to assign headings to the right place after content has been added? Perhaps special characters in the content to define style?
Your longer text gets messed up because currently you are working inside a single text frame. As soon as the text runs out of this one frame, you can't refer to them as this frame's "owned" paragraphs anymore. Use parentStory instead, as it points to the whole story, inside one text frame or spanning more than one. It also keeps on working if the text gets overset.
So if you have a starting frame called textFrame, set a new variable story to textFrame.parentStory and use that to add text.
As for adding text to this frame(/story): indeed, there is no fast way to add formatted text. Setting contents only works for long swathes with the same formatting. One way I've used is to write INX formatted text to a temporary file and importing that. It's slow for short fragments, but larger stories (up to several hundreds of pages) can be created very efficiently in Javascript itself, and then importing it into ID is .. well, it aint fast but faster than trying to do it "manually".
The other way is to add contents one paragraph at a time. The trick is to set formatting and add your text to story.insertionPoints[-1]. This, in a particularly handy notation, refers to the very last text insertion point of the story. You can think of an insertion point as "the text cursor"; you can 'apply' formatting to it, and any text added will then have this formatting as well.
Your code snippet reworked to add one data item at a time:
for (var i = 0; i < data.length; i++)
{
story.insertionPoints[-1].pointSize = 20;
story.insertionPoints[-1].contents = data[i].heading + "\r"; // Use a newline to split the paragraph
story.insertionPoints[-1].pointSize = 10;
for (var j = 0; j < data[i].content.length; j++)
{
story.insertionPoints[-1].contents = data[i].content[j] + "\r"; // Use a newline to split the paragraph
}
}
One thing to note is that you cannot temporarily override the pointSize here. If you set it to your larger size, you must also set it back to the original size again (the '10' in my snippet).
Can I convince you to look in to using paragraph styles? With paragraph styles, you'd have something like
hdrStyle = app.activeDocument.paragraphStyles.item("Header");
textStyle = app.activeDocument.paragraphStyles.item("Text");
for (var i = 0; i < data.length; i++)
{
story.insertionPoints[-1].contents = data[i].heading + "\r"; // Use a newline to split the paragraph
story.insertionPoints[-2].appliedParagraphStyle = hdrStyle;
for (var j = 0; j < data[i].content.length; j++)
{
story.insertionPoints[-1].contents = data[i].content[j] + "\r"; // Use a newline to split the paragraph
story.insertionPoints[-2].appliedParagraphStyle = textStyle;
}
}
Note that it's worth here to invert inserting contents and applying formatting. This is so any previous 'temporary' formatting gets cleared; applying a paragraph style this way overrides any and all local overrides. As you have to apply the style to the previous paragraph (the one before the hard return you just inserted), you would use insertionPoints[-2] here.
The advantages of using styles over local formatting are countless. You can apply all formatting you want with a single command, safely remove all local overridden formatting, and change any part of the formatting globally if you are not satisfied with it, rather than having to re-run your script with slightly different settings.

Resources