02/04 指定されたファイルのparentにラベルとコメントを付ける

指定されたファイルの親フォルダに指定のラベルと指定のコメントを付けるAppleScriptです。

実に簡単な内容で、あまり多くの人が気にも止めない内容に見えるのですが、AppleScript的な世界観における重要度はかなり高い処理です。下手をすると、高速ソートルーチンよりも重要かもしれません。

本処理は、さまざまなファイルを大量に処理するようなケースで、かつ、データが各フォルダに分けられて入っている(InDesignの書類とか)ようなケースを想定しています。そして、フォルダ内のデータにエラーが発生した場合には、親フォルダにラベルをつけて色を変え、さらにエラー原因をコメントとして残しておく、ためのものです。

こうした処理が入っているかどうかでツール系のScriptの使い勝手は大きく変わってくるため、「必須」を通り越して「ないとおかしい」というレベルのものです。さらに、Finder上で新規Windowを作成して、エラー対象ファイル/フォルダを選択状態にしておくとか……そうした処理は、ぜひやっておきたいものです(大量にあると困りますけれど)。

スクリプト名:指定されたファイルのparentにラベルとコメントを付ける
set aFile to choose file
set aComment to “エラーだぴよー”
setLabelAndCommentToParentFol(aFile, aComment) of me

–指定されたファイルの親フォルダにラベルとコメントを付ける
on setLabelAndCommentToParentFol(aFile, aComment)
  tell application “Finder”
    set aParent to (parent of aFile) as alias
    
set label index of aParent to 4 –ぶるーのラベル
    
set comment of aParent to aComment
  end tell
end setLabelAndCommentToParentFol

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

02/04 Preview.appで用紙サイズおよび用紙方向を指定して印刷 v2

GUI Scripting経由でPreview.appで印刷を実行。プリンタ名、用紙サイズ、用紙方向を指定して印刷を行うAppleScriptです。

GUI Scriptingを使用しているため、「システム環境設定」の「ユニバーサルアクセス」で、「補助装置にアクセスできるようにする」をオンにしている必要があります。

ただし、使用プリンタは各ユーザー環境によって異なるため、そのまま使えるものとは思わないでください。

また、Preview.appで「画像オープン→印刷→画像クローズ」といった連続したフローを実現するものでもありません。Preview.appで画像をオープンすると、WindowのIDが画像をオープンするたびに+1されるようで、画像を1枚しかオープンしていないのにwindow 2を指定する必要があるとか、そういう状況を考慮した作りにはなっていません。

スクリプト名:Preview.appで用紙サイズおよび用紙方向を指定して印刷 v2
(*
2010/1/19

v2
Preview.appでは、書類をオープンするたびにWindowのインデックスがインクリメントされるらしく、
1枚目の書類はwindow 1でアクセスできるが、2枚目の書類(1枚しかウィンドウは開いていない)に
対しては、Window 2でアクセスする必要がある。これに対処する必要がある(問題未解決)

v1
シンプルタイプのプリントダイアログから拡張プリントダイアログに大きさをひろげたケースと、
最初から拡張プリントダイアログが表示されているケースでは、ポップアップメニューのIDが異なる。

拡張ダイアログが表示されていなかったら、拡張表示にして一度キャンセルし、再試行するようにした(10回まで)

*)

–set directionF to "V" –用紙方向=たて方向
set directionF to "H" –用紙方向=たて方向

set printerName to "PS-NX650"
set paperSize to "A4"

printViaGUI(directionF, printerName, paperSize) of me

on printViaGUI(directionF, printerName, paperSize)
  activate application "Preview"
  
tell application "System Events"
    tell process "プレビュー"
      
      
set goF to false
      
repeat 10 times
        –メニューから印刷を実行
        
click menu item "プリント…" of menu 1 of menu bar item "ファイル" of menu bar 1
        
        
tell window 1
          tell sheet 1
            –拡張プリントダイアログを表示させる
            
set sheetClosed to value of checkbox 1
            
if sheetClosed = 0 then
              click checkbox 1
              
click button "キャンセル"
            else
              set goF to true
              
exit repeat
            end if
          end tell
        end tell
        
      end repeat
      
      
if goF = false then return
    end tell
  end tell
  
  
  
  
  
activate application "Preview"
  
tell application "System Events"
    tell process "プレビュー"
      
      
–メニューから印刷を実行
      
click menu item "プリント…" of menu 1 of menu bar item "ファイル" of menu bar 1
      
      
tell window 1
        tell sheet 1
          
          
–出力先のプリンタを指定
          
tell pop up button 4 –「プリンタ」ポップアップボタン
            set aTitle to value
            
if aTitle is not equal to printerName then
              click
              
tell menu 1
                set mList to title of every menu item
                
set aRes1 to retIHitItem(mList, printerName as Unicode text) of me
                
if aRes1 = false then
                  return mList
                end if
                
click menu item aRes1
                
              end tell
            end if
          end tell
          
          
          
–用紙サイズを変更
          
tell pop up button 1
            
            
set aTitle to value as string
            
if aTitle is not equal to paperSize then
              click
              
tell menu 1
                set mList to value of every menu item
                
                
set aLen to length of mList
                
select menu item 1 –最終アイテムを選択しておく
                
                
set aRes2 to retIHitItem(mList, paperSize as string) of me
                
if aRes2 = false then
                  return false
                end if
                
click menu item aRes2
              end tell
            end if
          end tell
          
          
–用紙方向を指定
          
if directionF = "V" then
            click radio button 1 of radio group 3
          else if directionF = "H" then
            click radio button 2 of radio group 3
          end if
          
          
–「用紙サイズに合わせる」をクリック
          
click radio button 2 of radio group 1
          
          
–「プリント」ボタンをクリック
          
–click button "プリント"–ここをコメントアウトすると印刷を行う。
          
beep
        end tell
      end tell
    end tell
  end tell
end printViaGUI

–指定リスト中の何アイテム目かを調べて返す
on retIHitItem(aList, anItem)
  set aCount to 1
  
set hitF to false
  
repeat with i in aList
    set j to contents of i
    
if j = anItem then
      set hitF to true
      
exit repeat
    end if
    
set aCount to aCount + 1
  end repeat
  
  
if hitF = false then return false
  
  
return aCount
end retIHitItem

–GUI Scriptingの命令が続く中でdelayコマンドをエラーになるので、
–wait部分だけサブルーチン化
on waitSec(aNum)
  delay aNum
end waitSec

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

02/03 Preview.appでプリンタと用紙サイズを指定して印刷

一般的なAppleScriptの命令を使用して、特定のプリンタへの印刷は実行できますが、用紙サイズまでは指定できません。そこで、仕方なくGUI Scriptingを使用して印刷を実行することになります。

ここで、「仕方なく」という前置きが入るのは、GUI Scriptingという仕組みが通常のAppleScriptによる命令よりも遅く、また確実性が劣るためです。確実性が高くないといっても、OSやアプリのクラッシュを伴うようなレベルではなく、アプリケーション側の状態を詳細に調べながら操作しないと「思い通りに動かない」という話です。

■GUI Scriptingを使えるようにするために

GUI Scriptingが動作するためには、システム環境設定の「ユニバーサルアクセス」で「補助装置にアクセスできるようにする」にチェックが入っている必要があります。GUI Scriptingは使用に注意を要する機能であるため、デフォルト状態ではオフになっています。

sysprop.jpg

このチェックボックスをオンにすれば、GUI Scripting系の命令を実行できるようになります(プログラムを作成するだけであれば、オンにする必要はありません)。

■GUI Scriptingとは何なのか?

OS標準で搭載されているSystem Events.appが持っている「Process Suites」という命令群が、GUI Scripting(=UI Element Scripting)の命令です。他のSystem Eventsの命令については、システム環境設定/ユニバーサルアクセスでオンにしなくても普通に使えます。

sys2.jpg

一般的なAppleScriptでは、アプケーション内部のオブジェクトを経由して機能を呼び出すのに対し、GUI Scriptingはアプリケーションの外部からGUI部品を指定して命令を行います。このため、あるボタンを押そうとしたときに、もちろんオンになっていないと押せないですし、アプリケーション内部の状態がそのボタンがオンになる条件を満たしている必要もあります。

簡単な記述でアプリケーションをコントロールできるというのがGUI Scriptingの「理想」ではあるものの、実際に書いてみると……通常のAppleScriptとはまた別のマニアックなノウハウが必要な記法、と見るべきです。内部命令を経由しないでGUI ScriptingだけですべてのAppleScriptのプログラムを作成するというのが「幻想」というより「無理」であることはよく覚えておいてほしいと思います。通常のAppleScriptの「補助」的に使うのがGUI Scriptingの正しい使い方です。

■GUI Scriptingをはじめる前に

いろいろと前置きが長くなってしまいましたが、アプリケーションを無理矢理操作するため、「奥の手」としてGUI Scriptingが必要になるケースは確実にあります。そういう意味では、不完全なソリューションではあるものの、「じゃあいらないんだね?」とGUI Scriptingになくなられると困ります。ものすごく困ります。

GUI Scriptingでは、画面上のGUI部品を指定して命令を記述することになりますが、この部品の番号や並び順を知るためには、どうしてもツールが必要です。

