Re: Asking User Input on First Run only
Re: Asking User Input on First Run only
- Subject: Re: Asking User Input on First Run only
- From: Kai Edwards <email@hidden>
- Date: Tue, 31 Dec 2002 19:29:30 +0000
on Mon, 30 Dec 2002 23:54:15 -0600, Joseph Weaks <email@hidden> wrote:
>
Kai,
>
This is great. Thanks so much.
Glad to be of help, Joe! :-)
>
It is really quite simple and straightforward.
- Sounds like a pretty fair description of me, too. (Well, certainly the
first part!) ;-)
>
I thought properties would work in this way. Though, I've never used this "to
>
blah blah blah" handler format.
Just syntax variations, which can sometimes help to clarify a handler's
function - and offer a few additional clues as to the handling of its
parameters [1].
>
One glitch has me puzzled. When it is run for the first time, after the
>
two files are selected, the script ends with no more dialog boxes.
Not exactly a glitch. I simply misinterpreted your original description [2].
>
Is that the purpose of the "error number -128"?
Exactly. Error number -128 causes the script to behave as if the user
canceled [3].
>
When I remove the line, the script busts.
Yeah - that doesn't surprise me. The 'error number -128' line was originally
intended to escape subsequent actions - so its removal forces the script to
handle situations it wasn't originally intended to.
You encountered an error because, as it stands (without the 'error number
-128' get-out), the 'getFileAliases' handler will return values of the wrong
class when it errors within the try block [4].
>
Shouldn't the script go ahead and do the synchronization once the files have
>
been selected?
It can certainly be persuaded to do that - given the odd nip'n'tuck:
===========================
property p1 : missing value
property p2 : missing value
property d0 : missing value
to getFileAliases()
try
{p1 as alias, p2 as alias}
on error
set {p1, p2} to {getFile for 1, getFile for 2}
if p1 = p2 then
set {p1, p2, d0} to {missing value, missing value, missing value}
beep
display dialog "You chose the same file." buttons [NO BREAK]
"Cancel" default button 1 with icon 0
end if
{p1 as alias, p2 as alias}
end try
end getFileAliases
to getFile for n
(choose file with prompt "Please choose file " & n) as string
end getFile
to getFileDates for {f1, f2}
tell application "Finder" to set {d1, d2} to [NO BREAK]
{f1's modification date, f2's modification date}
if d0 = missing value then
if d2 < d1 then
set d0 to d2
else
set d0 to d1
end if
end if
{d1, d2}
end getFileDates
on doubleMod on {d1, d2} from {f1, f2}
beep
display dialog [NO BREAK]
"Both files have been modified since the last update." & [NO BREAK]
return & return & "Update the older file anyway?" with icon 2
if d1 > d2 then
dupeMod on d1 from f1 to f2
else
dupeMod on d2 from f2 to f1
end if
end doubleMod
on noMod()
display dialog "Neither file has been modified." buttons [NO BREAK]
"Cancel" default button 1 with icon 0
end noMod
to dupeMod on d from src to tgt
display dialog "Source file: " & return & src & return & [NO BREAK]
return & "Target file: " & return & tgt & return & [NO BREAK]
return & "OK to duplicate source to target file?" with icon 1
tell application "Finder" to [NO BREAK]
duplicate src to tgt's container with replacing
set d0 to d
end dupeMod
set {f1, f2} to getFileAliases()
set {d1, d2} to getFileDates for {f1, f2}
if d1 > d0 then
if d2 > d0 then
doubleMod on {d1, d2} from {f1, f2}
else
dupeMod on d1 from f1 to f2
end if
else
if d2 > d0 then
dupeMod on d2 from f2 to f1
else
noMod()
end if
end if
===========================
Oh yeah - You'll see that I've also added a trap to escape the script -
should the same file be chosen twice. (Unlikely, perhaps - but anything's
possible).
--------------------------------------------------------
[1] To signify the start of a handler, many of the examples we see use 'on'.
('on noReply', 'on minusValue', 'on escapingTheMysteriousCavernOfDoom',etc.)
However, if the handler represents some action, then 'to' could be used
instead. ('to makeList', 'to getInfo', 'to enterTheGloriousHallOfFame',etc.)
And the "blah blah blah" bit?
Well, that's just another way of constructing handlers to help make them
resemble English a little better (which is supposed to be a feature of
AppleScript, after all). This approach can, in turn, reduce the need for
copious commenting.
Let's say, for example, that you wanted to filter out certain value bands
from a list. Since this could involve checking the values of several
parameters, you might end up with a handler that looks something like this:
- - - - - - - - - - - - - - - - - - - -
selectNumbers(numberList, 5, 50, 10, 30)
- - - - - - - - - - - - - - - - - - - -
However, at first glance, it's not immediately clear (to me, at any rate)
what the 'selectNumbers' handler will do with those parameters. And the
greater the ambiguity of a script (especially a lengthy one), the more
difficult it becomes to debug or modify.
Instead of lumping the parameters together in parentheses, it's possible to
clarify the handler's purpose better - by using a subroutine with labeled
parameters [5] instead. For instance:
- - - - - - - - - - - - - - - - - - - -
selectNumbers from numberList between 5 to 50 apart from 10 thru 30
- - - - - - - - - - - - - - - - - - - -
...or, if preferred, even:
- - - - - - - - - - - - - - - - - - - -
|select numbers| between 5 to 50 from |number list| apart from 10 thru 30
- - - - - - - - - - - - - - - - - - - -
So, just to complete the illustration, the whole thing might go:
===========================
to selectNumbers from lst between min to max apart from lowr thru uppr
set rslt to {}
repeat with n in lst
if n > min - 1 and n < max + 1 and [NO BREAK]
(n < lowr or n > uppr) then set rslt's end to n
end repeat
rslt's contents
end selectNumbers
set numberList to {1, 3, 5, 6, 8, 12, 15, 21, 26, 27, 33, 42, 49, 58, 63}
selectNumbers from numberList between 5 to 50 apart from 10 thru 30
--> {5, 6, 8, 33, 42, 49}
===========================
--------------------------------------------------------
[2] When you said...
>
> The first time the script is run, the user should specify the two locations
>
> of the files. After that, it can default to those two locations, check for
>
> modification dates, and overwrite the older file with the newer one.
...I took this to mean that, on the first run, the script should only select
the required files - leaving the other stuff to subsequent runs. (Sorry for
the misunderstanding - told you I was simple!)
--------------------------------------------------------
[3] Since error number -128 doesn't throw up an error message, the script is
'quietly' halted. (In normal circumstances, the user already knows that
he/she has canceled - so there's little point in telling him/her.)
However, if you want to check what actually happens when you cancel, try
running a script like this:
===========================
try
delay 5
on error e number n
error e & return & n
end try
===========================
Then, while the script is still running, hit Script Editor's 'Stop' button
or press the "command" + "." keys.
--------------------------------------------------------
[4] In this case (without the 'error number -128' line), the
'getFileAliases' handler's final act is to call the 'firstRun' handler -
which returns something like this:
- - - - - - - - - - - - - - - - - - - -
{"Macintosh HD:test folder 1:test file", "Macintosh HD:test folder 2:test
file", date "Tuesday, December 31, 2002 11:46:06 am"}
- - - - - - - - - - - - - - - - - - - -
Because these values are the final result of the 'getFileAliases' handler,
it passes them back to the main (run) handler. This then obligingly sets the
variables, f1 & f2, to the first 2 items of the returned value list.
Remember, these values are still strings - something like {"Macintosh
HD:test folder 1:test file", "Macintosh HD:test folder 2:test file"}.
They're not aliases or file references - which is what the Finder will
eventually expect [6].
The script then continues with:
- - - - - - - - - - - - - - - - - - - -
tell application "Finder" to set {d1, d2} to {f1's modification date, f2's
modification date}
- - - - - - - - - - - - - - - - - - - -
However, since the Finder can't get file properties from a string, an error
number -1728 is thrown up (indicating a run-time resolution error). The
error message you saw probably looked something like this:
- - - - - - - - - - - - - - - - - - - -
Can't get modification date of "Macintosh HD:test folder 1:test file".
- - - - - - - - - - - - - - - - - - - -
--------------------------------------------------------
[5] A subroutine parameter label is one of the following:
above / against / apart from / around / aside from / at / below / beneath /
beside / between / by / for / from / instead of / into / on / onto / out of
/ over / thru / to / under
For any given subroutine, you can't use the same label for more than one
parameter. (Although the ASLG doesn't include the label 'to', my impetuous
and reckless use of it doesn't appear to have given me any trouble - so
far...)
--------------------------------------------------------
[6] So why didn't I just store the file aliases, rather than path strings,
in the script's properties?
When the Finder replaces one file with another, the replaced file is moved
to the Trash. Since this can change an alias path stored in the script - it
could also produce somewhat... 'unexpected' results. By storing only path
strings, the script's file aliases are recreated on each run.
--------------------------------------------------------
I hope that I've been able to make the water a little less muddy - but do
let me know if you still have any queries or comments.
Best wishes.
--
Kai
_______________________________________________
applescript-users mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/applescript-users
Do not post admin requests to the list. They will be ignored.