Applescript and Quarkxpress Passport v 6.5

616 Views Asked by At

I have a script that goes through several paragraphs/lines and applies Paragraph and Character style sheets accordingly. Although the script runs perfectly (I hope it might help someone out there) - the process takes too long - I might have gone about it the long way... I was hoping that someone might help me to reduce the processing time. Below is the Applescript: as well a few lines of my text (The original text contains 80) lines.

The Quarxpress text:

R45m    HOUSE. Landmark property with panoramic views, 2000m2 on over 8 200m2.  web ref: 3036011  
R35m    HOUSE. Contemporary 4 bedroomed home on view slopes of Mount Street web ref: 3137609  
R27.5m  HOUSE. Ambassadorial 6 bedroomed home on over 5000m2    web ref: 3137592
R19.95m HOUSE. Brand new Georgian 5 bedroomed home on an acre   web ref: 3057625
R19m    ESTATE. Classical home of 1200m2 on 5000m2 of landscaped gardens    web ref: 234336
R17.5m  BOUTIQUE HOTEL. 11 Luxurious suites within a majestic setting on over 5000m2    web ref:3147123
R16.95m HOUSE. Classical 5 bedroomed home on 4127m2 in Hamilton Enclosure   web ref: 3230085
R15.5m  HOUSE. Georgian residence of 1100m2 close to the Country Club   web ref: 737272
R13.5m  HOUSE. A master-built contemporary home, amazing easterly views web ref: 3096574
R9.95m  HOUSE. Renovated family home with pool and court on an acre in Bryanston West   web ref: 3193537
R8.95m  ESTATE. 43 on Eccleston. Packages in R8m’s. Contemporary home with views    web ref: 3225098
R8.25m  HOUSE. Renovated 4 bedroom home in top ave in Bryanston East on 3255m2  web ref: 3248317
R6.95m  HOUSE. Nico van der Meulen contemporary masterpiece requiring final finishing   web ref: 3212495
R5.95m  HOUSE. Renovated 3 bedroom home in boomed enclosure on 4660m2.  web ref: 3247597
R5.5m   HOUSE. Prime position in boomed enclosure in Bryanston East, excellent potential    web ref: 3201665
To view any of the above call Regan: 088 888 8888 or Erica: 088 888 8888

My Applescript:

tell application "QuarkXPress Passport"
    tell document 1
        set MyStyle3 to object reference of character spec "RedCopy"
        set MyStyle1 to object reference of style spec "MainCopy"
        set MyStyle4 to object reference of character spec "BoldCopy"

        tell story 1 of current box
            set style sheet of every paragraph to null
            delay 5
            set ParagraphCounter to (get count of paragraphs)
            repeat with n from 1 to ParagraphCounter
                tell paragraph n
                    try
                        set style sheet to MyStyle1
                    end try
                    try
                        if words 1 thru 2 contains "." then
                            set character style of words 1 thru 3 to MyStyle4
                        else
                            set character style of words 1 thru 2 to MyStyle4
                        end if
                    end try
                    try
                        set character style of word 2 to MyStyle4
                    end try

                    try
                        set character style of words -3 thru -1 to MyStyle4
                    end try

                    try
                        if words 1 thru 2 starts with "To view" then
                            set character style of words 1 thru -1 to MyStyle3
                        end if
                    end try
                end tell
            end repeat



        end tell
    end tell
end tell
beep 3
1

There are 1 best solutions below

3
On

Why is Applescript slow?

The biggest trick to improving performance in Applescript is to remove as many AppleEvents as possible. Every command you issue directly to an application is executed as an AppleEvent. For example the following code executes two AppleEvents. One to get all of the words in a paragraph, and one to set the character style for the paragraph:

tell story 1 of current box
   tell paragraph n
        if words 1 thru 2 contains "." then
            set character style of words 1 thru 3 to MyStyle4
        else
            set character style of words 1 thru 2 to MyStyle4
        end if
    end tell
end tell

Analysis

So, looking at your script, you have 5 AppleEvents in setup, 7 that regularly get executed during the loop, and 1 that gets executed for the last line ("to view"). 5 + 80 * 6 + 1 = 486 AppleEvents for 80 lines of text.

By pulling some of those events into the setup and working directly with native Applescript types, you can bring that number down dramatically.

Fixes

1) Remove unnecessary code

You can remove the following line completely:

set character style of word 2 to MyStyle4

You're already applying MyStyle4 to word 2 when you check for a period.

--word 2 is covered under both "words 1 thru 2" and "words 1 thru 3".
if words 1 thru 2 contains "." then
    set character style of words 1 thru 3 to MyStyle4