(1)PreFab UI Browser
仕事でScriptを書く必要があるとか、確実かつ迅速にGUI Scriptingによるプログラムを作成する場合には必要です。ただし、このソフトでカバーできるのは8割程度であり、あとの残り2割をカバーするためには後述の「Accessibility Inspector」が必要になります(同ツールはXcode Toolsに含まれるため、Xcode Toolsのインストールが必須です)。

sys4.jpg

(2)Accessibility Inspector
Xcode Toolsをインストールすると、一緒に入ってきます。PreFab UI Browserでカバーできない一部のGUI部品の情報を調べるために必要です。具体的に言ってしまうと、PreFab UI Browserではポップアップメニューの内容までは追えません。とくに、ポップアップボタン「ではない」GUI部品からポップアップメニューを表示させるようなイレギュラーなプログラムでは本ツールの併用が必要です。

sys3.jpg

(3)「強引GUI Scripting」のためのツール
記述のために情報を調べるツールではなく、AppleScriptから命令して強引にマウスカーソルを移動させたりクリック動作させるようなツールです。ツールによって一長一短があるので、複数用意して用途に応じて使い分けるのが理想的です。プロのScripterはこの手のツールをいくつも手元に置いてあった、いざという時に備えています。何を使っているか、どの程度のAppleScriptライブラリを書きためているか等の情報はもちろんのこと、存在自体が門外不出のノウハウといえます。

これらのツールがそろってはじめて安心してGUI Scriptingのプログラムを作りはじめられます。……ない環境では、とても書く気になれません。

■アプリケーションの挙動を追う

GUI Scriptingでは、アプリケーションの状態を正確に認識した上で記述を行う必要があります。特定のウィンドウ上の特定のTabの中にあるGUI部品を操作する場合には、そのTabが表示されていなければなりません。ポップアップメニュー上の項目を選択するためには、ポップアップメニューを表示させておかなければなりません。通常のAppleScriptによるアプリケーション内部オブジェクト経由のコントロールの方が簡単と思えるほど、アプリケーションによってGUI部品の挙動が異なるため、正確な状況把握は欠かせません(PreFab UI Browser必須)。

■GUI部品の指定はIDか名前で

GUI ScriptingでGUI部品を指定する際には、window 1やmenu 1のように番号(ID)で指定する場合と、button “OK”のように名前で指定する場合があります。

名前で指定できたほうが、何を意味しているのか分りやすくてよさそうなものなのですが、名前で指定できるケースはあまり多くありませんし、だいたい……現在使用中の言語(日本語とか、英語とか)から別の言語環境でScriptを実行するような場合にはまったく動かなくなってしまいます。

このため、IDで指定することが多いのですが……アプリケーションがバージョンアップしたら、そのIDそのものも変わってしまうことが多々あり……GUI部品を検索して実行するような対策を行うケースもあります。

■実際に「プレビュー.app」のGUI Scriptingを行ってみよう

まずは、プレビュー.appで何も画像を開いていない状態で作業をはじめましょう。何もオープンしていない状態と画像をオープンしている状態でWindowの枚数がどう違うか、確認を行います。

何か画像をプレビュー.appでオープンすると、visibleなWindowの枚数が増えます。invisibleなwindowはほかにも何枚か用意しているようなので、ここでvisibleを指定しないで枚数を数えるとひどい目に遭います。

Windowの枚数だけでなく、画像をオープンしていない状態ではメニューの「プリント」の項目が有効になっていません。このため、「プリント」をGUI Scriptingで操作しようとしても、実行できません。このあたりで(オープンされている画像の有無を)判断するという手もあるわけです。

画像をオープンしている状態でメニューから「プリント」を実行できることを確認できたら、プリントダイアログの制御に入ります。

プリントダイアログは、デフォルトの小さいダイアログと拡張ダイアログで切り換えができるようになっており、この切り換えボタンの状態を取得して、「いま、どちらのダイアログが表示されているのか」を調べなければなりません。拡張ダイアログが表示されていないと、用紙サイズなどの詳細な情報にアクセスできません。

sys5.jpg

sys6.jpg

拡張ダイアログを表示して、用紙サイズやプリンタ名などを指定できるようになって、ようやくこれで出来上がった……と、安心していたのもつかの間……標準ダイアログの状態から拡張ダイアログに切り替えた後で、ポップアップメニューの操作が行えない。最初から拡張ダイアログが出ている分には問題ないのに……。

結論からいえば、同じGUI部品でも標準ダイアログと拡張の上でIDが異なっていました。さりとて、GUI部品に名前がついておらず名前による指定ができなかったので……拡張ダイアログが「出ていない」場合には、拡張ダイアログに切り換えたあとで、一度プリントをキャンセルし、再度プリント操作を行って拡張ダイアログ上の各種GUI部品をコントロールする……という方法で対処しました。

ちょっとしたことであれば、GUI Scriptingを少々かじったぐらいで処理できるかもしれません。ただし、そこに柔軟性を加えようとか、確実に動くようにしたい場合には、このぐらいの処理が必要になります。少々極端な例に見えるかもしれませんが、決して珍しいレベルではありません。

PreFab UI Browserを使って状態やIDを確認し、試行錯誤した末に最適な方法を見つけるなど、地道な……何かプログラミングとは別の作業のような気もするのですが、GUI Scriptingの実戦的なノウハウというのは、こういう感じのものです。

02/03 タイマー割り込み処理

AppleScriptには、タイマー割り込みの機能があります。タイマー割り込みとは、一定間隔で処理を行うことで……メインの処理を行っていても(割り込みを行って)、途中でその処理を行います。

タイマー割り込みがあるあたり、単なるスクリプト言語の処理系「らしからぬ」雰囲気ですが……たしかに、タイマー割り込みが活躍するケースは多いので、この機能があるのは助かります。

ただし、いくつか知っておくべきことがあります。

(1)タイマー割り込みは、AppleScriptをアプリケーション形式で保存して実行したときにしか効かない

timer1.jpg

AppleScriptエディタ上で実行したり、Script Menuから呼び出した場合には使用できません。アプリケーションとして保存し、アプリケーションとして起動された場合に限ります。

(2)タイマー割り込みは、「実行後、自動的に終了しない」をオンにしないと意味がない

timer2.jpg

すぐに終わるようにしている場合には、タイマー割り込みは効きません。

(3)タイマー割り込みは、秒単位でしか呼び出せない
0.1秒単位とか、1/64秒間隔で呼び出すといったことはできません。仮にできたとしても、あまり短い間隔で呼び出されると逆にメイン側の処理効率が落ちます(AppleScriptObjCでやってみたら、CPU負荷が増えてしまいました)。

(4)時間が長くかかる割り込み処理を実行中に、後続の割り込み処理を行わせてはいけない
10秒間隔で割り込み処理を呼び出すようにしているときに、実行完了に1分かかる処理を行うような場合……割り込み処理が完了する前に後続の割り込み処理が呼び出されてしまいます。

処理内容に矛盾が生じてしまったり、不具合が生じてしまう可能性があるため、後続の割り込みをブロックし、処理が終わったら割り込みを許可するようにしなくてはなりません。このあたり、割り込み処理の「基本」なのですが……AppleScriptの処理系では面倒を見てくれないので、自前で書いておく必要があります。

スクリプト名:タイマー割り込み
property enableF : true –タイマー割り込みイネーブルフラグ
property intervalSec : 1 –タイマー割り込み発生間隔(秒)
property vList : {“Agnes”, “Albert”, “Alex”, “Bad News”, “Bahh”, “Bells”, “Boing”, “Bruce”, “Bubbles”, “Cellos”, “Deranged”, “Fred”, “Good News”, “Hysterical”, “Junior”, “Kathy”, “Pipe Organ”, “Princess”, “Ralph”, “Trinoids”, “Vicki”, “Victoria”, “Whisper”, “Zarvox”}

–起動処理
on run
  set intervalSec to 5 –割り込み間隔を5秒に変更
  
set enableF to true –割り込みイネーブルフラグをtrue(割り込み可能)に変更
end run

–割り込みサービスハンドラ
on idle
  –割り込み処理メインで処理が終了するまで、タイマー割り込みは許可しない
  
if enableF = true then
    set enableF to false
    
    
idleMain() of me
    
    
–タイマー割り込みメインの処理が終わったら、割り込みを許可する
    
set enableF to true
  end if
  
  
–次回の割り込みを呼び出す相対秒数をリターンする(必須)
  
return intervalSec
  
end idle

–タイマー割り込み処理メイン
on idleMain()
  set aChar to contents of (some item of vList) –乱数選択
  
repeat 3 times
    say “Say Hello to piomal software.” using (aChar as text)
  end repeat
end idleMain

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

01/30 ちょっと気の利いた複数folder選択

仕事用にかなり凝ったAppleScriptのプログラムを作成したような場合には、処理対象のデータを自由に指定できるよう、処理先をchoose folderやchoose fileで指定することがあります。プログラム内にパスを固定で記述するよりも自由度が高く、ユーザーフレンドリーな処理になります。

ただ……1つのAppleScript中でいくつもフォルダを選択する必要があったりすると、そのたびにフォルダ選択ダイアログで処理対象のフォルダを指定しなければなりません。しかも、Folder Aを選択したあとでFolder Bを選択しようとすると、Folder Aの場所からスタートしなくてはなりません。

