Menu

Skip to content
AppleScriptの穴
  • Home
  • Products
  • Books
  • Docs
  • Events
  • Forum
  • About This Blog
  • License
  • 仕事依頼

AppleScriptの穴

Useful & Practical AppleScript archive. Click '★Click Here to Open This Script' Link to download each AppleScript

カテゴリー: GUI

Myriad Tables Libが1.0.9にアップデート

Posted on 3月 9, 2019 by Takaaki Naganoya

Shane StanleyのAppleScript Libraries「Myriad Tables Lib」の新バージョンv1.0.9がリリースされました。

→ ライブラリのページ


▲ソリューションによっては、機能のほとんどにテーブルビューUIが必要とされるものも

さまざまなソリューション開発時に登場頻度が高いものの、作ると割と手間が必要で大変な「テーブルビュー」を利用するScriptの作成を大幅に省力化できるライブラリです。

今回のv1.0.9ではリクエストを出していたhiddenフィールドの機能が追加されました。ユーザー名とパスワードを表UIで編集・表示したい場合にパスワード部分をhidden表示できると便利です。

このほか、macOS 10.14のDark Modeへの対応やドイツ語ローカライズの追加が行われました。

AppleScript名:Sample using version 1.0.9 hidden field.scpt
use AppleScript version "2.4"
use scripting additions
use script "Myriad Tables Lib" version "1.0.9"

set theHeads to {"First Name", "Last Name", "Index", "Police", "Score", "Some Date"}
set theDate to current date
set someData to {{"Saga", "Norén", 1, true, 12.0, theDate}, ¬
  {"Rasmus", "Larsson", 2, true, 13.5, missing value}, ¬
  {
"Freddie", "Holst", 3, false, 9.0, theDate + 40000}, ¬
  {
"Claes", "Sandberg", 4, false, 1.23456789E+4, theDate + 50000}, ¬
  {
"John", "Lundqvist", 5, true, 13.4567, theDate + 30000}, ¬
  {
"Annika", "Melander", 6, false, 22.0, theDate + 60000}}

— typical process: make table with "table dialog with data", modify if required, then display
set myTable to make new table with data someData with title "Sample table" column headings theHeads with prompt "You can select multiple rows. Everything is editable. Uses a row template. The Last Name field’s values are hidden." editable columns {} row template {"", "hidden", 1, true, 1.0, current date, missing value} with multiple selections allowed, row numbering and empty selection allowed
modify table myTable highlighted rows {2, 4} grid style grid both dashed between rows OK button name "Cool"
set theResult to display table myTable

★Click Here to Open This Script 

Posted in GUI | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy | Leave a comment

アラートダイアログ上に縦棒グラフを表示

Posted on 3月 4, 2019 by Takaaki Naganoya

アラートダイアログ上に縦棒グラフを表示するAppleScriptです。

グラフを作成するのであれば、NumbersやKeynoteなどを使ったほうがいいですが、簡単にデータの傾向だけダイアログ上で見せたいような場合のために作成した部品です。

NSImageViewの表示実験がしたかっただけなので、別に他の言語処理系で作成したグラフ画像を読み込んでNSImageに読み込んでからNSIMageViewで表示するぐらいの使い方でもぜんぜんOKでしょう。

WebViewを表示してインタラクティブなグラフ(マウスカーソルに反応してアニメーション表示を行うとか)を表示するといった使い方もよさそうです(アプリケーション化しないとダメかも)。

macOS 10.14上のDark Modeについては、実行環境によって対応度が異なります。


▲macOS 10.14上のDark Modeで実行したところ。左側からスクリプトエディタ、AppleScriptアプレット、スクリプトメニュー


▲macOS 10.14上のDark Modeで実行したところ。左側からScript Debugger、Script DebuggerからSD拡張アプレットで書き出したもの

グラフの描画については、色指定をblackColor()とかgrayColor()などと指定せずに、Dark Mode時に制御されるUI色で指定しておく必要があることでしょう。

AppleScript名:アラートダイアログ上に縦棒グラフを表示.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/03/04
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

property NSFont : a reference to current application’s NSFont
property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSImage : a reference to current application’s NSImage
property NSScreen : a reference to current application’s NSScreen
property NSDictionary : a reference to current application’s NSDictionary
property NSBezierPath : a reference to current application’s NSBezierPath
property NSImageView : a reference to current application’s NSImageView
property NSMutableArray : a reference to current application’s NSMutableArray
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSFontAttributeName : a reference to current application’s NSFontAttributeName
property NSAlertSecondButtonReturn : a reference to current application’s NSAlertSecondButtonReturn
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName
property NSImageScaleProportionallyUpOrDown : a reference to current application’s NSImageScaleProportionallyUpOrDown

property returnCode : 0

set plotData to {20, 30, 100, 80, 150, 90}
set paramObj to {myMessage:"This is a graph", mySubMessage:"Browse bar graph", aPlotData:plotData}
my performSelectorOnMainThread:"displayBarGraph:" withObject:(paramObj) waitUntilDone:true

on displayBarGraph:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set aTList to (aPlotData of paramObj) as list
  
  
— make NSIMageView with graph image
  
set anImage to makeGraphImage(aTList, 300, 200) of me
  
set anImageView to NSImageView’s alloc()’s initWithFrame:{origin:{x:0.0, y:0.0}, |size|:{width:300.0, height:200.0}}
  
anImageView’s setImageScaling:(NSImageScaleProportionallyUpOrDown)
  
anImageView’s setEditable:false
  
anImageView’s setImage:anImage
  
anImageView’s display()
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:anImageView
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
end displayBarGraph:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

on makeGraphImage(plotData, aWidth, aHeight)
  set innerGapL to 30
  
set innerGapU to 10
  
set innerGapR to 20
  
set innerGapD to 20
  
set barGap to 10
  
  
–パラメータから下地になる画像を作成する
  
set aSize to current application’s NSMakeSize(aWidth, aHeight)
  
set anImage to NSImage’s alloc()’s initWithSize:aSize
  
  
–各種パラメータの計算
  
–copy plotArea to {plotWidth, plotHeight}
  
set itemNum to count every item of plotData
  
set barThickness to (aWidth – (itemNum * barGap * 2)) div itemNum
  
  
–プロットデータの最大値
  
set anArray to NSArray’s arrayWithArray:plotData
  
set aYmax to (anArray’s valueForKeyPath:"@max.self")’s intValue()
  
set aMaxYVal to aHeight – innerGapU – innerGapD
  
set aYPlotArea to aHeight – innerGapU – innerGapD – 20
  
set aYUnit to aYPlotArea / aYmax
  
  
–数値データをもとに描画データを組み立てる
  
set drawList to {}
  
  
set startX to innerGapL
  
copy startX to origX
  
  
repeat with i in plotData
    set the end of drawList to current application’s NSMakeRect(startX, innerGapD, barThickness, innerGapD + (i * aYUnit))
    
set startX to startX + barThickness + barGap
  end repeat
  
  
–グラフ塗りつぶし処理呼び出し
  
set fillColor to (NSColor’s colorWithCalibratedRed:0.1 green:0.1 blue:0.1 alpha:0.3)
  
set resImage to drawImageWithColorFill(anImage, drawList, fillColor) of me
  
  
–数値データ(文字)をグラフィックに記入
  
set fillColor2 to NSColor’s blackColor()
  
set resImage to drawImageWithString(resImage, drawList, fillColor2, plotData, "Eurostile Bold", 20.0) of me
  
  
–補助線を引く
  
set fillColor3 to (NSColor’s colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:0.8)
  
set aVertical to current application’s NSMakeRect(origX, innerGapD, aWidth – innerGapL – innerGapR, 1)
  
set aHorizontal to current application’s NSMakeRect(origX, innerGapD, 1, aHeight – innerGapU – innerGapD)
  
set draw2List to {aVertical, aHorizontal}
  
set resImage to drawImageWithColorFill(resImage, draw2List, fillColor3) of me
  
  
return resImage
end makeGraphImage

–NSImageに対して文字を描画する
on drawImageWithString(anImage, drawList, fillColor, dataList, aPSFontName, aFontSize)
  set retinaF to (NSScreen’s mainScreen()’s backingScaleFactor()) as real
  
–>  2.0 (Retina) / 1.0 (Non Retina)
  
  
set aDict to (NSDictionary’s dictionaryWithObjects:{NSFont’s fontWithName:aPSFontName |size|:aFontSize, fillColor} forKeys:{NSFontAttributeName, NSForegroundColorAttributeName})
  
  
anImage’s lockFocus() –描画開始
  
  
set aLen to length of drawList
  
repeat with i from 1 to aLen
    set i1 to contents of item i of drawList
    
    
set v2 to system attribute "sys2"
    
if v2 ≤ 12 then
      –To macOS 10.12.x
      
set origX to (x of origin of i1) / retinaF
      
set origY to (y of origin of i1) / retinaF
      
set sizeX to (width of |size| of i1) / retinaF
      
set sizeY to (height of |size| of i1) / retinaF
      
set theRect to {{x:origX, y:origY}, {width:sizeX, height:sizeY}}
    else
      –macOS 10.13 or later
      
set origX to (item 1 of item 1 of i1) / retinaF
      
set origY to (item 2 of item 1 of i1) / retinaF
      
set sizeX to (item 1 of item 2 of i1) / retinaF
      
set sizeY to (item 2 of item 2 of i1) / retinaF
      
set theRect to {{origX, origY}, {sizeX, sizeY}}
    end if
    
    
set aString to (current application’s NSString’s stringWithString:((contents of item i of dataList) as string))
    (
aString’s drawAtPoint:(current application’s NSMakePoint(origX + (sizeX / 2), sizeY)) withAttributes:aDict)
  end repeat
  
  
anImage’s unlockFocus() –描画ここまで
  
  
return anImage –returns NSImage
end drawImageWithString

–NSImageに対して矩形を塗りつぶす
on drawImageWithColorFill(anImage, drawList, fillColor)
  set retinaF to (NSScreen’s mainScreen()’s backingScaleFactor()) as real
  
–>  2.0 (Retina) / 1.0 (Non Retina)
  
  
anImage’s lockFocus() –描画開始
  
  
repeat with i in drawList
    set v2 to system attribute "sys2"
    
if v2 ≤ 12 then
      –To macOS 10.12.x
      
set origX to (x of origin of i) / retinaF
      
set origY to (y of origin of i) / retinaF
      
set sizeX to (width of |size| of i) / retinaF
      
set sizeY to (height of |size| of i) / retinaF
      
set theRect to {{x:origX, y:origY}, {width:sizeX, height:sizeY}}
    else
      –macOS 10.13 or later
      
set origX to (item 1 of item 1 of i) / retinaF
      
set origY to (item 2 of item 1 of i) / retinaF
      
set sizeX to (item 1 of item 2 of i) / retinaF
      
set sizeY to (item 2 of item 2 of i) / retinaF
      
set theRect to {{origX, origY}, {sizeX, sizeY}}
    end if
    
    
set theNSBezierPath to NSBezierPath’s bezierPath
    (
theNSBezierPath’s appendBezierPathWithRect:theRect)
    
    
fillColor’s |set|() –色設定
    
theNSBezierPath’s fill() –ぬりつぶし
  end repeat
  
  
anImage’s unlockFocus() –描画ここまで
  
  
return anImage –returns NSImage
end drawImageWithColorFill

★Click Here to Open This Script 

Posted in GUI Image list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSAlert NSAlertSecondButtonReturn NSArray NSBezierPath NSBitmapImageRep NSColor NSDictionary NSFont NSFontAttributeName NSForegroundColorAttributeName NSImage NSImageScaleProportionallyUpOrDown NSImageView NSMutableArray NSRunningApplication NSScreen NSString | Leave a comment

アラートダイアログ上にBrowserを表示

Posted on 3月 2, 2019 by Takaaki Naganoya

アラートダイアログ上にNSBrowserを表示するAppleScriptの試作品です。

# 本Scriptは実験用であって実用性はありません(^ー^;;

Finderに使われていることで認知度は高いものの、使いどころが難しいうえにサンプル・コードも多くないので登場頻度が少ないNSBrowserです。(Mac OS Xの前身である)NEXTSTEPのFile Managerがこんな感じのUIでした。

(個人的に)敷居の高かったNSBrowserも、いろいろ試してみたらいい感じになってきました。現状では単に2次元配列っぽいものにアクセスしているだけですが、ツリー型の構造データを与えるようにするとか、配列から徐々にデータ抽出する(大分類→中分類→小分類)ようにすれば、だいたい期待どおりの動作になるはずです。

NSBrowserも、使いたいときに調べると情報が見つからずに困りますが、用のないときなら調べておくといろいろ大丈夫そうです。

macOS 10.14上のスクリプトエディタ/Script Debugger上で動くようにハンドラをメインスレッド上で明示的に動作させるように変更しましたが、10.14上でだけ独特な挙動があるため要注意です。ただ、テストプログラムなのでそんなものだろうかと。

AppleScript名:アラートダイアログ上にBrowserを表示 v1.1.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/03/02
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSBrowser : a reference to current application’s NSBrowser
property NSScrollView : a reference to current application’s NSScrollView
property NSMutableArray : a reference to current application’s NSMutableArray
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSAlertSecondButtonReturn : a reference to current application’s NSAlertSecondButtonReturn

property theResult : 0
property returnCode : 0
property theDataSource : {}

set paramObj to {myMessage:"Choose a data", mySubMessage:"Choose an appropriate data from tree structured data list", aTableList:{{"1", "1.1", "1.1.1"}, {"2", "2.1", "2.1.1"}, {"3", "3.1", "3.1.1"}, {"4", "4.1", "4.1.1"}}}
–set aRes to my chooseItemByBrowser:paramObj
my performSelectorOnMainThread:"chooseItemByBrowser:" withObject:(paramObj) waitUntilDone:true

on chooseItemByBrowser:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set aTList to (aTableList of paramObj) as list
  
  
— make browser view with scroll view
  
set aScrollWithTable to makeBrowserView(aTList, 500, 200) of me
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aScrollWithTable
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
end chooseItemByBrowser:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

on makeBrowserView(aList as list, aWidth as number, aHeight as number)
  set (my theDataSource) to NSMutableArray’s arrayWithArray:aList
  
  
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
set aView to NSBrowser’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
  
aView’s setDelegate:(me)
  
aView’s setMinColumnWidth:120
  
aView’s setSeparatesColumns:true
  
–aView’s setMaxVisibleColumns:2
  
aView’s setAutohidesScroller:true
  
–aView’s setBackgroundColor:(NSColor’s grayColor())
  
aView’s setReusesColumns:true
  
  
aScroll’s setDocumentView:aView
  
aView’s enclosingScrollView()’s setHasHorizontalScroller:true
  
aView’s enclosingScrollView()’s setHasVerticalScroller:true
  
  
return aScroll
end makeBrowserView

–NSBrowser Event Handlers
on browser:aView numberOfRowsInColumn:aColumn
  set aCount to my theDataSource’s |count|()
  
return aCount
end browser:numberOfRowsInColumn:

on browser:aView willDisplayCell:(aCell) atRow:rowIndex column:colIndex
  set selRow to (my theDataSource)’s objectAtIndex:(rowIndex)
  
set selCol to selRow’s objectAtIndex:(colIndex)
  
aCell’s setTitle:(selCol as string)
  
  
set colMax to ((my theDataSource)’s objectAtIndex:0)’s |count|()
  
log {"colMax, colIndex", colMax, colIndex}
  
set exMax to (colIndex < colMax – 1) as boolean
  
aCell’s setLeaf:(not exMax)
end browser:willDisplayCell:atRow:column:

★Click Here to Open This Script 

Posted in GUI list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSAlert NSAlertSecondButtonReturn NSBrowser NSColor NSMutableArray NSRunningApplication NSScrollView | Leave a comment

アラートダイアログの背景色を指定してTable Viewを表示

Posted on 2月 25, 2019 by Takaaki Naganoya

指定色のアラートダイアログを作成し、その上にScroll View+Table Viewを表示して選択肢の選択を行うAppleScriptです。

アラートダイアログの背景色変更のテストを行なったものです。また、メソッド名をテキストで(Table Viewから)取得し、そのメソッド名で色を作成するテスト(NSSelectorFromString)も行いました。

Table Viewで選択した色は、次回実行時に反映されます(スクリプトエディタ/Script Debugger上で)。

本当はTable View上で行を選択したときに、アラートダイアログの背景色を変更させたかったのですが、試してみたもののうまく動かなかったので、その機能は削りました。最初から指定色のダイアログウィンドウを表示するだけなら問題はないので、現状のようなコードに落ち着きました。

AppleScript名:アラートダイアログの背景色を指定してTable Viewを表示
— Created 2019-02-25 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSIndexSet : a reference to current application’s NSIndexSet
property NSScrollView : a reference to current application’s NSScrollView
property NSTableView : a reference to current application’s NSTableView
property NSTableColumn : a reference to current application’s NSTableColumn
property NSMutableArray : a reference to current application’s NSMutableArray
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSAlertSecondButtonReturn : a reference to current application’s NSAlertSecondButtonReturn
property NSFullSizeContentViewWindowMask : a reference to current application’s NSFullSizeContentViewWindowMask

property theResult : 0
property returnCode : 0
property theDataSource : {}
property theColList : {}
property theWindow : missing value
property selectedColor : missing value

set paramObj to {myMessage:"Choose a color", mySubMessage:"Choose an appropriate color from color name list", aTableList:{"redColor", "blueColor", "yellowColor", "greenColor", "grayColor", "blackColor"}}
set aRes to my chooseItemByTableView:paramObj

on chooseItemByTableView:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set aTList to (aTableList of paramObj) as list
  
  
— make table view with scroll view
  
set aScrollWithTable to makeTableView(aTList, 300, 120) of me
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aScrollWithTable
  end tell
  
  
— customize alert’s window style and color
  
if selectedColor = missing value then
    set tmpColor to NSColor’s grayColor()
  else
    set tmpSel to current application’s NSSelectorFromString(selectedColor)
    
set tmpColor to NSColor’s performSelector:tmpSel
  end if
  
  
