home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 March / Macworld (1998-03) (Disk 1).dmg / Shareware World / Utilities / Text Processing / Alpha / Tcl / SystemCode / appleEvents.tcl < prev    next >
Encoding:
Text File  |  1997-12-10  |  9.5 KB  |  322 lines  |  [TEXT/ALFA]

  1.  
  2. # make alias list to pass to AEBuild
  3. proc makeAlis {name} {
  4.     return "\[alis(«[coerce TEXT $name -x alis]»)\]"    
  5. }
  6.  
  7. proc makeFile {name} {
  8.     return "alis(«[coerce TEXT $name -x alis]»)"    
  9. }
  10.  
  11. ## 
  12.  # -------------------------------------------------------------------------
  13.  # 
  14.  # "makeAlises" --
  15.  # 
  16.  #  This proc has changed so it takes a list of items rather than an
  17.  #  unknown number of args 'args'.  If 'l' is a list you must call
  18.  #  this proc with 'makeAlises $l' rather than 'eval makeAlises $l'
  19.  #  as was previously required.
  20.  # -------------------------------------------------------------------------
  21.  ##
  22. proc makeAlises {names} {
  23.     set str "\["
  24.     set sep ""
  25.     foreach name $names {
  26.         append str "${sep}alis(«[coerce TEXT $name -x alis]»)"
  27.         set sep ","
  28.     }
  29.     append str "\]"
  30.     return $str
  31. }
  32.  
  33.  
  34. ## 
  35.  # -------------------------------------------------------------------------
  36.  # 
  37.  # "handleReply" --
  38.  # 
  39.  #  Queued replies are passed through AEPrint and then to this routine.
  40.  #  
  41.  #  If you write your own handleReply procedure, register it to this
  42.  #  proc with:
  43.  #  
  44.  #    currentReplyHandler 'my-proc-name'
  45.  #    
  46.  #  Do this each time you send an event which may receive a reply.
  47.  #  There is no need to register your proc at startup or any such
  48.  #  'pre-registering'.  Just call the above proc _each_ time.
  49.  #  
  50.  #  You proc should take one parameter (the reply), and should
  51.  #  return '1' if it handled the reply, otherwise it can do/return
  52.  #  anything else (although hopefully not much if it didn't handle
  53.  #  anything).
  54.  #  
  55.  #  If your replies often time-out or have other problems such
  56.  #  that you don't handle them correctly, you may wish to register
  57.  #  your reply-handler with 'currentReplyHandler 'my-proc' 1' which
  58.  #  says 'only register if it's not already registered'.  Or you
  59.  #  may wish to remove duplicates from the list of handlers 
  60.  #  directly.
  61.  #    
  62.  # Results:
  63.  #  depends on what is registered
  64.  # 
  65.  # Side effects:
  66.  #  calls other procs.  Removes handler from queue if it handled
  67.  #  the reply.
  68.  # 
  69.  # --Version--Author------------------Changes-------------------------------
  70.  #    1.0     <darley@fas.harvard.edu> first one with hook handling
  71.  #    2.0     <darley@fas.harvard.edu> different mechanism to give priority
  72.  # -------------------------------------------------------------------------
  73.  ##
  74. proc handleReply {rep} {
  75.     global lastReply replyHandlers
  76.     set lastReply $rep
  77.     set i 0
  78.     foreach h $replyHandlers {
  79.         if {$h != ""} {
  80.             catch [list $h $rep] res
  81.             if {$res == 1} {
  82.                 set replyHandlers [lreplace $replyHandlers $i $i]
  83.                 return
  84.             }
  85.         }
  86.         incr i
  87.     }
  88.     message "Reply '$rep' not handled"
  89. }
  90.  
  91. ensureset replyHandlers ""
  92.  
  93. ## 
  94.  # -------------------------------------------------------------------------
  95.  # 
  96.  # "currentReplyHandler" --
  97.  # 
  98.  #  Add item to end of queue to receive replies, even if it is already
  99.  #  in the queue, unless we set 'nodups'
  100.  # -------------------------------------------------------------------------
  101.  ##
  102. proc currentReplyHandler {proc {nodups 0}} {
  103.     global replyHandlers
  104.     if {!$nodups || (![lcontains replyHandlers $proc])} {
  105.         lappend replyHandlers $proc
  106.     }    
  107. }
  108.  
  109. # Return an object record specifying the desired think project file.
  110. proc fileObject {name} {
  111.     join [concat {obj\{want:type('SFIL'), from:'null'(), form:'name', seld:“} [file tail $name] {”\}}] ""
  112. }
  113.  
  114. proc sendOpenEvent {filler appname fname} {
  115.     if {$filler == "noReply"} {
  116.         AEBuild $appname aevt odoc "----" [makeAlis $fname]
  117.     } else {
  118.         AEBuild -r $appname aevt odoc "----" [makeAlis $fname]
  119.     }
  120. }
  121.  
  122.  
  123. # Send open folder event to Finder. Name must end in colon.
  124. proc openFolder {name} {
  125.     if {![regexp ":$" $name]} {
  126.         append name ":"
  127.     }
  128.     sendOpenEvent -r Finder $name
  129. }
  130.  
  131. proc launchDoc {name} {
  132.     set app [app::launchFore [getFileSig $name]]
  133.     sendOpenEvent -r [file tail $app] $name
  134. }
  135.  
  136. # Send multiple open events
  137. proc sendOpenEvents {appname args} {
  138.     AEBuild -r $appname aevt odoc "----" [makeAlises $args]
  139. }
  140.  
  141. proc openAndSendFile {sig} {
  142.     set fname [win::Current]
  143.     if {[winDirty]} {
  144.         if [dialog::yesno "Save '$fname'?"] {
  145.             save
  146.         }
  147.     }
  148.  
  149.     set name [file tail [app::launchFore $sig]]
  150.     sendOpenEvent noReply $name $fname
  151. }
  152.  
  153. #================================================================================
  154. # General Apple Event handling routines
  155. #
  156. # (written by Tom Pollard for use in the MacPerl package)
  157. #================================================================================
  158.  
  159. # Quit an application.
  160. proc sendQuitEvent {appname} {
  161.     AEBuild $appname "aevt" "quit" 
  162. }
  163.  
  164. # Close one of an application's windows, designated by number.
  165. proc sendCloseWinNum {appname num} {
  166.     AEBuild $appname "core" "clos" "----" [AEWinByPos $num]
  167. }
  168.  
  169. # Close one of an application's windows, designated by name.
  170. proc sendCloseWinName {appname name} {
  171.     AEBuild $appname "core" "clos" "----" [AEWinByName $name]
  172. }
  173.  
  174. # Obtain the number of lines in one of an application's
  175. # windows, designated by name.
  176. proc sendCountLines {appname name} {
  177.     set winObj [AEWinByName $name]
  178.     set res [AEBuild -r $appname "core" "cnte" "----" $winObj kocl type('clin')]    
  179.     if {[regexp {:(.*)\}} $res allofit nlines]} {
  180.         return $nlines
  181.     } else {
  182.         return 0
  183.     }
  184. }
  185.  
  186. # Get a selected range of lines from one of an application's
  187. # windows, designated by name.  If $last is missing, then a single
  188. # line is returned; if both $first and $last are missing, then
  189. # the complete window contents are returned.
  190. proc sendGetText {appname name {first {missing}} {last {missing}}} {
  191.     global ALPHA
  192.     set winObj [AEWinByName $name]
  193.     if {$first != "missing"} {
  194.         if {$last != "missing"} {
  195.             set rangDesc [AELineRange $first $last]
  196.         } else {
  197.             set rangDesc [AEAbsPos $first]
  198.         }
  199.         set objDesc "obj{want:type('clin'), from:$winObj, $rangDesc }"
  200.     } else {
  201.         set objDesc "obj{want:type('ctxt'), from:$winObj, form:'indx', seld:abso('all') }"
  202.     }
  203.     set res [AEBuild -r $appname "core" "getd" "----" $objDesc]    
  204.     if {![regexp {“.*”} $res text]} { set text {} }
  205.     return [string trim $text {“”}]
  206. }
  207.  
  208. # Set a selected range of lines in one of an application's
  209. # windows, designated by name.  If $last is missing, then a single
  210. # line is changed; if both $first and $last are missing, then
  211. # the complete window contents are replaced by the new text.
  212. proc sendSetText {appname name text {first {missing}} {last {missing}}} {
  213.     set winObj [AEWinByName $name]
  214.     if {$first != "missing"} {
  215.         if {$last != "missing"} {
  216.             set rangDesc [AELineRange $first $last]
  217.         } else {
  218.             set rangDesc [AEAbsPos $first]
  219.         }
  220.         set objDesc "obj{want:type('clin'), from:$winObj, $rangDesc }"
  221.     } else {
  222.         set objDesc "obj{want:type('ctxt'), from:$winObj, form:'indx', seld:abso('all') }"
  223.     }
  224.     set res [AEBuild -r $appname "core" "setd" "----" $objDesc "data" [curlyq $text]]    
  225.     if {![regexp {“.*”} $res text]} { set text {} }
  226.     return [string trim $text {“”}]
  227. }
  228.  
  229. ################################################################################
  230. # Utility functions for constructing AppleEvent descriptors for AEBuild
  231. ################################################################################
  232.  
  233. proc AEFilename {name} {
  234.     return "obj{want:type('file'), from:'null'(), [AEName $name] } "
  235. }
  236.  
  237. proc AEWinByName {name} {
  238.     return "obj{want:type('cwin'), from:'null'(), [AEName $name] } "
  239. }
  240.  
  241. proc AEWinByPos {absPos} {
  242.     return "obj{want:type('cwin'), from:'null'(), [AEAbsPos $absPos] } "
  243. }
  244.  
  245. proc AELineRange {absPos1 absPos2} {
  246.     set lineObj1 "obj{ want:type('clin'), from:'ccnt'(), [AEAbsPos $absPos1] }"
  247.     set lineObj2 "obj{ want:type('clin'), from:'ccnt'(), [AEAbsPos $absPos2] }"
  248.     return "form:'rang', seld:rang{star:$lineObj1, stop:$lineObj2 } "
  249. }
  250.  
  251. proc AEAbsPos {posName} {
  252. #
  253. # Use '1' or 'first' to specify first position
  254. # and '-1' or 'last' to specify last position.
  255. #
  256.     if {$posName == "first"} { 
  257.         set posName 1 
  258.     } elseif {$posName == "last"} { 
  259.         set posName -1 
  260.     }
  261.     if {$posName >= -1} {
  262.         return "form:indx, seld:long($posName)"
  263.     } else {
  264.         error "AEAbsPos: bad argument"
  265.     }
  266. }
  267.  
  268. proc AEName {name} {
  269.     return "form:'name', seld:[curlyq $name]"
  270. }
  271.  
  272. proc curlyq {str} {
  273.     regsub -all {([“”])} $str {"} newstr
  274.     return "\“$newstr\”"
  275. }
  276.  
  277. ################################################################################
  278. proc nullObject {}                     { return "'null'()" }
  279. proc objectType {type}                 { return "type($type)" }
  280. proc nameObject {type name from}     { return "obj \{form:name, want:[objectType $type], seld:$name, from:$from\}" }
  281. proc indexObject {type ind from}     { return "obj \{form:indx, want:[objectType $type], seld:$ind, from:$from\}" }
  282. proc propertyObject { prop object } { return "obj \{form:prop, want:[objectType prop], seld:[objectType $prop], from:$object\}" }
  283.  
  284. # 'process' must have single quotes
  285. proc buildMsgReply { process suite event args } { return [eval [list AEBuild -r $process $suite $event ] $args] }
  286.  
  287. proc countObjects { process fromObject class } {
  288.     set res [AEBuild -r $process core cnte ---- $fromObject kocl [objectType $class]]
  289.     if {[regexp {:([0-9]+)} $res dummy mtch]} {
  290.         return $mtch
  291.     } else {
  292.         error "Bad count proc"
  293.     }
  294. }
  295.  
  296. proc createThingAtEnd {process container class} {
  297.     set res [AEBuild -r $process core crel insh "insl \{kobj:$container\}" kocl "type($class)"]
  298. }
  299.  
  300.  
  301. proc getObjectData { process class name from } {
  302.     set res [AEBuild -r $process core getd ---- [nameObject $class "“$name”" $from] {rtyp{type:TEXT}}]
  303.     if {[regexp {“(.*)”} $res dummy mtch]} {
  304.         return $mtch
  305.     } else {
  306.         error "Bad count proc"
  307.     }
  308. }
  309.  
  310.  
  311. proc objectProperty { process property object } {
  312.     AEBuild -r $process core getd ---- [propertyObject $property $object]
  313. }
  314.  
  315. # Extract and return a path from a result.
  316. proc extractPath {res} {
  317.     if {[regexp {«(.*)»} $res dummy fss]} {
  318.         return [specToPathName $fss]
  319.     }
  320.     error "bad path $name"
  321. }    
  322.