これはけっこう面倒です。

dialog1.jpeg

dialog2.jpeg

そこで、choose folderで一度フォルダを選択したら、propertyの値に保持しておいて、各フォルダ選択ダイアログで個別に記録。二度目からはそれぞれ前回指定したフォルダを勝手に指定するよう、些細な改善を行ってみました。

その結果、大幅な操作性の改善を行うことができ、いくつフォルダ選択ダイアログが出てきても、うっとおしくなくなりました(たいていにおいて、前回と同じ場所を指定することのほうが多く、目視で確認してリターンキーを押していくだけ)。

スクリプト名:ちょっと気の利いた複数folder選択
property folderA : missing value
property folderB : missing value

if folderA is not equal to missing value then
  –前回の選択内容を使用
  
set folderA to choose folder default location folderA with prompt “folder Aを選択”
else
  –はじめて実行する場合など
  
set folderA to choose folder with prompt “folder Aを選択”
end if

if folderB is not equal to missing value then
  –前回の選択内容を使用
  
set folderB to choose folder default location folderB with prompt “folder Bを選択”
else
  –はじめて実行する場合など
  
set folderB to choose folder with prompt “folder Bを選択”
end if

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

01/27 lengthの同義語number of items

AppleScriptで配列変数(AppleScript的には「リスト型変数」)の要素数をカウントする場合には、「length of リスト型変数」で取得しますが、AppleのサンプルScriptを読んでいたら、「number of items of リスト型変数」という記述があるのを見つけました。

AppleScriptには同義語やら「使っても使わなくてもかまわない語」(theとか)などがあるので、人によってプログラムの書き方がバラバラで、記述の流派が違うとまったくプログラムを読めない(理解できない)場合があります。

とりあえず、numbers of itemsでも要素数をカウントできることは確認しました。

スクリプト名:number of itemsのじっけん(1)
set aList to {1, 2, 3, 4}

set aLen to number of items of aList
–> 4

set bLen to length of aList
–> 4

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

実際のところ、スピードはどうなんでしょう? なんとなく、感覚的にlength ofのほうが速そうな感じはするのですが……この程度の命令だと一瞬で終わってしまうので、1000万回実行してようやく意味のある差が出てきました。

気持ち分length ofのほうが速いですが、そもそも1000万回もループを回すような処理はAppleScriptでは行わないでしょうから、そんなに気にしなくてよさそうです(計測はMacBook Pro Core 2 Duo 2.4GHzにて実施)。

スクリプト名:number of itemsのじっけん(2)
set aList to {1, 2, 3, 4}

set sTime to current date

repeat 10000000 times
  set bLen to length of aList
end repeat

set eTime to current date
set elapsedTime to eTime - sTime

–1000万回ループ時に
–number of items で23秒
–length で14秒

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

01/22 元号変換v31

以前作成したものに(派手な)バグが見つかったので、修正しました。Wikipediaで確認していたつもりだったのですが、元号の切れ目の日付を間違えてしまいました。

指摘してくれたのが中国から日本に来ているプログラマーの女性で(汗)、ひたすら感謝です。

スクリプト名:元号変換v31
set a to "1989/1/18"
set a to parseDate(a) of me
set {aGengoStr, aGengoNum} to retJapaneseGengo(a) of me
–> {"平成", 1}

on retJapaneseGengo(aDate)
  
  
set aYear to year of aDate
  
set aMonth to month of aDate as number
  
set aDay to day of aDate
  
  
set aStr to retZeroPaddingText(aYear, 4) of me & retZeroPaddingText(aMonth, 2) of me & retZeroPaddingText(aDay, 2) of me
  
  
set aGengo to ""
  
–if aStr "19890118" then–間違ってた!!!
  
if aStr "19890108" then
    set aGengo to "平成"
    
set aGengoNum to aYear - 1989 + 1
  else if aStr "19261225" then
    set aGengo to "昭和"
    
set aGengoNum to aYear - 1926 + 1
  else if aStr "19120730" then
    set aGengo to "大正"
    
set aGengoNum to aYear - 1912 + 1
    
–else if aStr "18681125" then–間違ってた!!!
  else if aStr "18680125" then
    set aGengo to "明治"
    
set aGengoNum to aYear - 1868 + 1
  end if
  
  
return {aGengo, aGengoNum}
  
end retJapaneseGengo

–数値にゼロパディングしたテキストを返す
on retZeroPaddingText(aNum, aLen)
  set tText to ("0000000000" & aNum as text)
  
set tCount to length of tText
  
set resText to text (tCount - aLen + 1) thru tCount of tText
  
return resText
end retZeroPaddingText

on parseDate(inStr)
  set aClass to class of inStr
  
if aClass = string then
    try
      set aDate to date inStr
    on error
      return false
    end try
  else if aClass = date then
    set aDate to inStr
    
  end if
  
  
return aDate
  
end parseDate

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

01/17 リストから選択してアイテム番号を返す〜複数選択対応

choose from listで複数選択を行いつつ、選択した項目がそれぞれリストの何アイテム目かの情報を返すAppleScriptです。

以前に、複数選択ではないバージョンは作ってあったのですが、Omni Outlinerから選択部分を取得するAppleScriptを作成する際に、即興で作ったものです。

スクリプト名:リストから選択してアイテム番号を返す〜複数選択対応
set aList to {“red”, “blue”, “green”, “white”}
set aMes to “項目を選択してください(Command-クリックで複数選択可能)”
set aRes to retMultipleItemFromListByItemNo(aList, aMes) of me

–リストから選択してアイテム番号を返す(複数項目選択対応)
on retMultipleItemFromListByItemNo(aList, aMes)
  set aRes to choose from list aList with prompt aMes with multiple selections allowed
  
if aRes = false then return 0
  
  
set hitList to {}
  
repeat with i1 in aRes
    set aRes to contents of i1
    
set hitNum to 1
    
repeat with i in aList
      set j to contents of i
      
if j is equal to aRes then
        exit repeat
      end if
      
set hitNum to hitNum + 1
    end repeat
    
set the end of hitList to hitNum
  end repeat
  
return hitList
end retMultipleItemFromListByItemNo

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

01/17 OniOutlinerで選択中の行の内容のうち指定列のデータをすべて取得

OmniOutliner Professional v3.9.5で(通常のOmni Outlinerもtellブロックのアプリ名称を変更すればそのまま動作)、選択中の行のデータの中から指定列(カラム)のデータをすべて取得するAppleScriptです。

つまり、選択行の中の指定カラムのデータを取得するものです。こうした機能が標準搭載されていないほうがおかしいような気がします。そのままGUI上でExcelに選択データをペーストすると、1つの列の中にすべてのデータが入ってしまうなど、動作内容がいまいちです。

そこで、AppleScriptの登場となるわけで……旅行からの帰りの電車の中で勢いだけで作ってしまいました。

まずは、Onni Outliner上で行を選択。

omni1.jpg

スクリプトを実行すると、どの列のデータを取得するか聞いてきます。Command-クリックを行うことで、複数の列のデータを指定できます。

omni2.jpg

ためしに、「トピック」列と「Column2」列を選択すると……

{{”line2″, “”}, {”line3″, “●”}, {”line4″, “●”}, {”line5″, “”}}

といった結果が得られます。これは、Excelに貼付けることを前提としてデータを作成しているものであり、あとはExcelへのデータ貼り付けルーチンを作って用意すれば、便利に使えそうです。

excel1.jpg

……結局、Excelのワークシートを新規作成して、データ転送するところまで作り込んでしまいました。ここまでやると、たしかに便利。

スクリプト名:OniOutlinerで選択中の行の内容のうち指定列のデータをすべて取得
global tList, numRes
set tList to {}

tell application “OmniOutliner Professional”
  tell document 1
    set aSel to every row whose selected is true
    
if aSel = {} then
      display dialog “OmniOutliner上で選択されている行はありませんでした。” buttons {“OK”} default button 1
      
return
    end if
  end tell
end tell

–どの列を書き出すかを選択
tell application “OmniOutliner Professional”
  tell document 1
    set nList to name of every column
    
set aMes to “項目を選択してください(Command-クリックで複数選択可能)”
    
set numRes to retMultipleItemFromListByItemNo(nList, aMes) of me
  end tell
end tell

–選択部分を検出
tell application “OmniOutliner Professional”
  tell document 1
    set aaSel to first item of aSel
    
tell aaSel
      set aCell to text of every cell
      
set aCell to retSpecifiedItemFromList(numRes, aCell) of me
      
set the end of tList to aCell
      
set cList to every child
      
repeat with i in cList
        getChildText(i) of me
      end repeat
    end tell
  end tell
end tell

tList
–> {{”line2″, “”}, {”line3″, “●”}, {”line4″, “●”}, {”line5″, “”}}

–再帰で指定child以下のテキストをすべて取得する
on getChildText(aRoot)
  tell application “OmniOutliner Professional”
    tell document 1
      tell aRoot
        set aCell to text of every cell
        
set aCell to retSpecifiedItemFromList(numRes, aCell) of me
        
set the end of tList to aCell
        
        
set cList to every child
        
