Archive for 12月, 2012

2012/12/31 AppleScriptObjCで透明ウィンドウを表示

AppleScriptObjCで、透明なウィンドウを表示するプロジェクトです。

透明ウィンドウは比較的重要で応用範囲の広い「手口」です。

最近は減ってきましたが、アプリケーション起動時のスプラッシュスクリーンを表示するような場合は、透明ウィンドウの上にアプリケーションのタイトル画像を表示。こうすることで、スプラッシュスクリーンが簡単に出来上がります。

この透明ウィンドウはAppleが配布していたカスタムクラスをそのまま利用しています。

transwin1.png

transwin2.png

→ Xcodeプロジェクトのダウンロード

2012/12/31 AppleScriptObjCでViewを印刷

AppleScriptObjCで印刷を行うサンプルを、MacScripterの書き込みを元に組み立てて……そのままでは芸がないので「’s」でオブジェクト階層をつなぐ記法から「tell」文で階層をつなぐ記法に書き換えてみました。

AppleScriptObjC登場時から、「’s」でオブジェクト階層をつなぐ記法はいまひとつとっつきが悪く、読みにくさに拍車をかけていました。

この「’s」記法は、Objective-Cのプログラムとオブジェクト指定の並び順が同じため、Objective-Cのプログラムを参考にしてAppleScriptObjCのプログラムを書く場合には便利です。

set sharedPrintInfo to current application’s NSPrintInfo’s sharedPrintInfo()

という記述をtell文で展開すると、

tell current application
 tell class “NSPrintInfo”
  set mySharedPrintInfo to sharedPrintInfo()
 end tell
end tell

のようになります。class文を補う必要があるので、このあたり要注意でしょうか。

さらにすすめていくと、

thePrintOp’s runOperation

の箇所だけはtell文で展開できませんでした。

print1.png

WebViewを置いて、簡単なWebブラウザを作成。URL欄に入れたURLをWebViewで表示。

print2.png

printボタンを押すと印刷ダイアログを表示します。このダイアログ、いろいろとカスタマイズする方法があると楽しそう(応用範囲が広そう)です。

ただ、印刷前にViewを広げてあげないと印刷対象のViewが十分に印刷されなかったりと、いろいろケアしてあげないといけなさそうで…………

AppleScriptObjCファイル名:printingASOCAppDelegate.applescript

– printingASOCAppDelegate.applescript
– printingASOC

– Created by Takaaki Naganoya on 10/09/24.
– Copyright 2010 Takaaki Naganoya. All rights reserved.

– Original http://www.macscripter.net/viewtopic.php?id=37525

script printingASOCAppDelegate
  
  property parent : class “NSObject”
  
  property theView : missing value
  
  
  on applicationWillFinishLaunching_(aNotification)
    
  end applicationWillFinishLaunching_
  
  on applicationShouldTerminate_(sender)
    return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  
  –ボタンのクリックにBindしておいた
  
on thePrint_(sender)
    doPrinting()
  end thePrint_
  
  
  –指定のビューを印刷する
  
on doPrinting()
    
    tell current application
      tell class “NSPrintInfo”
        set mySharedPrintInfo to sharedPrintInfo()
      end tell
    end tell
    
    
    tell mySharedPrintInfo
      –上下左右のマージン設定
      
setLeftMargin_(20.0)
      
setRightMargin_(0.0)
      
setTopMargin_(20.0)
      
setBottomMargin_(10.0)
      
      –印刷方向設定
      
setOrientation_(0)
      
      –水平、垂直の各方向のページネーション(レイアウト?)設定
      
setHorizontalPagination_(1)
      
setVerticalPagination_(0)
      
      –上下左右のセンター設定
      
setVerticallyCentered_(0)
      
setHorizontallyCentered_(1)
      
    end tell
    
    
    tell current application
      tell class “NSPrintOperation”
        set thePrintOp to printOperationWithView_printInfo_(theView, mySharedPrintInfo)
      end tell
    end tell
    
    tell thePrintOp
      runOperation()
    end tell
  end doPrinting
  
  
end script

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

2012/12/29 AppleScriptObjCでサブルーチン(メソッド)間でbooleanの値を受け取る

AppleScriptObjCのプログラム内でサブルーチンを呼び出して、booleanの値(true/false)をやりとりした時に、予想外の動作を行うことがありました。

小規模な構成(AppleScriptのファイルが1つ)のときには動作していたプログラムが、複数のAppleScriptに分けて呼び出すようにするとエラーが頻発するようになり、その原因が値の受け渡し時にデータの「型」が変わってしまうことでした。Cocoaの各APIを呼び出すと、返ってくる値をそのまま使えずas unicode textとかas numberなどとcastしてあげないとAppleScript側でうまく扱えませんが、それと同様の現象が、単にAppleScriptのサブルーチン間のやりとりだけでも必要になるということです。

そこで、どういう場合に値の受け渡しで気を使う必要があるのか、サブルーチンの呼び出し方でさまざまなケースを想定して実際にテストを行ってみました。

exlib.png

(1)同一Scriptファイル内で同一ハンドラ内……true/falseで返ってくる
(2)同一Scriptファイル内でハンドラ(メソッド)呼び出し……true/falseで返ってくる
(3)同一Scriptファイル内で他のScriptオブジェクト内のハンドラ(メソッド)呼び出し……1/0で返ってくる
(4)他のScriptファイルで他のScriptオブジェクト内のハンドラ呼び出し……1/0で返ってくる