set theWindow to theAlert’s |window|()
  
theWindow’s setTitleVisibility:false
  
–theWindow’s setStyleMask:( NSFullSizeContentViewWindowMask)
  
theWindow’s setTitlebarAppearsTransparent:true
  
theWindow’s setBackgroundColor:tmpColor
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
  
  
return (aScrollWithTable’s documentView’s selectedRow()) + 1
end chooseItemByTableView:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

on makeTableView(aList as list, aWidth as number, aHeight as number)
  set aOffset to 40
  
  
set sourceList to {}
  
repeat with i in aList
    set the end of sourceList to {dataItem:(contents of i)}
  end repeat
  
  
set theDataSource to NSMutableArray’s alloc()’s init()
  
theDataSource’s addObjectsFromArray:sourceList
  
  
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aOffset, aWidth, aHeight))
  
set aView to NSTableView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aOffset, aWidth, aHeight))
  
  
  
set aColumn to (NSTableColumn’s alloc()’s initWithIdentifier:"dataItem")
  (
aColumn’s setWidth:aWidth)
  (
aColumn’s headerCell()’s setStringValue:"dataItem")
  (
aView’s addTableColumn:aColumn)
  
  
aView’s setDelegate:me
  
aView’s setDataSource:me
  
aView’s reloadData()
  
  
aScroll’s setDocumentView:aView
  
aView’s enclosingScrollView()’s setHasVerticalScroller:true
  
  
–1行目を選択
  
set aIndexSet to NSIndexSet’s indexSetWithIndex:0
  
aView’s selectRowIndexes:aIndexSet byExtendingSelection:false
  
  
–強制的にトップにスクロール
  
set aDBounds to aScroll’s documentView()’s |bounds|()
  
if class of aDBounds = list then
    –macOS 10.13 or later
    
set maxHeight to item 2 of item 1 of aDBounds
  else
    –macOS 10.10….10.12
    
set maxHeight to height of |size| of aDBounds
  end if
  
  
set aPT to current application’s NSMakePoint(0.0, -40.0) —— (aScroll’s documentView()’s |bounds|()’s |size|()’s height))
  
aScroll’s documentView()’s scrollPoint:aPT
  
  
return aScroll
end makeTableView

–TableView Event Handlers
on numberOfRowsInTableView:aView
  return my theDataSource’s |count|()
end numberOfRowsInTableView:

on tableView:aView objectValueForTableColumn:aColumn row:aRow
  set selRow to (aRow as number)
  
set aRec to (my theDataSource)’s objectAtIndex:selRow
  
set aTitle to (aColumn’s headerCell()’s title()) as string
  
set aRes to (aRec’s valueForKey:aTitle) as string
  
set my selectedColor to aRes
  
  
return aRes
end tableView:objectValueForTableColumn:row:

on tableView:aView shouldEditTableColumn:aTableColumn row:rowIndex
  return false –Not Editable
end tableView:shouldEditTableColumn:row:

★Click Here to Open This Script 

Posted in Color GUI list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSAlert NSAlertSecondButtonReturn NSColor NSFullSizeContentViewWindowMask NSIndexSet NSMutableArray NSRunningApplication NSScrollView NSTableColumn NSTableView | Leave a comment

アラートダイアログ上にTable View+Map View+Segmented Controlを表示

Posted on 2月 23, 2019 by Takaaki Naganoya

アラートダイアログを作成し、その上にScroll View+Table ViewおよびMap Viewを表示して選択肢の選択を行うAppleScriptです。Segmented Controlで地図の種別切り替えを行い、項目選択用のTable Viewを編集不可にしました。

Map Viewを使用するために、インターネット接続が必要です。地図表示パフォーマンスはインターネット接続速度次第です。


▲Map Type = Standard (Map)


▲Map Type = Satellite


▲Map Type = Hybrid (Satellite + Map)

本Scriptに与える緯度・経度情報についてはあらかじめ住所ジオコーダーによって「住所情報→緯度・経度情報」の変換を行なったものを書いておく必要がありますが、Yahoo!の住所ジオコーダーサービスなどを呼び出せば、住所情報をパラメーターとすることも可能です。

サンプルデータの緯度・経度情報は、例によって「戦場の絆」の入っている近所のゲーセンの情報を適当にみつくろって入れてみたものです。

本ダイアログは、それほど件数の多くない(20件ぐらい?)選択肢からの選択を意図して作ったものですが、数百件とか数千件のデータから選ぶような場合には、Outline Viewを利用して小エリアごとに分割するとか、Search Fieldを連動させてキーワードによる絞り込みを有効にするなど、それなりの対処が必要です。

AppleScript名:アラートダイアログ上にTable View+Map View+Segmented Controlを表示
— Created 2019-02-23 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "MapKit"

property NSAlert : a reference to current application’s NSAlert
property NSIndexSet : a reference to current application’s NSIndexSet
property MKMapView : a reference to current application’s MKMapView
property NSScrollView : a reference to current application’s NSScrollView
property NSTableView : a reference to current application’s NSTableView
property NSTableColumn : a reference to current application’s NSTableColumn
property NSMutableArray : a reference to current application’s NSMutableArray
property MKPointAnnotation : a reference to current application’s MKPointAnnotation
property NSSegmentedControl : a reference to current application’s NSSegmentedControl
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSAlertSecondButtonReturn : a reference to current application’s NSAlertSecondButtonReturn
property NSSegmentStyleTexturedRounded : a reference to current application’s NSSegmentStyleTexturedRounded

property MKMapTypeHybrid : a reference to current application’s MKMapTypeHybrid
property MKMapTypeSatellite : a reference to current application’s MKMapTypeSatellite
property MKMapTypeStandard : a reference to current application’s MKMapTypeStandard

property zLevel : 21 –Map Zoom Level (0:World View, 21:House/Building Zoom View)
property aMaxViewWidth : 800
property theResult : 0
property returnCode : 0
property theDataSource : {}
property curRow : 0
property aMapView : missing value
property nameL : {}
property placeL : {}

set aPlaceList to {{placeName:"Hey", aLat:"35.69906613", aLong:"139.77084064"}, {placeName:"namco中野", aLat:"35.70859274", aLong:"139.66584339"}, {placeName:"ゲームシティ板橋", aLat:"35.74572771", aLong:"139.67553260"}, {placeName:"ラウンドワンスタジアム板橋", aLat:"35.77661583", aLong:"139.67864491"}, {placeName:"キャロム練馬", aLat:"35.76386421", aLong:"139.66591600"}, {placeName:"アミュージアムOSC", aLat:"35.75308308", aLong:"139.59476696"}}

set paramObj to {myMessage:"場所の選択", mySubMessage:"適切な場所を以下のリストからえらんでください", placeList:aPlaceList}
my performSelectorOnMainThread:"chooseItemByTableViewWithMapAndSegment:" withObject:(paramObj) waitUntilDone:true
if (my theResult) = 0 then error number -128
return (my theResult)

on chooseItemByTableViewWithMapAndSegment:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set aTList to (placeList of paramObj) as list
  
  
set nameL to {}
  
set placeL to {}
  
repeat with i in aTList
    set the end of nameL to (placeName of i)
    
set the end of placeL to {contents of (aLat of i), contents of (aLong of i)}
  end repeat
  
  
— create a view
  
set theView to current application’s NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aMaxViewWidth, 400))
  
  
— make table view with scroll view
  
set aScrollWithTable to makeTableView(nameL, 200, 400) of me
  
  
set aMapView to MKMapView’s alloc()’s initWithFrame:(current application’s NSMakeRect(210, 30, aMaxViewWidth – 210, 370))
  
tell aMapView
    its setMapType:MKMapTypeStandard
    
its setZoomEnabled:true
    
its setScrollEnabled:true
    
its setPitchEnabled:true
    
its setRotateEnabled:true
    
its setShowsCompass:true
    
its setShowsZoomControls:true
    
its setShowsScale:true
    
its setShowsUserLocation:true
    
    
set aLocation to current application’s CLLocationCoordinate2DMake((first item of first item of placeL) as real, (second item of first item of placeL) as real)
    
its setCenterCoordinate:aLocation zoomLevel:(zLevel) animated:false
    
its setDelegate:me
  end tell
  
  
–MapにPinを追加
  
repeat with i from 1 to (length of nameL)
    set tmpAdr to contents of item i of nameL
    
copy item i of placeL to {tmpLat, tmpLong}
    
    
set aLocation to current application’s CLLocationCoordinate2DMake(tmpLat as real, tmpLong as real)
    
set anAnnotation to MKPointAnnotation’s alloc()’s init()
    (
anAnnotation’s setCoordinate:aLocation)
    (
anAnnotation’s setTitle:tmpAdr)
    (
aMapView’s addAnnotation:anAnnotation)
  end repeat
  
  
–Segmented Controlをつくる
  
set segTitleList to {"Map", "Satellite", "Satellite + Map"}
  
set aSeg to makeSegmentedControl(segTitleList, 210, 0, 150, 20) of me
  
  
theView’s setSubviews:{aScrollWithTable, aMapView, aSeg}
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:theView
  end tell
  
  
–To enable the first annotation visible
  
copy item 1 of placeL to {tmpLat, tmpLong}
  
set aLocation to current application’s CLLocationCoordinate2DMake(tmpLat as real, tmpLong as real)
  
aMapView’s setCenterCoordinate:aLocation zoomLevel:(zLevel) animated:false
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
set (my theResult) to (aScrollWithTable’s documentView’s selectedRow()) + 1
end chooseItemByTableViewWithMapAndSegment:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

on makeTableView(aList as list, aWidth as number, aHeight as number)
  set aOffset to 0
  
  
set sourceList to {}
  
repeat with i in aList
    set the end of sourceList to {dataItem:(contents of i)}
  end repeat
  
  
set theDataSource to NSMutableArray’s alloc()’s init()
  
theDataSource’s addObjectsFromArray:sourceList
  
  
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 30, aWidth, aHeight – 30))
  
set aView to NSTableView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 30, aWidth, aHeight – 30))
  
  
  
set aColumn to (NSTableColumn’s alloc()’s initWithIdentifier:"dataItem")
  (
aColumn’s setWidth:aWidth)
  (
aColumn’s headerCell()’s setStringValue:"dataItem")
  (
aView’s addTableColumn:aColumn)
  
  
aView’s setDelegate:me
  
aView’s setDataSource:me
  
aView’s reloadData()
  
  
aScroll’s setDocumentView:aView
  
aView’s enclosingScrollView()’s setHasVerticalScroller:true
  
  
–1行目を選択
  
set aIndexSet to NSIndexSet’s indexSetWithIndex:0
  
aView’s selectRowIndexes:aIndexSet byExtendingSelection:false
  
  
–強制的にトップにスクロール
  
set aDBounds to aScroll’s documentView()’s |bounds|()
  
if class of aDBounds = list then
    –macOS 10.13 or later
    
set maxHeight to item 2 of item 1 of aDBounds
  else
    –macOS 10.10, 10.11, 10.12
    
set maxHeight to height of |size| of aDBounds
  end if
  
  
set aPT to current application’s NSMakePoint(0.0, -40.0) —— (aScroll’s documentView()’s |bounds|()’s |size|()’s height))
  
aScroll’s documentView()’s scrollPoint:aPT
  
  
return aScroll
end makeTableView

–TableView Event Handlers
on numberOfRowsInTableView:aView
  return my theDataSource’s |count|()
end numberOfRowsInTableView:

on tableView:aView objectValueForTableColumn:aColumn row:aRow
  set (tmpRow) to aView’s selectedRow() as number
  
  
–Table View上で現在選択行「以外の」行が選択されたら、Mapを選択項目で更新
  
if (my curRow) is not equal to tmpRow then
    set tmpLat to (first item of item (tmpRow + 1) of placeL) as real
    
set tmpLong to (second item of item (tmpRow + 1) of placeL) as real
    
    
tell aMapView
      set aLocation to current application’s CLLocationCoordinate2DMake(tmpLat, tmpLong)
      
its setCenterCoordinate:aLocation zoomLevel:(zLevel) animated:false
    end tell
    
    
set (my curRow) to tmpRow
  end if
  
  
set aRec to (my theDataSource)’s objectAtIndex:(aRow as number)
  
set aTitle to (aColumn’s headerCell()’s title()) as string
  
set aRes to (aRec’s valueForKey:aTitle)
  
return aRes
end tableView:objectValueForTableColumn:row:

on tableView:aView shouldEditTableColumn:aTableColumn row:rowIndex
  return false –Not Editable
end tableView:shouldEditTableColumn:row:

–Segmented Controlをつくる
on makeSegmentedControl(titleList, startX, startY, aWidth, aHeight)
  set aLen to length of titleList
  
  
set aSeg to NSSegmentedControl’s alloc()’s init()
  
aSeg’s setSegmentCount:aLen
  
  
set aCount to 0
  
repeat with i in titleList
    set j to contents of i
    (
aSeg’s setLabel:j forSegment:aCount)
    
set aCount to aCount + 1
  end repeat
  
  
aSeg’s setTranslatesAutoresizingMaskIntoConstraints:false
  
aSeg’s setSegmentStyle:(NSSegmentStyleTexturedRounded)
  
aSeg’s setFrame:(current application’s NSMakeRect(startX, startY, aWidth, aHeight))
  
aSeg’s setTrackingMode:0
  
aSeg’s setTarget:me
  
aSeg’s setAction:"clickedSeg:"
  
aSeg’s setSelectedSegment:0
  
  
return aSeg
end makeSegmentedControl

–Segmented Controlのクリック時のイベントハンドラ
on clickedSeg:aSender
  set aSel to aSender’s selectedSegment()
  
set tList to {MKMapTypeStandard, MKMapTypeSatellite, MKMapTypeHybrid}
  
set tmpType to contents of item (aSel + 1) of tList
  
  
aMapView’s setMapType:(tmpType)
  
  
set selSeg to aSel
end clickedSeg:

★Click Here to Open This Script 

Posted in geolocation GUI | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy MKMapView MKPointAnnotation NSAlert NSAlertSecondButtonReturn NSIndexSet NSMutableArray NSRunningApplication NSScrollView NSSegmentedControl NSSegmentStyleTexturedRounded NSTableColumn NSTableView | Leave a comment

アラートダイアログ上にTable View+Map Viewを表示

Posted on 2月 22, 2019 by Takaaki Naganoya

アラートダイアログを作成し、その上にScroll View+Table ViewおよびMap Viewを表示して選択肢の選択を行うAppleScriptです。

Map Viewを使用するために、インターネット接続が必要です。地図表示パフォーマンスはインターネット接続速度次第です。

{{placeName:"Hey", aLat:"35.69906613", aLong:"139.77084064"}....}

のように位置データを、

名称, 緯度, 経度

とまとめたリストで選択肢を指定します。実行すると選択肢のアイテム番号(1からはじまる)を返してきます。


▲左から、macOS 10.12.6、10.13.6、10.14.4betaで同じAppleScriptを動かしたところ。同じ場所、同じZoom LevelでもOSバージョンごとに微妙に表示内容が違う

現状の実装では、表UI(Table View)内のデータがダブルクリックで編集できてしまうので、編集できないようにするあたりが改良対象でしょうか。あと、地図・衛星写真の切り替えもつけておくとよいでしょう。

本Scriptに与える緯度・経度情報についてはあらかじめ住所ジオコーダーによって「住所情報→緯度・経度情報」の変換を行なったものを書いておく必要がありますが、Yahoo!の住所ジオコーダーサービスなどを呼び出せば、住所情報をパラメーターとすることも可能です。

サンプルデータの緯度・経度情報は、例によって「戦場の絆」の入っている近所のゲーセンの情報を適当にみつくろって入れてみたものです。

AppleScript名:アラートダイアログ上にTable View+Map Viewを表示 v2
— Created 2019-02-22 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "MapKit"

property NSAlert : a reference to current application’s NSAlert
property NSIndexSet : a reference to current application’s NSIndexSet
property MKMapView : a reference to current application’s MKMapView
property NSScrollView : a reference to current application’s NSScrollView
property NSTableView : a reference to current application’s NSTableView
property NSTableColumn : a reference to current application’s NSTableColumn
property NSMutableArray : a reference to current application’s NSMutableArray
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSAlertSecondButtonReturn : a reference to current application’s NSAlertSecondButtonReturn

property zLevel : 18
property aMaxViewWidth : 800
property theResult : 0
property returnCode : 0
property theDataSource : {}
property curRow : 0
property aMapView : missing value
property nameL : {}
property placeL : {}

set aPlaceList to {{placeName:"Hey", aLat:"35.69906613", aLong:"139.77084064"}, {placeName:"namco中野", aLat:"35.70859274", aLong:"139.66584339"}, {placeName:"ゲームシティ板橋", aLat:"35.74572771", aLong:"139.67553260"}, {placeName:"ラウンドワンスタジアム板橋", aLat:"35.77661583", aLong:"139.67864491"}, {placeName:"キャロム練馬", aLat:"35.76386421", aLong:"139.66591600"}, {placeName:"アミュージアムOSC", aLat:"35.75308308", aLong:"139.59476696"}}

set paramObj to {myMessage:"場所の選択", mySubMessage:"適切な場所を以下のリストからえらんでください", placeList:aPlaceList}
my performSelectorOnMainThread:"chooseItemByTableViewWithMap:" withObject:(paramObj) waitUntilDone:true
return (my theResult)

on chooseItemByTableViewWithMap:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set aTList to (placeList of paramObj) as list
  
  
set nameL to {}
  
set placeL to {}
  
repeat with i in aTList
    set the end of nameL to (placeName of i)
    
set the end of placeL to {contents of (aLat of i), contents of (aLong of i)}
  end repeat
  
  
— create a view
  
set theView to current application’s NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aMaxViewWidth, 400))
  
  
— make table view with scroll view
  
set aScrollWithTable to makeTableView(nameL, 200, 400) of me
  
  
set aMapView to MKMapView’s alloc()’s initWithFrame:(current application’s NSMakeRect(210, 0, aMaxViewWidth – 210, 400))
  
tell aMapView
    its setMapType:(current application’s MKMapTypeStandard)
    