repeat with i in cList
          getChildText(i) of me –再帰処理
        end repeat
      end tell
    end tell
  end tell
end getChildText

–リストから選択してアイテム番号を返す(複数項目選択対応)
on retMultipleItemFromListByItemNo(aList, aMes)
  set aRes to choose from list aList with prompt aMes with multiple selections allowed
  
if aRes = false then return 0
  
  
set hitList to {}
  
repeat with i1 in aRes
    set aRes to contents of i1
    
set hitNum to 1
    
repeat with i in aList
      set j to contents of i
      
if j is equal to aRes then
        exit repeat
      end if
      
set hitNum to hitNum + 1
    end repeat
    
set the end of hitList to hitNum
  end repeat
  
return hitList
end retMultipleItemFromListByItemNo

–指定リストから、指定アイテム目を抽出して返す
on retSpecifiedItemFromList(itemNumList, dataList)
  set newList to {}
  
repeat with i in itemNumList
    set j to contents of i
    
set a to contents of (item j of dataList)
    
set the end of newList to a
  end repeat
  
return newList
end retSpecifiedItemFromList

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

01/11 UnicodeCheckerで指定文字のプロパティを取得

UnicodeCheckerで指定文字のプロパティを取得するAppleScriptです。

文字種別を取得できる機能は、なにげにものすごく便利です。

ucheck1.jpg

スクリプト名:UnicodeCheckerで指定文字のプロパティを取得
set a to "" –はしご高 ( Kanji Character )
set b to "A" –alphabet A
set c to "あ" –ひらがな

tell application "UnicodeChecker"
  set aCP to code point a
  
properties of aCP
  
–> {assigned:true, canonical combining class:0, canonical combining class description:"Not_Reordered", id:39641, general category:"Lo", unicode name:"<CJK Ideograph>", class:code point, general category description:"Other_Letter", assigned to abstract character:true, bidi class description:"Left_To_Right", bidi class:"L", name:"", containing plane:plane id 0 of application "UnicodeChecker", bidi mirrored:false, script name:"Han", containing block:block "CJK Unified Ideographs" of application "UnicodeChecker"}
  
  
set bCP to code point b
  
properties of bCP
  
–> {assigned:true, canonical combining class:0, canonical combining class description:"Not_Reordered", id:65, general category:"Lu", unicode name:"LATIN CAPITAL LETTER A", class:code point, general category description:"Uppercase_Letter", assigned to abstract character:true, bidi class description:"Left_To_Right", bidi class:"L", name:"A", containing plane:plane id 0 of application "UnicodeChecker", bidi mirrored:false, script name:"Latin", containing block:block "Basic Latin" of application "UnicodeChecker"}
  
  
set cCP to code point c
  
properties of cCP
  
–> {assigned:true, canonical combining class:0, canonical combining class description:"Not_Reordered", id:12354, general category:"Lo", unicode name:"HIRAGANA LETTER A", class:code point, general category description:"Other_Letter", assigned to abstract character:true, bidi class description:"Left_To_Right", bidi class:"L", name:"あ", containing plane:plane id 0 of application "UnicodeChecker", bidi mirrored:false, script name:"Hiragana", containing block:block "Hiragana" of application "UnicodeChecker"}
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

01/11 IGOR Proでコマンドを実行

WaveMetrics社が開発し、日本国内ではヒューリンクスが販売している、データ解析+ビジュアライズ用のソフトウェア「IGOR Pro」をAppleScriptからコントロールしてみました(掲載されているサンプルそのまま。変更点なし)。

AppleScriptからアプリケーションの各種情報を取得できるようにはなっておらず、Igor Proのコマンドや関数を使って情報を取得するようです(R.appなどと同じタイプ)。

igor1.jpg

スクリプト名:Igor Proでコマンドを実行
tell application “Igor Pro”
  Do Script “fprintf 0, \”%s\”, IgorInfo(1)”
end tell
–> “3DRotationsPanel”

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

01/11 LightWay TextをAppleScriptからコントロール

LightWay TextをAppleScriptからコントロールしてみました。

縦書き可能だったり、原稿用紙に記入するようにテキスト編集可能な老舗のテキストエディタLightWay Textですが、AppleScript系の機能については、残念ながら不完全かつ不十分であることを確認しました。

lwt.jpg

AppleScriptとの連携を考えるのであれば、Apple純正のテキストエディット、Jedit X、mi、BBeditやTextWranglerなどを使うのが適切でしょう。

以下、LightWay Textのコントロールを試みた内容です。

テキストの内容を取得できますが、そのままでは扱えないようです。

スクリプト名:LightWay Textで文章の内容を取得
tell application “LightWayText”
  tell document 1
    contents
  end tell
end tell
–>
(*

{”ぴよ〜うるふ
ぴよぴよ”, «data styl01000000000015000C00019000000E00000000000000», «data styw000100000000000000000000»}
*)

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

ドキュメントの内容をas stringでcastすれば、一応内容(contents)を取得できます。また、同様にSelectionの内容も、そのままでは使用できません。Application、Document、Windowといった主要なオブジェクトのプロパティも一切取得できません。できないことだらけです。

スクリプト名:LightWay Textで文章の選択部分を取得
tell application “LightWayText”
  tell document 1
    set a to selection
  end tell
end tell
–>
(*
{”ぴよぴよ”,
«data styl01000000000015000C00019000000E00000000000000», «data styw000100000000000000000000»}
*)

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

文章内の選択部分(selection)をas stringでcastすると文字列として取得できますが、逆に選択範囲の内容を書き換えることができません。

Selectionを介してAppleScriptとインタフェースを行うという、一般的なMac系のテキストエディタのような運用はできないことが分りました。無理矢理、GUI Scripting経由でアクセスすることは不可能ではありませんが、動作の確実性を保証できない(最前面にLightWay Textがいないと、メニューを操作して確実にPaste動作を行わせられない)ところです。

スクリプト名:LightWay Textで選択部分を文字列として取得
tell application “LightWayText”
  tell document 1
    set a to selection as string
  end tell
end tell
–> “ぴよぴよ”

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

01/04 動的に演算子を指定してリストから要素を取り出す

動的に「starts with」「ends with」「contains」と演算子を指定して、指定のリストから要素を取り出すAppleScriptです。

ありあわせの「リストをテキストに」するサブルーチンを引っ張り出してきて、テレビを見ながら15分ぐらいで作りました。

AppleScript Users MLでそういうことができないか、と質問が出て「できない」「そりゃ無理」と返事が続いていたので、さくっと組んで投稿したものです。

たしかに、言語仕様上では無理な処理ですが……こうしてダイナミックに(動的に)文字列を組み立ててrun scriptコマンドを実行すれば、たいていの無茶な内容も実現できます。そこまで組む根性があるかどうか。めんどうくさいと思うかどうかで「できない」が「できる」に変わります。この場合は、リストをテキスト化するサブルーチンのストックがあることを覚えていたのですぐに作れました。

ただ、これにどのぐらいの利用価値があるか、個人的にははてしなく疑問です。

スクリプト名:動的に演算子を指定してリストから要素を取り出す
set myVar to {“John Smith”, “Mike Smith”, “Michael Jackson”}
set myArray to {myVar, “ends with”, “Smith”}
set aList to retDynamicOperatedData(myArray) of me
–> {”John Smith”, “Mike Smith”}

on retDynamicOperatedData(myData)
  try
    set aVar to contents of item 1 of myData
    
set operatorCmd to contents of item 2 of myData
    
set operatorStr to contents of item 3 of myData
  on error
    return {}
  end try
  
  
–Command Check
  
if operatorCmd is not in {“starts with”, “ends with”, “contains”} then return {}
  
  
–Make Dynamic Script  
  
set aScript to “set aList to “ & listToText(aVar) of me &
  set rList to {}
  repeat with i in aList
  set j to contents of i
  if j “
& operatorCmd & ” \”" & operatorStr & “\” then
  set the end of rList to j
  end if
  end repeat
  return rList
  ”

  
try
    set aRes to (run script aScript)
  on error
    set aRes to {}
  end try
  
  
return aRes
  
end retDynamicOperatedData

–List to String Sub-routine
on listToText(aList)
  set listText to {“{”}
  
set quotChar to ASCII character 34
  
set firstFlag to true
  
repeat with i in aList
    set j to contents of i
    
set aClass to class of i
    
if (aClass = integer) or (aClass = number) or (aClass = real) then
      set the end of listText to (getFirst(firstFlag) of me & j as text)
      
set firstFlag to false
    else if (aClass = string) or (aClass = text) or (aClass = Unicode text) then
      set the end of listText to ((getFirst(firstFlag) of me & quotChar & j as text) & quotChar)
      
set firstFlag to false
    else if aClass is list then
      set the end of listText to (getFirst(firstFlag) of me & listToText(j)) –recursive call
      
set firstFlag to false
    end if
  end repeat
  
set the end of listText to “}”
  
set listText to listText as text
  
return listText
end listToText

on getFirst(aFlag)
  if aFlag = true then return “”
  
if aFlag = false then return “,”
end getFirst

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

01/04 指定形式でスクリーンキャプチャを撮る

指定形式(JPEG、PNG、GIFF、PDF、TIFF)で、指定フォルダ内にファイル名YYMMDDHMSSでスクリーンキャプチャを撮影するAppleScriptです。