……大きなプログラムを組むのであれば、サブルーチン間の値の受け渡しには十分に気を付ける必要があることが分りました。

→ Xcodeプロジェクトのダウンロード

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– booleanTest

– Created by Takaaki Naganoya on 2012/12/21.
– Copyright (c) 2012年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class “NSObject”
  
  property inSame : missing value
  
property exLib : missing value
  
  
  on applicationWillFinishLaunching_(aNotification)
    
  end applicationWillFinishLaunching_
  
  on applicationShouldTerminate_(sender)
    return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  
  
  
  
  on clicked_(sender)
    
    
    –イベントハンドラ内でサブルーチン呼び出しを行わない場合のbooleanの値の扱い
    
set a to true
    
set b to true as boolean
    
set c to (1 = 1)
    
    
    
    if a = true then
      display dialog is true”
    end if
    
    if b = true then
      display dialog is true”
    end if
    
    if c = true then
      display dialog is true”
    end if
    
    
    
    
    chkTrueA_B_C_(a, b, c) –同一Script内の他のハンドラ
    
    
    tell inSame
      chkTrueA_B_C_(a, b, c) –同一ファイル内の他のScriptオブジェクト内の他のハンドラ
    end tell
    
    
    tell exLib
      chkTrueA_B_C_(a, b, c) –他のファイルの他のScript Object内のハンドラ(これは無理)
      
chkTrue2A_B_C_(a, b, c) –他のファイルの他のScript Object内のハンドラ(最初にパラメータをすべて型変換して使用)
      
chkTrue3A_B_C_(a, b, c) –他のファイルの他のScript Object内のハンドラ(条件文のところでcastしつつ判定して使用)
    end tell
    
    
  end clicked_
  
  
  
  
  –同一ファイル内の同一Script Object内のハンドラ
  
on chkTrueA_B_C_(a, b, c)
    
    if a = true then
      display dialog “sub___ is true”
    end if
    
    if b = true then
      display dialog “sub___ is true”
    end if
    
    
    if c = true then
      display dialog “sub___ is true”
    end if
    
    
  end chkTrueA_B_C_
  
  
  
end script

script insideSameFile
  
  property parent : class “NSObject”
  
  
  –同一ファイル内の他のScript Object内のハンドラ
  
on chkTrueA_B_C_(a, b, c)
    
    display dialog “Same File External Script Object”
    
    set a to a as boolean
    
set b to b as boolean
    
set c to c as boolean
    
    
    if a = true then
      display dialog “ExObj_sub___ is true”
    end if
    
    if b = true then
      display dialog “ExObj_sub___ is true”
    end if
    
    
    if c = true then
      display dialog “ExObj_sub___ is true”
    end if
    
    
  end chkTrueA_B_C_
  
end script

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

AppleScriptObjCファイル名:subLib.applescript
script aSub
  
  property parent : class “NSObject”
  
  
  –他のファイル内の他のScript Object内のハンドラ
  
  –この状態だと引数として与えたBooleanの値をサブ側で認識できない
  
on chkTrueA_B_C_(a, b, c)
    
    if a = true then
      display dialog “exsub1___ is true”
    end if
    
    if b = true then
      display dialog “exsub1___ is true”
    end if
    
    
    if c = true then
      display dialog “exsub1___ is true”
    end if
    
  end chkTrueA_B_C_
  
  
  
  –ハンドラ冒頭でBooleanの値を明示的にcastしておく。これだと大丈夫
  
on chkTrue2A_B_C_(a, b, c)
    
    set a to a as boolean
    
set b to b as boolean
    
set c to c as boolean
    
    
    if a = true then
      display dialog “exsub2___ is true”
    end if
    
    if b = true then
      display dialog “exsub2___ is true”
    end if
    
    if c = true then
      display dialog “exsub2___ is true”
    end if
    
  end chkTrue2A_B_C_
  
  
  
  
  –条件文で使用する際にBooleanにcastして判定(めんどくさい)。これでも大丈夫
  
on chkTrue3A_B_C_(a, b, c)
    
    
    if a as boolean = true then
      display dialog “exsub3___ is true”
    end if
    
    if b as boolean = true then
      display dialog “exsub3___ is true”
    end if
    
    if c as boolean = true then
      display dialog “exsub3___ is true”
    end if
    
  end chkTrue3A_B_C_
  
  
  
end script

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

2012/12/28 Xcode 4.5.2上で、Xcodeプロジェクト内の選択中のファイル名を取得

Xcode 4.5.2上で、選択中のファイル名を取得するAppleScriptです。選択中のAppleScriptObjCコードを書式つきでHTML書き出しするプログラムを強化する際に作成しました。

XcodeのAppleScript用語辞書はどーしようもなく実用性が低く、実践的なタスクの自動化を行うには不十分です。

iPhoneアプリのプロジェクトのプロパティを変更してビルドしてAppStoreに申請するなどの「本来、できてしかるべき」作業の自動化が行えません(このあたり、Appleの担当が自動化をやりたいと思っていつつも能力不足のため実現できないでいるのか、おかしなプログラムをAppStoreに大量に流し込まれることを避けようとしてお茶を濁そうとしているのかいまひとつ不明)。

それどころか、プロジェクト内で選択中のファイルが何であるかを取得するための属性値すらありません。編集中のソースファイルの選択中のテキスト(文字単位、段落単位)を取得することはできるものの、肝心の編集中のファイルのファイル名の取得はできません。