its setZoomEnabled:true
    
its setScrollEnabled:true
    
its setPitchEnabled:true
    
its setRotateEnabled:true
    
its setShowsCompass:true
    
its setShowsZoomControls:true
    
its setShowsScale:true
    
its setShowsUserLocation:true
    
    
set aLocation to current application’s CLLocationCoordinate2DMake((first item of first item of placeL) as real, (second item of first item of placeL) as real)
    
    
its setCenterCoordinate:aLocation zoomLevel:(zLevel) animated:false
    
its setDelegate:me
  end tell
  
  
theView’s setSubviews:{aScrollWithTable, aMapView}
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:theView
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
  
  
set (my theResult) to (aScrollWithTable’s documentView’s selectedRow()) + 1
end chooseItemByTableViewWithMap:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

on makeTableView(aList as list, aWidth as number, aHeight as number)
  set aOffset to 0
  
  
set sourceList to {}
  
repeat with i in aList
    set the end of sourceList to {dataItem:(contents of i)}
  end repeat
  
  
set theDataSource to NSMutableArray’s alloc()’s init()
  
theDataSource’s addObjectsFromArray:sourceList
  
  
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aOffset, aWidth, aHeight))
  
set aView to NSTableView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aOffset, aWidth, aHeight))
  
  
  
set aColumn to (NSTableColumn’s alloc()’s initWithIdentifier:"dataItem")
  (
aColumn’s setWidth:aWidth)
  (
aColumn’s headerCell()’s setStringValue:"dataItem")
  (
aView’s addTableColumn:aColumn)
  
  
aView’s setDelegate:me
  
aView’s setDataSource:me
  
aView’s reloadData()
  
  
aScroll’s setDocumentView:aView
  
aView’s enclosingScrollView()’s setHasVerticalScroller:true
  
  
–1行目を選択
  
set aIndexSet to NSIndexSet’s indexSetWithIndex:0
  
aView’s selectRowIndexes:aIndexSet byExtendingSelection:false
  
  
–強制的にトップにスクロール
  
–強制的にトップにスクロール
  
–set maxHeight to aScroll’s documentView()’s |bounds|()’s |size|()’s height
  
set aDBounds to aScroll’s documentView()’s |bounds|()
  
if class of aDBounds = list then
    –macOS 10.13 or later
    
set maxHeight to item 2 of item 1 of aDBounds
  else
    –macOS 10.10….10.12
    
set maxHeight to height of |size| of aDBounds
  end if
  
  
set aPT to current application’s NSMakePoint(0.0, -40.0) —— (aScroll’s documentView()’s |bounds|()’s |size|()’s height))
  
aScroll’s documentView()’s scrollPoint:aPT
  
  
return aScroll
end makeTableView

–TableView Event Handlers
on numberOfRowsInTableView:aView
  return my theDataSource’s |count|()
end numberOfRowsInTableView:

on tableView:aView objectValueForTableColumn:aColumn row:aRow
  set (tmpRow) to aView’s selectedRow() as number
  
  
–Table View上で現在選択行「以外の」行が選択されたら、Mapを選択項目で更新
  
if (my curRow) is not equal to tmpRow then
    set tmpLat to (first item of item (tmpRow + 1) of placeL) as real
    
set tmpLong to (second item of item (tmpRow + 1) of placeL) as real
    
    
tell aMapView
      set aLocation to current application’s CLLocationCoordinate2DMake(tmpLat, tmpLong)
      
its setCenterCoordinate:aLocation zoomLevel:(zLevel) animated:false
    end tell
    
    
set (my curRow) to tmpRow
  end if
  
  
set aRec to (my theDataSource)’s objectAtIndex:(aRow as number)
  
set aTitle to (aColumn’s headerCell()’s title()) as string
  
set aRes to (aRec’s valueForKey:aTitle)
  
return aRes
end tableView:objectValueForTableColumn:row:

★Click Here to Open This Script 

Posted in geolocation GUI list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy MKMapView NSAlert NSAlertSecondButtonReturn NSIndexSet NSMutableArray NSRunningApplication NSScrollView NSTableColumn NSTableView | Leave a comment

アラートダイアログ上にTable Viewを表示

Posted on 2月 22, 2019 by Takaaki Naganoya

アラートダイアログを作成し、その上にScroll View+Table Viewを表示して選択肢の選択を行うAppleScriptです。

1D List(1次元配列)を与え、選択を行うUIです。実行すると選択肢のアイテム番号(1からはじまる)を返してきます。

とくにこれが作りたかったのではなく、位置情報(Geo Location)の選択をTable Viewで行い、該当する場所をMap Viewに表示させると擬似的に複数の固定位置情報から任意のものを選択させるダイアログが作れるだろうかと思って作成した試作品です。

東京への引っ越しの荷物が到着して、ようやく検証用のサブマシンが届いたものの、ネットワークを新規敷設しなくてはならないのでぼちぼちです。

AppleScript名:アラートダイアログ上にTable Viewを表示 v3
— Created 2019-02-21 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSAlert : a reference to current application’s NSAlert
property NSIndexSet : a reference to current application’s NSIndexSet
property NSScrollView : a reference to current application’s NSScrollView
property NSTableView : a reference to current application’s NSTableView
property NSTableColumn : a reference to current application’s NSTableColumn
property NSMutableArray : a reference to current application’s NSMutableArray
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSAlertSecondButtonReturn : a reference to current application’s NSAlertSecondButtonReturn

property theResult : 0
property returnCode : 0
property theDataSource : {}

set paramObj to {myMessage:"項目の選択", mySubMessage:"適切なものを以下からえらんでください", aTableList:{"なし", "りんご", "ひよこ", "ぎょうざ", "すなぎも", "ぼんじり", "もも"}}
set aRes to my chooseItemByTableView:paramObj

on chooseItemByTableView:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set aTList to (aTableList of paramObj) as list
  
  
–define the matrix size where you’ll put the radio buttons
  
set aScrollWithTable to makeTableView(aTList, 300, 150) of me
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aScrollWithTable
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
  
  
return (aScrollWithTable’s documentView’s selectedRow()) + 1
end chooseItemByTableView:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

on makeTableView(aList as list, aWidth as number, aHeight as number)
  set aOffset to 40
  
  
set sourceList to {}
  
repeat with i in aList
    set the end of sourceList to {dataItem:(contents of i)}
  end repeat
  
  
set theDataSource to NSMutableArray’s alloc()’s init()
  
theDataSource’s addObjectsFromArray:sourceList
  
  
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aOffset, aWidth, aHeight))
  
set aView to NSTableView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aOffset, aWidth, aHeight))
  
  
  
set aColumn to (NSTableColumn’s alloc()’s initWithIdentifier:"dataItem")
  (
aColumn’s setWidth:aWidth)
  (
aColumn’s headerCell()’s setStringValue:"dataItem")
  (
aView’s addTableColumn:aColumn)
  
  
aView’s setDelegate:me
  
aView’s setDataSource:me
  
aView’s reloadData()
  
  
aScroll’s setDocumentView:aView
  
aView’s enclosingScrollView()’s setHasVerticalScroller:true
  
  
–1行目を選択
  
set aIndexSet to NSIndexSet’s indexSetWithIndex:0
  
aView’s selectRowIndexes:aIndexSet byExtendingSelection:false
  
  
–強制的にトップにスクロール
  
–set maxHeight to aScroll’s documentView()’s |bounds|()’s |size|()’s height
  
set aDBounds to aScroll’s documentView()’s |bounds|()
  
if class of aDBounds = list then
    –macOS 10.13 or later
    
set maxHeight to item 2 of item 1 of aDBounds
  else
    –macOS 10.10….10.12
    
set maxHeight to height of |size| of aDBounds
  end if
  
  
set aPT to current application’s NSMakePoint(0.0, -40.0) —— (aScroll’s documentView()’s |bounds|()’s |size|()’s height))
  
aScroll’s documentView()’s scrollPoint:aPT
  
  
return aScroll
end makeTableView

–TableView Event Handlers
on numberOfRowsInTableView:aView
  return my theDataSource’s |count|()
end numberOfRowsInTableView:

on tableView:aView objectValueForTableColumn:aColumn row:aRow
  set aRec to (my theDataSource)’s objectAtIndex:(aRow as number)
  
set aTitle to (aColumn’s headerCell()’s title()) as string
  
set aRes to (aRec’s valueForKey:aTitle)
  
return aRes
end tableView:objectValueForTableColumn:row:

★Click Here to Open This Script 

Posted in GUI list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSAlert NSAlertSecondButtonReturn NSIndexSet NSMutableArray NSRunningApplication NSScrollView NSTableColumn NSTableView | 1 Comment

アラートダイアログ上にsegmented controlを表示

Posted on 2月 19, 2019 by Takaaki Naganoya

アラートダイアログを作成し、その上にsegmented control(タブみたいな複数項目1択UI部品)を表示して選択肢の選択を行うAppleScriptです。

選択肢のインデックス番号が(1からはじまる)返ってきます。

AppleScript名:アラートダイアログ上にsegmented controlを表示
— Created 2019-02-14 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSAlert : a reference to current application’s NSAlert
property NSView : a reference to current application’s NSView
property NSSegmentedControl : a reference to current application’s NSSegmentedControl
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSSegmentStyleTexturedRounded : a reference to current application’s NSSegmentStyleTexturedRounded

property theSegSel : 0
property returnCode : 0

set paramObj to {myMessage:"項目選択", mySubMessage:"どれか選択してください。", segmentMes:{"Red", "Blue", "Yellow", "Brown", "White", "Cyan", "Grey"}}
set segRes to my chooseSegment:paramObj

on chooseSegment:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set segMesList to segmentMes of paramObj
  
  
— create a view
  
set theView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 400, 200))
  
  
–Segmented Controlをつくる
  
set aSeg to makeSegmentedControl(segMesList, 400, 80) of me
  
  
theView’s setSubviews:{aSeg}
  
  
set theAlert to NSAlert’s alloc()’s init()
  
  
— set up alert
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aSeg
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
  
  
set (my theSegSel) to (aSeg’s selectedSegment()) as number
  
return (my theSegSel) + 1
end chooseSegment:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

on makeSegmentedControl(titleList, aWidth, aHeight)
  set aLen to length of titleList
  
  
set aSeg to NSSegmentedControl’s alloc()’s init()
  
aSeg’s setSegmentCount:aLen
  
  
set aCount to 0
  
repeat with i in titleList
    set j to contents of i
    (
aSeg’s setLabel:j forSegment:aCount)
    
set aCount to aCount + 1
  end repeat
  
  
aSeg’s setTranslatesAutoresizingMaskIntoConstraints:false
  
aSeg’s setSegmentStyle:(NSSegmentStyleTexturedRounded)
  
aSeg’s setFrame:(current application’s NSMakeRect(20, aHeight – 60, aWidth, aHeight – 40))
  
aSeg’s setTrackingMode:0
  
aSeg’s setTarget:me
  
aSeg’s setAction:"clickedSeg:"
  
aSeg’s setSelectedSegment:0
  
  
return aSeg
end makeSegmentedControl

on clickedSeg:aSender
  set aSel to aSender’s selectedSegment()
  
set selSeg to aSel
end clickedSeg:

★Click Here to Open This Script 

Posted in dialog GUI list | Tagged 10.11savvy 10.12savvy 10.13savvy NSAlert NSRunningApplication NSSegmentedControl NSSegmentStyleTexturedRounded NSView | Leave a comment

アラートダイアログ上にRadio Buttonを表示

Posted on 2月 19, 2019 by Takaaki Naganoya

アラートダイアログを作成し、その上にRadio Buttonを表示して位置座標の選択を行うAppleScriptです。

任意の選択肢をlist(配列)で指定すると、その通りのRadio Buttonを表示します。ユーザーが選択した項目のtitle文字列を返します。項目番号ではありません。

AppleScript名:アラートダイアログ上にRadio Buttonを表示 v2
— Created 2019-02-14 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSAlert : a reference to current application’s NSAlert
property NSMatrix : a reference to current application’s NSMatrix
property NSButtonCell : a reference to current application’s NSButtonCell
property NSRadioButton : a reference to current application’s NSRadioButton
property NSRadioModeMatrix : a reference to current application’s NSRadioModeMatrix
property NSAlertSecondButtonReturn : a reference to current application’s NSAlertSecondButtonReturn

property theResult : 0
property returnCode : 0

set paramObj to {myMessage:"項目の選択", mySubMessage:"適切なものを以下からえらんでください", matrixTitleList:{"なし", "りんご", "ひよこ", "ぎょうざ", "すなぎも", "ぼんじり", "もも"}}
set aRes to my chooseItemByRadioButton:paramObj

on chooseItemByRadioButton:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set aMatList to (matrixTitleList of paramObj) as list
  
set aLen to length of aMatList
  
  
–create the radio button prototype
  
set aProto to NSButtonCell’s alloc()’s init()
  
aProto’s setTitle:"Options"
  
aProto’s setButtonType:(NSRadioButton)
  
  
–define the matrix size where you’ll put the radio buttons
  
set matrixRect to current application’s NSMakeRect(20.0, 20.0, 200.0, (20.0 * aLen))
  
set aMatrix to NSMatrix’s alloc()’s initWithFrame:matrixRect mode:(NSRadioModeMatrix) prototype:aProto numberOfRows:(aLen) numberOfColumns:1
  
  
set cellList to aMatrix’s cells()
  
set aCount to 0
  
repeat with i in aMatList
    set j to contents of i
    ((
cellList’s objectAtIndex:aCount)’s setTitle:j)
    
set aCount to aCount + 1
  end repeat
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aMatrix
  end tell
  
  
— show alert in modal loop
  
current application’s NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
  
  
return (aMatrix’s selectedCell()’s title()) as string
end chooseItemByRadioButton:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

★Click Here to Open This Script 

Posted in dialog GUI list | Tagged 10.11savvy 10.12savvy 10.13savvy NSAlert NSAlertSecondButtonReturn NSButtonCell NSMatrix NSRadioButton NSRadioModeMatrix | Leave a comment

アラートダイアログ上にMap Viewを表示

Posted on 2月 19, 2019 by Takaaki Naganoya

アラートダイアログを作成し、その上にMap Viewを表示して位置座標の選択を行うAppleScriptです。

Map Viewを使用するためには、インターネット接続が必要です。

もしこれをAppleScriptのコマンドのように表現するなら「choose geo location」とかいうコマンドになるでしょうか。本当は地図.appのように地図中でクリックした場所にピンを打って選択箇所を明示するようなものを考えていたのですが、実際にASだけで作ろうとすると難しいものがありそうで。

こうした「ざっくり場所を選ぶ」ダイアログのほか、複数の地点をピンで表示し、そのうちのどれかを地図上で選択するといったコマンドがあると使いでがありそうです。

AppleScript名:アラートダイアログ上のMap Viewを表示
— Created 2019-02-14 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "MapKit"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSData : a reference to current application’s NSData
property MKMapView : a reference to current application’s MKMapView
property NSURLRequest : a reference to current application’s NSURLRequest
property NSURLConnection : a reference to current application’s NSURLConnection

property theResult : 0
property returnCode : 0

set nRes to hasInternetConnection("http://www.google.com") of me
if nRes = false then error "No Internet Connection…."

–地図表示初期座標。一般的にはWiFi経由でAssistive-GPSから現在位置を拾って指定
set aLong to 130.55723797
set aLat to 31.57868838

set paramObj to {myMessage:"場所の選択", mySubMessage:"目標の場所を地図中央に入れてください", aLongitude:aLong, aLatitude:aLat}
my performSelectorOnMainThread:"chooseCoordinate:" withObject:(paramObj) waitUntilDone:true
return theResult
–> {latitude:31.57868838, longitude:130.55723797}

on chooseCoordinate:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set aLong to aLongitude of paramObj
  
set aLat to aLatitude of paramObj
  
  
–MKMapViewをつくる
  
set aMapView to MKMapView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 500, 300))
  
tell aMapView
    its setMapType:(current application’s MKMapTypeStandard)
    
its setZoomEnabled:true
    
its setScrollEnabled:true
    
its setPitchEnabled:true
    
its setRotateEnabled:true
    
its setShowsCompass:true
    
its setShowsZoomControls:true
    
its setShowsScale:true
    
its setShowsUserLocation:true
    
    
set aLocation to current application’s CLLocationCoordinate2DMake(aLat, aLong)
    
its setCenterCoordinate:aLocation zoomLevel:17 animated:false
    
its setDelegate:me
  end tell
  
  
— set up alert  
  
set theAlert to current application’s NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aMapView
  end tell
  
  
— show alert in modal loop
  
current application’s NSRunningApplication’s currentApplication()’s activateWithOptions:(current application’s NSApplicationActivateIgnoringOtherApps)
  
set returnCode to theAlert’s runModal()
  
if returnCode = (current application’s NSAlertSecondButtonReturn) then error number -128
  
  
set (my theResult) to (aMapView’s centerCoordinate()) as record
end chooseCoordinate:

–Internet Connection Check
on hasInternetConnection(aURLString)
  set aURL to |NSURL|’s alloc()’s initWithString:aURLString
  
set aReq to NSURLRequest’s alloc()’s initWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:5.0
  
set urlRes to (NSURLConnection’s sendSynchronousRequest:aReq returningResponse:(missing value) |error|:(missing value))
  
if urlRes = missing value then
    return false
  else
    return true
  end if
end hasInternetConnection

★Click Here to Open This Script 

Posted in geolocation GUI Internet | Tagged 10.11savvy 10.12savvy 10.13savvy NSData NSURL NSView | Leave a comment

アラートダイアログ上にpath control x2を表示

Posted on 2月 18, 2019 by Takaaki Naganoya

アラートダイアログを作成し、その上にpath controlを2つ表示してパスの選択を行うAppleScriptです。

path controlには、対象のフォルダ/ファイルをドラッグ&ドロップしてファイルのパスを指定できます。使いやすい一方で、choose folderコマンドのようにフォルダの新規作成までサポートしているわけではありません。