screencaptureコマンドはGIFFでもスクリーンキャプチャを撮れるのですが、GIFFを指定する必然性はかなり低いことでしょう。

スクリーンキャプチャをAppleScript内で撮れると、エラーが起こった時に撮ってメールに添付して所定のアドレスに送信するなど、エラーレポートに威力を発揮するほか、ほかにも「いいこと」がいろいろあります。とくに、無人の環境で長時間連続運転を行っているような場合には、こうした配慮が必要です。

さらに、撮ったあとのレポート方法についても、バカの1つ覚えでメールに添付して送るだけでなく、Dropboxにアップロードするとか(AppleScriptから見るとローカルのPublicフォルダにコピーするだけなので、ものすごく簡単)、各種Webサービスにアップロードするなどの手段が使用でき、選択の幅が広がってきました。

もちろん、古典的にプリンターやFAXに送って印刷してもいいですし、(なぜか)Excelのワークシートに貼り付けてZip圧縮してメールに添付して送信してもよいでしょう。

スクリプト名:指定形式でスクリーンキャプチャを撮る
set a to choose folder
set aRes to screenCapture(a, “JPEG”) of me
–> “/Users/xxxx/Desktop/20100104155956.JPEG”–正常終了の場合。エラー時はfalse

–指定形式でスクリーンキャプチャを指定フォルダに撮る
on screenCapture(aFolder, aType)
  set aFolPOSIX to POSIX path of aFolder
  
set todayStr to do shell script “date +%Y%m%d%H%M%S” –YYMMDDHHMMSS
  
  
–大文字小文字を無視、ピリオドを無視
  
ignoring case and punctuation
    if aType is not in {“JPEG”, “PNG”, “GIFF”, “PDF”, “TIFF”} then
      return false –エラー
    end if
  end ignoring
  
  
–拡張子部分を小細工する
  
if aType begins with “.” then
    set aExt to aType
    
set aType to text 2 thru -1 of aType
  else
    set aExt to “.” & aType
  end if
  
  
set aPathPOSIX to (aFolPOSIX & todayStr & aExt)
  
set aPathPOSIXq to quoted form of aPathPOSIX
  
set sText to “screencapture -xt” & aType & ” “ & aPathPOSIXq
  
  
do shell script sText
  
return aPathPOSIX
  
end screenCapture

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

01/02 あけましておめでとうございます

新年あけましておめでとうございます。今年も、自作のアプリケーション「おかえり」で、MacのSleep解除時におかえりメッセージを表示。正月3が日の間は「謹賀新年」「あけましておめでとうございます」メッセージを表示しています。対応OSはMac OS X 10.4〜10.6。

okaeri.jpg

「おかえり」の前バージョンが2009年12月31日までの使用期限を設定してあったため、若干の機能アップを行った新バージョンを公開しました。本アプリもすべてAppleScript Studioで作成したものです(透明ウィンドウの部分のみObjective-C)。

12/30 指定日に在任中の内閣総理大臣の氏名を取得 v2

以前に作ったサブルーチンのデータを最新のものにアップデートしたものです。YYYY/MM/DD形式の日付文字列を与えると、その時に在任中の内閣総理大臣の氏名を返します。

スクリプト名:指定日に在任中の内閣総理大臣の氏名を取得 v2
set aDateStr to “2009/03/14″
set aName to retPrimeMinisterInJapan(aDateStr) of me
–> “麻生太郎”

–指定日に在任中の内閣総理大臣の氏名を取得
–【参照】 http://ja.wikipedia.org/wiki/内閣総理大臣の一覧
on retPrimeMinisterInJapan(aDate)
  –議院内閣制成立以前ならfalse
  
set lowDate to “1885/12/22″
  
if aDate < date lowDate then
    display dialog “まだ議院内閣制がはじまっていない時代です。”
    
return false
  end if
  
  
set primeList to {{“伊藤博文”, “1885/12/22″}, {“黒田清隆”, “1888/04/30″}, {“三條實美”, “1889/10/25″}, {“山縣有朋”, “1889/12/24″}, {“松方正義”, “1891/05/06″}, {“伊藤博文”, “1892/08/08″}, {“黒田清隆(臨時兼任)”, “1896/08/31″}, {“松方正義”, “1896/09/18″}, {“伊藤博文”, “1898/01/12″}, {“大隈重信”, “1898/06/30″}, {“山縣有朋”, “1898/11/8″}, {“伊藤博文”, “1900/10/19″}, {“西園寺公望(臨時兼任)”, “1901/05/10″}, {“桂太郎”, “1901/06/02″}, {“西園寺公望”, “1906/01/07″}, {“桂太郎”, “1908/07/14″}, {“西園寺公望”, “1911/08/30″}, {“桂太郎”, “1912/12/21″}, {“山本權兵衞”, “1913/02/20″}, {“大隈重信”, “1914/04/16″}, {“寺内正毅”, “1916/10/09″}, {“原敬”, “1918/09/29″}, {“内田康哉(臨時兼任)”, “1921/11/04″}, {“高橋是清”, “1921/11/13″}, {“加藤友三郎”, “1922/06/12″}, {“内田康哉(臨時兼任)”, “1923/08/24″}, {“山本權兵衞”, “1923/09/02″}, {“若槻禮次郎”, “1926/01/30″}, {“田中義一”, “1927/04/20″}, {“濱口雄幸”, “1929/07/02″}, {“若槻禮次郎”, “1931/04/14″}, {“犬養毅”, “1931/12/13″}, {“高橋是清(臨時兼任)”, “1932/05/16″}, {“齋藤實”, “1932/05/26″}, {“岡田啓介”, “1934/07/08″}, {“廣田弘毅”, “1936/03/09″}, {“林銑十郎”, “1937/02/02″}, {“近衞文麿”, “1937/06/04″}, {“平沼騏一郎”, “1939/01/05″}, {“阿部信行”, “1939/08/30″}, {“米内光政”, “1940/01/16″}, {“近衞文麿”, “1940/07/22″}, {“東條英機”, “1941/10/18″}, {“小磯國昭”, “1944/7/22″}, {“鈴木貫太郎”, “1945/04/07″}, {“東久邇宮稔彦王”, “1945/08/17″}, {“幣原喜重郎”, “1945/10/09″}, {“吉田茂”, “1946/05/22″}, {“片山哲”, “1947/05/24″}, {“芦田均”, “1948/03/10″}, {“吉田茂”, “1948/10/15″}, {“鳩山一郎”, “1954/12/10″}, {“石橋湛山”, “1956/12/23″}, {“岸信介”, “1957/02/25″}, {“池田勇人”, “1960/07/19″}, {“佐藤榮作”, “1964/11/09″}, {“田中角榮”, “1972/07/07″}, {“三木武夫”, “1974/12/09″}, {“福田赳夫”, “1976/12/24″}, {“大平正芳”, “1978/12/07″}, {“伊東正義(臨時代理)”, “1980/06/12″}, {“鈴木善幸”, “1980/07/17″}, {“中曾根康弘”, “1982/11/27″}, {“竹下登”, “1987/11/06″}, {“宇野宗佑”, “1989/06/03″}, {“海部俊樹”, “1989/08/10″}, {“宮澤喜一”, “1991/11/05″}, {“細川護熙”, “1993/08/09″}, {“羽田孜”, “1994/04/28″}, {“村山富市”, “1994/06/30″}, {“橋本龍太郎”, “1996/01/11″}, {“小渕恵三”, “1998/07/30″}, {“森喜朗”, “2000/04/05″}, {“小泉純一郎”, “2001/04/26″}, {“安倍晋三”, “2006/09/26″}, {“福田康夫”, “2007/09/26″}, {“福田康夫”, “2007/09/26″}, {“麻生太郎”, “2008/09/24″}, {“鳩山由紀夫”, “2009/09/16″}}
  
  
set prList to reverse of primeList
  
  
set hitF to false
  
repeat with i in prList
    set aPrimeDate to contents of (item 2 of i)
    
if aDate > aPrimeDate then
      set hitF to true
      
exit repeat
    end if
  end repeat
  
  
if hitF = false then return false
  
  
return contents of (item 1 of i)
  
end retPrimeMinisterInJapan

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

12/30 伏せ字文字列を返す

伏せ字文字列を返すAppleScriptです。

以前にAppleScriptエディタ上の選択部分の文字数をカウントして、同一の文字数の「X」に置換するAppleScriptを作成しましたが、それをさらに高機能にすべく作成したのがこれです。

0〜9、A〜Z、a〜zを個別に別々の文字(9、X、x)に置換します。このため、「03-1234-5678」は「99-9999-9999」になり、「This is a pen.」は「Xxxx xx x xxx.」になります。

数値とアルファベットの区別が分ってしまうとまずいケースも多々ありますが、なんとなくそれっぽく伏せ字になっていればよい、という場合には気が利いていてよいのではないでしょうか?

スクリプト名:伏せ字文字列を返す
set a to “This is a pen. 03-012345″
set aRes to retMaskedStr(a) of me
–> “Xxxx xx x xxx. 99-999999″

–伏せ字文字列を返す
on retMaskedStr(aStr)
  set aList to characters of aStr
  
set outStr to “”
  