xc1.png

ただ、「できないできない」と駄々をこねていても仕方がないので、できる範囲で何かやってみようという話です(多いな〜、こういうの)。

Xcodeのウィンドウをよく見ると、タイトル部分にXcode書類名と選択中の書類名が表示されています。

xc2.png

そこで、Windowオブジェクトのname属性を調べてみると、表示されているとおりの文字列を取得できました。

xc3.png

取得したあとにparseして、選択中のファイル名の一丁上がり。

ただし、XcodeのようにひんぱんにバージョンアップするアプリケーションのScriptingは、同様にひんぱんに状況が変わるので、バージョンアップのたびごとに動作の確認が必要になることでしょう。

スクリプト名:Xcodeで選択中のファイルを取得する

–Xcodeのプロジェクト中で選択中のファイルを取得する
tell application “Xcode”
  tell window 1
    set aWintitle to name
  end tell
end tell

set aList to parseByDelim(aWintitle, ” ― “) of me

if (length of aList) is not equal to 2 then
  return –エラー時
end if

set {xcodeDocName, selectedFileName} to aList
–> {”booleanTest.xcodeproj “, “subLib.applescript”}

–取得したファイル名でsource documentにアクセスしてXcodeプロジェクト内のファイルの存在確認
tell application “Xcode”
  tell source document selectedFileName
    properties
  end tell
end tell

–与えられた文字列を、指定デリミタ文字でparseしてリストにして返す
on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

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

2012/12/28 AppleScriptObjCでボタンの文字色を変更

最初はAppleScriptObjCでWindowのタイトルの文字色を変更できないか試していたのですが、それが(かなり組まないと)ムリだと気付き……逆に、簡単に文字色を変更できるGUI部品がないかテストした試作品です。

NSAttributedStringがどのGUI部品に対して設定可能なのか、APIのドキュメントをキーワード検索して調べました。

coloredb.png

NSTextFieldの中身は当然として、NSButtonのほかNSMenuの内容などに色つき文字(NSAttributedString)を指定できることが分り、とりあえず調査はこのぐらいにしておきました。試作プロジェクトの「WindowTitleTest」はWindowのタイトル色を変更できないか試していた頃の名残りです。

→ Xcodeプロジェクトのダウンロード

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– windowTitleTest

– Created by Takaaki Naganoya on 2012/12/25.
– Copyright (c) 2012年 Takaaki Naganoya. All rights reserved.
– original http://www.macscripter.net/viewtopic.php?id=38088

script AppDelegate
  
  property parent : class “NSObject”
  
  property nsc : class “NSColor”
  
  property tf : missing value
  
property aWin : missing value
  
property aButton : missing value
  
  
  on applicationWillFinishLaunching_(aNotification)
    
    –set colorArray to current application’s NSArray’s arrayWithObjects_(nsc’s redColor(),nsc’s orangeColor(),nsc’s yellowColor(),nsc’s greenColor(),nsc’s blueColor,nsc’s purpleColor(),missing value)
    
    
    tell current application’s NSColorList to set AppleColors to colorListNamed_(“Apple”)
    
set redColor to AppleColors’s colorWithKey_(“Red”)
    
tell current application’s NSFont to set myFont to fontWithName_size_(“HiraKakuPro-W6″, 24)
    
    set attrsDict to current application’s NSDictionary’s dictionaryWithObjects_forKeys_({myFont, redColor}, {current application’s NSFontAttributeName, current application’s NSForegroundColorAttributeName})
    
tell current application’s NSAttributedString to set aString to alloc()’s initWithString_attributes_(“色つき文字を設定できるGUI部品のテスト”, attrsDict)
    
    
    tf’s setAttributedStringValue_(aString) –NSTextField
    
aButton’s setAttributedTitle_(aString) –NSButton
    
  end applicationWillFinishLaunching_
  
  
  on applicationShouldTerminate_(sender)
    – Insert code here to do any housekeeping before your application quits
    
return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
end script

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

2012/12/27 AppleScriptObjCでPDFViewを使ってPDFをプレビュー

PDFのファイルを選択して、Photoshopで画像フォーマット変換を行うため、対象ページ数と解像度を指定しなければなりませんでした。そこで、PDF内の各ページのプレビューを行うウィンドウを表示すべく、AppleScriptObjCでPDFプレビュー用の試作品を作ってみました。

pdfview.png

とりあえず、指定したPDFのファイルをプレビューできています。本来なら、これで十分なはずですが……PDFビューで表示しているPDF内のリンクなどをDisableにできていないので、表示中の内容をクリックすると別のページに飛べてしまったりします。

あとは、現在表示中のページ数を取得できるとよいのですが……まだ構造を調べながらいろいろつっついている状態なので、まだできていません。さらに、パスワードが設定されていた場合への対処なども手を打っておく必要があるでしょう。

→ Xcodeプロジェクトのダウンロード

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– pdftest2

– Created by Takaaki Naganoya on 2012/10/23.
– Copyright (c) 2012年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class “NSObject”
  
property nsurl : class “NSURL”
  
property PDFDocument : class “PDFDocument”
  
  
  property pdfPreviewWin : missing value
  
property pdfView : missing value
  
property pdfThumb : missing value
  
  property pdfPageText : missing value
  
  
  
  on applicationWillFinishLaunching_(aNotification)
    
    pdfView’s setAllowsDragging_(true)
    