スクリプトエディタ、Script Debugger、Appletなどでは正常に動作しますが、スクリプトメニュー上から呼び出すとアラートダイアログが最前面に表示されず、前に出す操作が必要になります。

AppleScript名:アラートダイアログ上のpath control x2を表示
— Created 2019-02-14 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property theResult : 0
property returnCode : 0

set paramObj to {myMessage:"項目選択", mySubMessage:"どれか選択してください。", fromPathMes:"移動元:", toPathMes:"移動先:"}
set segRes to my chooseTwoPath:paramObj
–> {fromPathRes:"/Users/me/Documents/AppleScript/パスコントロール", toPathRes:"/Users/me/Documents/AppleScript/タッチバー"}

on chooseTwoPath:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set fromLabel to fromPathMes of paramObj
  
set toLabel to toPathMes of paramObj
  
  
— create a view
  
set theView to current application’s NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 800, 60))
  
  
— create two path control & text field
  
set aPathControl to current application’s NSPathControl’s alloc()’s initWithFrame:(current application’s NSMakeRect(100, 35, 700, 20))
  
set bPathControl to current application’s NSPathControl’s alloc()’s initWithFrame:(current application’s NSMakeRect(100, 0, 700, 20))
  
aPathControl’s setBackgroundColor:(current application’s NSColor’s cyanColor())
  
bPathControl’s setBackgroundColor:(current application’s NSColor’s yellowColor())
  
  
set aHome to current application’s |NSURL|’s fileURLWithPath:(current application’s NSHomeDirectory()) –initial dir
  
aPathControl’s setURL:aHome
  
bPathControl’s setURL:aHome
  
  
set a1TF to current application’s NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 35, 100, 20))
  
set a2TF to current application’s NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 100, 20))
  
a1TF’s setEditable:false
  
a2TF’s setEditable:false
  
a1TF’s setStringValue:fromLabel
  
a2TF’s setStringValue:toLabel
  
a1TF’s setDrawsBackground:false
  
a2TF’s setDrawsBackground:false
  
a1TF’s setBordered:false
  
a2TF’s setBordered:false
  
  
theView’s setSubviews:{a1TF, aPathControl, a2TF, bPathControl}
  
  
— set up alert
  
set theAlert to current application’s NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:theView
  end tell
  
  
— show alert in modal loop
  
current application’s NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
  
  
set s1Val to (aPathControl’s |URL|’s |path|()) as string
  
set s2Val to (bPathControl’s |URL|’s |path|()) as string
  
  
return {fromPathRes:s1Val, toPathRes:s2Val}
end chooseTwoPath:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

★Click Here to Open This Script 

Posted in File path GUI | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

アラートダイアログ上のDate Pickerで日付選択

Posted on 2月 18, 2019 by Takaaki Naganoya

アラートダイアログを作成し、その上にDate Pickerを表示して日付の選択を行うAppleScriptです。

スクリプトエディタ、Script Debugger、Appletなどでは正常に動作しますが、スクリプトメニュー上から呼び出すとアラートダイアログが最前面に表示されず、前に出す操作が必要になります。

もともとはShane Stanleyが作成したカレンダー選択ダイアログでしたが、メインスレッドでの実行を強制しなくてはならなかったのと、汎用的に使える構造になっていなかったので、機能を整理しました。

このDate Pickerダイアログをもとに、さまざまなGUI部品を配置してちょっとしたユーザーの操作を受け付ける汎用ダイアログとして整備してみました。最終的には、SDEF(AppleScript用語辞書)をつけたAppleScript Librariesに仕上げるといい感じでしょうか。

アラートダイアログという、サイズ固定のダイアログウィンドウ上に各種GUI部品を表示するのは、使いにくいんじゃないかと疑問を持っていたのですが、表示後のリサイズはできないものの、中に入れるViewのサイズ次第でダイアログの大きさも可変なので、予想よりも使えそうです。

AppleScript名:アラートダイアログ上のDate Pickerで日付選択
— Created 2019-02-14 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSAlert : a reference to current application’s NSAlert
property NSDate : a reference to current application’s NSDate
property NSView : a reference to current application’s NSView
property NSDatePicker : a reference to current application’s NSDatePicker
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSClockAndCalendarDatePickerStyle : a reference to current application’s NSClockAndCalendarDatePickerStyle
property NSYearMonthDayDatePickerElementFlag : a reference to current application’s NSYearMonthDayDatePickerElementFlag
property NSHourMinuteSecondDatePickerElementFlag : a reference to current application’s NSHourMinuteSecondDatePickerElementFlag

property theResult : missing value
property returnCode : 0

set paramObj to {myMessage:"月選択", mySubMessage:"作成対象の月を選択してください。日付はどれでもけっこうです。"}
set {targYear, targMonth, targDate} to my chooseDate:((paramObj) of me)
–> {2018, 10, 8}

on chooseDate:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
  
— create a view
  
set theView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 200, 300))
  
set datePicker to NSDatePicker’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 300, 200))
  
datePicker’s setDatePickerStyle:(NSClockAndCalendarDatePickerStyle)
  
datePicker’s setDatePickerElements:((NSYearMonthDayDatePickerElementFlag) + (NSHourMinuteSecondDatePickerElementFlag as integer))
  
  
datePicker’s setDateValue:(NSDate’s |date|())
  
  
set theSize to datePicker’s fittingSize()
  
  
theView’s setFrameSize:theSize
  
datePicker’s setFrameSize:theSize
  
  
theView’s setSubviews:{datePicker}
  
  
set theAlert to NSAlert’s alloc()’s init()
  
  
— set up alert
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:theView
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
  
  
set (my theResult) to (datePicker’s dateValue()) as date
  
  
set aYear to year of theResult
  
set aMonth to month of theResult as number
  
set aDate to day of theResult
  
return {aYear, aMonth, aDate}
end chooseDate:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

★Click Here to Open This Script 

Posted in GUI | Tagged 10.11savvy 10.12savvy NSAlert NSDate NSDatePicker NSRunningApplication NSView | 1 Comment

Keynoteの最前面のドキュメントの現在のスライドに指定月の日曜日はじまりカレンダーを表で作成

Posted on 2月 14, 2019 by Takaaki Naganoya

Keynoteの最前面の書類の現在選択中のスライド(ページ)に、指定月の日曜日はじまりカレンダーを、表オブジェクトで作成するAppleScriptです。

Keynoteで資料を作成していると、資料にカレンダーを入れたいケースが多々あります。Terminal.appを起動してcalコマンドでカレンダーを作ってみたり、Dashboardのカレンダーをコピーして入れることも多いですが、Dashboardはもうあるんだかないんだ分からない状態。かわりのものを用意してみました。

あとは、サイズやスタイル、土日のデータを削除するなど用途に応じて編集して表カレンダーを利用するとよいでしょう。

macOS標準装備のスクリプトメニューに入れて呼び出す場合には、アプリケーション形式で書き出したものを使う必要があります。

世の中のカレンダーは日曜日はじまりだけではないので、月曜日はじまりなど、その国、その現場ごとのルールに合わせて変更することが重要です。曜日名についても、実行中のユーザーの言語環境から取得して入れることも可能なので、そのようにしてもよいでしょう。

同じぐらいのスペックのマシンで本Scriptを動かすと、macOS 10.14, Mojave上では10.12.6上の(Keynote v8.1の)倍ぐらい速くて驚かされます。10.13.6上でも同様なのでOS側の対応というよりは、Keynote側のバージョンアップ(v8.1 –> v8.3)によるものかもしれません。

AppleScript名:指定月の日曜日はじまりカレンダーを表で作成 v2.scptd
— Created 2019-02-14 by Takaaki Naganoya
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property theDate : missing value

property daysList : {"日", "月", "火", "水", "木", "金", "土"} –Japanese
–property daysList : {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}–English

set paramObj to {myMessage:"月選択", mySubMessage:"作成対象の月を選択してください。日付はどれでもけっこうです。"}
set {targYear, targMonth} to chooseMonth(paramObj) of me

–指定月のカレンダーを1D List(7 days x 6 weeks) で作成
set aCalList to retListCalendar(targYear, targMonth) of me

set fullCalList to daysList & aCalList

set aTitle to (targYear as string) & (targMonth as string)
set dCount to 1

tell application "Keynote"
  tell front document
    tell current slide
      set aTable to make new table with properties {header column count:0, header row count:1, row count:7, column count:7, name:aTitle}
      
tell aTable
        repeat with i from 1 to 49
          tell cell i
            ignoring application responses
              set value to contents of item dCount of fullCalList
            end ignoring
          end tell
          
set dCount to dCount + 1
        end repeat
      end tell
    end tell
  end tell
end tell

–カレンダー作成対象の年、月を選択(ただし、日付をクリックして選択しないと値を取得できないので注意)
on chooseMonth(paramObj)
  my performSelectorOnMainThread:"chooseDate:" withObject:(paramObj) waitUntilDone:true
  
set aYear to year of theDate
  
set aMonth to month of theDate as number
  
return {aYear, aMonth}
end chooseMonth

on chooseDate:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
  
— create a view
  
set theView to current application’s NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 100, 200))
  
set datePicker to current application’s NSDatePicker’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 100, 100))
  
datePicker’s setDatePickerStyle:(current application’s NSClockAndCalendarDatePickerStyle)
  
datePicker’s setDatePickerElements:((current application’s NSYearMonthDayDatePickerElementFlag) + (current application’s NSHourMinuteSecondDatePickerElementFlag as integer))
  
  
datePicker’s setDateValue:(current application’s NSDate’s |date|())
  
  
set theSize to datePicker’s fittingSize()
  
  
theView’s setFrameSize:theSize
  
datePicker’s setFrameSize:theSize
  
  
theView’s setSubviews:{datePicker}
  
  
set theAlert to current application’s NSAlert’s alloc()’s init()
  
  
— set up alert
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:theView
  end tell
  
  
— show alert in modal loop
  
set returnCode to theAlert’s runModal()
  
if returnCode = (current application’s NSAlertSecondButtonReturn) then error number -128
  
  
— retrieve date
  
set (my theDate) to (datePicker’s dateValue()) as date
  
end chooseDate:

–指定月のカレンダーを1D List(7 days x 6 weeks) で返す
on retListCalendar(tYear, tMonth)
  set mLen to getMlen(tYear, tMonth) of me
  
set aList to {}
  
  
set fDat to getDateInternational(tYear, tMonth, 1) of me
  
tell current application
    set aOffset to (weekday of fDat) as number
  end tell
  
  
–header gap
  
repeat (aOffset – 1) times
    set the end of aList to ""
  end repeat
  
  
–calendar body
  
repeat with i from 1 to mLen
    set the end of aList to (i as string)
  end repeat
  
  
–footer gap
  
repeat (42 – aOffset – mLen + 1) times
    set the end of aList to ""
  end repeat
  
  
return aList
end retListCalendar

–現在のカレンダーで指定年月の日数を返す(国際化対応版)
on getMlen(aYear as integer, aMonth as integer)
  set theNSCalendar to current application’s NSCalendar’s currentCalendar()
  
set theDate to theNSCalendar’s dateWithEra:1 |year|:aYear |month|:aMonth |day|:1 hour:0 minute:0 |second|:0 nanosecond:0
  
set theResult to theNSCalendar’s rangeOfUnit:(current application’s NSDayCalendarUnit) inUnit:(current application’s NSMonthCalendarUnit) forDate:theDate
  
return |length| of theResult
end getMlen

–現在のカレンダーで指定年月のdate objectを返す
on getDateInternational(aYear, aMonth, aDay)
  set theNSCalendar to current application’s NSCalendar’s currentCalendar()
  
set theDate to theNSCalendar’s dateWithEra:1 |year|:aYear |month|:aMonth |day|:aDay hour:0 minute:0 |second|:0 nanosecond:0
  
return theDate as date
end getDateInternational

★Click Here to Open This Script 

Posted in Calendar GUI list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote NSAlert NSAlertSecondButtonReturn NSCalendar NSClockAndCalendarDatePickerStyle NSDate NSDatePicker NSDayCalendarUnit NSHourMinuteSecondDatePickerElementFlag NSMonthCalendarUnit NSView NSYearMonthDayDatePickerElementFlag | Leave a comment

Finder上で選択中のAppleScriptの行数をカウントする

Posted on 2月 8, 2019 by Takaaki Naganoya

Finder上で選択中のAppleScript書類の行数や種別を取得して表UIで表示するAppleScriptです。

Myriad Tables Libを用いて結果を表UIで表示しています。

当初はAppleScript書類からソースを取得するのに/usr/bin/osadecompileコマンドを使っていたのですが、OSAKit経由で処理したほうが高速な印象があります。

–> Download Executable archive for macOS 10.14 (include Myriad Tables Lib)

macOS 10.14上で動作させるためには、Script Debugger上で本Scriptをオープンするか、本Scriptをバンドル形式で保存し、バンドル内(/Contents/Resources/Script Libraries フォルダ)にMyriad Tables Libを入れ、AppleScriptアプレットとして書き出す必要があります。

また、初回実行時には「セキュリティ」の承認ダイアログが表示されるため、これをOKする必要があります。AppleScriptアプレットはFinder上でアイコンをダブルクリックすると「Finder上で選択中のアイテム」を拾えないため(その瞬間、Finder上での選択アイテムはアプレット自身になってしまうため)、DockやmacOS標準装備のスクリプトメニューに登録して起動する必要があります。

AppleScript名:Finder上で選択中のAppleScriptの行数をカウントする v2.scpt
— Created 2019-02-04 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "OSAKit"
use script "Myriad Tables Lib" version "1.0.8" –https://www.macosxautomation.com/applescript/apps/Script_Libs.html#MyriadTablesLib

property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property OSAScript : a reference to current application’s OSAScript
property NSPredicate : a reference to current application’s NSPredicate
property NSURLIsPackageKey : a reference to current application’s NSURLIsPackageKey
property NSURLIsDirectoryKey : a reference to current application’s NSURLIsDirectoryKey
property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey

–Finder上で選択中のファイルのうちAppleScript書類のみ抽出
tell application "Finder"
  set inFiles to selection as alias list
  
if inFiles = {} then return
end tell
set filRes1 to filterAliasListByUTIList(inFiles, {"com.apple.applescript.script", "com.apple.applescript.script-bundle"}) of me
if filRes1 = {} then return

–AppleScript書類の種別判定および行数カウント
set outList to {}
repeat with i in filRes1
  set aName to (NSString’s stringWithString:i)’s lastPathComponent() as string
  
set sInfo to detectScriptIsPureASorASOC(i) of me
  
set sText to scriptSource of getASsourceFor(i) of me
  
set sNum to count every paragraph of sText
  
set sUTI to retUTIfromPath(i) of me
  
if sUTI = "com.apple.applescript.script" then
    set sKind to "Script"
  else if sUTI = "com.apple.applescript.script-bundle" then
    set sKind to "Script Bundle"
  else
    set sKind to "Other"
  end if
  
  
set the end of outList to {aName, sInfo, sKind, sNum}
end repeat

–結果を表UIで表示する
tell script "Myriad Tables Lib"
  set aDispBounds to my makeInitialBounds:1200 withHeight:500
  
set theTable to make new table with data outList column headings {"script name", "ASOC", "Script Kind", "lines"} with title "AppleScript Line Count" with prompt "Your Selected Scripts" with row numbering and empty selection allowed –and can add and delete
  
modify table theTable initial position aDispBounds column widths pattern {1, 2, 3, 4} with hidden cancel button
  
modify columns in table theTable user date format {user format full, user format full} entry alignment align left
  (
display table theTable)
end tell

–Alias listから指定UTI Listに含まれるものをPOSIX pathのリストで返す
on filterAliasListByUTIList(aList as list, targUTIList as list)
  set outList to {}
  
repeat with i in targUTIList
    set j to contents of i
    
set aRes to filterAliasListByUTI(aList, j) of me
    
if aRes is not equal to {} then
      set outList to outList & aRes
    end if
  end repeat
  
return outList
end filterAliasListByUTIList

–Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す
on filterAliasListByUTI(aList as list, targUTI)
  set newList to {}
  
repeat with i in aList
    set j to POSIX path of i
    
set tmpUTI to my retUTIfromPath(j)
    
set utiRes to my filterUTIList({tmpUTI}, targUTI)
    
if utiRes is not equal to {} then
      set the end of newList to j
    end if
  end repeat
  
return newList
end filterAliasListByUTI

–指定のPOSIX pathのファイルのUTIを求める
on retUTIfromPath(aPOSIXPath)
  set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath
  
set {theResult, theValue} to aURL’s getResourceValue:(specifier) forKey:NSURLTypeIdentifierKey |error|:(missing value)
  
  
if theResult = true then
    return theValue as string
  else
    return theResult
  end if
end retUTIfromPath

–UTIリストが指定UTIに含まれているかどうか演算を行う
on filterUTIList(aUTIList, aUTIstr)
  set anArray to NSArray’s arrayWithArray:aUTIList
  
set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr)
  
set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list
  
return bRes
end filterUTIList

on makeInitialBounds:(aTWidth as integer) withHeight:(aTHeight as integer)
  set aDispBounds to current application’s NSScreen’s mainScreen()’s frame()
  
if class of item 1 of aDispBounds = record then
    –macOS 10.10/10.11/10.12
    
set aWidth to (width of |size| of aDispBounds)
    
set aHeight to (height of |size| of aDispBounds)
  else
    –macOS 10.13 or later?
    
set aWidth to (item 1 of item 2 of aDispBounds)
    
set aHeight to (item 2 of item 2 of aDispBounds)
  end if
  
  
set xPos to (aWidth div 2) – (aTWidth div 2)
  
set yPos to (aHeight div 2) – (aTHeight div 2)
  
  
return {xPos, yPos, aTWidth, aTHeight}
end makeInitialBounds:withHeight:

–指定AppleScriptファイルがPure ASかASOCかを判定して返す
on detectScriptIsPureASorASOC(aFile)
  set sRes to getASsourceFor(aFile) of me
  
set sName to scriptKind of sRes –Name
  
set sText to scriptSource of sRes –Source
  