repeat with i in aList
    set j to contents of i
    
set jID to ASCII number of j
    
    
if jID 48 and jID 57 then
      –0〜9
      
set outStr to outStr & “9″
      
    else if jID 65 and jID 90 then
      –A〜Z
      
set outStr to outStr & “X”
      
    else if jID 97 and jID 122 then
      –a〜z
      
set outStr to outStr & “x”
      
    else
      –上記以外はそのまま出力
      
set outStr to outStr & j
      
    end if
  end repeat
  
  
return outStr
end retMaskedStr

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

12/29 1〜9999までの数値を日本語的漢数字表現でエンコード v2

1〜9999までの数値を、「百二十」「九千九百九十九」といった日本語的な漢数字表現でエンコードするAppleScriptです。

以前に、無量大数まで対応した数値→日本語的漢数字表現(およびその逆を行う)のサブルーチンは作ってあったのですが、0〜9999までの数値についてはそのままアラビア数字(0〜9)で出力していました。

enc1.jpg

enc2.jpg

これをすべて漢数字でエンコード出力できるよう作成したものです。

スクリプト名:1〜9999までの数値を日本語的漢数字表現でエンコード v2
set a to 1121
set aKanji to convNumToKanjiNum(a) of me
–> "千百二十一"

–1〜9999までの数値を日本語的漢数字表現でエンコード
on convNumToKanjiNum(aNum)
  –1万以上の場合にはヌルを返す(エラー)
  
if aNum > 9999 then return ""
  
  
copy aNum to bNum
  
  
set aNumList to {}
  
repeat with i from 3 to 0 by -1
    set aDigit to 10 ^ i
    
    
set tmpA to bNum div aDigit
    
set bNum to bNum - (aDigit * tmpA)
    
    
set the end of aNumList to tmpA
    
  end repeat
  
  
set outStr to ""
  
  
set digitStrList to {"千", "百", "十", ""}
  
set kanjiNumList to {"一", "二", "三", "四", "五", "六", "七", "八", "九"}
  
  
repeat with i from 1 to 4
    set cNum to item i of aNumList
    
if cNum is not equal to 0 then
      set cNum1 to contents of item cNum of kanjiNumList
      
set cNum2 to contents of item i of digitStrList
      
      
if cNum = 1 and cNum2 is not "" then
        –「1千」、「1百」、「1十」 というパターンは日本語表現的にはおかしいので補正する(きわめて日本的な慣例的表現。"one thousand"とはいわず、"thousand"というわけだ。ただ、声に出して読み上げるときには「いっせんまん」という)
        
set outStr to outStr & cNum2
      else
        set outStr to outStr & cNum1 & cNum2
      end if
    end if
  end repeat
  
  
return outStr
  
end convNumToKanjiNum

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

12/26 指定文字列の中に指定文字が何回出現するかカウントする

指定文字列の中に指定文字が何回出現するかをカウントするAppleScriptです。

たとえば、「XXX-XXX-XXXXXXX-XXXX」という文字列の中に「-」が何回出現するかを数えたいような場合に使用します。

作り捨てするレベルのAppleScriptなので、何回か作っているかもしれません。

スクリプト名:指定文字列の中に指定文字が何回出現するかカウントする
set aData to “XXX XXXXX XXXXX XX XXXXXX”
set lookUpStr to ” “
set aRes to countSpecifiedChar(aData, lookUpStr) of me
–> 4

–指定文字列の中に指定文字が何回出現するかカウントする
on countSpecifiedChar(aStrData, aChar)
  set aList to characters of aStrData
  
set aCount to 0
  
repeat with i in aList
    set j to contents of i
    
if j = aChar then
      set aCount to aCount + 1
    end if
  end repeat
  
return aCount
end countSpecifiedChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

12/26 選択文字列を伏せ字に

AppleScriptエディタ上で選択中の文字列を伏せ字に置き換えます(文字数は同じですべて「X」の文字)。

/Library/Scripts/Script Editor Scriptsフォルダ以下に入れて、AppleScriptエディタのコンテクストメニューから呼び出すことを前提に作成したものです。

AppleScriptエディタ上で文字列を選択しておき……

ed1.jpg

Controlキーを押しながらマウスクリック、あるいはマウスの副(右)ボタンをクリックしてコンテクストメニューを表示して、

ed2.jpg

メニューから本Scriptを実行すると……

ed21.jpg

選択部分が伏せ字になります。

ed3.jpg

スクリプト名:選択文字列を伏せ字に
tell application “AppleScript Editor”
  try
    tell document 1
      set ab to contents of selection
      
set aCount to length of ab
      
set outStr to “”
      
repeat aCount times
        set outStr to outStr & “X”
      end repeat
      
set contents of selection to outStr
    end tell
  end try
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

12/26 連続する文字(たぶんスペース)を1つにまとめる

指定文字列の中から、連続する文字(たぶんスペース)を1つにまとめるAppleScriptです。

姓と名の間にスペースが入っているんだけれど、1つとは限らない。いくつも入ってきている可能性がある……というケースに備えて、連続する文字(たぶんスペース)を1つにまとめます。

スクリプト名:連続する文字(たぶんスペース)を1つにまとめる

set aStr to "XXX XXXXX XXXXX XX XXXXXX"
set aRes to mergeMultipleChar(aStr, " ") of me

–連続する文字(たぶんスペース)を1つにまとめる
on mergeMultipleChar(aStr, aChar)
  set outStr to ""
  
set aList to characters of aStr
  
  
set successF to false
  
repeat with i in aList
    set j to contents of i
    
if j = aChar then
      if successF = false then
        set successF to true
        
set outStr to outStr & j
      else if successF = true then
        –なんにもしないよ
      end if
    else
      set successF to false
      
set outStr to outStr & j
    end if
  end repeat
  
  
return outStr
end mergeMultipleChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

12/26 指定値を構成するペアの全パターンのリストを求める

指定値を構成するペアの全パターンのリストを求めるAppleScriptです。

……こう書いてもさっぱり意味が通じないようなので説明すると……1〜n文字の長さの文字列、たとえば人名のような文字列の姓+名のパターンを合計10文字の人名について、各文字数の出現パターンを本ルーチンで計算しておき、それぞれのパターンに該当する文字数の人名の統計をまとめる……といった用途のために作成したサブルーチンです。

実行しても、割と面白味のないリストデータが出来上がるだけですが、このような全パターンを手で確認すると骨が折れるし、プログラムリストの中にそのまま書くことがためらわれる場合もあるでしょう(例:数が多すぎる etc)。そのような場合に、このサブルーチンで組み合わせパターンのリストを生成し、プログラム内で使用するとよいかもしれません。

これでも分りづらい場合には、プログラムのパラメータと計算結果を見てください。うだうだ説明されるよりも、分りやすいと思われます。

スクリプト名:指定値を構成するペアの全パターンのリストを求める
set aRes to getPairNumListInAllPattern(10, false) of me
–> {{1, 1}, {1, 2}, {2, 1}, {1, 3}, {2, 2}, {3, 1}, {1, 4}, {2, 3}, {3, 2}, {4, 1}, {1, 5}, {2, 4}, {3, 3}, {4, 2}, {5, 1}, {1, 6}, {2, 5}, {3, 4}, {4, 3}, {5, 2}, {6, 1}, {1, 7}, {2, 6}, {3, 5}, {4, 4}, {5, 3}, {6, 2}, {7, 1}, {1, 8}, {2, 7}, {3, 6}, {4, 5}, {5, 4}, {6, 3}, {7, 2}, {8, 1}, {1, 9}, {2, 8}, {3, 7}, {4, 6}, {5, 5}, {6, 4}, {7, 3}, {8, 2}, {9, 1}}

set aRes to getPairNumListInAllPattern(10, true) of me
–> {{0, 2}, {1, 1}, {2, 0}, {0, 3}, {1, 2}, {2, 1}, {3, 0}, {0, 4}, {1, 3}, {2, 2}, {3, 1}, {4, 0}, {0, 5}, {1, 4}, {2, 3}, {3, 2}, {4, 1}, {5, 0}, {0, 6}, {1, 5}, {2, 4}, {3, 3}, {4, 2}, {5, 1}, {6, 0}, {0, 7}, {1, 6}, {2, 5}, {3, 4}, {4, 3}, {5, 2}, {6, 1}, {7, 0}, {0, 8}, {1, 7}, {2, 6}, {3, 5}, {4, 4}, {5, 3}, {6, 2}, {7, 1}, {8, 0}, {0, 9}, {1, 8}, {2, 7}, {3, 6}, {4, 5}, {5, 4}, {6, 3}, {7, 2}, {8, 1}, {9, 0}, {0, 10}, {1, 9}, {2, 8}, {3, 7}, {4, 6}, {5, 5}, {6, 4}, {7, 3}, {8, 2}, {9, 1}, {10, 0}}

–指定値を構成するペアの全パターンのリストを求める
on getPairNumListInAllPattern(maxNum, allowZero)
  set outList to {}
  
  
if allowZero = true then
    set startNum to 0
  else
    set startNum to 1
  end if
  
  
repeat with i from 2 to maxNum
    repeat with ii from startNum to i
      set a to ii
      
set b to i - ii
      
