/****************************** Module Header ******************************* * * Module Name: hooks.e * * Copyright (c) Netlabs EPM Distribution Project 2004 * * $Id$ * * =========================================================================== * * This file is part of the Netlabs EPM Distribution package and is free * software. You can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * Netlabs EPM Distribution. This library is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * ****************************************************************************/ ; Hook definitions ; ; A hook can hold a stack of EPM commands (and their args), that can be ; extended e.g. by user definitions. They can be executed at a specific ; event. Don't forget to add the postme command, if your command doesn't ; work properly, but try to avoid it, because it slows processing down. ; ; One advantage is that the definition, that adds a command to the hook, ; doesn't need to know where it will be executed. Just the hook's name must ; be known. ; ; Hooks are not able to call procedures due to a missing interpret ; statement in E. ; ; Thanks to Martin Lafaix, who implemented this stuff first in his (for ; 5.51 great) package MLEPM. ; ; Following standard hook names currently exist: ; - init executed (once) at defmain, after InitConfig ; - main executed (once) at the end of defmain ; - load executed at the end of defload ; (can be used to change file or mode specific settings, ; e.g. margins, tabs, tabkeys, toolbar, font) ; - loadonce executed once at the end of defload ; (like load, but change settings for next defload ; only) ; - postfilesloaded executed after all defloads are finished ; - postfilesloadedonce ; executed once after all defloads are finished ; - postpostfilesloadeonce ; executed once after postfilesloadedonce ; - fileswitched usually contains ProcessSelectSettings, to be used ; for user additions as well ; - fileswitchedonce user additions, deleted after execution ; - modechanged executed when the mode has changed on file switching ; and on changing the mode for a file ; - expandmodechanged ; executed when the expand mode has changed on file ; switching ; - postfileswitched usually contains ProcessRefreshInfoLine ; - postselect user additions ; - postselectonce user additions, deleted after execution ; - modify executed at every defmodify event ; - modifyonce executed once at every defmodify event ; - save executed before a file is saved ; - saveonce executed once before a file is saved ; - postsave executed after a file is saved ; - postsaveonce executed once after a file is saved ; - quit executed before a file is quit ; - quitonce executed once before a file is quit ; - addmenu executed by loaddefaultmenu, when the menu is built, ; before the help menu. ; (can be used for user's submenus) ; - cascademenu executed with postme after adding standard cascade ; menu items ; The *once types are deleted after being executed, so that they get ; executed 1 time only. ; ; Use the 'select' hook for settings, you want to change on every ; defselect event. That should be only stuff, that don't stick with the ; file. If your stuff sticks, better use the 'load' hook to avoid loss ; of performance and stability. ; ; Some events (definit, defselect, defmodify, defexit) are extendable ; properly, so no hooks are required therefore. But hooks were added for ; them to make them configurable from EPM REXX. ; ; Note: Settings executed at defload don't require additional refreshs if ; field vars for these settings exist. They stick with the file. All ; other settings must be refreshed at defselect as well. Use array ; vars with the name . to get a file specific ; array for this setting. ; Examples: .margins --> A field var exists. Once set, it will stick ; with the file (it was already set at defload). ; mode --> An array var mode. exists. Its value ; can be queried with the Get_Array_Value ; proc together with the fileid or easier with ; the GetMode procedure. Because the mode ; causes (sticky) settings changes at defload ; usually, there's no need to query the mode ; at defselect again, except if it is shown in ; e.g. the statusbar. ; Instead of get_array_var, the simplier proc ; GetAVar can be used. It is defined as command ; as well. ; toolbar --> No array var exists. Create a new array var ; toolbar. and use 'HookAdd load' to ; prepare the creation of the array var holding ; the mode- or extension-specific name of a ; toolbar. The hook will be executed at ; defload and this will save the toolbar name. ; As a 2nd step, at every defselect the array ; var must be queried and maybe the toolbar has ; to be changed. This can be achived with a ; a new command, that can be executed via ; 'HookAdd fileswitched'. ; This is just an example for the case that ; no array var exists. In the meantime, the ; command SetToolBar was defined. ; --------------------------------------------------------------------------- ; Adds an entry ; Syntax: HookAdd defc HookAdd prefix = 'hook.' parse arg HookName Cmd HookName = strip( lowcase( HookName)) Cmd = strip( Cmd) if Cmd <> '' then -- don't increase imax if no Cmd -- Query imax imax = GetAVar( prefix''HookName'.0') if imax = '' then imax = 0 endif -- Delete Cmd from hook array, if already present and change imax imaxnew = imax do i = 1 to imax -- If Cmd already exists in the hook array, delete it next = GetAVar( prefix''HookName'.'i) if next = '' then iterate endif if upcase( Cmd) = upcase( next) then DropAVar( prefix''HookName'.'i) imaxnew = imaxnew - 1 -- Move following entries do j = i + 1 to imax next = GetAVar( prefix''HookName'.'j) if next = '' then leave endif SetAVar( prefix''HookName'.'j - 1, next) enddo endif enddo imax = imaxnew -- Append Cmd to ensure that it is executed last imax = imax + 1 SetAVar( prefix''HookName'.'imax, Cmd) SetAVar( prefix''HookName'.0', imax) endif ; --------------------------------------------------------------------------- ; Change an entry, if the first word of args is in the list, otherwise append ; it. ; Syntax: HookChange defc HookChange prefix = 'hook.' parse arg HookName Cmd parse value Cmd with CmdName CmdArgs HookName = strip( lowcase( HookName)) Cmd = strip( Cmd) CmdName = strip( CmdName) CmdArgs = strip( CmdArgs) if Cmd <> '' then -- don't increase imax if no Cmd Append = 1 imax = GetAVar( prefix''HookName'.0') if imax = '' then imax = 0 else do i = 1 to imax next = GetAVar( prefix''HookName'.'i) if next <> '' then -- if next set parse value next with first rest if upcase( first) = upcase( CmdName) then SetAVar( prefix''HookName'.'i, Cmd) Append = 0 leave endif endif enddo endif if Append then imax = imax + 1 SetAVar( prefix''HookName'.'imax, Cmd) SetAVar( prefix''HookName'.0', imax) endif endif ; --------------------------------------------------------------------------- ; Replaces all entries with a new entry ; Syntax: HookSet defc HookSet prefix = 'hook.' parse arg HookName Cmd HookName = strip( lowcase( HookName)) Cmd = strip( Cmd) if Cmd <> '' then -- don't increase imax if no Cmd -- delete all old Cmds first imax = GetAVar( prefix''HookName'.0') if imax <> '' then do i = 1 to imax Cmd = GetAVar( prefix''HookName'.'i) if Cmd <> '' then DropAVar( prefix''HookName'.'i) -- delete entry endif enddo endif -- set new Cmd imax = 1 SetAVar( prefix''HookName'.'imax, Cmd) SetAVar( prefix''HookName'.0', imax) endif ; --------------------------------------------------------------------------- ; Deletes all entries ; Syntax: HookDelAll defc HookDelAll prefix = 'hook.' parse arg HookName HookName = strip( lowcase( HookName)) imax = GetAVar( prefix''HookName'.0') if imax <> '' then do i = 1 to imax Cmd = GetAVar( prefix''HookName'.'i) if Cmd <> '' then DropAVar( prefix''HookName'.'i) endif enddo DropAVar( prefix''HookName'.0') endif ; --------------------------------------------------------------------------- ; Deletes every Cmd from a hook array, that is in the list. Specifying just ; an abbreviation for Cmd matches a stored hook definition as well. ; Syntax: HookDel defc HookDel prefix = 'hook.' parse arg HookName Cmd HookName = strip( lowcase( HookName)) Cmd = strip( Cmd) if Cmd <> '' then -- don't try to process if no Cmd imax = GetAVar( prefix''HookName'.0') if imax <> '' then imaxnew = imax do i = 1 to imax next = GetAVar( prefix''HookName'.'i) if next <> '' then if abbrev( upcase( next), upcase( Cmd)) then -- if abbreviation matches the entry DropAVar( prefix''HookName'.'i) -- move following entries do j = i + 1 to imax next = GetAVar( prefix''HookName'.'j) if next = '' then leave endif SetAVar( prefix''HookName'.'j - 1, next) enddo --if not ret then imaxnew = imaxnew - 1 --endif endif endif enddo if imaxnew <> imax then SetAVar( prefix''HookName'.0', imaxnew) endif endif endif ; --------------------------------------------------------------------------- ; Executes all entries (FIFO) ; Syntax: HookExecute defc HookExecute prefix = 'hook.' parse arg HookName HookName = strip( lowcase( HookName)) display -1 imax = GetAVar( prefix''HookName'.0') if imax <> '' then do i = 1 to imax Cmd = GetAVar( prefix''HookName'.'i) Cmd enddo endif display 1 ; --------------------------------------------------------------------------- ; Executes all entries (FIFO) and deletes them afterwards ; Syntax: HookExecuteOnce defc HookExecuteOnce prefix = 'hook.' parse arg HookName HookName = strip( lowcase( HookName)) display -1 imax = GetAVar( prefix''HookName'.0') if imax <> '' then do i = 1 to imax Cmd = GetAVar( prefix''HookName'.'i) Cmd DropAVar( prefix''HookName'.'i) enddo DropAVar( prefix''HookName'.0') endif display 1 ; --------------------------------------------------------------------------- ; Executes last entry ; Syntax: HookExecuteLast defc HookExecuteLast prefix = 'hook.' parse arg HookName HookName = strip( lowcase( HookName)) display -1 imax = GetAVar( prefix''HookName'.0') if imax <> '' then i = imax Cmd = GetAVar( prefix''HookName'.'i) Cmd endif display 1 ; --------------------------------------------------------------------------- ; Executes first entry ; Syntax: HookExecuteFirst defc HookExecuteFirst prefix = 'hook.' parse arg HookName HookName = strip( lowcase( HookName)) display -1 imax = GetAVar( prefix''HookName'.0') if imax <> '' then i = 1 Cmd = GetAVar( prefix''HookName'.'i) Cmd endif display 1 ; --------------------------------------------------------------------------- ; Returns number of entries ; Syntax: HookGetNum defproc HookGetNum prefix = 'hook.' parse arg HookName HookName = strip( lowcase( HookName)) num = 0 imax = GetAVar( prefix''HookName'.0') if imax <> '' then num = imax endif return num ; --------------------------------------------------------------------------- ; Returns 1 if number of entries > 0, otherwise 0 ; Syntax: HookIsDefined defproc HookIsDefined prefix = 'hook.' parse arg HookName HookName = strip( lowcase( HookName)) num = 0 imax = GetAVar( prefix''HookName'.0') if imax <> '' then num = imax endif return (num > 0) ; --------------------------------------------------------------------------- ; Returns value of specified HookName. In the returned string, the single ; entries are prepended by '|'. ; Syntax: HookGet defproc HookGet prefix = 'hook.' parse arg HookName HookName = strip( lowcase( HookName)) next = '' imax = GetAVar( prefix''HookName'.0') if imax <> '' then do i = 1 to imax Cmd = GetAVar( prefix''HookName'.'i) if Cmd = '' then iterate else next = next'|'Cmd endif enddo endif return next ; --------------------------------------------------------------------------- ; Shows all entries ; Syntax: HookShow defc HookShow next = HookGet( arg( 1)) 'SayError Hook value for' arg( 1)' = 'next', .filename = '.filename ; --------------------------------------------------------------------------- defc HookShowAll HookList = 'init main load loadonce postfilesloaded postfilesloadedonce' || ' postpostfilesloadeonce fileswitched fileswitchedonce' || ' postfileswitched modechanged expandmodechanged'|| ' postselect postselctonce' || ' modify modifyonce save saveonce postsave postsaveonce' || ' quit quitonce addmenu cascademenu' TmpFileName = '.HOOK_ARRAY_VARS' getfileid startfid display -3 if IsFileLoaded( TmpFileName) then 'xcom e /n' TmpFileName -- activate tmp file else 'xcom e /c' TmpFileName -- create tmp file if rc <> -282 then -- NEW_FILE_RC activatefile startfid return 1 endif deleteline -- delete first line (EPM automatically creates line 1) endif savedlast = .last .autosave = 0 parse value GetDateTime() with Hour24 Minutes Seconds . Day MonthNum Year0 Year1 . Date = rightstr( Year0 + (256 * Year1), 4, 0)'-'rightstr( monthnum, 2, 0)'-'rightstr( Day, 2, 0) Time = rightstr( hour24, 2)':'rightstr( Minutes, 2, '0')':'rightstr( Seconds, 2, '0') insertline copies( '-', 78), .last + 1 insertline 'Hook array vars - created on 'Date' 'Time, .last + 1 -- First, find longest hook name len = 0 do w = 1 to words( HookList) wrd = word( HookList, w) len = Max( length( wrd), len) enddo -- Next, write var = value lines do w = 1 to words( HookList) wrd = word( HookList, w) line = leftstr( wrd, len)' = 'HookGet( wrd) insertline line, .last + 1 enddo insertline '', .last + 1 .modify = 0 .line = savedlast + 1 display 3 return 0 ; --------------------------------------------------------------------------- ; Some useful commands, that can be used as parameters for program objects ; or in PROFILE.ERX. ; Examples: ; 'AtLoad UserCmd' ; 'AtStartup UserCmd' ; 'mc ;AtLoad UserCmd1 ;AtStartup UserCmd2' ; --------------------------------------------------------------------------- ; Syntax: AtInit ; is executed after the first initialization, before the to EPM ; submitted files and commands are processed. defc AtInit 'HookAdd init' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtLoad ; is executed for every file that is loaded at the end of ; processing the defload event. defc AtLoad 'HookAdd load' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtNextLoad ; is executed for the next loaded file only at the end of ; processing the defload event. defc AtNextLoad 'HookAdd loadonce' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtPostLoad ; is executed after the EPM window was opened and after all load ; actions are processed. If the EPM window was already open, is ; executed as well after all load actions are finished, at the first ; defselect event after loading. defc AtPostLoad 'HookAdd postfilesloaded' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtStartup ; is executed after the EPM window was opened and after all load ; actions are processed. After execution, the hook is deleted, so that it's ; executed at the first defselect event only. defc AtStartup 'HookAdd postfilesloadedonce' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtPostStartup ; is posted after the EPM window was opened and after all load ; actions are processed. Before execution, the screen is refreshed to ensure ; that all pending paintings are done. After execution, the hook is deleted, ; so that it's posted at the first defselect event only. defc AtPostStartup 'HookAdd postpostfilesloadedonce' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AfterStartup ; During file loading, this is executed as AtStartup. After all files are ; loaded, this is executed immediately. defc AfterStartup universal loadstate if loadstate <> 0 then -- After all files are loaded 'AtPostStartup' arg( 1) else -- Now 'PostMe' arg( 1) endif ; --------------------------------------------------------------------------- ; Syntax: AtFileSwitched ; is executed at the end of every file switching at defselect. defc AtFileSwitched 'HookAdd fileswitched' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtNextFileSwitched ; is executed at the end of the next file switching at defselect. defc AtNextFileSwitched 'HookAdd fileswitchedonce' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtPostFileSwitched ; is executed at the end of every file switching at defselect. defc AtPostFileSwitched 'HookAdd postfileswitched' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtPostSelect ; is executed at the end of every defselect event. defc AtPostSelect 'HookAdd postselect' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtNextPostSelect ; is executed at the end of the next defselect event. defc AtNextPostSelect 'HookAdd postselectonce' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtModify ; is executed at every defmodify event. defc AtModify 'HookAdd modify' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtNextModify ; is executed at the next defmodify event only. defc AtNextModify 'HookAdd modifyonce' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtSave ; is executed before a file is saved. defc AtSave 'HookAdd save' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtNextSave ; is executed once before a file is saved. defc AtNextSave 'HookAdd saveonce' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtPostSave ; is executed after a file is saved. defc AtPostSave 'HookAdd postsave' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtNextPostSave ; is executed once after a file is saved. defc AtNextPostSave 'HookAdd postsaveonce' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtQuit ; is executed before a file is quit. defc AtQuit 'HookAdd quit' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtNextQuit ; is executed once before a file is quit. defc AtNextQuit 'HookAdd quitonce' arg( 1) ; --------------------------------------------------------------------------- ; Syntax: AtMenuLoad ; is executed during menu loading, beforing the help menu is added. defc AtMenuLoad 'HookAdd addmenu' arg( 1) ; --------------------------------------------------------------------------- -- Todo: add this to other menus as well. ; Syntax: AtCascadeMenuLoad ; is executed during menu loading, beforing the help menu is added. defc AtCascadeMenuLoad 'HookAdd cascademenu' arg( 1) ; --------------------------------------------------------------------------- ; Makes a Cmd been executed at a specific event. ; Syntax: AtEvent ; This can also be used in parameters for program objects or in PROFILE.ERX. ; Examples: ; 'AtEvent Load UserCmd' ; 'AtEvent Startup UserCmd' ; 'mc ;AtEvent Load UserCmd1 ;AtEvent Startup UserCmd2' ; Following events exist: ; init, load, nextload, postload, startup, poststartup, afterstartup, ; fileswitched, nextfileswitched, postselect, nextpostselect, modify, ; nextmodify, save, nextsave, postsave, nextpostsave, quit, nextquit, ; menuloaded, cascademenuloaded. defc AtEvent universal loadstate parse arg Event Cmd Event = lowcase( strip( Event)) Cmd = strip( Cmd) if Event = 'init' then -- Cmd is executed after the first initialization, before the to EPM -- submitted files and commands are processed. 'HookAdd init 'Cmd elseif Event = 'load' then -- Cmd is executed for every file that is loaded at the end of -- processing the defload event. 'HookAdd load 'Cmd elseif Event = 'nextload' then -- Cmd is executed for the next loaded file only at the end of -- processing the defload event. 'HookAdd loadonce 'Cmd elseif Event = 'postload' then -- Cmd is executed after the EPM window was opened and after all load -- actions are processed. If the EPM window was already open, is -- executed as well after all load actions are finished, at the first -- defselect event after loading. 'HookAdd postfilesloaded 'Cmd elseif Event = 'startup' then -- Cmd is executed after the EPM window was opened and after all load -- actions are processed. After execution, the hook is deleted, so that it's -- executed at the first defselect event only. 'HookAdd postfilesloadedonce 'Cmd elseif Event = 'poststartup' then -- Cmd is posted after the EPM window was opened and after all load -- actions are processed. Before execution, the screen is refreshed to ensure -- that all pending paintings are done. After execution, the hook is deleted, -- so that it's posted at the first defselect event only. 'HookAdd postpostfilesloadedonce 'Cmd elseif Event = 'afterstartup' then -- During file loading, this is executed as AtStartup. After all files are -- loaded, this is executed immediately. if loadstate <> 0 then -- After all files are loaded 'HookAdd postpostfilesloadedonce 'Cmd else -- Now 'PostMe' arg( 1) endif elseif Event = 'fileswitched' then -- Cmd is executed at the end of every file switching at defselect. 'HookAdd fileswitched 'Cmd elseif Event = 'nextfileswitched' then -- Cmd is executed at the end of the next file switching at defselect. 'HookAdd fileswitchedonce 'Cmd elseif Event = 'modechanged' then -- Cmd is executed when the mode has changed on file switching and on -- changing the mode for a file 'HookAdd modechanged 'Cmd elseif Event = 'expandmodechanged' then -- Cmd is executed when the expand mode has changed on file switching 'HookAdd expandmodechanged 'Cmd elseif Event = 'postselect' then -- Cmd is executed at the end of every file switching at defselect. 'HookAdd postselect 'Cmd elseif Event = 'nextpostselect' then -- Cmd is executed at the end of the next defselect event. 'HookAdd postselectonce 'Cmd elseif Event = 'modify' then -- Cmd is executed at every defmodify event. 'HookAdd modify 'Cmd elseif Event = 'nextmodify' then -- Cmd is executed at the next defmodify event only. 'HookAdd modifyonce 'Cmd elseif Event = 'save' then -- Cmd is executed before a file is saved. 'HookAdd save 'Cmd elseif Event = 'nextsave' then -- Cmd is executed once before a file is saved. 'HookAdd saveonce 'Cmd elseif Event = 'postsave' then -- Cmd is executed after a file is saved. 'HookAdd postsave 'Cmd elseif Event = 'nextpostsave' then -- Cmd is executed once after a file is saved. 'HookAdd postsaveonce 'Cmd elseif Event = 'quit' then -- Cmd is executed before a file is quit. 'HookAdd quit 'Cmd elseif Event = 'nextquit' then -- Cmd is executed once before a file is quit. 'HookAdd quitonce 'Cmd elseif Event = 'menuload' then -- Cmd is executed during menu loading, beforing the help menu is added. 'HookAdd addmenu 'Cmd elseif Event = 'cascademenuload' then -- Todo: add this to other menus as well. -- Cmd is executed during menu loading, beforing the help menu is added. 'HookAdd cascademenu 'Cmd else 'SayError AtEvent: Unknown event "'Event'" specified.' rc = -328 -- Invalid first parameter stop endif