if sText = "" or sText = missing value then return missing value
  
  
if sName = "AppleScript" then
    if sText contains "use framework \"Foundation\"" then
      return true –ASOC
    else
      return false –Pure AppleScript
    end if
  else
    –JXAなど他のOSA言語の場合
    
return sName
  end if
end detectScriptIsPureASorASOC

–指定AppleScriptファイルのソースコードを取得する(実行専用Scriptからは取得できない)
on getASsourceFor(aPOSIXPath)
  set aURL to |NSURL|’s fileURLWithPath:(aPOSIXPath)
  
set theScript to current application’s OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
set scriptName to theScript’s |language|()’s |name|() as string
  
set theSource to theScript’s source() as text
  
return {scriptKind:scriptName, scriptSource:theSource}
end getASsourceFor

★Click Here to Open This Script 

Posted in file File path GUI OSA | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSPredicate NSString NSURL OSAScript | Leave a comment

Keynote書類の現在のスライド上の表1の背景色を置換 v1

Posted on 1月 31, 2019 by Takaaki Naganoya

Keynoteでオープン中の最前面の書類の現在表示中のスライドに存在する表1の背景色を置換するAppleScriptです。

Pages用のScriptをごく一部修正してkeynoteの表に対して処理できるようにしてみました。macOS 10.11, 10.12, 10.13ではスクリプトエディタ上で動作します。macOS 10.14ではSIPを解除してスクリプトエディタで動かすか、アプレット形式で書き出して、アプレットのバンドル中にdbColNamesKit.frameworkを入れると動きます。

Script DebuggerとScript Menu上では動作しません。

ポップアップメニュー中に色の名称の動的な推定に、オープンソースの「DBColorNames」をフレームワーク化した
「dbColNamesKit.framework」を利用しています。

–> dbColNamesKit.framework (To ~/Library/Frameworks)

AppleScript名:Keynote書類の現在のスライド上の表の背景色を置換 v1
— Created 2019-01-29 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "dbColNamesKit" –https://github.com/daniel-beard/DBColorNames/
use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

–v1:Convert Pages version to Keynote

property NSView : a reference to current application’s NSView
property NSColor : a reference to current application’s NSColor
property NSArray : a reference to current application’s NSArray
property NSMenu : a reference to current application’s NSMenu
property NSImage : a reference to current application’s NSImage
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property NSWindow : a reference to current application’s NSWindow
property NSTextField : a reference to current application’s NSTextField
property NSMenuItem : a reference to current application’s NSMenuItem
property NSBezierPath : a reference to current application’s NSBezierPath
property NSPopUpButton : a reference to current application’s NSPopUpButton
property NSWindowController : a reference to current application’s NSWindowController
property NSTitledWindowMask : a reference to current application’s NSTitledWindowMask
property NSRoundedBezelStyle : a reference to current application’s NSRoundedBezelStyle
property NSFloatingWindowLevel : a reference to current application’s NSFloatingWindowLevel
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property NSMomentaryLightButton : a reference to current application’s NSMomentaryLightButton

property windisp : true
property wController : missing value
property pop1ind : 1

–初期化
set (my windisp) to true
set (my pop1ind) to 1
load framework

–Pagesの1ページ目にある表の塗り色を取得
tell application "Keynote"
  tell front document
    tell current slide
      tell table 1
        set c1List to background color of every cell
        
set aProp to properties
        
set xCount to column count of aProp
      end tell
    end tell
  end tell
end tell

–Convert 1D List to 2D List
set c3List to (current application’s SMSForder’s subarraysFrom:c1List groupedBy:xCount |error|:(missing value)) as list

–色データをユニーク化(重複削除)
set bList to uniquifyList(c1List) of me

–missing value(背景色なし)を除外する
set c2List to (current application’s SMSForder’s arrayByDeletingBlanksIn:(bList)) as list

–Popup Menuで置換色選択
set paramObj to {c2List, 65535, "OK", "Select Target Color", 180} –Timeout = 180 sec, Color val range = 16bit
my performSelectorOnMainThread:"getPopupValues:" withObject:(paramObj) waitUntilDone:true
if pop1ind = false then return –timed out
set fromCol to (contents of item pop1ind of c2List)

–カラーピッカーで置換色選択
set tCol to choose color default color fromCol

set d1 to current date

–実際に表の背景色を置換する
set hitList to findDataFrom2DList(fromCol, c3List) of me –データ上で当該色のセル情報を計算する

–Rangeを横スキャンと縦スキャンの2通りで試算(Two way Simulation)
set rList1 to retRangeFromPosListHorizontal(hitList) of me –横方向へのrange評価
set rList2 to retRangeFromPosListVertival(hitList) of me –縦方向へのrange評価

–Simulationの結果、要素数の少ない方(=処理時間の短い方=高速な方)を採用する
log {"Simulation", (length of rList1), (length of rList2)}
if (length of rList1) < (length of rList2) then
  copy rList1 to rangeList
else
  copy rList2 to rangeList
end if

tell application "Keynote"
  activate
  
tell front document
    tell current slide
      tell table 1
        repeat with i in rangeList
          set j to contents of i
          
          
ignoring application responses –非同期実行モードで高速実行
            set background color of range j to tCol
          end ignoring
          
        end repeat
      end tell
    end tell
  end tell
end tell

set d2 to current date
return d2 – d1

–カラーポップアップメニューをウィンドウ表示
on getPopupValues:paramObj
  copy (paramObj as list) to {ap1List, aColMax, aButtonMSG, aSliderValMSG, timeOutSecs}
  
  
set (my windisp) to true
  
  
set aView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 360, 100))
  
  
–Labelをつくる
  
set a1TF to NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(30, 60, 80, 20))
  
a1TF’s setEditable:false
  
a1TF’s setStringValue:"Color:"
  
a1TF’s setDrawsBackground:false
  
a1TF’s setBordered:false
  
  
–Ppopup Buttonをつくる
  
set a1Button to NSPopUpButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(80, 60, 200, 20)) pullsDown:false
  
a1Button’s removeAllItems()
  
  
set a1Menu to NSMenu’s alloc()’s init()
  
set aCDB to current application’s DBColorNames’s alloc()’s init()
  
  
set iCount to 1
  
repeat with i in ap1List
    copy i to {r1, g1, b1}
    
    
set nsCol to makeNSColorFromRGBAval(r1, g1, b1, aColMax, aColMax) of me
    
set anImage to makeRoundedNSImageWithFilledWithColor(64, 64, nsCol, 4) of me
    
    
set aTitle to "#" & (iCount as string) & " " & (aCDB’s nameForColor:nsCol) as string
    
set aMenuItem to (NSMenuItem’s alloc()’s initWithTitle:aTitle action:"actionHandler:" keyEquivalent:"")
    (
aMenuItem’s setImage:anImage)
    (
aMenuItem’s setEnabled:true)
    (
a1Menu’s addItem:aMenuItem)
    
    
set iCount to iCount + 1
  end repeat
  
  
a1Button’s setMenu:a1Menu
  
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(80, 10, 140, 40)))
  
bButton’s setButtonType:(NSMomentaryLightButton)
  
bButton’s setBezelStyle:(NSRoundedBezelStyle)
  
bButton’s setTitle:aButtonMSG
  
bButton’s setTarget:me
  
bButton’s setAction:("clicked:")
  
bButton’s setKeyEquivalent:(return)
  
  
aView’s addSubview:a1TF
  
  
aView’s addSubview:a1Button
  
aView’s addSubview:bButton
  
aView’s setNeedsDisplay:true
  
  
–NSWindowControllerを作ってみた(いらない?)
  
set aWin to (my makeWinWithView(aView, 300, 100, aSliderValMSG))
  
  
set wController to NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
  
wController’s showWindow:me
  
  
set aCount to timeOutSecs * 100
  
  
set hitF to false
  
repeat aCount times
    if (my windisp) = false then
      set hitF to true
      
exit repeat
    end if
    
delay 0.01
    
set aCount to aCount – 1
  end repeat
  
  
my closeWin:aWin
  
  
if hitF = true then
    set s1Val to ((a1Button’s indexOfSelectedItem() as number) + 1)
  else
    set s1Val to false
  end if
  
  
copy s1Val to my pop1ind
  
end getPopupValues:

on clicked:aSender
  set (my windisp) to false
end clicked:

–make Window for Display
on makeWinWithView(aView, aWinWidth as integer, aWinHeight as integer, aTitle as string)
  set aScreen to NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
  
set aBacking to NSTitledWindowMask
  
  
set aDefer to NSBackingStoreBuffered
  
  
— Window
  
set aWin to NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
  
aWin’s setTitle:aTitle
  
aWin’s setDelegate:me
  
aWin’s setDisplaysWhenScreenProfileChanges:true
  
aWin’s setHasShadow:true
  
aWin’s setIgnoresMouseEvents:false
  
aWin’s setLevel:(NSFloatingWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
  
aWin’s setContentView:aView
  
  
return aWin
end makeWinWithView

–close win
on closeWin:aWindow
  repeat with n from 10 to 1 by -1
    (aWindow’s setAlphaValue:n / 10)
    
delay 0.02
  end repeat
  
aWindow’s |close|()
end closeWin:

–Popup Action Handler
on actionHandler:sender
  set aTag to tag of sender as integer
  
set aTitle to title of sender as string
end actionHandler:

–aMaxValを最大値とする数値でNSColorを作成して返す
on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
  
return aColor
end makeNSColorFromRGBAval

–指定サイズのNSImageを作成し、指定色で塗ってNSImageで返す
on makeNSImageWithFilledWithColor(aWidth as integer, aHeight as integer, fillColor)
  set anImage to NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))
  
anImage’s lockFocus()
  
—
  
set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}}
  
set theNSBezierPath to NSBezierPath’s bezierPath
  
theNSBezierPath’s appendBezierPathWithRect:theRect
  
—
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
—
  
anImage’s unlockFocus()
  
—
  
return anImage
end makeNSImageWithFilledWithColor

–指定サイズのNSImageを作成し、指定色で塗ってNSImageで返す、anRadiusの半径の角丸で
on makeRoundedNSImageWithFilledWithColor(aWidth as integer, aHeight as integer, fillColor, anRadius as real)
  set anImage to NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))
  
anImage’s lockFocus()
  
—
  
set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}}
  
set theNSBezierPath to NSBezierPath’s bezierPathWithRoundedRect:theRect xRadius:anRadius yRadius:anRadius
  
—
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
—
  
anImage’s unlockFocus()
  
  
return anImage
end makeRoundedNSImageWithFilledWithColor

on uniquifyList(aList as list)
  set aArray to NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquifyList

on findDataFrom2DList(anItem, aList as list)
  script spd
    property aList : {}
    
property resList : {}
  end script
  
  
set (aList of spd) to aList
  
set (resList of spd) to {}
  
  
set yCount to 1
  
  
repeat with i in (aList of spd)
    
    
set aResList to (Bplus’s indexesOfItem:anItem inList:i inverting:false) as list
    
    
set tmpList to {}
    
if aResList is not equal to {} then
      repeat with ii in aResList
        set jj to contents of ii
        
set the end of tmpList to {jj, yCount}
      end repeat
      
set (resList of spd) to (resList of spd) & tmpList
    end if
    
    
set yCount to yCount + 1
  end repeat
  
  
return (resList of spd) –return {{x, y}…..} item list (1-based)
end findDataFrom2DList

on retRangeFromPosListVertival(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
–縦方向へのrange評価に都合がいいようにソート
  
set (posList2 of rangeSPD) to shellSortListAscending(posList, {1, 2}) of me
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 = tmpX) and (curY1 + 1 = tmpY) then
      –Y方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListVertival

on retRangeFromPosListHorizontal(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
copy posList to (posList2 of rangeSPD)
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 + 1 = tmpX) and (curY1 = tmpY) then
      –X方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListHorizontal

–2008/05/01 By Takaaki Naganoya
–10進数数値をExcel 2004/2008的カラム表現にエンコードするサブルーチン を使いまわし
–1〜1351までの間であれば正しいエンコーディング結果を返す
on aNumToExcelColumn(origNum as integer)
  if origNum > 1351 then
    error "エラー:Excel 2004/2008的カラム表現(A1形式)への変換ルーチンにおいて、想定範囲外(1351以上)のパラメータが指定されました"
  end if
  
  
set upperDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
set lowerDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
  
set oNum to origNum
  
set nTh to 26
  
set stringLength to 4
  
  
–数字が1桁の場合の対応
  
if origNum < 27 then
    set aRes to (item origNum of upperDigitEncTable) as string
    
return aRes
  end if
  
  
  
if origNum > 702 then
    –3桁になる場合
    
set upupNum to oNum div 676 –整数除算–上の上の桁
    
set oNum to oNum – (upupNum * 676)
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upupChar to (item upupNum of upperDigitEncTable) as string
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upupChar & upChar & lowChar
    
  else
    –2桁の場合
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upChar & lowChar
    
  end if
  
  
return resText
end aNumToExcelColumn

–入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
  return sort2DList(a, keyItem, {true}) of me
end shellSortListAscending

–入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
  return sort2DList(a, keyItem, {false}) of me
end shellSortListDecending

–2D Listをソート
on sort2DList(aList as list, sortIndexes as list, sortOrders as list)
  
  
–index値をAS流(アイテムが1はじまり)からCocoa流(アイテムが0はじまり)に変換
  
set newIndex to {}
  
repeat with i in sortIndexes
    set j to contents of i
    
set j to j – 1
    
set the end of newIndex to j
  end repeat
  
  
–Sort TypeのListを作成(あえて外部から指定する内容でもない)
  
set sortTypes to {}
  
repeat (length of sortIndexes) times
    set the end of sortTypes to "compare:"
  end repeat
  
  
–Sort
  
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:newIndex ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list
  
  
return resList
end sort2DList

★Click Here to Open This Script 

Posted in Color GUI | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote NSArray NSBezierPath NSButton NSColor NSImage NSMenu NSMenuItem NSPopUpButton NSScreen NSTextField NSView NSWindow NSWindowController | 1 Comment

Numbers書類の現在のシート上の表1の背景色を置換 v1

Posted on 1月 31, 2019 by Takaaki Naganoya

Numbersでオープン中の最前面の書類の現在表示中のシートに存在する表1の背景色を置換するAppleScriptです。

Pages用のScriptをごく一部修正してNumbersの表に対して処理できるようにしてみました。macOS 10.11, 10.12, 10.13ではスクリプトエディタ上で動作します。macOS 10.14ではSIPを解除してスクリプトエディタで動かすか、アプレット形式で書き出して、アプレットのバンドル中にdbColNamesKit.frameworkを入れると動きます。

Script DebuggerとScript Menu上では動作しません。

ポップアップメニュー中に色の名称の動的な推定に、オープンソースの「DBColorNames」をフレームワーク化した
「dbColNamesKit.framework」を利用しています。

–> dbColNamesKit.framework (To ~/Library/Frameworks)

AppleScript名:Numbers書類の現在のシート上の表1の背景色を置換 v1
— Created 2019-01-29 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "dbColNamesKit" –https://github.com/daniel-beard/DBColorNames/
use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

–v1:Change Pages part to Numbers

property NSView : a reference to current application’s NSView
property NSColor : a reference to current application’s NSColor
property NSArray : a reference to current application’s NSArray
property NSMenu : a reference to current application’s NSMenu
property NSImage : a reference to current application’s NSImage
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property NSWindow : a reference to current application’s NSWindow
property NSTextField : a reference to current application’s NSTextField
property NSMenuItem : a reference to current application’s NSMenuItem
property NSBezierPath : a reference to current application’s NSBezierPath
property NSPopUpButton : a reference to current application’s NSPopUpButton
property NSWindowController : a reference to current application’s NSWindowController
property NSTitledWindowMask : a reference to current application’s NSTitledWindowMask
property NSRoundedBezelStyle : a reference to current application’s NSRoundedBezelStyle
property NSFloatingWindowLevel : a reference to current application’s NSFloatingWindowLevel
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property NSMomentaryLightButton : a reference to current application’s NSMomentaryLightButton

property windisp : true
property wController : missing value
property pop1ind : 1

–初期化
set (my windisp) to true
set (my pop1ind) to 1
load framework

–Pagesの1ページ目にある表の塗り色を取得
tell application "Numbers"
  tell front document
    tell active sheet
      tell table 1
        set c1List to background color of every cell
        
set aProp to properties
        
set xCount to column count of aProp
      end tell
    end tell
  end tell
end tell

–Convert 1D List to 2D List
set c3List to (current application’s SMSForder’s subarraysFrom:c1List groupedBy:xCount |error|:(missing value)) as list

–色データをユニーク化(重複削除)
set bList to uniquifyList(c1List) of me

–missing value(背景色なし)を除外する
set c2List to (current application’s SMSForder’s arrayByDeletingBlanksIn:(bList)) as list

–Popup Menuで置換色選択
set paramObj to {c2List, 65535, "OK", "Select Target Color", 180} –Timeout = 180 sec, Color val range = 16bit
my performSelectorOnMainThread:"getPopupValues:" withObject:(paramObj) waitUntilDone:true
if pop1ind = false then return –timed out
set fromCol to (contents of item pop1ind of c2List)

–カラーピッカーで置換色選択
set tCol to choose color default color fromCol

set d1 to current date

–実際に表の背景色を置換する
set hitList to findDataFrom2DList(fromCol, c3List) of me –データ上で当該色のセル情報を計算する

–Rangeを横スキャンと縦スキャンの2通りで試算(Two way Simulation)
set rList1 to retRangeFromPosListHorizontal(hitList) of me –横方向へのrange評価
set rList2 to retRangeFromPosListVertival(hitList) of me –縦方向へのrange評価

–Simulationの結果、要素数の少ない方(=処理時間の短い方=高速な方)を採用する
if (length of rList1) < (length of rList2) then
  copy rList1 to rangeList
else
  copy rList2 to rangeList
end if

tell application "Numbers"
  activate
  
tell front document
    tell active sheet
      tell table 1
        repeat with i in rangeList
          set j to contents of i
          
          
ignoring application responses –非同期実行モードで高速実行
            set background color of range j to tCol
          end ignoring
          
        end repeat
      end tell
    end tell
  end tell