if allowZero = false then
        –要素の中に0が入ることを許容しない場合
        
if a is not equal to 0 and b is not equal to 0 then
          set the end of outList to {a, b}
        end if
      else
        –要素の中に0が入ることを許容する場合
        
set the end of outList to {a, b}
      end if
    end repeat
  end repeat
  
  
return outList
end getPairNumListInAllPattern

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

12/25 元号変換v3

日付から元号および年を返すAppleScriptです。→ 2010/1/22 本バージョンにはバグが見つかったので、修正版を使うようにしてください。

元号の切り換えについては、年単位ではなく日単位で計算しています。

stringをdateオブジェクトにする部分は、普通に1行で組める程度の内容ですが……将来的に、文字パラメータから月や日が省略されていた場合に補う処理を入れようと考えていたものです。たとえば、2009という文字が渡されたら、それに月と日を補ってdateオブジェクトに変換する下準備を行おう、ぐらいの考えです。

日が省略されていた場合には末日を、月+日が省略されていた場合には「12/31」を補えば、世間一般で期待しているような処理になるだろうか……と考えています。

スクリプト名:元号変換v3
set a to “1989/1/18″
set a to parseDate(a) of me
set {aGengoStr, aGengoNum} to retJapaneseGengo(a) of me
–> {”平成”, 1}

on retJapaneseGengo(aDate)
  
  
set aYear to year of aDate
  
set aMonth to month of aDate as number
  
set aDay to day of aDate
  
  
set aStr to retZeroPaddingText(aYear, 4) of me & retZeroPaddingText(aMonth, 2) of me & retZeroPaddingText(aDay, 2) of me
  
  
set aGengo to “”
  
if aStr “19890118″ then
    set aGengo to “平成”
    
set aGengoNum to aYear - 1989 + 1
  else if aStr “19261225″ then
    set aGengo to “昭和”
    
set aGengoNum to aYear - 1926 + 1
  else if aStr “19120730″ then
    set aGengo to “大正”
    
set aGengoNum to aYear - 1912 + 1
  else if aStr “18681125″ then
    set aGengo to “明治”
    
set aGengoNum to aYear - 1868 + 1
  end if
  
  
return {aGengo, aGengoNum}
  
end retJapaneseGengo

–数値にゼロパディングしたテキストを返す
on retZeroPaddingText(aNum, aLen)
  set tText to (“0000000000″ & aNum as text)
  
set tCount to length of tText
  
set resText to text (tCount - aLen + 1) thru tCount of tText
  
return resText
end retZeroPaddingText

on parseDate(inStr)
  set aClass to class of inStr
  
if aClass = string then
    try
      set aDate to date inStr
    on error
      return false
    end try
  else if aClass = date then
    set aDate to inStr
    
  end if
  
  
return aDate
  
end parseDate

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

12/24 dict.orgで指定の単語の意味を調べて返す

JN SoftwareのAppleScriptObjCサンプル「MenuApp ASOC」に入っていたサブルーチンを抜き出して、個人的な趣味に合うように書き換えたものです。dict.orgで指定の英単語を調べて意味を返します。

searchAndReplaceというサブルーチンは、オリジナルでは「snr」という名前であり、プログラムを読めば置換ルーチンであることは理解できるのですが、そんなアセンブラのニーモニック並みに短い名前にされては可読性が落ちまくりです(かといって、AppleScriptObjCのCocoaのClass名並みにダラダラ長くても困るのですが……なんであれは別名命名機能でも用意して短縮名称で呼ぶようなことができないんだろう ーー;)

人のソースを分析しては、使えるものはきちんと整理、分析、評価を行って、再利用しやすいように補助コードをつけて保存していますが、世界はけっこう広いので、流儀がまったく異なる流派もあってなかなか苦労することがあります。

分析時には、まず自分の流儀に合うようにプログラムを書き換えることが重要です。実にそう思います。

「my」を使う派 vs 「of me」を使う派。「toでハンドラを宣言する派」vs「onでハンドラを宣言する派」。「tellブロックで対象objectをまとめる派」vs「object’sで対象を記述する派」といった、些細な相違点があって……ASOC系のサンプルコードは「tellブロックが嫌い派」のChris Page@Appleの影響が色濃く出ており、いまひとつ読みにくいように感じます。