else
    set character style of words 1 thru 2 to MyStyle4
end if

2) Apply defaults outside of the loop.

You apply a null style sheet to all of the paragraphs, then re-apply MyStyle1 to each paragraph one-by-one. So remove these lines

set style sheet of every paragraph to null
[...]
set style sheet to MyStyle1

and replace it, before the loop, with

set style sheet of every paragraph to MyStyle1

You can apply the same thing to bolding the last three words:

-- this is being run during every iteration of the loop
set character style of words -3 thru -1 to MyStyle4

Apply it all before the loop, and it only costs you one AppleEvent

set character style of words -3 thru -1 of every paragraph to MyStyle4

3) Don't use AppleEvents when you don't have to

As discussed before, every time you request information from Quark, it costs you an AppleEvent. During your 80 line text, you are sending 160 AppleEvents for the following checks:

tell paragraph n
    if words 1 thru 2 contains "." then [...]
    if words 1 thru 2 starts with "To view" then [...]
end tell

To fix this, you can get all of the text up front, which will make the paragraphs Applescript native types, and run your conditional checking on that. So, before the loop:

tell story 1 of current box
    set quarkText to every paragraph
end tell

This will give you a list of strings that you can process, and run conditionals on without needing to send AppleEvents to Quark.

Putting it all together

So, what would a script like that look like?

tell application "QuarkXPress Passport"
    tell document 1
        set MyStyle1 to object reference of style spec "MainCopy"
        set MyStyle3 to object reference of character spec "RedCopy"
        set MyStyle4 to object reference of character spec "BoldCopy"

        tell story 1 of current box
            -- Anything that is run during every iteration should be moved outside
            -- the loop, and targeted at every paragraph.
            set style sheet of every paragraph to MyStyle1
            set character style of words -3 thru -1 of every paragraph to MyStyle4

            delay 5

            -- Transform data once, instead of every loop iteration
            set quarkText to every paragraph
            set ParagraphCounter to (get count of quarkText)

            repeat with n from 1 to ParagraphCounter
                -- currentLine is now a string that is not dependent on Quark, which
                -- means you have cut way down on AppleEvents
                set currentLine to item n of quarkText
                tell paragraph n
                    if word 1 of currentLine contains "." then
                        set character style of words 1 thru 3 to MyStyle4 -- AppleEvent
                    else
                        set character style of words 1 thru 2 to MyStyle4 -- AppleEvent
                    end if

                    if currentLine starts with "To view" then
                        set character style of words 1 thru -1 to MyStyle3 -- AppleEvent
                    end if
                end tell
            end repeat
        end tell
    end tell
end tell
beep 3

Note that I changed the if statement that looks for a period. In pure Applescript, if there are no spaces surrounding the period, it apparently counts it as part of the word.

word 1 of "R27.5m   HOUSE." --> "R27.5m"

Now, there are 6 AppleEvents in the setup, only one that gets executed regularly during the loop, and one for the last line, bringing the count down to 6 + 80 * 1 + 1 = 87 AppleEvents

Caveat

I do not have Quark installed on my machine, but looking at the code you've written, the keyword word may have a collision with the Quark dictionary. In this case, you may need to move all of your string checking outside of a Quark tell block. My first thought is, you could make a subroutine that actually applies the styles, and call that subroutine when necessary:

on apply_style(characterStyle, paragraphNumber, startWord, endWord)
    tell application "QuarkXPress Passport"
        tell document 1
            tell story 1 of current box
                tell paragraph paragraphNumber
                    set character style of words startWord thru endWord to MyStyle4
                end tell
            end tell
        end tell
    end tell
end apply_style


tell application "QuarkXPress Passport"
    tell document 1
        set MyStyle1 to object reference of style spec "MainCopy"
        set MyStyle3 to object reference of character spec "RedCopy"
        set MyStyle4 to object reference of character spec "BoldCopy"

        tell story 1 of current box
            set style sheet of every paragraph to MyStyle1
            set character style of words -3 thru -1 of every paragraph to MyStyle4

            delay 5

            set quarkText to every paragraph
        end tell
    end tell
end tell

set ParagraphCounter to (get count of quarkText)
repeat with n from 1 to ParagraphCounter
    set currentLine to item n of quarkText
    if word 1 of currentLine contains "." then
        set myStyle to MyStyle4
        set startingAt to 1
        set endingAt to 3
    else if currentLine starts with "To view" then
        set myStyle to MyStyle3
        set startingAt to 1
        set endingAt to -1
    else
        set myStyle to MyStyle4
        set startingAt to 1
        set endingAt to 2
    end if

    my apply_style(myStyle, n, startingAt, endingAt)
end repeat
beep 3