iWork Apps(Keynote、Pages、Numbers)にはAppleScript系の機能でいろいろ勘弁してほしい仕様がありますが、その中でも最大のものが、書類内の各オブジェクトがIndexで管理されていることです。
Indexというのは、1からはじまる連番の数値です。
iWork Apps(Keynote、Pages、Numbers)のドキュメント上でオブジェクトの削除を行おうとすると、「地獄」を見ることになります。
iWork Appsの書類上でオブジェクトの削除を行うと、このIndex値が振り直されてしまうために、正しく「対象」を指し示すことが(途中から)できなくなってしまうのです。あるいは、まったく関係のない別のオブジェクトが削除されるとか。
これが、idで管理されていれば、何かのオブジェクトを削除されても影響はありません。何かUUID的な重複しないidが割り振られて、最初から最後まで(アプリケーションが起動してから終了するまで、あるいは書類がオープンされてからクローズされるまで)個別に識別されます。
対策
各オブジェクトを識別する場合に、それ専用の属性値を持たせることがあります。
Adobe InDesign:script label AppleScriptから設定・確認が可能なラベル(文字列)を設定できる
もともとある仕組みを本来の目的以外の用途に使うことができるケースもあります。
OmniGraffle:URL urlとかいいつつ、文字列だったらだいたいなんでも入った記憶が
そして、iWork Apps(Keynote、Pages、Numbers)。普段ほとんど使わなくて、AppleScriptから操作できて害のない属性値なんて便利なものがあるわけが……ありました。
Keynoteで使っている例は見かけましたが、他で使ったことのない「reflectin value」。つまり、「反射」属性。
PagesでもNumbersでも使ったことがありません。個人的には、Keynoteでも使ったことがないと思います。
選択状態にあるオブジェクトをもとに何らかの処理を行なって、選択していたオブジェクトを削除する場合に、普通に処理すると(オブジェクトがIndexで管理されているので)、地獄を見ます。
なので、削除対象のオブジェクトのreflection valueに100とか(1〜100のうち、0でないお好きな値を)を設定しておいて、ひととおり処理し終わったら、reflection valueが指定値になっているオブジェクトだけをフィルタ参照で削除する、といった対策が有効です。
実際のAppleScript
前処理Scriptで、最初にreflection valueが何か設定されているオブジェクトが存在しないことを確認したうえで、選択中のオブジェクトのreflection valueに100を設定し……
AppleScript名:削除_前処理.scptd |
tell application "Pages" tell front document set reList to every iWork item whose reflection value is 100 if length of reList is not equal to 0 then return set aSel to selection repeat with i in aSel set j to contents of i set reflection value of j to 100 end repeat end tell end tell |
処理を行なったあとで、reflection valueに100と設定されているオブジェクトを削除します。
AppleScript名:削除_後処理.scptd |
tell application "Pages" tell front document tell current page set aSel to delete (every iWork item whose reflection value = 100) end tell end tell end tell |