end tell

set d2 to current date
return d2 – d1

–カラーポップアップメニューをウィンドウ表示
on getPopupValues:paramObj
  copy (paramObj as list) to {ap1List, aColMax, aButtonMSG, aSliderValMSG, timeOutSecs}
  
  
set (my windisp) to true
  
  
set aView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 360, 100))
  
  
–Labelをつくる
  
set a1TF to NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(30, 60, 80, 20))
  
a1TF’s setEditable:false
  
a1TF’s setStringValue:"Color:"
  
a1TF’s setDrawsBackground:false
  
a1TF’s setBordered:false
  
  
–Ppopup Buttonをつくる
  
set a1Button to NSPopUpButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(80, 60, 200, 20)) pullsDown:false
  
a1Button’s removeAllItems()
  
  
set a1Menu to NSMenu’s alloc()’s init()
  
set aCDB to current application’s DBColorNames’s alloc()’s init()
  
  
set iCount to 1
  
repeat with i in ap1List
    copy i to {r1, g1, b1}
    
    
set nsCol to makeNSColorFromRGBAval(r1, g1, b1, aColMax, aColMax) of me
    
set anImage to makeRoundedNSImageWithFilledWithColor(64, 64, nsCol, 4) of me
    
    
set aTitle to "#" & (iCount as string) & " " & (aCDB’s nameForColor:nsCol) as string
    
set aMenuItem to (NSMenuItem’s alloc()’s initWithTitle:aTitle action:"actionHandler:" keyEquivalent:"")
    (
aMenuItem’s setImage:anImage)
    (
aMenuItem’s setEnabled:true)
    (
a1Menu’s addItem:aMenuItem)
    
    
set iCount to iCount + 1
  end repeat
  
  
a1Button’s setMenu:a1Menu
  
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(80, 10, 140, 40)))
  
bButton’s setButtonType:(NSMomentaryLightButton)
  
bButton’s setBezelStyle:(NSRoundedBezelStyle)
  
bButton’s setTitle:aButtonMSG
  
bButton’s setTarget:me
  
bButton’s setAction:("clicked:")
  
bButton’s setKeyEquivalent:(return)
  
  
aView’s addSubview:a1TF
  
  
aView’s addSubview:a1Button
  
aView’s addSubview:bButton
  
aView’s setNeedsDisplay:true
  
  
–NSWindowControllerを作ってみた(いらない?)
  
set aWin to (my makeWinWithView(aView, 300, 100, aSliderValMSG))
  
  
set wController to NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
  
wController’s showWindow:me
  
  
set aCount to timeOutSecs * 100
  
  
set hitF to false
  
repeat aCount times
    if (my windisp) = false then
      set hitF to true
      
exit repeat
    end if
    
delay 0.01
    
set aCount to aCount – 1
  end repeat
  
  
my closeWin:aWin
  
  
if hitF = true then
    set s1Val to ((a1Button’s indexOfSelectedItem() as number) + 1)
  else
    set s1Val to false
  end if
  
  
copy s1Val to my pop1ind
  
end getPopupValues:

on clicked:aSender
  set (my windisp) to false
end clicked:

–make Window for Display
on makeWinWithView(aView, aWinWidth as integer, aWinHeight as integer, aTitle as string)
  set aScreen to NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
  
set aBacking to NSTitledWindowMask
  
  
set aDefer to NSBackingStoreBuffered
  
  
— Window
  
set aWin to NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
  
aWin’s setTitle:aTitle
  
aWin’s setDelegate:me
  
aWin’s setDisplaysWhenScreenProfileChanges:true
  
aWin’s setHasShadow:true
  
aWin’s setIgnoresMouseEvents:false
  
aWin’s setLevel:(NSFloatingWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
  
aWin’s setContentView:aView
  
  
return aWin
end makeWinWithView

–close win
on closeWin:aWindow
  repeat with n from 10 to 1 by -1
    (aWindow’s setAlphaValue:n / 10)
    
delay 0.02
  end repeat
  
aWindow’s |close|()
end closeWin:

–Popup Action Handler
on actionHandler:sender
  set aTag to tag of sender as integer
  
set aTitle to title of sender as string
end actionHandler:

–aMaxValを最大値とする数値でNSColorを作成して返す
on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
  
return aColor
end makeNSColorFromRGBAval

–指定サイズのNSImageを作成し、指定色で塗ってNSImageで返す
on makeNSImageWithFilledWithColor(aWidth as integer, aHeight as integer, fillColor)
  set anImage to NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))
  
anImage’s lockFocus()
  
—
  
set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}}
  
set theNSBezierPath to NSBezierPath’s bezierPath
  
theNSBezierPath’s appendBezierPathWithRect:theRect
  
—
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
—
  
anImage’s unlockFocus()
  
—
  
return anImage
end makeNSImageWithFilledWithColor

–指定サイズのNSImageを作成し、指定色で塗ってNSImageで返す、anRadiusの半径の角丸で
on makeRoundedNSImageWithFilledWithColor(aWidth as integer, aHeight as integer, fillColor, anRadius as real)
  set anImage to NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))
  
anImage’s lockFocus()
  
—
  
set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}}
  
set theNSBezierPath to NSBezierPath’s bezierPathWithRoundedRect:theRect xRadius:anRadius yRadius:anRadius
  
—
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
—
  
anImage’s unlockFocus()
  
  
return anImage
end makeRoundedNSImageWithFilledWithColor

on uniquifyList(aList as list)
  set aArray to NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquifyList

on findDataFrom2DList(anItem, aList as list)
  script spd
    property aList : {}
    
property resList : {}
  end script
  
  
set (aList of spd) to aList
  
set (resList of spd) to {}
  
  
set yCount to 1
  
  
repeat with i in (aList of spd)
    
    
set aResList to (Bplus’s indexesOfItem:anItem inList:i inverting:false) as list
    
    
set tmpList to {}
    
if aResList is not equal to {} then
      repeat with ii in aResList
        set jj to contents of ii
        
set the end of tmpList to {jj, yCount}
      end repeat
      
set (resList of spd) to (resList of spd) & tmpList
    end if
    
    
set yCount to yCount + 1
  end repeat
  
  
return (resList of spd) –return {{x, y}…..} item list (1-based)
end findDataFrom2DList

on retRangeFromPosListVertival(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
–縦方向へのrange評価に都合がいいようにソート
  
set (posList2 of rangeSPD) to shellSortListAscending(posList, {1, 2}) of me
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 = tmpX) and (curY1 + 1 = tmpY) then
      –Y方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListVertival

on retRangeFromPosListHorizontal(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
copy posList to (posList2 of rangeSPD)
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 + 1 = tmpX) and (curY1 = tmpY) then
      –X方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListHorizontal

–2008/05/01 By Takaaki Naganoya
–10進数数値をExcel 2004/2008的カラム表現にエンコードするサブルーチン を使いまわし
–1〜1351までの間であれば正しいエンコーディング結果を返す
on aNumToExcelColumn(origNum as integer)
  if origNum > 1351 then
    error "エラー:Excel 2004/2008的カラム表現(A1形式)への変換ルーチンにおいて、想定範囲外(1351以上)のパラメータが指定されました"
  end if
  
  
set upperDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
set lowerDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
  
set oNum to origNum
  
set nTh to 26
  
set stringLength to 4
  
  
–数字が1桁の場合の対応
  
if origNum < 27 then
    set aRes to (item origNum of upperDigitEncTable) as string
    
return aRes
  end if
  
  
  
if origNum > 702 then
    –3桁になる場合
    
set upupNum to oNum div 676 –整数除算–上の上の桁
    
set oNum to oNum – (upupNum * 676)
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upupChar to (item upupNum of upperDigitEncTable) as string
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upupChar & upChar & lowChar
    
  else
    –2桁の場合
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upChar & lowChar
    
  end if
  
  
return resText
end aNumToExcelColumn

–入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
  return sort2DList(a, keyItem, {true}) of me
end shellSortListAscending

–入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
  return sort2DList(a, keyItem, {false}) of me
end shellSortListDecending

–2D Listをソート
on sort2DList(aList as list, sortIndexes as list, sortOrders as list)
  
  
–index値をAS流(アイテムが1はじまり)からCocoa流(アイテムが0はじまり)に変換
  
set newIndex to {}
  
repeat with i in sortIndexes
    set j to contents of i
    
set j to j – 1
    
set the end of newIndex to j
  end repeat
  
  
–Sort TypeのListを作成(あえて外部から指定する内容でもない)
  
set sortTypes to {}
  
repeat (length of sortIndexes) times
    set the end of sortTypes to "compare:"
  end repeat
  
  
–Sort
  
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:newIndex ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list
  
  
return resList
end sort2DList

★Click Here to Open This Script 

Posted in Color GUI | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSBezierPath NSButton NSColor NSImage NSMenu NSMenuItem NSPopUpButton NSRoundedBezelStyle NSScreen NSTextField NSTitledWindowMask NSView NSWindow NSWindowController Numbers | Leave a comment

Pages書類の1ページ目の表の背景色を置換 v4

Posted on 1月 30, 2019 by Takaaki Naganoya

Pagesでオープン中の最前面の書類の1ページ目に存在する表オブジェクト中の背景色を置換するAppleScriptです。

例によって、Pages書類上の表オブジェクトは「配置」を「移動しない」に設定しないとAppleScriptからアクセスできないので、あらかじめ「移動しない」設定にしておく必要があります。

本バージョンでは、データの連続部分をrangeとしてまとめて処理する方法を、1行ずつ横方向に(左→右)スキャンした場合と、1列ずつ(上→下)縦方向にスキャンした場合の2パターンで処理し、より少ないデータ単位(より多くのセルを一括で指定)で処理できる方の方式を採用するようにしました。

このため、処理データによって塗りつぶし動作が変わってきます。横方向のみのスキャンでは大幅に遅くなるタイプのデータ(縦に処理対象セルが並んでいて、横方向にはつながっていない)でも「遅くならない」ことがテーマです。

ほかには、オープンソースの「DBColorNames」を利用して色から色名称を動的に取得したり、ポップアップメニューに表示する色イメージ画像を角丸にしたりしています。

–> dbColNamesKit.framework (To ~/Library/Frameworks)

これ以上の高速化は、「縦横混在のrangeシミュレーション」でも行わないとできないと思いますが、方法についてはいろいろ思いつくので論理的には可能だと思います。ただ、単に塗りつぶしを高速化するためだけに何日も試行錯誤するのはちょっと………なので、このぐらいにしておこうかと。

macOS 10.14上では、「csrutil disable」でSIPをオフにすると、ホームディレクトリ下の~/Library/Frameworksフォルダ内のFrameworkにアクセスでき、本Scriptをそのままスクリプトエディタで実行できました。アプレット形式で書き出して、アプレット内にFrameworkを入れればSIPをオフにしなくても実行できるはずです。Script Debugger/Script Menu上では実行できないというあたりが困りどころです。

AppleScript名:Pages書類の1ページ目の表の背景色を置換 v4.1
— Created 2017-07-15 by Takaaki Naganoya
— Modified 2019-01-29 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "dbColNamesKit" –https://github.com/daniel-beard/DBColorNames/
use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

–v1:First Version
–v2:Pick Up target cells by calculate every background color (35% speed up)
–v3:Draw cells by range (x20 speed up)
–v3.1:Bug Fix (retRangeFromPosList)
–v3.1.1:Bug Fix (retRangeFromPosList)
–v4:Two-way Simulation (Horizontal / Vertical scan), Corner-Rounded NSImage, Dynamic Color Naming
–v4.1:Correct Vertical Scan simulation (Sort list for vertical range evaluation, at first)

property NSView : a reference to current application’s NSView
property NSColor : a reference to current application’s NSColor
property NSArray : a reference to current application’s NSArray
property NSMenu : a reference to current application’s NSMenu
property NSImage : a reference to current application’s NSImage
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property NSWindow : a reference to current application’s NSWindow
property NSTextField : a reference to current application’s NSTextField
property NSMenuItem : a reference to current application’s NSMenuItem
property NSBezierPath : a reference to current application’s NSBezierPath
property NSPopUpButton : a reference to current application’s NSPopUpButton
property NSWindowController : a reference to current application’s NSWindowController
property NSTitledWindowMask : a reference to current application’s NSTitledWindowMask
property NSRoundedBezelStyle : a reference to current application’s NSRoundedBezelStyle
property NSFloatingWindowLevel : a reference to current application’s NSFloatingWindowLevel
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property NSMomentaryLightButton : a reference to current application’s NSMomentaryLightButton

property windisp : true
property wController : missing value
property pop1ind : 1

–初期化
set (my windisp) to true
set (my pop1ind) to 1
load framework

–Pagesの1ページ目にある表の塗り色を取得
tell application "Pages"
  tell front document
    tell table 1
      set c1List to background color of every cell
      
set aProp to properties
      
set xCount to column count of aProp
    end tell
  end tell
end tell

–色データをユニーク化(重複削除)
set bList to uniquifyList(c1List) of me

–Convert 1D List to 2D List
set c3List to (current application’s SMSForder’s subarraysFrom:c1List groupedBy:xCount |error|:(missing value)) as list

–missing value(背景色なし)を除外する
set c2List to (current application’s SMSForder’s arrayByDeletingBlanksIn:(bList)) as list

–Popup Menuで置換色選択
set paramObj to {c2List, 65535, "OK", "Select Target Color", 180} –Timeout = 180 sec, Color val range = 16bit
my performSelectorOnMainThread:"getPopupValues:" withObject:(paramObj) waitUntilDone:true
if pop1ind = false then return –timed out
set fromCol to (contents of item pop1ind of c2List)

–カラーピッカーで置換色選択
set tCol to choose color default color fromCol

set d1 to current date

–実際に表の背景色を置換する
set hitList to findDataFrom2DList(fromCol, c3List) of me –データ上で当該色のセル情報を計算する

–Rangeを横スキャンと縦スキャンの2通りで試算(Two way Simulation)
set rList1 to retRangeFromPosListHorizontal(hitList) of me –横方向へのrange評価
set rList2 to retRangeFromPosListVertival(hitList) of me –縦方向へのrange評価

–Simulationの結果、要素数の少ない方(=処理時間の短い方=高速な方)を採用する
log {"Simulation", (length of rList1), (length of rList2)}
if (length of rList1) < (length of rList2) then
  copy rList1 to rangeList
else
  copy rList2 to rangeList
end if

tell application "Pages"
  activate
  
tell front document
    tell table 1
      repeat with i in rangeList
        set j to contents of i
        
        
ignoring application responses –非同期実行モードで高速実行
          set background color of range j to tCol
        end ignoring
        
      end repeat
    end tell
  end tell
end tell

set d2 to current date
return d2 – d1

–カラーポップアップメニューをウィンドウ表示
on getPopupValues:paramObj
  copy (paramObj as list) to {ap1List, aColMax, aButtonMSG, aSliderValMSG, timeOutSecs}
  
  
set (my windisp) to true
  
  
set aView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 360, 100))
  
  
–Labelをつくる
  
set a1TF to NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(30, 60, 80, 20))
  
a1TF’s setEditable:false
  
a1TF’s setStringValue:"Color:"
  
a1TF’s setDrawsBackground:false
  
a1TF’s setBordered:false
  
  
–Ppopup Buttonをつくる
  
set a1Button to NSPopUpButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(80, 60, 200, 20)) pullsDown:false
  
a1Button’s removeAllItems()
  
  
set a1Menu to NSMenu’s alloc()’s init()
  
set aCDB to current application’s DBColorNames’s alloc()’s init()
  
  
set iCount to 1
  
repeat with i in ap1List
    copy i to {r1, g1, b1}
    
    
set nsCol to makeNSColorFromRGBAval(r1, g1, b1, aColMax, aColMax) of me
    
set anImage to makeRoundedNSImageWithFilledWithColor(64, 64, nsCol, 4) of me
    
    
set aTitle to "#" & (iCount as string) & " " & (aCDB’s nameForColor:nsCol) as string
    
set aMenuItem to (NSMenuItem’s alloc()’s initWithTitle:aTitle action:"actionHandler:" keyEquivalent:"")
    (
aMenuItem’s setImage:anImage)
    (
aMenuItem’s setEnabled:true)
    (
a1Menu’s addItem:aMenuItem)
    
    
set iCount to iCount + 1
  end repeat
  
  
a1Button’s setMenu:a1Menu
  
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(80, 10, 140, 40)))
  
bButton’s setButtonType:(NSMomentaryLightButton)
  
bButton’s setBezelStyle:(NSRoundedBezelStyle)
  
bButton’s setTitle:aButtonMSG
  
bButton’s setTarget:me
  
bButton’s setAction:("clicked:")
  
bButton’s setKeyEquivalent:(return)
  
  
aView’s addSubview:a1TF
  
  
aView’s addSubview:a1Button
  
aView’s addSubview:bButton
  
aView’s setNeedsDisplay:true
  
  
–NSWindowControllerを作ってみた(いらない?)
  
set aWin to (my makeWinWithView(aView, 300, 100, aSliderValMSG))
  
  
set wController to NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
  
wController’s showWindow:me
  
  
set aCount to timeOutSecs * 100
  
  
set hitF to false
  
repeat aCount times
    if (my windisp) = false then
      set hitF to true
      
exit repeat
    end if
    
delay 0.01
    
set aCount to aCount – 1
  end repeat
  
  
my closeWin:aWin
  
  
if hitF = true then
    set s1Val to ((a1Button’s indexOfSelectedItem() as number) + 1)
  else
    set s1Val to false
  end if
  
  
copy s1Val to my pop1ind
  
end getPopupValues:

on clicked:aSender
  set (my windisp) to false
end clicked:

–make Window for Display
on makeWinWithView(aView, aWinWidth as integer, aWinHeight as integer, aTitle as string)
  set aScreen to NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
  
set aBacking to NSTitledWindowMask
  
  
set aDefer to NSBackingStoreBuffered
  
  
— Window
  
set aWin to NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
  
aWin’s setTitle:aTitle
  
aWin’s setDelegate:me
  