pdfView’s setDelegate_(me)
    
    
    pdfThumb’s setMaximumNumberOfColumns_(2)
    
    
    –書類が変更になった(オープンされた場合)
    
set noter1 to current application’s NSNotificationCenter’s defaultCenter()
    
noter1’s addObserver_selector_name_object_(me, “pdfChange:”, current application’s PDFViewDocumentChangedNotification, missing value)
    
    –ページが変更になった
    
set noter2 to current application’s NSNotificationCenter’s defaultCenter()
    
noter2’s addObserver_selector_name_object_(me, “pdfChange:”, current application’s PDFViewPageChangedNotification, missing value)
    
    
    –ファイルを選択
    
set aFile to choose file of type “com.adobe.pdf”
    
set aFileString to aFile as Unicode text
    
dispPDFWithHFSpath_(aFileString)
    
    
  end applicationWillFinishLaunching_
  
  
  
  –プレビューウィンドウをセンタリング(見た目以外にとくに意味なし)
  
on applicationDidFinishLaunching_(aNotification)
    
    pdfPreviewWin’s |center|()
    
  end applicationDidFinishLaunching_
  
  
  
  –HFSパスの文字列を渡すとPDFViewに表示する
  
on dispPDFWithHFSpath_(aFileString)
    
    set aFileString to aFileString as Unicode text
    
    tell application “Finder”
      set aFileURL to (URL of file aFileString)
    end tell
    
    set aFileURL to aFileURL as Unicode text
    
set theURL to nsurl’s URLWithString_(aFileURL)
    
    set aPDFdoc to PDFDocument’s alloc()’s initWithURL_(theURL) –allocわすれてた、、、
    
pdfView’s setDocument_(aPDFdoc)
    
  end dispPDFWithHFSpath_
  
  
  on applicationShouldTerminate_(sender)
    return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  
  –ファイルの新規オープン、および表示ページが変更になった場合にnotificationでこちらを呼び出している
  
–ここで、選択中のページのノンブルを取得したい(まだできていない)
  
on pdfChange_(sender)
    set curPage to pdfView’s currentPage
    
–set curPageNum to curPage’s indexForPage
    
    log curPage
  end pdfChange_
  
end script

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

2012/12/21 指定フォルダが共有されているかチェック

指定のフォルダが「共有」されているかどうかチェックするAppleScriptです。

システム環境設定の「共有」>「ファイル共有」で共有対象として指定されているフォルダより下の階層に指定のフォルダが存在しているかどうかをチェックします。

share1.png

share2.png

share3.png

指定フォルダが共有ポイントでなければ、1階層ずつフォルダ階層をさかのぼり、ユーザーのホームディレクトリまでたどったらそこで探索を打ち切ります。

Macintosh HD:Users:user1:Desktop:Test 1:Test 2:Test3:
Macintosh HD:Users:user1:Desktop:Test 1:Test 2:
Macintosh HD:Users:user1:Desktop:Test 1:
Macintosh HD:Users:user1:Desktop:

……と、階層をさかのぼりつつ共有チェックを行い、この「Desktop」が共有されていれば、{true, alias “Macintosh HD:Users:user1:Desktop:”} を返します。上位フォルダが共有されているということは、その下にある指定フォルダも共有対象だといえます。

