Publi-Script Forums

Applescript / Javascript => Quark XPress scripting => Topic started by: AutoFetishist on April 21, 2010, 02:08:02 PM

Title: How would you?
Post by: AutoFetishist on April 21, 2010, 02:08:02 PM
I have a document with text blocks that need their lines to manually be run down (with soft returns).
Like so:
(http://dl.dropbox.com/u/499885/rundown.png)

I'm wondering how the other people on this board would automate this?

Would you go through the Xpress tags in a text editor, line by line, and just count a certain number of characters from the beginning / then insert an ASCII character 7?
Title: Re: How would you?
Post by: Publi-Script on April 22, 2010, 12:01:05 AM
I would NEVER lay this out like this... It simply does not make sense

If a bunch of text is meant to be together (as your "left column" appears to be) than I set it in its own text box. The same goes for your apparent table on the right.

Furthermore, I doubt your text came to you like this, so you would need to parse your left and right text together which is a pain at scripting time and more pain at editing time when the powers that be realizes they for got a word or two in there.

Now, if you are lucky, you can use a two-columns text box.If not, simply lay two text boxes next to each other.

Just my 2 cents.
Title: Re: How would you?
Post by: AutoFetishist on April 22, 2010, 07:49:45 AM
Sorry, I don't think I worded that properly:

These are rows of text. The first "column" (basically the text before the first tab) needs to wrap if it exceeds a certain length.
(http://dl.dropbox.com/u/499885/picture2.png)

Does that make it clearer?
Title: Re: How would you?
Post by: Publi-Script on April 22, 2010, 08:25:11 AM
I got that from the get go AF.

What I said is I would NEVER lay this out like this.

That said, your example made it clearer in the sense that I did not originally realized that the "Jabber Text" was actually part of the table.
So my question is now this:

Why don't you lay this out in a table?
Title: Re: How would you?
Post by: AutoFetishist on April 22, 2010, 09:43:42 AM
I've never been able to convince my coworkers to make the switch, and frankly, the table tool was very unstable in QX6.5. I had hoped it would have been patched up in 7, but so far it seems to still cause random crashing of Q.

Title: Re: How would you?
Post by: Publi-Script on April 22, 2010, 10:02:06 AM
I agree that the table tool is clunky but that is just the API that allows you to make changes to that table.

At the base, a table in Quark is really a collection of text and picture boxes that have been grouped together (Plus the API to control them). Since you are doing this with AppleScript you can simply generate text boxes that will follow the same layout scheme.

That said, I sure hope you are using Xtags for this as it can generate text, picture and graphic boxes based on the location of other boxes (static or previously drawn) on you page.

To see what I mean, install Xtags on your Quark and make a table in Quark. While the table is selected, do a "Copy with Xtags" from your Edit menu. Paste the result in a text editor window. There you will see the code to generate all these single boxes and their content.

HTH
Title: Re: How would you?
Post by: AutoFetishist on April 22, 2010, 11:25:35 AM
Yeah, the table method seems the way to go, especially now that 7 allows breaking tables across multiple pages.
Oh well.

Thanks again Michel.
Title: Re: How would you?
Post by: Publi-Script on April 22, 2010, 12:35:06 PM
Have you looked at the Xtags Xtension?
Title: Re: How would you?
Post by: AutoFetishist on April 22, 2010, 03:58:06 PM
I downloaded it, but I'm still "feeling my way" with regular XPress tags / Tex Edit Plus.

What if I try to go with my original idea, inserting soft returns after a certain number of characters on each line.

I thought maybe loop through the document, and isolate the first space after character #35 of each line, and then replace it with (ascii character 7).

What do you think of doing that in Tex Edit Plus?

Title: Re: How would you?
Post by: Publi-Script on April 22, 2010, 04:39:21 PM
I think you would be opening a bigger can of worms...

You will more than likely be cutting words in half, so you would have to account for that by either preventing it of supplying sufficient hyphenation info
Title: Re: How would you?
Post by: AutoFetishist on April 22, 2010, 04:46:50 PM
Not if I specify that the character to replace be a space character?
Title: Re: How would you?
Post by: cdms on April 23, 2010, 02:48:31 AM
I have to agree with publi-script here (although not sure he needs my support). Although I haven't done a lot of Quark tagged text, I spent a year building InDesign tagged text files and the basic principles hold. Unless you can 100% guarantee that the text is clean (What if someone has not placed a space following some punctuation?) and will not change, then all text wrapping, soft returns etc. should be left as the responsibility of the app. What would you do if character 32 was the first letter of a long or hyphenated word? 

In my opinion this definitely wants to be a table with bottom aligned text.
Title: Re: How would you?
Post by: AutoFetishist on April 25, 2010, 05:36:50 PM
you're right, I would definitely do some preliminary cleanup to verify no oddly placed space characters.

but as I said, use table boxes is not an option for me.

As far as automating text wrapping, I actually do this on a smaller scale with strings that are already known:
for instance I set
"the quick brown fox jumped over"
  to
"the quick" & (ascii character 7) & "brown fox" & (ascii character 7) & "jumped over"


Title: Re: How would you?
Post by: AutoFetishist on April 25, 2010, 05:43:55 PM
so if I wanted to search for a particular character within only a specified range of each paragraph,
ie

the first (if any) space character found after the 35th character of a paragraph
but only before the first tab character

how would I code for only that specific area on each line to search within?

I guess I'm thinking within a text editor, not QuarkXpress.
Title: Re: How would you?
Post by: cdms on April 26, 2010, 02:50:07 AM
The basic construction of this is relatively simple;

I would find the offset of the first tab

set theTabCount to offset of tab in (theParagraph as string)

then chop out characters 35 to this position as a separate string

set theSearchBit to (characters 35 thru theTabCount of (theParagraph as string)) as string

then find the offset of the first space in this bit and add back on the "skipped" 34 characters.

set theSpacePosition to (offset of " " in theSearchBit) + 34

However, the tricky bit will still be making sure you deal with all the exceptions.
The ones that spring to mind immediately are
1. the tab position is before character 35 (presumably just do not insert the sr)
2. the first space is after the maximum width of the allowed string in your layout.
3. the bit between character 35 and the tab does not contain a space. (this may mean you also have case 2).
4. someone changes the font (presumably you are not limited to fixed width fonts) and you have to start again with your allowed string lengths.
Title: Re: How would you?
Post by: AutoFetishist on April 27, 2010, 04:04:19 PM
cdms,

I'm still going over the code you posted, but I just wanted to thank you.

Title: Re: How would you?
Post by: AutoFetishist on May 07, 2010, 03:51:01 PM
OK, here's what I've got.
(Its able to compile and run, but then conks out with an error type -116)
Can you see where I'm going wrong?

Quote
tell document 1 of application "QuarkXPress"
     activate
     tell current box
          tell story 1
               repeat with i from 1 to count of paragraphs
                    if name of style sheet of paragraph i is "Company Table" then
                         set currentparagraph to paragraph i as string
                         --find the offset of the first tab
                         set theFirstTabCount to (offset of first character where it is (ASCII character 9) in paragraph i) as integer
                         --if the tab's offset is greater than 35 continue, otherwise skip to next paragraph
                         if theFirstTabCount < 35 then
                              exit repeat
                         else
                              --chop out characters 35 to the first tab as a separate string
                              set theSearchBit to (characters 35 thru (character theFirstTabCount) of paragraph i)
                         end if
                         --find the offset of the first space in this bit and add back on the "skipped" 34 characters
                         set the space2replace to (offset of first character where it is (ASCII character 32) in theSearchBit) as integer
                         --set theSpacePosition to offset of (first character where it is (ASCII character 32) in theSearchBit)
                         set character space2replace to (ASCII character 7)
                    end if
               end repeat
          end tell
     end tell
end tell

Title: Re: How would you?
Post by: cdms on May 08, 2010, 03:02:07 AM
Not got access to Quark at the minute so I can't test this. However two immediate issues;
When you do the replace you will need to target the paragraph. Something like
set character space2replace of paragraph i to ....

On your check of the first tab count position you have an exit repeat. This will not skip to then next paragraph it will stop the loop completely (i.e. not do this one or any subsequent ones)

One other thought. Will you need to recheck from the position of the new soft return to the first tab in case it is still too long?

HTH
Title: Re: How would you?
Post by: AutoFetishist on May 08, 2010, 06:02:40 AM
Neither do I (have access to Q), but

When you do the replace you will need to target the paragraph.
--wouldn't I want to target just the "searchbit" portion of the paragraph -- not the entire paragraph?


On your check of the first tab count position you have an exit repeat.
--glad you pointed that out; I wasn't sure how to code "go on to the next paragraph, and continue with the loop"

Will you need to recheck from the position of the new soft return to the first tab in case it is still too long?
--I can worry about that later, for now I'd just like to learn to do one line wrap.

You're a saint for helping me with this, on a Saturday!
Title: Re: How would you?
Post by: cdms on May 08, 2010, 08:46:46 AM
The searchbit portion is not part of the paragraph it is now a completely separate string although you may well have a list at the minute (put as string on the end)
Also you have not got the +34 on the end of the setting the Space position.
Missed this earlier (it has been a veeery long night).


for the exit repeat bit just reverse the if condition and get rid of the else (i.e. only do the work if theFirstTabCount > 34)

Title: Re: How would you?
Post by: AutoFetishist on May 10, 2010, 08:26:31 AM
Alright, back in Quark on a Monday...

I made the fixes you recommended.
But I'm noticing that this code

                         set theFirstTabCount to (offset of first text where it is (ASCII character 9) in currentparagraph) as integer

isn't returning the proper value. Its actually giving me the last tab character in the paragraph, not the first.

Weird. Would QX be counting from the right instead of the left?
Title: Re: How would you?
Post by: cdms on May 10, 2010, 09:54:34 AM
I am using 8.0.2 and I can't get your bit to work at all.
However doing it as

tell currentparagraph
set theFirstTabCount to (offset of first text where it is (ASCII character 9)
end tell

seems to work. ???  It should be the same but these are the vagaries of Applescript dictionaries that keep us amused. :P
Title: Re: How would you?
Post by: AutoFetishist on May 10, 2010, 10:31:51 AM
AAAAAAAAGH!!

When I try your way, I get "xxx corporation    6,566    abb   $17.00    $32.45     14.8   11.5   0.0%     42.9" (the content of the string)
 doesn't understand the ASCII character message.
Title: Re: How would you?
Post by: cdms on May 10, 2010, 12:07:44 PM
OK, my fault. I have just gone back and read your code again. We need to be more careful with using your currentparagraph variable. This is a copy of the actual paragraph as a string.
try using my last post with tell paragraph i NOT tell currentparagraph.
Title: Re: How would you?
Post by: AutoFetishist on May 10, 2010, 12:45:13 PM
Here's a Quark file to test on:
http://dl.dropbox.com/u/499885/test.zip (http://dl.dropbox.com/u/499885/test.zip)

When you run the script on it, do you get the offset of the first tab being returned as 89?

Title: Re: How would you?
Post by: cdms on May 10, 2010, 01:37:46 PM
Right I can see what is happening now. Quark have hijacked the offset command. This means that using offset inside a tell application "QuarkXpress" block does not behave the same as using it outside that block. This is more than a little naughty. The only thing that comes to mind at the moment is to find the suspect paragraphs. Work out the space positions outside Quark and then go back in to apply the returns.

this looks like;


Code: [Select]
tell document 1 of application "QuarkXPress"
activate
tell current box
tell story 1
set theParagraphs to {}
repeat with i from 1 to count of paragraphs
if name of style sheet of paragraph i is "Company Table" then
set end of theParagraphs to text of paragraph i
end if
end repeat
end tell
end tell
end tell


set thePositionList to {}
repeat with eachParagraph in theParagraphs
set theFirstTabCount to offset of tab in eachParagraph
--if the tab's offset is greater than 35 continue, otherwise skip to next paragraph
if theFirstTabCount < 34 then
set end of thePositionList to 0
else
--chop out characters 35 to the first tab as a separate string
set theSearchBit to (characters 35 thru theFirstTabCount of eachParagraph) as string
--find the offset of the first space in this bit and add back on the "skipped" 34 characters
set end of thePositionList to (offset of " " in theSearchBit) + 34
end if
end repeat

tell document 1 of application "QuarkXPress"
activate
tell current box
tell story 1
set j to 0
repeat with i from 1 to count of paragraphs
if name of style sheet of paragraph i is "Company Table" then
set j to j + 1
if item j of thePositionList is not equal to 0 then
set character (item j of thePositionList) of paragraph i to (ASCII character 7)
end if
end if
end repeat
end tell
end tell
end tell

It appears to work on your document but it is not quick and there is a big wait before anything happens at all.

I'm off home now. See you tomorrow.
Title: Re: How would you?
Post by: AutoFetishist on May 10, 2010, 04:03:51 PM
It works!

Intermittently.

I'll write back tomorrow.
Title: Re: How would you?
Post by: AutoFetishist on May 11, 2010, 08:40:09 AM
cdms,

Its working!
Of course now I see that unless using a monospace font, attempting to use character count as a method of measuring horizontal distance is going to be a crapshoot.

But it was fascinating at any rate.

What was Quark doing wrong?
Title: Re: How would you?
Post by: Publi-Script on May 11, 2010, 10:52:45 AM
You can calculate EXACTLY how wide variable width text will be by asking quark to return the width of each characters.

Here some food for tought:
Quote
001     property CharWidth : {}
002     property AsciiSpace : 32

003     my GetCharWidths() -- Run this only once prior to running your final script
004     set ColumnTexts to my getColumnText("Trailers gossips noisily. Five putrid wart hogs quite annoyingly fights umpteen progressive tickets. Putrid chrysanthemums drunkenly kisses one mat, even though umpteen aardvarks grew up very quickly, but two purple Klingons bought umpteen trailers. Five progressive tickets auctioned off dwarves.
005     Darin slightly drunkenly kisses umpteen very quixotic poisons, because five dogs annoyingly fights umpteen dwarves. The schizophrenic cat gossips, then umpteen subways auctioned off Springfield. The chrysanthemum gossips.
006     Five bureaux quite cleverly tickled Jupiter, because two speedy elephants abused umpteen schizophrenic subways, and two aardvarks laughed, because umpteen speedy bureaux comfortably untangles two silly chrysanthemums, but one partly obese orifice tickled umpteen televisions, because schizophrenic chrysanthemums bought Darin.
007     Five mostly quixotic mats laughed. Putrid subways grew up cleverly, and umpteen obese Klingons gossips partly quickly. Two aardvarks towed the progressive trailer. One Macintosh gossips. Five sheep grew up, even though Quark tickled Tokyo, although dwarves mostly drunkenly perused the quixotic wart hogs. Almost bourgeois poisons laughed, but umpteen partly speedy botulisms tastes the mat. Jabberwockies grew up comfortably. Two quite schizophrenic poisons kisses umpteen cats. Two chrysanthemums sacrificed five almost quixotic lampstands, then the televisions marries mostly schizophrenic mats. The almost bourgeois pawnbrokers grew up drunkenly, however five progressive Jabberwockies tastes one orifice, and umpteen irascible dogs bought two mostly purple subways. Umpteen sheep gossips, because the orifices quickly abused one quixotic ticket. Two dwarves drunkenly bought umpteen trailers. Two poisons gossips almost noisily. One bourgeois Macintosh sacrificed Mark.
008     Umpteen botulisms tastes two chrysanthemums. One partly putrid fountain marries umpteen Macintoshes, yet two speedy fountains grew up mostly comfortably. Umpteen dwarves perused progressive elephants, although the quite bourgeois aardvarks gossips, and speedy cats noisily tastes five schizophrenic Klingons.", 300)

009     set OldDelims to AppleScript's text item delimiters
010     set AppleScript's text item delimiters to {return}
011     set TheText to ColumnTexts as string
012     set AppleScript's text item delimiters to OldDelims

013     tell application "QuarkXPress Passport 7.x"
014          activate
015          set DocName to name of document 1
016          tell document DocName
017               tell text box 1
018                    set story 1 to TheText
019               end tell
020          end tell
021     end tell

022     on GetCharWidths()
023          tell application "QuarkXPress Passport 7.x"
024               activate
025               set DocName to name of document 1
026               tell document DocName
027                    tell text box 1
028                         -- Pad the beginning of the list to allow direct acces with asciiNum later
029                         repeat with a from 1 to 31
030                              set end of CharWidth to 0
031                         end repeat
032                         
033                         -- Populate the rest of the list with actual charcater width of the cuurent font
034                         repeat with a from 32 to 255
035                              set story 1 to ASCII character a
036                              set TheWidth to width of story 1
037                              set end of CharWidth to TheWidth as real
038                         end repeat
039                    end tell
040               end tell
041          end tell
042     end GetCharWidths

043     on getTextWidth(TheText)
044          -- TheText: The string to calculate the total width of
     
045          set TextWidth to 0
046          repeat with ThisChar in TheText
047               set TextWidth to TextWidth + (item (ASCII number of ThisChar) of CharWidth)
048          end repeat
049          return TextWidth
050     end getTextWidth

051     on getColumnText(TheText, ColumnWidth)
052          local TextColumns, AllWords, ThisColumnText, CurWidth
053          -- TheText: The text to separate into visual columns
054          -- ColumnWidth: the width of the column in pts
     
055          set TextColumns to {}
056          -- First, let's separate our text into words
057          set AllWords to my GetTextItem(TheText, space, 0)
     
058          set CurWidth to 0
059          set ThisColumnText to ""
060          repeat with w from 1 to count of AllWords
061               set ThisWordWidth to my getTextWidth(item w of AllWords)
062               if (CurWidth + ThisWordWidth) > ColumnWidth then
063                    set end of TextColumns to ThisColumnText
064                    set ThisColumnText to ""
065                    set CurWidth to 0
066                    set w to w - 1
067               else
068                    set CurWidth to CurWidth + (item AsciiSpace of CharWidth) + ThisWordWidth
069                    set ThisColumnText to ThisColumnText & space & (item w of AllWords) as text
070               end if
071          end repeat
     
072          return TextColumns
073     end getColumnText

074     on GetTextItem(ThisString, ThisDelim, ThisItem)
075          -- ThisString -> String to look in
076          -- ThisDelim -> Text element that delimit the string
077          -- ThisItem -> Number of the element to return
078          copy the text item delimiters to OldDelims
079          set the text item delimiters to ThisDelim
080          if class of ThisItem is list then
081               set fromItem to (item 1 of ThisItem) as integer
082               set toitem to (item 2 of ThisItem) as integer
083               set arrItem to (text items fromItem thru toitem of ThisString)
084          else
085               set arrItem to every text item of ThisString
086          end if
087          set the text item delimiters to OldDelims
     
     
088          if class of ThisItem is list then
089               return arrItem as text
090          else
091               if ThisItem is not 0 then
092                    return (item ThisItem of arrItem) as text
093               else
094                    return arrItem -- return every items
095               end if
096          end if
097     end GetTextItem

This script will break your original TEXT into paragraphs of a certain length based on the supplied character widths.

To make use of this script:


This script returns a list of lines of text, in this example, On line 010, I inserted a paragraph return between each line but you can put whatever you want.

HTH
Title: Re: How would you?
Post by: cdms on May 11, 2010, 10:53:47 AM
Quark documents use 'offset' as a property of various elements to do with where things are aligned on a grid. Hence, when we are inside the tell "QuarkXpress" block, and try to use offset as an applescript command, Quark is grabbing it and trying to return the relative position on the base grid of where ever the character is that we have found.
This is really not good.

The works 'intermittently' affect you were seeing is due to some of the exceptions we discussed earlier. The main culprit being no space in the string between position 35 and the tab character. Also a slight problem was arising where the tab was character 36. Just for completeness, the following code resolves the last option and has performance enhancements by storing the paragraph numbers and accessing them directly the second time, rather than re-looping through then all again.

Code: [Select]
tell document 1 of application "QuarkXPress"
activate
tell current box
tell story 1
set theParagraphs to {}
repeat with i from 1 to count of paragraphs
if name of style sheet of paragraph i is "Company Table" then
set end of theParagraphs to {text of paragraph i, i}
end if
end repeat
end tell
end tell
end tell


set thePositionList to {}
repeat with eachPair in theParagraphs
set eachparagraph to item 1 of eachPair
set theFirstTabCount to offset of tab in eachparagraph
--if the tab's offset is greater than 35 continue, otherwise skip to next paragraph
if theFirstTabCount > 35 then
--chop out characters 35 to the first tab as a separate string
set theSearchBit to (characters 35 thru theFirstTabCount of eachparagraph) as string
--find the offset of the first space in this bit and add back on the "skipped" 34 characters
set theSpacePosition to ((offset of " " in theSearchBit) + 34)
-- check not 34 as this means tab was next character (or no space found)
if theSpacePosition > 35 then
set end of thePositionList to {theSpacePosition, (item 2 of eachPair)}
end if
end if
end repeat

tell document 1 of application "QuarkXPress"
activate
tell current box
tell story 1
set j to 0
repeat with eachEntry in thePositionList
set theSpacePosition to item 1 of eachEntry
set theParagraph to item 2 of eachEntry
set character theSpacePosition of paragraph theParagraph to (ASCII character 7)
end repeat
end tell
end tell
end tell

Maybe a table?  :P

Title: Re: How would you?
Post by: AutoFetishist on May 12, 2010, 09:36:48 AM
Michel,
I'm in awe.

I ran the GetCharWidths handler, got 0.0332...

When you say only run that handler once, would that mean I can remove code lines 001-008, as well as 022-042?
Title: Re: How would you?
Post by: Publi-Script on May 12, 2010, 10:15:50 AM
In short... NO!

001 -> You NEED this line in the main script, BUT, after running the GetCharWidths() handler, you need to copy the resulting list (all 255 items) withing the empty brackets.
002 -> You NEED this in the main script to return the width of a single space.
003 -> You can DELETE this line
004 - 008 -> You NEED these lines (it should have been 1 line really) in the main script. This is the line that will return your separated lines given your column width.
022-042 -> You can DELETE these lines.

It appears that you only have the last CharWidth measured, to ensure that you see them all, add the following line after theGetCharWidths() call:

    return CharWidth

Replace the empty curly braces of you CharWidths property with the content of the result window.

HTH
Title: Re: How would you?
Post by: AutoFetishist on May 12, 2010, 11:24:55 AM
Would I copy the values as points or need to translate them as real?

ie: {"p1.8", "p1.994", "p2.671", "p3.6", "p3.6"}
Title: Re: How would you?
Post by: Publi-Script on May 12, 2010, 12:35:33 PM
Values should already be as REAL as per line 037 and that is what they need to be
Title: Re: How would you?
Post by: AutoFetishist on May 12, 2010, 04:00:23 PM
questions, questions...

why, in lines 022-042, do you separate ASCII characters 1-31 from characters 32-255?

Would I replace lines 004-008 with my document's text?

 
Title: Re: How would you?
Post by: Publi-Script on May 12, 2010, 05:28:08 PM
The first 31 Ascii characters are special characters and have no width. I put them in anyway just to be able to access the list with the AsciiNum of any char without having to substract 31 every time.

Yes your text will go on lines 004-008 but be careful to keep the handler call part as well as the column width parameter.
Title: Re: How would you?
Post by: cdms on May 13, 2010, 01:15:52 AM
I maybe speaking out of turn here, but the way I read this and looking at your example document, you cannot just put all your documents text into this in one go. I think you need to chop your text off at the first tab, pass each front bit through this handler and then stick it back onto the front of the other columns.
With a small doc I would be tempted to do all this in an array in the script, however, if your example is a typical size doc it may be better to do it one line at a time and build the results back into a second text box.
Although your character count method is not accurate there should be some lower number that is safe just to help prevent unnecessary passes through.

Title: Re: How would you?
Post by: Publi-Script on May 13, 2010, 07:53:33 AM
You are not speaking out of turn, these are valid points you are making.

I did not state this but you are right, this handler on process the text that makes up the content of 1 visual cell. Of course, it could be modified to accept the text of the whole table and return the formatted table text.
Title: Re: How would you?
Post by: AutoFetishist on May 13, 2010, 08:43:26 AM
You're right cdms, the handlers would need to be pointed at each paragraph in the story.

I know I might be the only one, but I think this is fascinating. Thanks to both of you.