aWin’s setDisplaysWhenScreenProfileChanges:true
  
aWin’s setHasShadow:true
  
aWin’s setIgnoresMouseEvents:false
  
aWin’s setLevel:(NSFloatingWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
  
aWin’s setContentView:aView
  
  
return aWin
end makeWinWithView

–close win
on closeWin:aWindow
  repeat with n from 10 to 1 by -1
    (aWindow’s setAlphaValue:n / 10)
    
delay 0.02
  end repeat
  
aWindow’s |close|()
end closeWin:

–Popup Action Handler
on actionHandler:sender
  set aTag to tag of sender as integer
  
set aTitle to title of sender as string
end actionHandler:

–aMaxValを最大値とする数値でNSColorを作成して返す
on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
  
return aColor
end makeNSColorFromRGBAval

–指定サイズのNSImageを作成し、指定色で塗ってNSImageで返す
on makeNSImageWithFilledWithColor(aWidth as integer, aHeight as integer, fillColor)
  set anImage to NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))
  
anImage’s lockFocus()
  
—
  
set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}}
  
set theNSBezierPath to NSBezierPath’s bezierPath
  
theNSBezierPath’s appendBezierPathWithRect:theRect
  
—
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
—
  
anImage’s unlockFocus()
  
—
  
return anImage
end makeNSImageWithFilledWithColor

–指定サイズのNSImageを作成し、指定色で塗ってNSImageで返す、anRadiusの半径の角丸で
on makeRoundedNSImageWithFilledWithColor(aWidth as integer, aHeight as integer, fillColor, anRadius as real)
  set anImage to NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))
  
anImage’s lockFocus()
  
—
  
set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}}
  
set theNSBezierPath to NSBezierPath’s bezierPathWithRoundedRect:theRect xRadius:anRadius yRadius:anRadius
  
—
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
—
  
anImage’s unlockFocus()
  
  
return anImage
end makeRoundedNSImageWithFilledWithColor

on uniquifyList(aList as list)
  set aArray to NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquifyList

on findDataFrom2DList(anItem, aList as list)
  script spd
    property aList : {}
    
property resList : {}
  end script
  
  
set (aList of spd) to aList
  
set (resList of spd) to {}
  
  
set yCount to 1
  
  
repeat with i in (aList of spd)
    
    
set aResList to (Bplus’s indexesOfItem:anItem inList:i inverting:false) as list
    
    
set tmpList to {}
    
if aResList is not equal to {} then
      repeat with ii in aResList
        set jj to contents of ii
        
set the end of tmpList to {jj, yCount}
      end repeat
      
set (resList of spd) to (resList of spd) & tmpList
    end if
    
    
set yCount to yCount + 1
  end repeat
  
  
return (resList of spd) –return {{x, y}…..} item list (1-based)
end findDataFrom2DList

on retRangeFromPosListVertival(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
–縦方向へのrange評価に都合がいいようにソート
  
set (posList2 of rangeSPD) to shellSortListAscending(posList, {1, 2}) of me
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 = tmpX) and (curY1 + 1 = tmpY) then
      –Y方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListVertival

on retRangeFromPosListHorizontal(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
copy posList to (posList2 of rangeSPD)
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 + 1 = tmpX) and (curY1 = tmpY) then
      –X方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListHorizontal

–2008/05/01 By Takaaki Naganoya
–10進数数値をExcel 2004/2008的カラム表現にエンコードするサブルーチン を使いまわし
–1〜1351までの間であれば正しいエンコーディング結果を返す
on aNumToExcelColumn(origNum as integer)
  if origNum > 1351 then
    error "エラー:Excel 2004/2008的カラム表現(A1形式)への変換ルーチンにおいて、想定範囲外(1351以上)のパラメータが指定されました"
  end if
  
  
set upperDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
set lowerDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
  
set oNum to origNum
  
set nTh to 26
  
set stringLength to 4
  
  
–数字が1桁の場合の対応
  
if origNum < 27 then
    set aRes to (item origNum of upperDigitEncTable) as string
    
return aRes
  end if
  
  
  
if origNum > 702 then
    –3桁になる場合
    
set upupNum to oNum div 676 –整数除算–上の上の桁
    
set oNum to oNum – (upupNum * 676)
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upupChar to (item upupNum of upperDigitEncTable) as string
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upupChar & upChar & lowChar
    
  else
    –2桁の場合
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upChar & lowChar
    
  end if
  
  
return resText
end aNumToExcelColumn

–入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
  return sort2DList(a, keyItem, {true}) of me
end shellSortListAscending

–入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
  return sort2DList(a, keyItem, {false}) of me
end shellSortListDecending

–2D Listをソート
on sort2DList(aList as list, sortIndexes as list, sortOrders as list)
  
  
–index値をAS流(アイテムが1はじまり)からCocoa流(アイテムが0はじまり)に変換
  
set newIndex to {}
  
repeat with i in sortIndexes
    set j to contents of i
    
set j to j – 1
    
set the end of newIndex to j
  end repeat
  
  
–Sort TypeのListを作成(あえて外部から指定する内容でもない)
  
set sortTypes to {}
  
repeat (length of sortIndexes) times
    set the end of sortTypes to "compare:"
  end repeat
  
  
–Sort
  
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:newIndex ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list
  
  
return resList
end sort2DList

★Click Here to Open This Script 

Posted in Color GUI list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSBezierPath NSButton NSColor NSImage NSMenu NSMenuItem NSPopUpButton NSScreen NSTextField NSView NSWindow NSWindowController Pages | 2 Comments

Pages書類の1ページ目の表の背景色を置換 v3.1(約20倍速)

Posted on 1月 29, 2019 by Takaaki Naganoya

Pagesでオープン中の最前面の書類の1ページ目に存在する表オブジェクト中の背景色を置換するAppleScriptの高速化版です。

初版では表中のセルをすべて取得し、すべてのセルについて順次背景色を求め、置換対象色であれば塗り直していました。セル1個ずつ塗っていたので、それなりの時間(テストデータでは20秒)がかかっていました。GUIアプリケーションを操作するために存在しているAppleScriptですが、アプリケーションとの通信はコストが高いので、この通信部分を減らすことが高速化の基本です。

ちなみに、「ignoring application responses」〜「end ignoring」で囲った範囲は非同期実行モードで実行され、2.5倍ぐらい高速になります。AppleScriptでは、GUIアプリケーションに対してコマンドを実行した場合、「コマンド実行」「コマンド処理」「コマンド結果受信」の3ステップを行なっています。非同期実行モードでは「コマンド実行」だけを行うので高速ですが、設定値や状態を知りたいような場合には(結果が返ってこないので)使う意味がありません。本Blogを「ignoring application responses」で検索しても、あまり出てこないはずです。

v2では、高速化のために全セルの背景色を抽出したあとに、2次元配列データ上で当該セルの座標を計算し、塗り替え対象セルのみ処理することで約35%のスピードアップを行いました。GUIアプリケーションにコマンドを送る(そして、処理を待って結果を受信する)よりも配列変数上で検索を行ったほうがはるかに高速です。

本v3では、さらなる高速化のために、2次元配列データ上で当該セルの座標を計算したあと、それらを横方向にスキャンして、点ではなく範囲(range)として評価し、極力複数のセルを連続する範囲(range)としてまとめて、rangeを一括塗りすることで初版から約20倍の高速化を行なったものです。v1やv2ではセルを1つずつ塗りつぶしていましたが、v3からは横方向に複数まとめてぬりつぶします。

実際のPages書類上の表の塗りつぶし領域が、ヘッダーや年表のような横方向に連続した塗りエリアを持つことが多いことに着目して、複数セルを一度に塗りつぶすことで高速化しました(1セル塗るのと複数セルを塗るのとで時間かわらず)。本Scriptでも1マスごとに塗りつぶしが存在するようなハッチング模様の表の塗りつぶし色を変更する場合にはパフォーマンスが最悪の状態に落ち込みますが、v2のレベル以下に落ちることはないでしょう。

この世のどこかには、さらにデータを1D Arrayではなく2D Arrayとして評価して、最大限まとめた面積のrangeとみなすことで本ルーチンの2倍ぐらいの速度で処理できるプログラムも存在しそうですが、人類の叡智のレベルを超えそうなので、自分はこのぐらいの速度が出れば満足です(総当たり的なアプローチで全パターンをシミュレーションして、一番いい結果が出るものを採用というのも考えないではないですが、シミュレーションをていねいに行うと処理時間が余計にかかるので、、、)。

1D Listに入っている座標値をX軸方向に評価して、連続値であればrangeに変換するルーチン「retRangeFromPosList」については、それほど真剣にテストしていないので処理が間違っている可能性もあります。
→ 処理に誤りがあったので修正しました(v3.1)

また、数値からExcelのA1形式のアドレスに変換するために作ってホコリをかぶっていた「aNumToExcelColumn」ルーチンも、一応テストはしてありますが変換できるアドレスの上限値が存在しているため注意が必要です。

AppleScript名:Pages書類の1ページ目の表の背景色を置換 v3.11
— Created 2017-07-15 by Takaaki Naganoya
— Modified 2019-01-29 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

–v1:First Version
–v2:Pick Up target cells by calculate every background color (35% speed up)
–v3:Draw cells by range (x20 speed up)
–v3.1:Bug Fix (retRangeFromPosList)
–v3.1.1:Bug Fix (retRangeFromPosList)

property NSView : a reference to current application’s NSView
property NSColor : a reference to current application’s NSColor
property NSArray : a reference to current application’s NSArray
property NSMenu : a reference to current application’s NSMenu
property NSImage : a reference to current application’s NSImage
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property NSWindow : a reference to current application’s NSWindow
property NSTextField : a reference to current application’s NSTextField
property NSMenuItem : a reference to current application’s NSMenuItem
property NSBezierPath : a reference to current application’s NSBezierPath
property NSPopUpButton : a reference to current application’s NSPopUpButton
property NSWindowController : a reference to current application’s NSWindowController
property NSTitledWindowMask : a reference to current application’s NSTitledWindowMask
property NSRoundedBezelStyle : a reference to current application’s NSRoundedBezelStyle
property NSNormalWindowLevel : a reference to current application’s NSNormalWindowLevel
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property NSMomentaryLightButton : a reference to current application’s NSMomentaryLightButton

property windisp : true
property wController : missing value
property pop1ind : 1

–初期化
set (my windisp) to true
set (my pop1ind) to 1
load framework

–Pagesの1ページ目にある表の塗り色を取得
tell application "Pages"
  tell front document
    tell table 1
      set c1List to background color of every cell
      
set aProp to properties
      
set xCount to column count of aProp
    end tell
  end tell
end tell

–色データをユニーク化(重複削除)
set bList to uniquifyList(c1List) of me

–Convert 1D List to 2D List
set c3List to (current application’s SMSForder’s subarraysFrom:c1List groupedBy:xCount |error|:(missing value)) as list

–missing value(背景色なし)を除外する
load framework
set c2List to (current application’s SMSForder’s arrayByDeletingBlanksIn:(bList)) as list

–Popup Menuで置換色選択
set aButtonMSG to "OK"
set aSliderValMSG to "Select Target Color"
set paramObj to {c2List, 65535, aButtonMSG, aSliderValMSG, 20}
my performSelectorOnMainThread:"getPopupValues:" withObject:(paramObj) waitUntilDone:true
set fromCol to (contents of item pop1ind of c2List)

–カラーピッカーで置換色選択
set tCol to choose color default color fromCol

set d1 to current date

–実際に表の背景色を置換する
set hitList to findDataFrom2DList(fromCol, c3List) of me –データ上で当該色のセル情報を計算する

set rangeList to retRangeFromPosList(hitList) of me

tell application "Pages"
  tell front document
    tell table 1
      repeat with i in rangeList
        set j to contents of i
        
        
ignoring application responses –非同期実行モードで高速実行
          set background color of range j to tCol
        end ignoring
      end repeat
    end tell
  end tell
end tell

set d2 to current date
return d2 – d1

–カラーポップアップメニューをウィンドウ表示
on getPopupValues:paramObj
  copy (paramObj as list) to {ap1List, aColMax, aButtonMSG, aSliderValMSG, timeOutSecs}
  
  
set (my windisp) to true
  
  
set aView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 360, 100))
  
  
–Labelをつくる
  
set a1TF to NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(30, 60, 80, 20))
  
a1TF’s setEditable:false
  
a1TF’s setStringValue:"Color:"
  
a1TF’s setDrawsBackground:false
  
a1TF’s setBordered:false
  
  
–Ppopup Buttonをつくる
  
set a1Button to NSPopUpButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(80, 60, 200, 20)) pullsDown:false
  
a1Button’s removeAllItems()
  
  
set a1Menu to NSMenu’s alloc()’s init()
  
  
set iCount to 1
  
repeat with i in ap1List
    copy i to {r1, g1, b1}
    
    
set nsCol to makeNSColorFromRGBAval(r1, g1, b1, aColMax, aColMax) of me
    
set anImage to makeNSImageWithFilledWithColor(64, 64, nsCol) of me
    
    
set aTitle to "color_" & (iCount as string)
    
set aMenuItem to (NSMenuItem’s alloc()’s initWithTitle:aTitle action:"actionHandler:" keyEquivalent:"")
    (
aMenuItem’s setImage:anImage)
    (
aMenuItem’s setEnabled:true)
    (
a1Menu’s addItem:aMenuItem)
    
    
set iCount to iCount + 1
  end repeat
  
  
a1Button’s setMenu:a1Menu
  
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(80, 10, 140, 40)))
  
bButton’s setButtonType:(NSMomentaryLightButton)
  
bButton’s setBezelStyle:(NSRoundedBezelStyle)
  
bButton’s setTitle:aButtonMSG
  
bButton’s setTarget:me
  
bButton’s setAction:("clicked:")
  
bButton’s setKeyEquivalent:(return)
  
  
aView’s addSubview:a1TF
  
  
aView’s addSubview:a1Button
  
aView’s addSubview:bButton
  
aView’s setNeedsDisplay:true
  
  
–NSWindowControllerを作ってみた(いらない?)
  
set aWin to (my makeWinWithView(aView, 300, 100, aSliderValMSG))
  
  
set wController to NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
  
wController’s showWindow:me
  
  
set aCount to timeOutSecs * 100
  
  
set hitF to false
  
repeat aCount times
    if (my windisp) = false then
      set hitF to true
      
exit repeat
    end if
    
delay 0.01
    
set aCount to aCount – 1
  end repeat
  
  
my closeWin:aWin
  
  
if hitF = true then
    set s1Val to ((a1Button’s indexOfSelectedItem() as number) + 1)
  else
    set s1Val to false
  end if
  
  
copy s1Val to my pop1ind
  
end getPopupValues:

on clicked:aSender
  set (my windisp) to false
end clicked:

–make Window for Display
on makeWinWithView(aView, aWinWidth, aWinHeight, aTitle)
  set aScreen to NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
  
set aBacking to NSTitledWindowMask
  
  
set aDefer to NSBackingStoreBuffered
  
  
— Window
  
set aWin to NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
  
aWin’s setTitle:aTitle
  
aWin’s setDelegate:me
  
aWin’s setDisplaysWhenScreenProfileChanges:true
  
aWin’s setHasShadow:true
  
aWin’s setIgnoresMouseEvents:false
  
aWin’s setLevel:(NSNormalWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
  
aWin’s setContentView:aView
  
  
return aWin
end makeWinWithView

–close win
on closeWin:aWindow
  repeat with n from 10 to 1 by -1
    (aWindow’s setAlphaValue:n / 10)
    
delay 0.02
  end repeat
  
aWindow’s |close|()
end closeWin:

–Popup Action Handler
on actionHandler:sender
  set aTag to tag of sender as integer
  
set aTitle to title of sender as string
end actionHandler:

–aMaxValを最大値とする数値でNSColorを作成して返す
on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
  
return aColor
end makeNSColorFromRGBAval

–指定サイズのNSImageを作成し、指定色で塗ってNSImageで返す
on makeNSImageWithFilledWithColor(aWidth, aHeight, fillColor)
  set anImage to NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))
  
anImage’s lockFocus()
  
—
  
set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}}
  
set theNSBezierPath to NSBezierPath’s bezierPath
  
theNSBezierPath’s appendBezierPathWithRect:theRect
  
—
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
—
  
anImage’s unlockFocus()
  
—
  
return anImage
end makeNSImageWithFilledWithColor

on uniquifyList(aList as list)
  set aArray to NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquifyList

on findDataFrom2DList(anItem, aList)
  script spd
    property aList : {}
    
property resList : {}
  end script
  
  
set (aList of spd) to aList
  
set (resList of spd) to {}
  
  
set yCount to 1
  
  
repeat with i in (aList of spd)
    
    
set aResList to (Bplus’s indexesOfItem:anItem inList:i inverting:false) as list
    
    
set tmpList to {}
    
if aResList is not equal to {} then
      repeat with ii in aResList
        set jj to contents of ii
        
set the end of tmpList to {jj, yCount}
      end repeat
      
set (resList of spd) to (resList of spd) & tmpList
    end if
    
    
set yCount to yCount + 1
  end repeat
  
  
return (resList of spd) –return {{x, y}…..} item list (1-based)
end findDataFrom2DList

on retRangeFromPosList(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
copy posList to (posList2 of rangeSPD)
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 + 1 = tmpX) and (curY1 = tmpY) then
      –X方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosList

–2008/05/01 By Takaaki Naganoya
–10進数数値をExcel 2004/2008的カラム表現にエンコードするサブルーチン を使いまわし
–1〜1351までの間であれば正しいエンコーディング結果を返す
on aNumToExcelColumn(origNum as integer)
  if origNum > 1351 then
    display dialog "エラー:Excel 2004/2008的カラム表現(A1形式)への変換ルーチンにおいて、想定範囲外(1351以上)のパラメータが指定されました" buttons {"OK"} default button 1
    
return ""
  end if
  
  
set upperDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
set lowerDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
  
set oNum to origNum
  
set nTh to 26
  
set stringLength to 4
  
  
–数字が1桁の場合の対応
  