自分は、「tellブロックでまとめる派」なので、サンプルを書き換えてから読むようにしていますが、いつかChris Pageとは直接話をして決着を付ける必要がありそうです(ーー;。

スクリプト名:dict.orgで指定の単語の意味を調べて返す
set ASCII_13 to (ASCII character 13)
set word_to_define to "AppleScript"
set the_definitions to get_definition(word_to_define) of me
set aRes to string_to_list(the_definitions, (ASCII_13 & "." & ASCII_13)) of me

–>
(*
{"\"applescript\" foldoc \"The Free On-line Dictionary of Computing (27 SEP 03)\"
AppleScript

<language> An {object-oriented} {shell} language for the
{Macintosh}, approximately a superset of {HyperTalk}.

(1995-12-10)

."}
*)

on get_definition(word_to_define)
  try
    set ASCII_13 to (ASCII character 13)
    
set the_script to snr(("dict://dict.org/d:" & word_to_define & ":*"), " ", "%20") of me
    
–Thanks to Greg Spense for the grep code
    
set the_definitions to do shell script "curl -s " & (quoted form of the_script) & " | egrep -v ‘^220.*|^250.*|^150.*|^221.*’"
    
set the_definitions to searchAndReplace(the_definitions, "151 ", "") of me
    
set the_definitions to string_to_list(the_definitions, (ASCII_13 & "." & ASCII_13)) of me
    
return the_definitions
  on error the_err
    return the_err
  end try
end get_definition

on searchAndReplace(the_string, search_string, replace_string)
  tell (a reference to AppleScript’s text item delimiters)
    set {old_tid, contents} to {contents, search_string}
    
set {the_string, contents} to {the_string’s text items, replace_string}
    
set {the_string, contents} to {the_string as Unicode text, old_tid}
  end tell
  
return the_string
end searchAndReplace

on string_to_list(s, d)
  tell (a reference to AppleScript’s text item delimiters)
    set {o, contents} to {contents, d}
    
set {s, contents} to {s’s text items, o}
  end tell
  
return s
end string_to_list

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

12/23 JN SoftwareがMenuApp ASOCのプロジェクトを公開

JN Softwareは、昔からAppleScript Studioの各種サンプルソースコードを公開しており、個人的に大変参考にしていたサイトです。同サイトで、AppleScript Objective-Cのサンプルコード「MenuApp ASOC」を公開しているのを見つけました。

メニューバーに対してメニューを付加し、メニューのサブメニューを動的に生成して、生成したメニューの各項目からハンドラを呼び出しています。

asoc1.jpg

メニューのアイコンもプログレスアイコン、アニメーションアイコンなどに変更できるようになっており、いろいろ利用価値は高そうです。これらの機能のメイン部分はObjective-Cで書かれたプログラムを呼び出すようになっており、ASOC側はコントロールを行うだけになっています。

コード内容を読んでみて、さすがのJN SoftwareもまだASOCに慣れていないためなのか、記述が冗長になっている部分が散見されます。機能を考えるとこれだけの内容で390行(コメント、空行含む)というのは、いくらなんでも長過ぎです(半分ぐらいで納めたい)。分かりやすさを優先したためか、普通ならサブルーチン化するような部分がダラダラ展開されています。

asoc2.jpg

とくにこの(↑)あたり。ここは、サブルーチン化してコンパクトにするだろー、ふつーー。……と思うのですが、ダラダラと代わり映えのしないコードが続きます。ああ、こういうのを見ると無性に効率化したくなる、、、

全体的に、使い回しを重視したようなコードが少なく、流儀の違いを感じます(とくに、User defaultの読み書きを行うあたり。ここを汎用化しないでどーする?)。この調子で大きなプログラムを作っていくのは、自分には大変危険に思えます。また、これだけ見ていると、とうてい高級言語のプログラムとは思えないほど記述効率がよくありません。

AppleScript Studioの頃は、プログラムコードを分割してload scriptで変数に読み込んで実行することで、プログラム分割+共通モジュールの使い回しを実現していました。ASOCでは、どうもこれとは違うアプローチで分割+共通モジュールの使い回しを行うことになりそうです。

ASOCに関しては上級者から初級者まで、まだ手探り状態で「汚いコード、非効率なコードのオンパレード」なのが気になります。……Apple自身がサンプルコードをそれほど出せていないところを見ると、AppleのAppleScriptチーム自身も手探り状態なのでしょうか。

12/23 Photoshop CS3で指定エリアを切り出して新規保存

Photoshop CS3上で現在オープンしている画像から指定座標の範囲の内容を別画像として保存するAppleScriptです。

指定フォルダ内の画像をすべて処理するために、その1枚分の画像処理部分を試作したものです。あらかじめPhotoshopで画像をオープンしておかないとエラーになります。

ただ……Adobeのアプリケーションは、連続して処理を行わせると必ずクラッシュするもの(断言)なので、AppleScriptでクラッシュ検出処理を行うようにして、Photoshop CS3のクラッシュに備えることが重要です。

InDesignやPhotoshopなど、JavaScriptでもコントロールできるようになっていますが、動作原理上、クラッシュからのリカバリを行うにはやはりAppleScriptで外部からコントロールしたほうが便利なように思います。人がそばについて監視していないと動かせないのでは、夜間に勝手に仕事をさせておくわけにいきません。

スクリプト名:Photoshop CS3で指定エリアを切り出して新規保存
set {x1, y1} to {259, 40}
set {x2, y2} to {639, 242}

makePhotoshopSelectionRegion(x1, y1, x2, y2) of me

tell application “Adobe Photoshop CS3″
  activate
  
copy
  
set newDoc to make new document with properties {height:(y2 - y1), width:(x2 - x1)}
  
tell newDoc
    paste
  end tell
end tell

set newFilePath to (choose file name) as string

tell application “Adobe Photoshop CS3″
  set myOptions to {class:JPEG save options, embed color profile:true, format options:progressive, quality:12, scans:3}
  
save newDoc in newFilePath as JPEG with options myOptions appending lowercase extension with copying
  
close document 1 saving no
end tell

–Photoshop上で指定矩形を選択する
on makePhotoshopSelectionRegion(x1, y1, x2, y2)
  tell application “Adobe Photoshop CS3″
    tell current document
      select region {{x1, y1}, {x2, y1}, {x2, y2}, {x1, y2}} combination type replaced
    end tell
  end tell
end makePhotoshopSelectionRegion

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

12/23 Photoshop上で指定矩形を選択する

Photoshop CS3上で現在オープンしている画像に対して、指定矩形座標を選択するAppleScriptです。

選択範囲を取得するのは簡単なのに、選択範囲を作成するのにはけっこう骨が折れました。Photoshp CS3のAppleScript用語辞書を調べ、Adobeが配布しているPhotoshopのScripting Guide(情報量が多い割に、サンプルScriptがイケてないのは何故?)を調べ、AppleScript Users MLの過去ログを調べ……意外と、欲しい情報というのは転がっていないもので……。

selectコマンドでパラメータを指定するというのは意外でした。さらに、座標の指定方法が四隅すべての座標を必要とするとは……。

スクリプト名:Photoshop上で指定矩形を選択する

makePhotoshopSelectionRegion(259, 36, 639, 242) of me

–Photoshop上で指定矩形を選択する
on makePhotoshopSelectionRegion(x1, y1, x2, y2)
  tell application “Adobe Photoshop CS3″
    tell current document
      select region {{x1, y1}, {x2, y1}, {x2, y2}, {x1, y2}} combination type replaced
    end tell
  end tell
end makePhotoshopSelectionRegion

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

12/23 Photoshop CS3から画像の選択範囲を取得する

Photoshop CS3で画像の選択範囲の座標を取得するAppleScriptです。

ps1.jpg

大量の画像から、同じ箇所を切り取って別フォルダに別名で保存したいような場合に、最初にサンプル用の画像を1枚オープンしておいて、その画像上で選択範囲を作成しておき、AppleScriptを実行すると選択範囲の座標情報を学習。指定フォルダの画像をオープンして、最初に指定した選択範囲を切り出して別のフォルダに保存する(以下、繰り返し)……といった処理のための下調べのために作成してみました。

selectionのboundsを取得すれば選択範囲は分るのですが、何も選択していなかった場合にはこの動作を行うとエラーになってしまうため、try文でエラートラップを仕掛けておき、エラー時には何も選択されていないものと見なし、{0,0,0,0}を返します。

ps21.jpg

スクリプト名:Photoshop CS3から画像の選択範囲を取得する
tell application “Adobe Photoshop CS3″
  tell document 1
    set aSel to selection
    
try
      set {x1, y1, x2, y2} to bounds of selection
    on error
      set {x1, y1, x2, y2} to {0, 0, 0, 0}
    end try
  end tell
end tell

–> {209.0, 96.0, 777.0, 312.0}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

12/22 Excel選択範囲から各種文字列長のデータをピックアップ v6

Excel上の選択範囲から、各種文字列長のデータをピックアップするAppleScriptです。

Excel上に日本人の名前が姓と名の間に半角スペースが入った状態で並んでいたとして……諸般の都合でこれを姓1文字+名1文字のパターン、姓1文字+名2文字のパターンなど……さまざまな文字長に場合分けして、それぞれの文字長に最初に合致したデータをピックアップする、というものです。

excel1.jpg

Excelからデータを取得してはいますが、実際にはリストに突っ込んでゴリゴリ回しています。処理速度の向上のためにa reference toで高速化を行っており、これによって10倍以上は高速化できています(多くて数百件ぐらいのデータを処理していたので、割とすぐに結果が返ってきます@Core 2 Duo 2.4GHz)。

これも、最初は手作業で行っていたのですが、「そのぐらい、プログラムで処理すれば一瞬だ!」とブチ切れて、すぐに最初の試作品を作成。運用しているうちに、どんどん改良を加えて、半日もたたないうちにここまで機能が追加されました。

スクリプト名:Excel選択範囲から各種文字列長のデータをピックアップ v6
set procList to {{1, 1}, {1, 2}, {2, 1}, {2, 2}, {1, 3}, {3, 1}, {2, 3}, {3, 2}, {3, 3}}
global gaList, gaList_r
global aSelection, aSelection_r
global gaaList, gaaList_r

tell application “Microsoft Excel”
  set aSelection to formula of selection
end tell
set aSelection_r to a reference to aSelection

set gaList to {}
set gaList_r to a reference to gaList

set dameList to {}

repeat with i in aSelection_r
  set j to contents of first item of i
  
set j to repChar(j, “ ”, ” “) of me –全角スペースを半角に置換しておく
  
  
if j ends with ” “ then
    set j to deleteBackSPC(j) of me
  end if
  
  
considering hyphens
    considering white space
      set j0 to offset of ” “ in j
      
if j0 is not equal to 0 then
        set j1 to text 1 thru (j0 - 1) of j
        
        
set revJ to (reverse of (characters of j)) as string
        
set j00 to offset of ” “ in revJ
        
set j2 to text ((length of j) - j00 + 2) thru -1 of j
      else
        set j0 to offset of “ ” in j
        
if j0 is not equal to 0 then
          set j1 to text 1 thru (j0 - 1) of j
          
          
set revJ to (reverse of (characters of j)) as string
          
set j00 to offset of “ ” in revJ
          
set j2 to text ((length of j) - j00 + 2) thru -1 of j
        else
          set the end of dameList to j
        end if
      end if
    end considering
  end considering
  
  
set the end of gaList_r to {j, j1, j2, {length of j1, length of j2}}
end repeat

if dameList is not equal to {} then
  choose from list dameList with prompt “だめだった名前のリスト”
end if

set gaaList to {}
set gaaList_r to a reference to gaaList
repeat with i in procList
  set j to contents of i
  
set tmpList to {}
  
  
repeat with ii in gaList_r
    set jj to contents of item 4 of ii
    
set jj2 to contents of ii
    
if jj = j then
      set the end of tmpList to jj2
      
exit repeat
    end if
  end repeat
  
  
set the end of gaaList_r to {j, tmpList}
end repeat

gaaList
–> {{{1, 1}, {{”ぴ よ”, “ぴ”, “よ”, {1, 1}}}}, {{1, 2}, {{”ぴ よ子”, “ぴ”, “よ子”, {1, 2}}}}, {{2, 1}, {{”ぴよ こ”, “ぴよ”, “こ”, {2, 1}}}}, {{2, 2}, {{”ぴよ まる”, “ぴよ”, “まる”, {2, 2}}}}, {{1, 3}, {{”ぴ よまる”, “ぴ”, “よまる”, {1, 3}}}}, {{3, 1}, {{”ぴよま る”, “ぴよま”, “る”, {3, 1}}}}, {{2, 3}, {{”ぴよ まるお”, “ぴよ”, “まるお”, {2, 3}}}}, {{3, 2}, {{”ぴよま るお”, “ぴよま”, “るお”, {3, 2}}}}, {{3, 3}, {{”ぴよま るるこ”, “ぴよま”, “るるこ”, {3, 3}}}}}

on deleteBackSPC(a)
  set aCount to 1
  
considering hyphens
    considering white space
      
      
set aList to reverse of characters of a
      
repeat with i in aList
        set j to contents of i
        
if j is not in {” “, “  ”, “ ”} then
          exit repeat
        end if
        
        
set aCount to aCount + 1
        
      end repeat
      
    end considering
  end considering
  
  
set aa to text 1 thru ((length of a) - aCount + 1) of a
  
return aa
  
end deleteBackSPC

–文字置換ルーチン
on repChar(origText, targStr, repStr)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

12/22 指定フォルダの中のフォルダをオープン

Finder上で選択しているフォルダの中に入っているフォルダをオープンします。

Script Menuに入れて使っています。正確にいえば、選択中のフォルダの1階層下にあるフォルダをすべてオープンします。「指定フォルダ中のファイルを消してフォルダだけ残す」AppleScriptで処理をしたフォルダに対して、再度Windowを並べるために実行するものです。

スクリプト名:指定フォルダの中のフォルダをオープン
tell application "Finder"
  set a to selection
  
set aa to first item of a
  
set aaa to aa as alias
  
  
tell folder aaa
    tell every folder to open
  end tell
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に