「Macintosh HD:Users:user1:」までさかのぼって、共有されていなければ、{false,”"}を返します。

このように、起動ディスク(システムが入っていて、ユーザーのホームディレクトリが想定の階層にある)を前提として処理を組み立てているため、外付けのディスクやUSBメモリーなどを対象に処理を行う場合には書き換える必要が出てきます。アンマウント可能なディスクであれば、起動ディスクではないと判断できますので、そうした情報をもとに「共有チェックを行う上限」の制御を動的に行えばよいのでしょう(文章で説明するよりもプログラムを書いたほうが早そう……)。

本Scriptは、OS X 10.8.2上で動作確認を行いましたが、特殊な処理は行っていないので10.7や10.6でも動くはずです。

ただ、勢いで作ってしまってみたものの、いまひとつ用途が…………

スクリプト名:指定フォルダが共有されているかチェック
–指定のフォルダが共有されているかどうかチェックするAppleScript
–指定フォルダからさかのぼって、各ユーザーのホームディレクトリまでたどって共有チェックする
– By Takaaki Naganoya

set my_chosen_folder to (choose folder with prompt “共有されているかどうか、調査する対象のフォルダを指定”)
set {aRes, sharedPath} to chkTheFolderIsShared(my_chosen_folder) of me

–> {false, “”}–上位フォルダも含めて共有されていない場合の返り値
–> {true, alias “Macintosh HD:Users:someone:Desktop:”} –上位フォルダが共有されている場合の返り値

–指定のフォルダが共有されているかどうかディレクトリ階層をさかのぼりつつチェック
– Macintosh HD:Users:someone: までの階層まで、指定フォルダから順にさかのぼって共有チェックを行う
–ユーザーのホームディレクトリの下を探すことを目的としている。外付けHDDやUSBメモリーなどは制限を外すべき
on chkTheFolderIsShared(my_chosen_folder)
  set aPathStr to my_chosen_folder as string
  
  
set aList to parseByDelim(aPathStr, “:”) of me –フォルダのパスを階層ごとにリストに分解(最後にゴミができるので次で除去)
  
  
set aLen to ((length of aList) - 1) –リスト末尾のゴミをスキップするために-1する
  
  
repeat with i from aLen to 3 by -1 – Macintosh HD:Users:someone: までサーチ。自分のホームフォルダまでを探索限界とする
    
    
set pList to contents of items 1 thru i of aList
    
set tmpPath to retListCombinedText(pList, “:”) of me
    
    
set tmpPath to tmpPath as alias
    
    
–指定フォルダの共有チェック
    
set pRes to chkSub(tmpPath) of me
    
    
if pRes = true then
      return {true, tmpPath}
    end if
    
  end repeat
  
  
return {false, “”}
  
end chkTheFolderIsShared

–与えられた文字列を、指定デリミタ文字でparseしてリストにして返す
on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

–与えられたリストを、指定デリミタ文字を使用してテキストにして返す
on retListCombinedText(aList, aDelim)
  set aText to “”
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retListCombinedText

–指定フォルダの共有チェック
–Original By Laine Lee 2012/12/21 05:39 JST and Robert Poland
on chkSub(aFolderpath)
  set P to quoted form of (characters 1 thru -2 of (POSIX path of aFolderpath) as string)
  
if length of (do shell script “/usr/bin/dscl . search /SharePoints dsAttrTypeNative:directory_path” & space & P) is not 0 then
    return true –the folder is shared
  else
    return false –the folder is *not* shared
  end if
end chkSub

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

2012/12/16 Mail.app上で選択したメールの発信元に応じてメール一覧の背景色を変える v2

同じメールアドレスの持ち主にメールではなく電話で連絡を取ろうとして、会社に電話をしたところ……相手は自宅からメールを出していたので、自宅に連絡し直す必要があった……というケースは、往々にしてあり得ることです。

そこで、メールの経由サーバーの違いをメールヘッダーから検出し、職場以外の場所(と思われる場所)からメールが送信された場合に、Mail.appのメール一覧の背景に色を付けて区分けしようとするAppleScriptを書いてみました。

mail1.png

電子メールのメールヘッダーをすべて表示させ、「Recieved:」ヘッダーを調べてみると……メールの伝送経路が変われば、その内容が変わるわけで、相手が職場「以外の場所」から送信した場合には変わります。その「違い」を調べておいてプログラム中に直接書いてあります(これは、相手の環境によって異なるため、プログラム内に書く検出用のサーバー名は書き換える必要があります)。

本Scriptは、Mail.app上でメールを選んでおいて実行すると……メールヘッダの「Recieved:」を調べて指定したメールサーバー名が入っている場合には件名の色を変更します。

本来、メール受信時に実行する「ルール」で「AppleScriptを実行」のアクションで実行したかったのですが………OS X 10.8.2上のMail.app v6.2ではこの「AppleScriptを実行」アクションにバグがあって、任意のAppleScriptを実行できません。早いところ直してほしいところです。

スクリプト名:Mail.app上で選択したメールの発信元に応じてメール一覧の背景色を変える v2
script spd
  property aHead : missing value
  
property hList : {}
end script

tell application “Mail”
  set aSel to selection
  
if aSel = {} or aSel = “” then
    display dialog “何もメールが選択されていません” buttons {“OK”} default button 1 with icon 2
    
return
  end if
  
set aMes to contents of first item of aSel
end tell

procAMailBGColorBySnetNetworkLocation(aMes) of me

–指定メールの発信元のネットワークに応じてメール一覧の背景色を変更する
on procAMailBGColorBySnetNetworkLocation(aMes)
  tell application “Mail”
    –選択したメール(1通)のメールヘッダーをすべて取得する  
    
set aHead of spd to all headers of aMes
    
    
–メールヘッダーをなめてみる
    
set hList of spd to paragraphs of aHead of spd
    
    
repeat with i in hList of spd
      set j to contents of i
      
      
if j begins with “Received:” then
        if j contains “.flets.hi-ho.ne.jp” then
          
          
–自宅の固定回線の場合
          
set background color of aMes to green –グリーン
          
return
          
        else if j contains “.emobile.ad.jp” then
          
          
–Emobile経由(移動中)の場合
          
set background color of aMes to yellow –イエロー
          
return
          
        end if
      end if
    end repeat
    
  end tell
end procAMailBGColorBySnetNetworkLocation

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

2012/12/15 PhotoshopでJavaScript経由でEPS/PDFをオープン

Adobe Photoshopには、「(AppleScriptからの)ファイルオープン時に、パスに全角の英数字もしくは全角スペースが含まれているとファイルオープンできない。フォルダ階層が深くなると指定のファイルをオープンできない」というバグが、最新のAdobe Photoshop CS6でも存在しています。

CS6.5とかCS7でこれが修正されるかどうかは定かではありません。

そこで、Adobeには期待せずAppleScriptからJavaScriptを呼び出して、ファイルのオープンを行うという方法を(IllustratorのCS2あたりでは多用していましたが)採用することになるわけですが、PDFやEPSをオープンする場合にはOpen Optionを指定しなければなりません。

そこで、JavaScriptのScripting Manualを読みつつ、JavaScript経由でOpen Optionを指定してEPS/PDFファイルをオープンするルーチンをさくっと作ってみました。

実際には、AppleScriptObjCのプログラムに組み込んで、CMYK画像だったらPhotoshopでプロファイル変換を行ってAppleScriptObjCのプログラムで表示したり、ファイルの保存を行ったりしています。

動作確認は、Photoshop CS6で行っています。

スクリプト名:PhotoshopでJavaScript経由でEPSをオープンする
set aTmpFile to choose file
set aRes to openEPSbyPhotoshop(aTmpFile, 72, “CMYK”)

–AppleScriptで直接Photoshopにファイルをオープンさせようとすると、日本語環境ではパスのハンドリングで
–問題が出ることがある(Photoshopのバグ)ので、JavaScript経由でEPSをオープンさせる
on openEPSbyPhotoshop(aFile, aResol, colorMode)
  
  
set aTmpPOSIX to quoted form of POSIX path of aFile
  
  
set jsText to
var fileRef = new File(” & aTmpPOSIX & “)

var epsOpenOptions = new EPSOpenOptions

epsOpenOptions.antiAlias = true
epsOpenOptions.constrainProportions = true
epsOpenOptions.mode = OpenDocumentMode.”
& colorMode &
epsOpenOptions.resolution = “
& (aResol as string) &

app.open( fileRef, epsOpenOptions )

  
  
with timeout of 600 seconds
    tell application id “com.adobe.photoshop”
      try
        do javascript jsText
      on error
        return false
      end try
    end tell
  end timeout
  
  
  
return true
  
end openEPSbyPhotoshop

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

スクリプト名:PhotoshopでJavaScript経由でPDFをオープンする
set aTmpFile to choose file
set aRes to openPDFbyPhotoshop(aTmpFile, 72, 1, “CMYK”)

–AppleScriptで直接Photoshopにファイルをオープンさせようとすると、日本語環境ではパスのハンドリングで
–問題が出ることがある(Photoshopのバグ)ので、JavaScript経由でPDFをオープンさせる
on openPDFbyPhotoshop(aFile, aResol, targPage, colorMode)
  
  
set aTmpPOSIX to quoted form of POSIX path of aFile
  
  
set jsText to
var fileRef = new File(” & aTmpPOSIX & “)

var pdfOpenOptions = new PDFOpenOptions

pdfOpenOptions.antiAlias = true
pdfOpenOptions.cropPage = CropToType.MEDIABOX
pdfOpenOptions.mode = OpenDocumentMode.”
& colorMode &
pdfOpenOptions.resolution = “
& (aResol as string) &
pdfOpenOptions.page = “
& (targPage as string) &

app.open( fileRef, pdfOpenOptions )

  
  
with timeout of 600 seconds
    tell application id “com.adobe.photoshop”
      try
        do javascript jsText
      on error
        return false
      end try
    end tell
  end timeout
  
  
return true
  
end openPDFbyPhotoshop

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

2012/12/15 AppleScriptObjCでAES128暗号化ライブラリを用いて暗号化/復号化

xcatsanさんが「AES128暗号化ライブラリ FBEncryptor」を公開されているのを見つけたので、AppleScriptObjCから呼び出して暗号化/復号化のテストを行ってみました。

とりあえず、記事にあったように必要なファイルを自分のAppleScriptObjCのプロジェクトにコピーして、AppleScriptObjCから呼び出してみました。

NSDataベースの暗号化/復号化はちょっと試してみてうまくインタフェースがとれなかったので、文字ベースの暗号化/復号化のメソッドを呼び出したら、うまくやりとりができました。

enc1.png

enc2.png

こんな風に、公開されているさまざまなObjective-CのコードをAppleScriptから呼び出せて、さらに他のアプリケーションをコントロールできると面白いですね。

→ Xcodeプロジェクトのダウンロード

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– encryptionTest

– Created by Takaaki Naganoya on 2012/12/14.
– Copyright (c) 2012年 Takaaki Naganoya. All rights reserved.
–  http://cocoadays.blogspot.jp/2011/06/ios-aes128-fbencryptor.html

script AppDelegate
  property parent : class “NSObject”
  
property FBEncryptorAES : current application’s class “FBEncryptorAES”
  
  property aKeyTF : missing value
  
property aTV : missing value
  
  property aButton : missing value
  
property bButton : missing value
  
  
  property encDecF : true
  
  
  
  on clicked_(sender)
    
    set aTag to tag of sender
    
set aTag to aTag as integer
    
    
    set textStorage to (my aTV’s textStorage())
    
set theText to textStorage’s |string|()
    
set aStr to theText as Unicode text
    
    –set aKeyPhrase to “KeyPhrase_YouMust_change”
    
    set aKeyPhrase to aKeyTF’s stringValue()
    
set aKeyPhrase to aKeyPhrase as Unicode text
    
    if aKeyPhrase = “” then
      tell current application to display dialog “Keyphrase Blank Error” buttons {“OK”} default button 1 with icon 1
      
return
    end if
    
    
    if aTag = 100 then
      
      set aRes to ectryptStr_Keyphrase_(aStr, aKeyPhrase)
      
aButton’s setEnabled_(false)
      
bButton’s setEnabled_(true)
      
    else if aTag = 200 then
      
      set aRes to decryptStr_Keyphrase_(aStr, aKeyPhrase)
      
aButton’s setEnabled_(true)
      
bButton’s setEnabled_(false)
      
    end if
    
    
    my aTV’s setString_(aRes)
    
  end clicked_
  
  
  
  –文字ベースの暗号化
  
on ectryptStr_Keyphrase_(aStr, aKeyPhrase)
    return FBEncryptorAES’s encryptBase64String_keyString_separateLines_(aStr, aKeyPhrase, true)
  end ectryptStr_Keyphrase_
  
  
  –文字ベースの復号化
  
on decryptStr_Keyphrase_(aStr, aKeyPhrase)
    return FBEncryptorAES’s decryptBase64String_keyString_(aStr, aKeyPhrase)
  end decryptStr_Keyphrase_
  
  
  
  
  
  on applicationWillFinishLaunching_(aNotification)
    
    aButton’s setEnabled_(true)
    
bButton’s setEnabled_(false)
    
  end applicationWillFinishLaunching_
  
  on applicationShouldTerminate_(sender)
    return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
end script

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

2012/12/10 AppleScriptObjCでOpen Panel/Save Panelを表示

AppleScriptObjCでファイルオープンのダイアログOpen Panel、ファイル保存のSave Panelをオープンするサンプルです。

Open Panelは比較的どーーでもいいのですが、Save Panelは各種オプションを表示してユーザーからの指定を受け付けたりするので、重要。そのための習作です。

panel.png

penel2.png

拡張して、最終的にはこんな感じになりました……

panel3.png

→ Xcodeプロジェクトのダウンロード

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– saveP1

– Created by Takaaki Naganoya on 2012/12/10.
– Copyright (c) 2012年 Takaaki Naganoya. All rights reserved.

–  open, save両方のパネルが表示できている(OS X 10.8.2)

script AppDelegate
  
  property parent : class “NSObject”
  
  
  on applicationWillFinishLaunching_(aNotification)
    – Insert code here to initialize your application before any files are opened
  end applicationWillFinishLaunching_
  
  on applicationShouldTerminate_(sender)
    – Insert code here to do any housekeeping before your application quits
    
return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  
  
  
  on clicked_(sender)
    
    set aTag to tag of sender
    
set aTag to aTag as integer
    
    if aTag = 1 then
      
      –Openダイアログ
      
set filePathList to showModalOpen_()
      
log filePathList
      
    else if aTag = 2 then
      –Saveダイアログ
      
set filePathList to showModalSave_()
      
log filePathList
      
    end if
  end clicked_
  
  
  
  
  
  on showModalSave_()
    
    set theFullPath to “”
    
    set thePanel to current application’s NSSavePanel’s savePanel()
    
set productFolder to POSIX path of (path to desktop)
    
    set myDirectoryPath to current application’s |NSURL|’s fileURLWithPath_(productFolder)
    
    tell thePanel
      
      setMessage_(“Save File:”)
      
setAllowedFileTypes_({“png”})
      
      setTitle_(“My Save Panel”)
      
setShowsHiddenFiles_(false)
      
setDirectoryURL_(myDirectoryPath)
      
setCanChooseFiles_(false)
      
setCanChooseDirectories_(false)
      
setAllowsMultipleSelection_(false)
      
      set returnCode to runModal()
      
    end tell
    
    set returnCode to returnCode as integer
    
    
    
    if returnCode = (current application’s NSFileHandlingPanelOKButton) as integer then
      
      set theURL to thePanel’s directoryURL()
      
tell theURL to set thePosixPath to |path|()
      
set thePosixPath to thePosixPath as string
      
      set theName to thePanel’s nameFieldStringValue()
      
set theName to theName as string
      
      set theFullPath to thePosixPath & “/” & theName
      
set hfsPath to (((theFullPath as text) as POSIX file) as text)
      
    else
      
      –log “Cancel pressed”
      
error -128
      
    end if
    
    return hfsPath
    
  end showModalSave_
  
  
  
  –NSSavePanel Problem
  
–http://macscripter.net/viewtopic.php?id=39639
  
  on showModalOpen_()
    
    set myFile to {}
    
    set thePanel to current application’s NSOpenPanel’s openPanel()
    
set productFolder to POSIX path of (path to desktop)
    
    set myDirectoryPath to current application’s |NSURL|’s fileURLWithPath_(productFolder)
    
    tell thePanel
      
      setMessage_(“Open File:”)
      
setAllowedFileTypes_({“png”})
      
      setTitle_(“My Open Panel”)
      
setShowsHiddenFiles_(false)
      
setDirectoryURL_(myDirectoryPath)
      
setCanChooseFiles_(true)
      
setCanChooseDirectories_(true)
      
setAllowsMultipleSelection_(true)
      
      set returnCode to runModal()
      
    end tell
    
    set returnCode to returnCode as integer
    
    
    
    if returnCode = (current application’s NSFileHandlingPanelOKButton) as integer then
      
      set theURLs to thePanel’s URLs() as list
      
set progressCount to count of theURLs
      
      repeat with i from 1 to count of theURLs
        
        tell item i of theURLs to set thePosixPath to |path|()
        
set hfsPath to (((thePosixPath as text) as POSIX file) as text)
        
set end of myFile to hfsPath
        
      end repeat
      
    else
      
      –log “Cancel pressed”
      
error -128
      
    end if
    
    return myFile
    
  end showModalOpen_
  
  
  
end script

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

2012/12/07 write命令実行時のファイル書き込みテキストエンコーディングが10.8で変更に

AppleScriptのWrite命令(ファイルへの書き込みを実行)にオプションを付けることでファイル書き込み時のテキストエンコーディングを変更することができるようになっています。

Appleとしては、テキストエンコーディングを「存在しないもの」として、AppleScriptの言語処理系から「隠ぺい」するというのがねらいです。そのために、いま何の文字コードを使っているかが見えにくいといいますか、確認する方法がないので不便なケースが多々あります。

しかし、write命令に「as XXXXX」と指定を行うことで、ある程度テキストエンコーディングの指定が可能、という指摘を本Blogのコメント欄でいただきました。OSAXで文字コード指定を行ってファイルの読み書きを行うもの(Satimage OSAX)もありますし、その種類のサブルーチンをいろいろと揃えてきました。

コメント欄でご指摘のあったすべての方法を、実際にOS X 10.8.2上で試してみたところ……予想外にコメントで指摘していただいた結果と異なる結果が得られました。

そこで、Mac OS X 10.5〜10.8の各環境で、write命令に「オプションなし」「as Unicode textを指定」「as «class ut16»を指定」「as «class utf8»を指定」の4パターンを試して比較してみました。

すると……

write_option.png

のように、シフトJIS(無指定時)、UTF-16BE、UTF-16LE(BOMつき)、UTF8の結果が得られたものの、最新のOS X 10.8のみその結果が異なる、という結果が出ました。

write命令で、オプションなしかUTF8で書き込むことが多いのですが、なかなか興味深い結果です。10.8の変更が「仕様(意図してのもの)」と見るか、「バグ(意図していなかった)」と見るかは難しいところですが、無指定かあるいはUTF8を使うのが安全なように思えます。

ちなみに、本調査の確認は実際にwrite命令でファイルに同じ文字列「あいうえお」の書き込みを行い、Terminal.app上からhexdumpコマンドで書き込んだファイルの内容を16進ダンプすることで行いました。10.5〜10.8すべてIntel Macで動作確認を行っています。

以下に掲載する各プログラムの実行結果は、OS X 10.8.2上のものです。

スクリプト名:ファイル書き込み(無指定時→MacJapanese or SJIS、言語環境依存)
–書き込み先のパスを指定
set aTargFile to choose file name

set aStr to “あいうえお”

–環境依存(日本語環境ではShift_JISだかMacJapanese?、英語だとASCII)
write_to_file(aStr, aTargFile, false) of me

–> 0000000 82 a0 82 a2 82 a4 82 a6 82 a8

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_file(this_data, target_file, append_data)
  try
    set the target_file to the target_file as text
    
set the open_target_file to open for access file target_file with write permission
    
if append_data is false then set eof of the open_target_file to 0
    
write this_data to the open_target_file starting at eof
    
close access the open_target_file
    
return true
  on error error_message
    try
      close access file target_file
    end try
    
return error_message
  end try
end write_to_file

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

スクリプト名:ファイル書き込み(as string指定時→MacJapanese or SJIS、言語環境依存)
–書き込み先のパスを指定
set aTargFile to choose file name

set aStr to “あいうえお”

–環境依存(日本語環境ではShift_JISだかMacJapanese?、英語だとASCII)
write_to_file(aStr, aTargFile, false) of me

–> 0000000 82 a0 82 a2 82 a4 82 a6 82 a8

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_file(this_data, target_file, append_data)
  try
    set the target_file to the target_file as text
    
set the open_target_file to open for access file target_file with write permission
    
if append_data is false then set eof of the open_target_file to 0
    
write this_data as string to the open_target_file starting at eof
    
close access the open_target_file
    
return true
  on error error_message
    try
      close access file target_file
    end try
    
return error_message
  end try
end write_to_file

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

スクリプト名:ファイル書き込み(as Unicode text指定時→UTF-16LE(BOM付き)
–書き込み先のパスを指定
set aTargFile to choose file name

set aStr to “あいうえお”

–UTF-16LE(BOM付き)
write_to_file(aStr, aTargFile, false) of me

–> 0000000 ff fe 42 30 44 30 46 30 48 30 4a 30

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_file(this_data, target_file, append_data)
  try
    set the target_file to the target_file as text
    
set the open_target_file to open for access file target_file with write permission
    
if append_data is false then set eof of the open_target_file to 0
    
write this_data as Unicode text to the open_target_file starting at eof
    
close access the open_target_file
    
return true
  on error error_message
    try
      close access file target_file
    end try
    
return error_message
  end try
end write_to_file

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

スクリプト名:ファイル書き込み(as «class ut16»指定時→UTF-16BE
–書き込み先のパスを指定
set aTargFile to choose file name

set aStr to “あいうえお”

–UTF-16BE
write_to_file(aStr, aTargFile, false) of me

–> 0000000 30 42 30 44 30 46 30 48 30 4a

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_file(this_data, target_file, append_data)
  try
    set the target_file to the target_file as text
    
set the open_target_file to open for access file target_file with write permission
    
if append_data is false then set eof of the open_target_file to 0
    
write this_data as «class ut16» to the open_target_file starting at eof
    
close access the open_target_file
    
return true
  on error error_message
    try
      close access file target_file
    end try
    
return error_message
  end try
end write_to_file

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

スクリプト名:ファイル書き込み(as «class utf8»指定時→UTF-8)
–書き込み先のパスを指定
set aTargFile to choose file name

set aStr to “あいうえお”

–UTF-8
write_to_file(aStr, aTargFile, false) of me

–> 0000000 e3 81 82 e3 81 84 e3 81 86 e3 81 88 e3 81 8a

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_file(this_data, target_file, append_data)
  try
    set the target_file to the target_file as text
    
set the open_target_file to open for access file target_file with write permission
    
if append_data is false then set eof of the open_target_file to 0
    
write this_data as «class utf8» to the open_target_file starting at eof
    
close access the open_target_file
    
return true
  on error error_message
    try
      close access file target_file
    end try
    
return error_message
  end try
end write_to_file

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