if origNum < 27 then
    set aRes to (item origNum of upperDigitEncTable) as string
    
return aRes
  end if
  
  
  
if origNum > 702 then
    –3桁になる場合
    
set upupNum to oNum div 676 –整数除算–上の上の桁
    
set oNum to oNum – (upupNum * 676)
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upupChar to (item upupNum of upperDigitEncTable) as string
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upupChar & upChar & lowChar
    
  else
    –2桁の場合
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upChar & lowChar
    
  end if
  
  
return resText
end aNumToExcelColumn

★Click Here to Open This Script 

Posted in Color GUI list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSBackingStoreBuffered NSBezierPath NSButton NSColor NSImage NSMenu NSMenuItem NSMomentaryLightButton NSNormalWindowLevel NSPopUpButton NSRoundedBezelStyle NSScreen NSTextField NSTitledWindowMask NSView NSWindow NSWindowController Pages | Leave a comment

Pages書類の1ページ目の表の背景色を置換

Posted on 1月 28, 2019 by Takaaki Naganoya

Pagesでオープン中の最前面の書類の1ページ目に存在する表オブジェクト中の背景色を置換するAppleScriptです。

Pages書類の「表オブジェクト」にAppleScriptからアクセスするためには、Pages上で表オブジェクトを選択した状態で、

「オブジェクトの配置」を「移動しない」に事前に設定しておく必要があります。

本AppleScriptを実行可能なランタイム環境は、スクリプトエディタ、アプレットの2つです。スクリプトメニューおよびScript Debuggerでは各GUI部品のクリックイベントを拾えないために、実行しても選択などが行えません。

のように、1ページのみのPages書類に表オブジェクトを入れて、「移動しない」設定にしてある状態で本AppleScriptを実行。

表のセル中の色をすべて取得して、ユニーク化してポップアップメニューから「変更元」の色を選択できます。

選択して、「OK」ボタンをクリック。ここで選択した色が置換されます。

選択した色をどの色に変更(置換)するのかを指定します。

黒い色を選択。

ちょっと置換に時間がかかりますが(テストデータ+開発環境で20秒前後)、セルの背景色をします。このあたり、Pagesの表オブジェクト中のセルに対して、background colorでフィルタ参照できればよかったのですが、自分が試した範囲ではフィルタ参照で抽出できませんでした。全セルを取得してループで背景色のチェックと置換を行なっています。

こういう機能が最初からPagesに実装されているわけでもないので、手作業よりははるかに高速なのでしばらく放っておけば終わるのでいいんじゃないでしょうか。

本来であれば、指定色に該当するセルをフィルタ参照で抽出して、ヒットしたセルだけでループして背景色を変更できるとベストですが、実際にフィルタ参照で抽出できるかどうかはアプリケーション側の対応度次第なので、実際にやってみないとわかりません。

AppleScript名:Pages書類の1ページ目の表の背景色を置換
— Created 2017-07-15 by Takaaki Naganoya
— Created 2019-01-28 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

property NSView : a reference to current application’s NSView
property NSColor : a reference to current application’s NSColor
property NSArray : a reference to current application’s NSArray
property NSMenu : a reference to current application’s NSMenu
property NSImage : a reference to current application’s NSImage
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property NSWindow : a reference to current application’s NSWindow
property NSTextField : a reference to current application’s NSTextField
property NSMenuItem : a reference to current application’s NSMenuItem
property NSBezierPath : a reference to current application’s NSBezierPath
property NSPopUpButton : a reference to current application’s NSPopUpButton
property NSWindowController : a reference to current application’s NSWindowController
property NSTitledWindowMask : a reference to current application’s NSTitledWindowMask
property NSRoundedBezelStyle : a reference to current application’s NSRoundedBezelStyle
property NSNormalWindowLevel : a reference to current application’s NSNormalWindowLevel
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property NSMomentaryLightButton : a reference to current application’s NSMomentaryLightButton

property windisp : false
property wController : false
property pop1ind : missing value

–Pagesの1ページ目にある表の塗り色を取得
tell application "Pages"
  tell front document
    tell table 1
      set cList to background color of every cell
    end tell
  end tell
end tell

–色データをユニーク化(重複削除)
set bList to uniquifyList(cList) of me

–missing value(背景色なし)を除外する
load framework
set cList to (current application’s SMSForder’s arrayByDeletingBlanksIn:(bList)) as list

–Popup Menuで置換色選択
set aButtonMSG to "OK"
set aSliderValMSG to "Select Target Color"
set paramObj to {cList, 65535, aButtonMSG, aSliderValMSG, 20}
my performSelectorOnMainThread:"getPopupValues:" withObject:(paramObj) waitUntilDone:true

–カラーピッカーで色選択
set fromCol to (contents of item pop1ind of cList)
set tCol to choose color default color fromCol

–実際に表の背景色を置換する
tell application "Pages"
  tell front document
    tell table 1
      set cellList to every cell
      
      
repeat with i in cellList
        set aBG to background color of i
        
        
if aBG = fromCol then
          ignoring application responses
            set background color of i to tCol
          end ignoring
        end if
      end repeat
    end tell
  end tell
end tell

–カラーポップアップメニューをウィンドウ表示
on getPopupValues:paramObj
  copy (paramObj as list) to {ap1List, aColMax, aButtonMSG, aSliderValMSG, timeOutSecs}
  
  
set (my windisp) to true
  
  
set aView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 360, 100))
  
  
–Labelをつくる
  
set a1TF to NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(30, 60, 80, 20))
  
a1TF’s setEditable:false
  
a1TF’s setStringValue:"Color:"
  
a1TF’s setDrawsBackground:false
  
a1TF’s setBordered:false
  
  
–Ppopup Buttonをつくる
  
set a1Button to NSPopUpButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(80, 60, 200, 20)) pullsDown:false
  
a1Button’s removeAllItems()
  
  
set a1Menu to NSMenu’s alloc()’s init()
  
  
set iCount to 0
  
repeat with i in ap1List
    copy i to {r1, g1, b1}
    
    
set nsCol to makeNSColorFromRGBAval(r1, g1, b1, aColMax, aColMax) of me
    
set anImage to makeNSImageWithFilledWithColor(64, 64, nsCol) of me
    
    
set aTitle to "color_" & (iCount as string)
    
set aMenuItem to (NSMenuItem’s alloc()’s initWithTitle:aTitle action:"actionHandler:" keyEquivalent:"")
    (
aMenuItem’s setImage:anImage)
    (
aMenuItem’s setEnabled:true)
    (
a1Menu’s addItem:aMenuItem)
    
    
set iCount to iCount + 1
  end repeat
  
  
a1Button’s setMenu:a1Menu
  
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(80, 10, 140, 40)))
  
bButton’s setButtonType:(NSMomentaryLightButton)
  
bButton’s setBezelStyle:(NSRoundedBezelStyle)
  
bButton’s setTitle:aButtonMSG
  
bButton’s setTarget:me
  
bButton’s setAction:("clicked:")
  
bButton’s setKeyEquivalent:(return)
  
  
aView’s addSubview:a1TF
  
  
aView’s addSubview:a1Button
  
aView’s addSubview:bButton
  
aView’s setNeedsDisplay:true
  
  
–NSWindowControllerを作ってみた(いらない?)
  
set aWin to (my makeWinWithView(aView, 300, 100, aSliderValMSG))
  
  
set wController to NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
  
wController’s showWindow:me
  
  
set aCount to timeOutSecs * 100
  
  
set hitF to false
  
repeat aCount times
    if (my windisp) = false then
      set hitF to true
      
exit repeat
    end if
    
delay 0.01
    
set aCount to aCount – 1
  end repeat
  
  
my closeWin:aWin
  
  
if hitF = true then
    set s1Val to ((a1Button’s indexOfSelectedItem() as number) + 1)
  else
    set s1Val to false
  end if
  
  
copy s1Val to my pop1ind
  
end getPopupValues:

on clicked:aSender
  set (my windisp) to false
end clicked:

–make Window for Display
on makeWinWithView(aView, aWinWidth, aWinHeight, aTitle)
  set aScreen to NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
  
set aBacking to NSTitledWindowMask
  
  
set aDefer to NSBackingStoreBuffered
  
  
— Window
  
set aWin to NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
  
aWin’s setTitle:aTitle
  
aWin’s setDelegate:me
  
aWin’s setDisplaysWhenScreenProfileChanges:true
  
aWin’s setHasShadow:true
  
aWin’s setIgnoresMouseEvents:false
  
aWin’s setLevel:(NSNormalWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
  
aWin’s setContentView:aView
  
  
return aWin
end makeWinWithView

–close win
on closeWin:aWindow
  repeat with n from 10 to 1 by -1
    (aWindow’s setAlphaValue:n / 10)
    
delay 0.02
  end repeat
  
aWindow’s |close|()
end closeWin:

–Popup Action Handler
on actionHandler:sender
  set aTag to tag of sender as integer
  
set aTitle to title of sender as string
end actionHandler:

–aMaxValを最大値とする数値でNSColorを作成して返す
on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
  
return aColor
end makeNSColorFromRGBAval

–指定サイズのNSImageを作成し、指定色で塗ってNSImageで返す
on makeNSImageWithFilledWithColor(aWidth, aHeight, fillColor)
  set anImage to NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))
  
anImage’s lockFocus()
  
—
  
set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}}
  
set theNSBezierPath to NSBezierPath’s bezierPath
  
theNSBezierPath’s appendBezierPathWithRect:theRect
  
—
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
—
  
anImage’s unlockFocus()
  
—
  
return anImage
end makeNSImageWithFilledWithColor

on uniquifyList(aList as list)
  set aArray to NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquifyList

★Click Here to Open This Script 

Posted in Color GUI | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSBackingStoreBuffered NSBezierPath NSButton NSColor NSImage NSMenu NSMenuItem NSMomentaryLightButton NSNormalWindowLevel NSPopUpButton NSRoundedBezelStyle NSScreen NSTextField NSTitledWindowMask NSView NSWindow NSWindowController Pages | 1 Comment

Xcode 10.1+macOS MojaveでGUIアプリケーションを作成

Posted on 1月 16, 2019 by Takaaki Naganoya

Apple Developper Accountの契約を行い、Xcode上で(他のアプリケーションをコントロールする)AppleScriptアプリケーションを作れるようにしたときに、macOS 10.14+Xcode最新版の10.1だと実際どうなのかをまとめてみました。

Xcode上でこれまでと同様にScriptアプリケーションを記述しただけではダメ

Sandbox対応させると制約事項が増えるため、Sandbox非対応のアプリケーションをビルドしてどこまで行けるかは興味深いところです。

ですが、とりあえず(安全のために)、Code Sign+Sandboxの設定を行ってXcode上でAppleScriptアプリケーションを作成。Keynoteに新規ドキュメントを作成させる程度のお気軽なコードを書き、ビルドして実行。すると、

2019-01-15 99:99:99.999999+0900 1014test[13673:1813575] *** -[AppDelegate applicationWillFinishLaunching:]: Not authorized to send Apple events to Keynote. (error -1743)

などとエラーが出るだけで、AppleScriptからの操作対象アプリケーション(ここではNumbers)は、動かせませんでした。Automationのセキュリティダイアログ自体が表示されない状態です。


▲セキュリティダイアログはこんなやつ

Info.plistにエントリを追加するとSecurityダイアログが表示されるようになる

こういう場合には海外のサイトを調べてみるのが一番手っ取り早いところです。いろいろ調べてみたところ、Info.plistに対して、

Privacy - AppleEvents Sending Usage Description

というエントリを追加する必要があるとのこと。

このInfo.plist上のエントリ、例のMojaveから出るようになったSecurityダイアログにアプリケーション側から出力するカスタムメッセージを定義するエントリのようです。エントリさえ存在すれば、とくに何か気の利いたメッセージを入れる必要はないようです。

英語で書いても、日本語で書いてもそのままダイアログに出力されます。Info.plistの内容自体はローカライズできないので、本エントリの内容は広域に配布するものであれば英語で、特定の日本国内の顧客に向けて納品するものであれば日本語で書けばいいんじゃないでしょうか(一般的なメッセージ同様にローカライズできることが望ましい)。このあたり、ローカライズできないのは仕様的におかしいので、そのうち仕様が変わりそうです、、、、

Securityダイアログを表示させるためには、AppleScriptアプリケーション側から対象のアプリケーションに対して命令を発行する必要があるのですが、これが、activateさせるとかバージョン番号を調べるぐらいのコマンドではそのまま実行されてしまって、セキュリティダイアログは表示されません。

せめて新規ドキュメントを作成(make new document)して破棄(close without saving)するぐらいのことを行わないと、ダメなようです。このあたり、実際に試してみるしかないようです。

■セキュリティダイアログを表示させる程度の意味のない(ウォームアップのための)Scriptサンプル

tell application "Microsoft Excel"
  set aDoc to (make new document)
  
close active workbook without saving
end tell

★Click Here to Open This Script 

tell application "Keynote"
  set aDoc to (make new document)
  
close aDoc without saving
end tell

★Click Here to Open This Script 

tell application "Finder"
  make new Finder window
  
close Finder window 1
end tell

★Click Here to Open This Script 

–Touch Barの有無の検出
on detectTouchBar()
  tell application "System Events"
    set frontApp to first application process whose frontmost is true
    
try
      set touchBar to first UI element of frontApp whose role is "AXFunctionRowTopLevelElement"
    on error errMsg number errNum
      return false
    end try
    
    
set touchBarItems to value of attribute "AXChildren" of touchBar
    
return (touchBarItems is not equal to {})
  end tell
end detectTouchBar

★Click Here to Open This Script 

対象アプリケーションに対してコマンドを実行し、Securityダイアログが表示され、ユーザーによってきちんと認証されれば、tccKitを用いて認証状況を確認して、すべてのアプリケーションの認証完了状態をAppleScriptから知ることができます。

AppleScriptアプリケーションの冒頭(applicationWillFinishLaunchingイベントハンドラなど)でtccKitによって認証状態をチェックし、未認証の状態であれば操作対象のアプリケーションに対して試験的にコマンドを実行するようにすればよいでしょう。

AppleScriptアプリケーションがCode Signされていれば、セキュリティ認証ダイアログでユーザー認証する必要があるのは初回のみです。現在、Xcode上でGUIアプリケーションをビルドするためにはApple Developper Accountが必須となっているため、この点は必然的にクリアされることになります。

なお、この認証フローにおいてアプリケーション自体がSandbox化されている必要はありません(確認ずみ)。

Posted in AppleScript Application on Xcode GUI Security | Tagged 10.14savvy | 2 Comments

Post navigation

  • Older posts
  • Newer posts

電子書籍(PDF)をオンラインストアで販売中!

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • macOS 13.6.5 AS系のバグ、一切直らず
  • CotEditorで2つの書類の行単位での差分検出
  • Apple純正マウス、キーボードのバッテリー残量取得
  • macOS 15, Sequoia
  • ディスプレイをスリープ状態にして処理続行
  • 初心者がつまづきやすい「log」コマンド
  • Adobe AcrobatをAppleScriptから操作してPDF圧縮
  • 与えられた文字列の1D Listのすべての順列組み合わせパターン文字列を返す v3(ベンチマーク用)
  • メキシカンハットの描画
  • macOS 13 TTS環境の変化について
  • 新刊発売 AppleScript最新リファレンス v2.8対応
  • 2023年に書いた価値あるAppleScript
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • 指定のWordファイルをPDFに書き出す
  • 可変次元のベクトルに対応したコサイン類似度計算
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • Cocoa Scripting Course 続刊計画
  • macOS 13.6.2アップデート Cocoa-AppleScript Applet修正はなし
  • AdobeがInDesign v19.4からPOSIX pathを採用

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1391) 10.14savvy (586) 10.15savvy (437) 11.0savvy (281) 12.0savvy (201) 13.0savvy (129) 14.0savvy (77) 15.0savvy (49) CotEditor (62) Finder (50) iTunes (19) Keynote (110) NSAlert (60) NSArray (51) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (51) NSDictionary (27) NSFileManager (23) NSFont (19) NSImage (41) NSJSONSerialization (21) NSMutableArray (62) NSMutableDictionary (21) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (117) NSURL (97) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (65) Pages (51) Safari (44) Script Editor (25) WKUserContentController (21) WKUserScript (20) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • Beginner
  • Benchmark
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • Clipboard
  • Code Sign
  • Color
  • Custom Class
  • dialog
  • diff
  • drive
  • exif
  • file
  • File path
  • filter
  • folder
  • Font
  • Font
  • GAME
  • geolocation
  • GUI
  • GUI Scripting
  • Hex
  • History
  • How To
  • iCloud
  • Icon
  • Image
  • Input Method
  • Internet
  • iOS App
  • JavaScript
  • JSON
  • JXA
  • Keychain
  • Keychain
  • Language
  • Library
  • list
  • Locale
  • Localize
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • parallel processing
  • PDF
  • Peripheral
  • PRODUCTS
  • QR Code
  • Raw AppleEvent Code
  • Record
  • rectangle
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • Review
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • sdef
  • search
  • Security
  • selection
  • shell script
  • Shortcuts Workflow
  • Sort
  • Sound
  • Spellchecker
  • Spotlight
  • SVG
  • System
  • Tag
  • Telephony
  • Text
  • Text to Speech
  • timezone
  • Tools
  • Update
  • URL
  • UTI
  • Web Contents Control
  • WiFi
  • XML
  • XML-RPC
  • イベント(Event)
  • 未分類

アーカイブ

  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2024年2月
  • 2024年1月
  • 2023年12月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年2月
  • 2023年1月
  • 2022年12月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年12月
  • 2019年11月
  • 2019年10月
  • 2019年9月
  • 2019年8月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年11月
  • 2018年10月
  • 2018年9月
  • 2018年8月
  • 2018年7月
  • 2018年6月
  • 2018年5月
  • 2018年4月
  • 2018年3月
  • 2018年2月

https://piyomarusoft.booth.pm/items/301502

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org

Forum Posts

  • 人気のトピック
  • 返信がないトピック

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org
Proudly powered by WordPress
Theme: Flint by Star Verte LLC