/****************************** Module Header ******************************* * * Module Name: filelist.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. * ****************************************************************************/ compile if not defined( SMALL) -- If compiled separately EA_comment 'This defines macros for file lists.' define INCLUDING_FILE = 'FILELIST.E' include 'stdconst.e' const tryinclude 'mycnf.e' const compile if not defined( NLS_LANGUAGE) NLS_LANGUAGE = 'ENGLISH' compile endif include NLS_LANGUAGE'.e' compile endif #define FID_CLIENT 0x8008 ; Defs used for Last history (\NEPMD\Var\History\Last) ; SaveAllLastRings ; SaveLastRing ; ProcessPostSelect -> RefreshLastRing -> SaveLastRing ; Defs used for Load history (\NEPMD\Var\History\Load) ; ProcessLoad-> AddToHistory LOAD ; Defs used for Edit history (\NEPMD\Var\History\Edit) ; Edit -> AddToHistory EDIT ; Defs used for Save history (\NEPMD\Var\History\Save) ; Save -> AddToHistory SAVE ; CheckAllRingsModify ; Defs used for Search history (\NEPMD\Var\History\Search) ; Save -> AddToHistory SEARCH ; o When an EPM frame window is closed, no E command is executed. Therefore ; closing the window can't be recognized by E. Otherwise that would be the ; preferred event to save a ring. To achieve a similar result, the rings ; are saved now after all files are loaded and after closing a single file ; of an existing ring. ; o RefreshLastRing is executed by ProcessPostSelect. It executes ; SaveLastRing. Without a passed ringnum, SaveLastRing calls ; SaveAllLastRings. ; o SaveAllLastRings determines ringnum according to the current Z-order of ; EPM windows. It executes SaveLastRing with that ringnum in a loop for ; all rings. ; o SaveLastRing saves all filenames to the Last\ ; history. At the end, it saves the passed number as universal ringnum. ; o Universal vars are specific to EPM windows (rings). Once set per ring, ; the value is kept until window close. ; o A new EPM window doesn't have ringnum set and therefore SaveAllLastRings ; is called when opening a new EPM window. ; o When adding a file to an existing EPM window (ring), ringnum is already ; set. RefreshLastRing passes that to SaveLastRing. Then only the current ; ring is saved. ; --------------------------------------------------------------------------- ; Save and restore all rings or one ring ; --------------------------------------------------------------------------- ; --------------------------------------------------------------------------- ; This executes SaveLastRing for all rings, starting with = 1. ; Syntax: SaveAllLastRings( ) ; It is called on opening a new EPM window. The current window gets ; ringnum = 1, the next EPM window in Z-order gets ringnum = 2 etc. defproc SaveAllLastRings KeyPath = arg( 1) --dprintf( 'SaveAllLastRings: arg( 1) = 'KeyPath' -------------------------------------------') fRestart = (GetCheckModifyRestart() = 1) --dprintf( 'SaveAllLastRings: GetCheckModifyRestart() = 'GetCheckModifyRestart()', fRestart = 'fRestart) -- Check if this is an extra instance, e.g. opened by "svn ci". -- Other EPM windows, opened with "epm /m" also don't save anything -- here. If this window from an extra instance executes a PostTo -- cmd to another EPM window, all other windows would close. if (IsExtraInstance() <> 0) then return endif -- Save first ring -- Restart: This one is closed as last one. Num = 1 --dprintf( 'SaveAllLastRings: SaveNextLastRing 'Num) 'SaveNextLastRing 'Num -- Find next rings. Post SaveLastRings to next ring. Wait until hwnd -- is written. buf = leftstr( '', 128, \0) desktop = 1 -- (1 == HWND_DESKTOP) my_hwnd = getpminfo( EPMINFO_EDITFRAME) --dprintf( ' 0: my_hwnd = 'getpminfo( EPMINFO_EDITFRAME)) len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName GethWndC( EPMINFO_EDITFRAME) || atol( 128) || address( buf), 2) ClsFrame = leftstr( buf, len) -- Get ClsName (NewEditWndClass) of current edit client window len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName GethWndC( EPMINFO_EDITCLIENT) || atol( 128) || address( buf), 2) ClsName = leftstr( buf, len) --dprintf( ' 0: my_hwnd = F: 'ClsFrame', C: 'ClsName', hwndF = 'getpminfo( EPMINFO_EDITFRAME)', hwndC = 'getpminfo( EPMINFO_EDITCLIENT)) -- Examine desktop windows for client of same edit class henum = atol( dynalink32( 'PMWIN', '#702', -- WinBeginEnumWindows atol( desktop), 2)) cnt = 0 do while cnt < 250 cnt = cnt + 1 hwnd = dynalink32( 'PMWIN', '#756', -- WinGetNextWindow henum, 2) if not hwnd then -- No more top-level windows leave elseif hwnd == my_hwnd then -- Just me, never mind --dprintf( rightstr( cnt, 2)': 1) hwnd = F: 'ClsFrame', C: 'ClsName', hwndF = 'hwnd', hwndC = 'getpminfo( EPMINFO_EDITCLIENT)) iterate endif len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName atol( hwnd) || atol( 128) || address( buf), 2) ClsFrame = leftstr( buf, len) hwndClient = dynalink32( 'PMWIN', '#899', -- WinWindowFromId atol( hwnd) || atol( FID_CLIENT), 2) -- get client len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName atol( hwndClient) || atol( 128) || address( buf), 2) ClsClient = leftstr( buf, len) --dprintf( rightstr( cnt, 2)': 1) hwnd = F: 'ClsFrame', C: 'ClsClient', hwndF = 'hwnd', hwndC = 'hwndClient) -- Same class as me? if ClsName = ClsClient then --dprintf( 'ClsName = 'ClsName) --dprintf( rightstr( cnt, 2)': 2) hwnd = F: 'ClsFrame', C: 'ClsClient', hwndF = 'hwnd', hwndC = 'hwndClient) -- Don't process windows startet with /m (extra instance). -- Sending PostTo messages would make windows crash. if (IsExtraInstance( hwndClient) <> 0) then iterate endif Num = Num + 1 if fRestart then --dprintf( 'SaveAllLastRings: PostTo 'hwndClient' SaveCloseNextLastRing 'Num) 'PostTo 'hwndClient' SaveCloseNextLastRing 'Num else --dprintf( 'SaveAllLastRings: PostTo 'hwndClient' SaveNextLastRing 'Num) 'PostTo 'hwndClient' SaveNextLastRing 'Num endif endif enddo call dynalink32( 'PMWIN', '#737', -- WinEndEnumWindows henum, 2) return ; --------------------------------------------------------------------------- ; This saves all rings to the 'Last' tree in config. ; Syntax: SaveLastRing defc SaveLastRing, SaveAllLastRings KeyPath = '\NEPMD\Var\History\Last' -- Delete Last history first. --dprintf( 'DeleteConfigTree( 'KeyPath')') DeleteConfigTree( KeyPath) -- Find all EPM windows and execute SaveLastRing from there. -- is determined from the Z-order of found EPM windows: -- 1, 2, 3, ... is also saved as universal ringnum (local). call SaveAllLastRings( KeyPath) ; --------------------------------------------------------------------------- ; This saves the ring specified by . It is executed by SaveAllLastRings ; for the first ring. ; Syntax: SaveNextLastRing defc SaveNextLastRing parse arg Num Num = strip( Num) SaveNextLastRing( Num) ; --------------------------------------------------------------------------- ; This saves the ring specified by . After that, the window is closed. ; It is posted by SaveAllLastRings for other rings. ; Syntax: SaveCloseNextLastRing defc SaveCloseNextLastRing parse arg Num Num = strip( Num) Cmd = 'Close' SaveNextLastRing( Num, Cmd) ; --------------------------------------------------------------------------- ; This saves the ring specified by . It allows for an optional ; that is executed after the ring is saved. ; Syntax: SaveNextLastRing( [], []) defproc SaveNextLastRing universal ringnum universal savelastringdisabled do once = 1 to 1 CheckRc = 0 rc = 0 getfileid startfid fid = startfid --dprintf( ' SaveNextLastRing 'arg( 1)': savelastringdisabled = 'savelastringdisabled) if savelastringdisabled then leave endif Num = arg( 1) Cmd = arg( 2) --dprintf( 'SaveNextLastRing: Num = 'Num', Cmd = 'Cmd) KeyPath = '\NEPMD\Var\History\Last' 'VSyncCursor' -- Reset universal ringnum = '' -- Write 'RestorePos ', loop through all files in ring n = 0 RestartDir = GetTmpPath()'nepmd\restart' RestartNumDir = RestartDir'\'Num -- Restart: The window with Num = 1 is not closed by -- 'SaveCloseNextLastRing'. 'SaveNextLastRing' is executed instead -- and that window (the last one) is closed specially. During Restart -- GetCheckModifyRestart is set to 1, so this is used here. fRestart = (upcase( Cmd) = 'CLOSE' | GetCheckModifyRestart() = 1) --dprintf( 'SaveNextLastRing: fRestart = 'fRestart) display -1 dprintf( 'RINGCMD', 'SaveLastRing') do f = 1 to filesinring( 1) -- Provide an upper limit; prevent looping forever -- Store virtual and modified states before save fVirtual = IsVirtual() VirtualFilename = '' fModified = (.modify > 0) fIsAShell = IsAShell() --dprintf( 'SaveNextLastRing: fVirtual = 'fVirtual', fRestart = 'fRestart', fModified = 'fModified', '.filename) n = n + 1 if fVirtual & fRestart then --dprintf( 'SaveNextLastRing: Virtual file: '.filename) VirtualFilename = .filename WriteConfigKey( KeyPath'\'Num'\'n'\Filename', VirtualFilename) SaveFilename = RestartNumDir'\restart.'n --dprintf( 'SaveNextLastRing: Save as 'SaveFilename', .filename = '.filename) if not NepmdDirExists( RestartNumDir) then MakeTree( RestartNumDir) endif .filename = SaveFilename 'xcom s /o /nt /ne' --dprintf( 'SaveNextLastRing: Saved as 'SaveFilename', reset .modify.') if GetMode() = 'SHELL' then 'ShellSaveEnv 'SaveFilename endif elseif fModified & fRestart then --dprintf( 'SaveNextLastRing: Existing and modified file: '.filename', call CheckModify') CheckRc = CheckModify() if CheckRc then rc = CheckRc leave endif SaveFilename = .filename elseif fVirtual & fRestart then -- Don't save virtual files for a file list iterate else SaveFilename = .filename endif --dprintf( 'SaveNextLastRing: Store in Last as 'SaveFilename) pSave_Pos( SavedPos) SavedPos = subword( SavedPos, 1, 4) -- Omit the last two sizes -- Save filename and pos ConfigValue = EnquoteFileSpec( SaveFilename) if fVirtual & fRestart & fModified then --dprintf( 'SaveNextLastRing: Virtual file: 'SaveFilename) if fIsAShell then -- At the end of shell start 'DiscardChanges' is executed. -- Therefore save modified state as file array var. ConfigValue = ConfigValue" 'mc ;RestorePos "SavedPos";RestoreFilename "VirtualFilename";SetFileAVar shellrestoremodify 1'" else ConfigValue = ConfigValue" 'mc ;RestorePos "SavedPos";RestoreFilename "VirtualFilename";RestoreModify 1'" endif elseif fVirtual & fRestart then --dprintf( 'SaveNextLastRing: Virtual file: 'SaveFilename) ConfigValue = ConfigValue" 'mc ;RestorePos "SavedPos";RestoreFilename "VirtualFilename"'" else ConfigValue = ConfigValue" 'RestorePos "SavedPos"'" endif WriteConfigKey( KeyPath'\'Num'\'n, ConfigValue) nextfile getfileid fid if fid = startfid then leave endif enddo pActivateFile( startfid) display 1 if CheckRc then leave endif -- Save window pos and size WindowPos = NepmdQueryWindowPos( EPMINFO_EDITFRAME) WriteConfigKey( KeyPath'\'Num'\WindowPos', WindowPos) -- Save WorkDir for first ring only, because it's global if Num = 1 then WriteConfigKey( KeyPath'\'Num'\WorkDir', directory()) endif -- Frame window handle doesn't need to be saved -- Save client window handle hwndClient = getpminfo( EPMINFO_EDITCLIENT) WriteConfigKey( KeyPath'\'Num'\hwnd', hwndClient) --dprintf( ' SaveNextLastRing 'Num': WriteConfigKey( 'KeyPath'\'Num'\hwnd, 'hwndClient')') -- Save universal ringnum ringnum = Num --dprintf( ' SaveNextLastRing 'Num': ringnum = 'ringnum', hwndClient = 'hwndClient', 'n' filenames saved') if Cmd then --dprintf( ' SaveNextLastRing: 'Cmd) Cmd endif enddo ; --------------------------------------------------------------------------- ; Syntax: CheckAllRingsModify defc CheckAllRingsModify universal excludehwndlist --dprintf( 'CheckAllRingsModify: --------------------------------------------------------------------') CheckRc = 0 -- Check if this is an extra instance, e.g. opened by "svn ci". -- Other EPM windows, opened with "epm /m" also don't save anything -- here. If this window from an extra instance executes a PostTo -- cmd to another EPM window, all other windows would close. if (IsExtraInstance() <> 0) then -- Returns 0 | 1 | '?' return endif -- Check current ring 'RingCheckModify' CheckRc = rc --dprintf( 'CheckAllRingsModify: RingCheckModify returns CheckRc = 'CheckRc', file on top = '.filename) if CheckRc then --dprintf( 'CheckAllRingsModify: RingCheckModify: File in this ring modified, file on top = '.filename) return CheckRc endif -- Find next rings. Post SaveLastRings to next ring. Wait until hwnd -- is written. buf = leftstr( '', 128, \0) desktop = 1 -- (1 == HWND_DESKTOP) my_hwnd = getpminfo( EPMINFO_EDITFRAME) --dprintf( ' 0: my_hwnd = 'getpminfo( EPMINFO_EDITFRAME)) len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName GethWndC( EPMINFO_EDITFRAME) || atol( 128) || address( buf), 2) ClsFrame = leftstr( buf, len) -- Get ClsName (NewEditWndClass) of current edit client window len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName GethWndC( EPMINFO_EDITCLIENT) || atol( 128) || address( buf), 2) ClsName = leftstr( buf, len) --dprintf( ' 0: my_hwnd = F: 'ClsFrame', C: 'ClsName', hwndF = 'getpminfo( EPMINFO_EDITFRAME)', hwndC = 'getpminfo( EPMINFO_EDITCLIENT)) -- Examine desktop windows for client of same edit class henum = atol( dynalink32( 'PMWIN', '#702', -- WinBeginEnumWindows atol( desktop), 2)) cnt = 0 do while cnt < 250 cnt = cnt + 1 hwnd = dynalink32( 'PMWIN', '#756', -- WinGetNextWindow henum, 2) if not hwnd then -- No more top-level windows leave elseif hwnd == my_hwnd then -- Just me, never mind --dprintf( rightstr( cnt, 2)': 1) hwnd = F: 'ClsFrame', C: 'ClsName', hwndF = 'hwnd', hwndC = 'getpminfo( EPMINFO_EDITCLIENT)) iterate endif len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName atol( hwnd) || atol( 128) || address( buf), 2) ClsFrame = leftstr( buf, len) hwndClient = dynalink32( 'PMWIN', '#899', -- WinWindowFromId atol( hwnd) || atol( FID_CLIENT), 2) -- get client len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName atol( hwndClient) || atol( 128) || address( buf), 2) ClsClient = leftstr( buf, len) --dprintf( rightstr( cnt, 2)': 1) hwnd = F: 'ClsFrame', C: 'ClsClient', hwndF = 'hwnd', hwndC = 'hwndClient) -- Same class as me? if ClsName <> ClsClient then iterate endif --dprintf( 'ClsName = 'ClsName) --dprintf( rightstr( cnt, 2)': 2) hwnd = F: 'ClsFrame', C: 'ClsClient', hwndF = 'hwnd', hwndC = 'hwndClient) -- The config value must be deleted first. -- In the first loop, it is checked if the passed cmd by PostTo is known. -- If known, the value '*' is written. If not, the short timeout of 1 s -- applies, rc is set and this proc returns. -- If the value '*' was written, the second loop is started with a larger -- timeout value. This is the real check. -- The advantage of the additional first loop is that a shorter timeout -- value can be used here. Previously, it was waited for the timeout of -- 60 s when the 'Quick Reference' window received the -- RingCheckModifyConfigKey cmd. -- Delete a global temp. config key first KeyPath = '\NEPMD\Var\RingCheckModify\DoneRc' DeleteConfigKey( KeyPath) -- Don't process windows startet with /m (extra instance). -- Sending PostTo messages would make windows crash. -- IsExtraInstance returns '?' if an EPM window is started without -- writing the LoaderArgs config key. if (IsExtraInstance( hwndClient) <> 0) then -- Returns 0 | 1 | '?' --dprintf( 'CheckAllRingsModify: Adding hwndClient = 'hwndClient' to excludehwndlist = 'excludehwndlist) if excludehwndlist = '' then excludehwndlist = hwndClient else excludehwndlist = excludehwndlist hwndClient endif endif -- Don't process already excluded windows if wordpos( hwndClient, excludehwndlist) then rc = -5 --dprintf( 'CheckAllRingsModify: hwndClient = 'hwndClient', excludehwndlist = 'excludehwndlist', rc = 'rc) iterate endif -- WaitNextCheckModify does 2 checks to shorten the timeout if -- RingCheckModifyConfigKey is unknown. The first check writes the value -- '*' with a shorter timeout of 1 s to show that the cmd is understood. -- The second check uses the following timeout value: TimeoutMs = 60000 -- 60 s --dprintf( 'CheckAllRingsModify: call WaitNextCheckModify( 'hwndClient', 'KeyPath', 'TimeoutMs')') call WaitNextCheckModify( hwndClient, KeyPath, TimeoutMs) CheckRc = rc --dprintf( 'CheckAllRingsModify: CheckRc = 'CheckRc) if CheckRc = -22 then --dprintf( 'Timeout on waiting for config key 'KeyPath' in CheckAllRingsModify') 'SayError Timeout on waiting for config key 'KeyPath' in CheckAllRingsModify' --dprintf( 'CheckAllRingsModify: Ring not checked, hwndClient = 'hwndClient', CheckRc = 'CheckRc) leave elseif CheckRc = -293 then --dprintf( 'CheckAllRingsModify: Cancel, hwndClient = 'hwndClient', CheckRc = 'CheckRc) leave elseif CheckRc = 0 then --dprintf( 'CheckAllRingsModify: Included file not modified, hwndClient = 'hwndClient', CheckRc = 'CheckRc) else -- This should not happen --dprintf( 'CheckAllRingsModify: other CheckRc, hwndClient = 'hwndClient', CheckRc = 'CheckRc) endif enddo -- Cleanup DeleteConfigKey( KeyPath) call dynalink32( 'PMWIN', '#737', -- WinEndEnumWindows henum, 2) rc = CheckRc ; --------------------------------------------------------------------------- ; This is executed by a child EPM window. ; This works almost as RingCheckModify, except that a config key with the ; rc from the checks is written. Config keys are global and can be used ; across EPM windows. ; WaitNextCheckModify does 2 checks to shorten the timeout if ; RingCheckModifyConfigKey is unknown. The first check writes the value '*' ; with a shorter timeout of 1 s to show that the cmd is understood. defc RingCheckModifyConfigKey KeyPath = strip( arg( 1)) CheckRc = 0 CurVal = QueryConfigKey( KeyPath) --dprintf( ' RingCheckModifyConfigKey: QueryConfigKey( 'KeyPath') = 'CurVal', hwndClient = 'getpminfo( EPMINFO_EDITCLIENT)) if CurVal = '' then -- Show that the cmd is understood WriteConfigKey( KeyPath, '*') --dprintf( ' RingCheckModifyConfigKey: WriteConfigKey( 'KeyPath', *)') elseif CurVal = '*' then --dprintf( 'RINGCMD', 'RingCheckModifyConfigKey') 'RingCheckModify' CheckRc = rc --dprintf( ' RingCheckModifyConfigKey: RingCheckModify sets CheckRc = 'CheckRc) WriteConfigKey( KeyPath, CheckRc) --dprintf( ' RingCheckModifyConfigKey: WriteConfigKey( 'KeyPath', 'CheckRc')') endif rc = CheckRc ; --------------------------------------------------------------------------- ; This posts RingCheckModifyConfigKey to the next window. defproc WaitNextCheckModify( hwndClient, KeyPath, TimeoutMs) rc = 0 -- Check next ring 'PostTo 'hwndClient' RingCheckModifyConfigKey' KeyPath --dprintf( 'WaitNextCheckModify: call WaitForConfigKey( 1000, 'KeyPath', *)') call WaitForConfigKey( 1000, KeyPath, '*') -- 1 s --dprintf( 'WaitNextCheckModify: WaitForConfigKey returns rc = 'rc) if not rc then 'PostTo 'hwndClient' RingCheckModifyConfigKey' KeyPath --dprintf( 'WaitNextCheckModify: call WaitForConfigKey( 'TimeoutMs', 'KeyPath')') call WaitForConfigKey( TimeoutMs, KeyPath) --dprintf( 'WaitNextCheckModify: WaitForConfigKey returns rc = 'rc) endif return ; --------------------------------------------------------------------------- ; Syntax: WaitForConfigKey( , [, ]) ; This is executed by the parent EPM window. ; Loops until config value found or timeout occurs. Waits 200 ms between ; checks. ; Config keys are global. Sets rc = 0 or rc = -22 if timeout occurs. defproc WaitForConfigKey( TimeoutMs, KeyPath) CheckVal = arg( 3) SleepMs = 200 -- Cycle time in ms --dprintf( 'WaitForConfigKey: TimeoutMs = 'TimeoutMs', KeyPath = 'KeyPath', CheckVal = 'CheckVal) --dprintf( 'Parent: WaitChildDone: reg key = 'QueryConfigKey( KeyPath)', wait for val = 'CheckVal) fChildDone = 0 CurVal = '' i = 0 do forever if TimeoutMs <> 0 then if i >= TimeoutMs/SleepMs then leave endif endif i = i + 1 CurVal = QueryConfigKey( KeyPath) if CheckVal = '*' then if CurVal = '*' then fChildDone = 1 leave endif elseif CheckVal = '' then -- No CheckVal specified: Check for any CurVal if CurVal <> '*' then fChildDone = 1 leave endif else -- CheckVal specified: Check for word within CurVal if wordpos( CheckVal, CurVal) then fChildDone = 1 leave endif endif Sleep( SleepMs) enddo if fChildDone then rc = 0 --dprintf( ' WaitForConfigKey: rc = 'rc', CurVal = 'CurVal', CheckVal = 'CheckVal) else rc = -22 --dprintf( ' WaitForConfigKey: timeout') endif return ; --------------------------------------------------------------------------- ; Stops if current window is not the only EPM window, so this can be used as ; command. defc CheckOnlyEpmWindow Cmd = strip( arg( 1)) if Cmd = '' then CurCmd = 'The current command' else CurCmd = 'The '''Cmd''' command' endif do while not IsOnlyEpmWindow() refresh Title = 'Multiple EPM windows' Text = CurCmd' can''t be executed as long as multiple' || ' EPM windows are open.'\n\n || 'Press "OK" to try again or "Cancel" to abort.' rcx = WinMessageBox( Title, Text, MB_OKCANCEL + MB_WARNING + MB_MOVEABLE) if rcx = MBID_OK then iterate else rc = -269 -- User Break. Command halted stop --leave endif enddo ; --------------------------------------------------------------------------- ; Returns 0 or 1. defproc IsOnlyEpmWindow ptr = dynalink32( 'PMWIN', '#839', -- Win32QueryWindowPtr GethWndC( EPMINFO_OWNERFRAME) || atol( 0), 2) listptr = ltoa( peek32( ptr, 1856, 4), 10) hwndx = peek32( listptr, 0, 4) next = ltoa( peek32( listptr, 8, 4), 10) if not next then return 1 else return 0 endif ; --------------------------------------------------------------------------- defproc SetCheckModifyRestart Restart = arg( 1) KeyPath = '\NEPMD\Var\RingCheckModify\Restart' call WriteConfigKey( KeyPath, Restart) return ; --------------------------------------------------------------------------- defproc GetCheckModifyRestart KeyPath = '\NEPMD\Var\RingCheckModify\Restart' Restart = QueryConfigKey( KeyPath, Restart) return Restart ; --------------------------------------------------------------------------- defproc SetCheckModifyOptions IncludeFileSpecs = arg( 1) IncludeModes = arg( 2) ExcludeFileSpecs = arg( 3) ExcludeModes = arg( 4) KeyPath = '\NEPMD\Var\RingCheckModify' call WriteConfigKey( KeyPath'\IncludeFileSpecs', IncludeFileSpecs) call WriteConfigKey( KeyPath'\IncludeModes' , IncludeModes) call WriteConfigKey( KeyPath'\ExcludeFileSpecs', ExcludeFileSpecs) call WriteConfigKey( KeyPath'\ExcludeModes' , ExcludeModes) return ; --------------------------------------------------------------------------- ; This uses config key values to make it configurable across multiple rings. defproc GetCheckModifyIncluded( Filename, Mode) do once = 1 to 1 fIncludeFile = 1 UpFilename = upcase( Filename) KeyPath = '\NEPMD\Var\RingCheckModify' IncludeFileSpecs = upcase( QueryConfigKey( KeyPath'\IncludeFileSpecs')) IncludeModes = upcase( QueryConfigKey( KeyPath'\IncludeModes')) ExcludeFileSpecs = upcase( QueryConfigKey( KeyPath'\ExcludeFileSpecs')) ExcludeModes = upcase( QueryConfigKey( KeyPath'\ExcludeModes')) --dprintf( ' GetCheckModifyIncluded: IncludeFileSpecs = 'IncludeFileSpecs', IncludeModes = 'IncludeModes', ExcludeFileSpecs = 'ExcludeFileSpecs', ExcludeModes = 'ExcludeModes) Rest = IncludeFileSpecs do while Rest <> '' if leftstr( Rest, 1) = '"' then parse value Rest with '"'Next'"' Rest else parse value Rest with Next Rest endif if not StrMatch( UpFilename, Next) then fIncludeFile = 0 --dprintf( ' GetCheckModifyIncluded: 1) not StrMatch( Filename, 'Next')') leave endif enddo if not fIncludeFile then leave endif if IncludeModes = '' then -- nop elseif not wordpos( Mode, IncludeModes) then fIncludeFile = 0 --dprintf( ' GetCheckModifyIncluded: 2) not wordpos( 'Mode', 'IncludeModes')') leave endif Rest = ExcludeFileSpecs do while Rest <> '' if leftstr( Rest, 1) = '"' then parse value Rest with '"'Next'"' Rest else parse value Rest with Next Rest endif if StrMatch( UpFilename, Next) then fIncludeFile = 0 --dprintf( ' GetCheckModifyIncluded: 3) StrMatch( Filename, 'Next')') leave endif enddo if not fIncludeFile then leave endif if ExcludeModes = '' then -- nop elseif wordpos( Mode, ExcludeModes) then fIncludeFile = 0 --dprintf( ' GetCheckModifyIncluded: 4) wordpos( 'Mode', 'ExcludeModes')') leave endif enddo return fIncludeFile ; --------------------------------------------------------------------------- ; This calls CheckModify for every loaded file. It return CheckRc from it. ; On Restart virtual files are not checked, because they are saved to disk ; by SaveNextLastRing. ; CheckModify switches to a modified file and opens a messgae box for to ; save/discard/cancel. ; This ensures that special files can be closed without popping up a message ; box that asks "Are you sure?" defc RingCheckModify CheckRc = 0 getfileid fid startfid = fid dprintf( 'RINGCMD', 'RingCheckModify') 'VSyncCursor' fRestart = (GetCheckModifyRestart() == 1) --dprintf( 'RingCheckModify: fRestart = 'fRestart) do i = 1 to filesinring( 1) -- just as an upper limit --dprintf( 'RingCheckModify: .filename = '.filename', .modify = '.modify) Mode = GetMode() if not GetCheckModifyIncluded( .filename, Mode) then --dprintf( 'RingCheckModify: not included, .filename = '.filename', Mode = 'Mode) -- nop elseif IsVirtual() & fRestart then --dprintf( 'RingCheckModify: IsVirtual & fRestart => ignored, .filename = '.filename) -- Don't check virtual files on Restart, they are saved in -- SaveNextLastRing. SaveNextLastRing is executed e.g. on Restart, -- but not here. -- nop else --dprintf( 'RingCheckModify: .filename = '.filename) CheckRc = CheckModify() --dprintf( 'RingCheckModify: CheckModify() returns CheckRc = 'CheckRc) if CheckRc then activatefile startfid leave endif endif nextfile getfileid fid if fid = startfid then leave endif enddo rc = CheckRc ; --------------------------------------------------------------------------- defc CheckModify CheckRc = CheckModify() rc = CheckRc if CheckRc then stop endif ; --------------------------------------------------------------------------- ; Resets .modify for Yes or No button. Yes: Save, No: Discard. ; Button Action rc ; Yes Save 0 ; No Discard 0 ; Cancel - -293 defproc CheckModify CheckRc = 0 if .modify then refresh Title = 'Save modified file' Text = .filename\n\n || 'The above file is modified. Press "Yes" to save it,' || ' "No" to discard it or "Cancel" to abort.'\n\n || 'Do you want to save it?' rcx = WinMessageBox( Title, Text, MB_YESNOCANCEL + MB_QUERY + MB_DEFBUTTON1 + MB_MOVEABLE) if rcx = MBID_YES then 'Save' elseif rcx = MBID_NO then .modify = 0 else -- Cancel CheckRc = -293 -- has been modified endif --dprintf( 'CheckModify: CheckRc from msg box = 'CheckRc) endif return CheckRc ; --------------------------------------------------------------------------- ; Some PMWIN.H constants: #define QW_NEXT 0 #define QW_PREV 1 #define QW_TOP 2 #define QW_BOTTOM 3 #define QW_OWNER 4 #define QW_PARENT 5 #define QW_NEXTTOP 6 #define QW_PREVTOP 7 #define QW_FRAMEOWNER 8 #define FID_CLIENT 0x8008 #define HWND_DESKTOP 1 #define HWND_TOP 3 #define HWND_BOTTOM 4 #define QWL_STYLE (-2) #define SWP_SIZE 0x0001 #define SWP_MOVE 0x0002 #define SWP_ZORDER 0x0004 #define SWP_ACTIVATE 0x0080 #define SWP_RESTORE 0x1000 #define WS_MINIMIZED 0x01000000 ; --------------------------------------------------------------------------- ; EPM /m windows are not included. It works with minimized windows. The focus ; is set to the next window in the Z-order. defc Next_Win, NextWin ptr = dynalink32( 'PMWIN', '#839', -- Win32QueryWindowPtr GethWndC( EPMINFO_OWNERFRAME) || atol( 0), 2) listptr = ltoa( peek32( ptr, 1856, 4), 10) hwndx = peek32( listptr, 0, 4) next = ltoa( peek32( listptr, 8, 4), 10) if not next then 'SayError This is the only edit window.' return endif first_hwndx = hwndx my_hwndx = GethWndC( EPMINFO_EDITCLIENT) do while hwndx /== my_hwndx listptr = next hwndx = peek32( listptr, 0, 4) next = ltoa( peek32( listptr, 8, 4), 10) enddo if next then hwndx = peek32( next, 0, 4) else hwndx = first_hwndx endif EFrame_hwnd = dynalink32( 'PMWIN', '#834', -- Win32QueryWindow hwndx || atol( QW_PARENT), 2) call MakeWindowTopmost( EFrame_hwnd) -- Give the focus to the edit window of EFrame_hwnd. Otherwise an open -- search window changes its owner to that topmost window and takes the -- focus, what is not intended in that case. PostMe is required to -- process SetFocus as last one. 'PostMe SetFocus' ltoa( hwndx, 10) -- Highlight the cursor of that window PostCmdToEditWindow( 'HighlightCursor', ltoa( hwndx, 10)) /* ; --------------------------------------------------------------------------- ; Not really part of next_win, but throw it in anyway... defc ewin = -- List edit windows call windowmessage( 0, getpminfo( APP_HANDLE), -- Send message to owner client 32, -- WM_COMMAND - 0x0020 203, -- IDM_EDITWNDS 0) */ /* ; --------------------------------------------------------------------------- ; Following PMWIN calls switch to the next *topmost* EPM window, not to that ; one with the next hwnd. ; Bug: hidden windows are not restored. ; This includes EPM /m windows, but the focus is toggled between the two ; topmost windows. ; I am not aware of any EPM commands or procs to help switch the ; focus between files in separate edit rings, like godoc in LPEX. ; So I wrote this little utility to toggle between EPM windows. ; It works by checking all top level frame windows for a client ; belonging to the same class as the current EPM window. ; *------------------------------------------------+ ; | EPM macro code to jump to the other edit ring | ; | Author: Michael Golding, IBM (STL), 8-543-3569 | ; +------------------------------------------------* ; def c_F12 = 'KWIKJMP' include 'stdconst.e' defc kwikjmp buf = leftstr( '', 128, \0) desktop = atol( 1) -- (1 == HWND_DESKTOP) hndFrame = GethWndC( EPMINFO_EDITFRAME) len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName GethWndC( EPMINFO_EDITCLIENT) || atol( 128) || address( buf), 2) henum = atol( dynalink32( 'PMWIN', '#702', -- WinBeginEnumWindows desktop, 2)) clsname = leftstr( buf, len) found = 0 cnt = 0 --- examine desktop windows for client of same edit class do while cnt < 250 cnt = cnt + 1 hnd = dynalink32( 'PMWIN', '#756', -- WinGetNextWindow henum, 2) hndF = atol( hnd) if not hnd then leave -- no more top-level windows elseif hndF = hndFrame then iterate -- just me, never mind endif hnd = dynalink32( 'PMWIN', '#899', -- WinWindowFromId hndF || atol( 32776), 2) -- get client len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName atol( hnd) || atol( 128) || address( buf), 2) if clsname = leftstr( buf, len) then -- same class as me? found = 1 -- YES!! leave endif enddo call dynalink32( 'PMWIN', '#737', -- WinEndEnumWindows henum, 2) if found then call dynalink32( 'PMWIN', '#851', -- WinSetActiveWindow desktop || atol( hnd), 2) elseif cnt < 250 then 'SayError *** window not found: cnt='cnt else 'SayError *** bailed out: cnt='cnt endif */ ; --------------------------------------------------------------------------- defc CloseOtherWin buf = leftstr( '', 128, \0) desktop = atol( 1) -- (1 == HWND_DESKTOP) my_hwndx = GethWndC( EPMINFO_EDITFRAME) --dprintf( 'CloseOtherWin, '.filename) -- Get ClsName (NewEditWndClass) of current edit client window len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName GethWndC( EPMINFO_EDITCLIENT) || atol( 128) || address( buf), 2) ClsName = leftstr( buf, len) -- Examine desktop windows for client of same edit class henum = atol( dynalink32( 'PMWIN', '#702', -- WinBeginEnumWindows desktop, 2)) cnt = 0 do while cnt < 250 cnt = cnt + 1 hwnd = dynalink32( 'PMWIN', '#756', -- WinGetNextWindow henum, 2) if not hwnd then -- No more top-level windows leave elseif atol( hwnd) == my_hwndx then -- Just me, never mind iterate endif hwndClient = dynalink32( 'PMWIN', '#899', -- WinWindowFromId atol( hwnd) || atol( FID_CLIENT), 2) -- get client len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName atol( hwndClient) || atol( 128) || address( buf), 2) -- Same class as me? if ClsName = leftstr( buf, len) then --dprintf( 'ClsName = 'ClsName) -- Make minimized windows topmost first. This is useful if the -- 'Ask to quit on modified' dialog opens on posting a WM_CLOSE msg. Style = dynalink32( 'PMWIN', '#843', -- Win32QueryWindowULong atol( hwnd) || atol( QWL_STYLE), 2) if Style bitand WS_MINIMIZED then opts = SWP_ZORDER bitor SWP_ACTIVATE bitor SWP_RESTORE call dynalink32( 'PMWIN', '#875', -- Win32SetWindowPos atol( hwnd) || atol( HWND_TOP) || atol( 0) || atol( 0) || atol( 0) || atol( 0) || atol( opts)) endif -- Close window call windowmessage( 0, hwnd, 41, -- WM_CLOSE 0, 0) endif enddo call dynalink32( 'PMWIN', '#737', -- WinEndEnumWindows henum, 2) ; --------------------------------------------------------------------------- defproc IsATmpFile Filename = arg( 1) if Filename = '' then Filename = .filename endif TmpDir = GetTmpDir() fTmpFile = (upcase( leftstr( Filename, length( TmpDir))) = upcase( TmpDir)) return fTmpFile defproc IsATempFile return (IsATmpFile( arg( 1))) ; --------------------------------------------------------------------------- defproc IsARestartFile Filename = arg( 1) if Filename = '' then Filename = .filename endif RestartTree = GetTmpPath()'nepmd\restart' fRestartFile = (upcase( leftstr( Filename, length( RestartTree))) = upcase( RestartTree)) return fRestartFile ; --------------------------------------------------------------------------- ; Check for a modified file in ring. If not, save all rings and restart all. ; Syntax: Restart [Args] defc Restart universal excludehwndlist do once = 1 to 1 Args = arg( 1) if Args = '' then Cmd = 'RestoreLastRing' else Cmd = 'mc ;RestoreLastRing;AfterStartup' Args endif SetCheckModifyRestart( '1') 'DeleteRestartTree' excludehwndlist = '' SetCheckModifyOptions() --dprintf( 'Restart: Executing CheckAllRingsModify, rc before = 'rc) 'CheckAllRingsModify' --dprintf( 'Restart: rc from CheckAllRingsModify = 'rc) if rc then return endif -- This saves all rings to config. Because the restart flag is set, -- the windows of all rings except the current window are closed. -- Current window is closed after executing the delayed -- RestoreLastRing cmd. --dprintf( '* Restart: Executing SaveLastRing, rc from CheckAllRingsModify = 'rc) 'SaveLastRing' excludehwndlist = '' SetCheckModifyRestart( '0') -- Write flag that last rings have to be restored KeyPath = '\NEPMD\Var\RestoreLastRing\Done' WriteConfigKey( KeyPath, 0) EpmArgs = "'"Cmd"'" --dprintf( 'Restart: Executing PostMe Restart2 'EpmArgs) 'PostMe Restart2 'EpmArgs enddo defc Restart2 parse arg EpmArgs compile if 0 -- Doesn't work really reliable everytime (but even though useful): -- o Sometimes EPM.EX is not reloaded. -- o Sometimes EPM crashes on 'SaveLastRing' or on executing arg( 1). -- -> Still happens? 'Open' EpmArgs compile else -- Using external .cmd now. It includes a delay: EpmExe = Get_Env( 'NEPMD_LOADEREXECUTABLE') --dprintf( '* Restart2: Executing start /c /min epmresume' EpmExe EpmArgs' for 'getpminfo( EPMINFO_EDITCLIENT)) 'start /c /min epmresume' EpmExe EpmArgs --dprintf( '* Restart2: Executing Close for hwnd = 'getpminfo( EPMINFO_EDITCLIENT)) 'Close 'getpminfo( EPMINFO_EDITCLIENT) compile endif ; --------------------------------------------------------------------------- ; This restores multiple rings, as previously saved by SaveLastRing. ; Syntax: RestoreLastRing [ []] ; If is omitted, then all rings are restored. ; If is omitted, then fFirstRing = 0. defc RestoreLastRing, LoadLastRing universal edithistorydisabled universal loadhistorydisabled universal savelastringdisabled universal ringnum --dprintf( 'RestoreLastRing 'arg( 1)': savelastringdisabled = 'savelastringdisabled', ringnum = 'ringnum) parse arg Num fFirstRing Num = strip( Num) fFirstRing = (strip( fFirstRing) = 1) fAllRings = 0 if not IsNum( Num) then fAllRings = 1 endif KeyPath = '\NEPMD\Var\History\Last' -- Restore next rings if fAllRings then call RestoreAllLastRings( KeyPath) return endif edithistorydisabled = 1 loadhistorydisabled = 1 savelastringdisabled = 1 NextKeyPath = '\NEPMD\Var\History\Last\'Num --dprintf( ' NextKeyPath = 'NextKeyPath) -- Restore window pos and size WindowPos = QueryConfigKey( NextKeyPath'\WindowPos') 'WindowPos 'WindowPos -- Restore ring FirstFid = '' NextKey = '' do while NepmdGetNextConfigKey( -3, NextKeyPath, 'K', NextKey) if not IsNum( NextKey) then iterate endif FileNamePos = QueryConfigKey( NextKeyPath'\'NextKey) --dprintf( ' FileNamePos = 'FileNamePos) --dprintf( 'RestoreLastRing: Edit FileNamePos, FileNamePos = 'FileNamePos) 'Edit 'FileNamePos if FirstFid = '' then getfileid FirstFid endif enddo -- Restore WorkDir for first ring if fFirstRing then WorkDir = QueryConfigKey( NextKeyPath'\WorkDir') if WorkDir <> '' then call Directory2( WorkDir) endif endif -- Switch to first loaded file pActivateFile( FirstFid) -- Renew hwnd for current Num WriteConfigKey( NextKeyPath'\hwnd', getpminfo( EPMINFO_EDITCLIENT)) -- Write ringnum after restore ringnum = Num if fFirstRing then -- Open recompile message box if cmd exists KeyPath = '\NEPMD\Var\RestoreLastRing' MsgCmd = QueryConfigKey( KeyPath'\AfterRestoreCmd') if MsgCmd <> '' then -- With the additional PostMe, the MsgBox is hopefully opened -- after the file was highlighted: 'AtEvent AfterStartup PostMe 'MsgCmd endif --dprintf( 'RestoreLastRing: AtEvent AfterStartup PostMe DeleteConfigTree quiet 'KeyPath) 'AtEvent AfterStartup PostMe DeleteConfigTree quiet 'KeyPath endif edithistorydisabled = 0 -- loadhistorydisabled is automatically reset by ProcessPostFilesLoaded -- savelastringdisabled is reset by the following RefreshLastRing --dprintf( ' Exit RestoreLastRing 'arg( 1)': savelastringdisabled = 'savelastringdisabled', ringnum = 'ringnum', hwndClient = 'getpminfo( EPMINFO_EDITCLIENT)) ; --------------------------------------------------------------------------- ; This is executed per file defc RestoreFilename Filename = strip( arg( 1)) -- Save the temp. filename for virtual shell files. That makes -- ShellRestore find the saved .env file for virtual files. RestartDir = GetTmpPath()'nepmd\restart' if upcase( leftstr( .filename, length( RestartDir))) = upcase( RestartDir) & IsAShellFilename( Filename) then SetFileAVar( 'restartfilename', .filename) endif if Filename <> '' then .filename = Filename endif ; --------------------------------------------------------------------------- ; This executes RestoreLastRing for all rings, starting with last ; . ; Syntax: RestoreAllLastRings( ) defproc RestoreAllLastRings universal nepmd_hini KeyPath = arg( 1) --dprintf( 'RestoreAllLastRings: ----------------------------------------------') -- Query all numbers at once with queryprofile, -- because window opening should be bottom to top Container = queryprofile( nepmd_hini, 'RegContainer', KeyPath) rest = translate( Container, ' ', \0) -- Filter non-numbers out, can use the word functions here NumList = '' do w = 1 to words( rest) ThisWrd = word( rest, w) if not IsNum( ThisWrd) then iterate endif if NumList = '' then NumList = ThisWrd else NumList = NumList ThisWrd endif enddo -- Restore all rings do w = words( NumList) to 1 by -1 Num = word( NumList, w) -- Submit fFirstRing for restore of WorkDir and for to execute a cmd if w = 1 then fFirstRing = 1 else fFirstRing = 0 endif if w = words( NumList) then fLastRing = 1 else fLastRing = 0 endif -- First delete hwnd HandleKeyPath = KeyPath'\'Num'\hwnd' DeleteConfigKey( HandleKeyPath) if fLastRing then -- Restore the last ring in current window --dprintf( " RestoreLastRing "Num fFirstRing) 'RestoreLastRing 'Num fFirstRing else 'Sleep '500 -- Required to open in a row -- Open new window with Num as arg to restore it --dprintf( " Open 'RestoreLastRing "Num fFirstRing"'") "Open 'RestoreLastRing "Num fFirstRing"'" endif if not fFirstRing then -- Wait until hwnd key is written to continue NumList loop -- and restore next ring --dprintf( 'RestoreAllLastRings: call WaitForConfigKey( 3000, 'HandleKeyPath')') call WaitForConfigKey( 3000, HandleKeyPath) -- 3 s if rc then 'SayError Timeout on waiting for config key 'HandleKeyPath' in RestoreAllLastRings' endif endif enddo return ; --------------------------------------------------------------------------- defc DeleteRestartTree NepmdDeleteTree( GetTmpPath()'nepmd\restart') ; --------------------------------------------------------------------------- ; Renews saved ring data in config for current ring only. If ringnum isn't ; set, all rings are saved. This is executed by ProcessPostSelect and there ; filtered out for non-existant files. ; savelastringdisabled is set by RestoreLastRing and reset by ; ProcessPostSelect. defc RefreshLastRing universal savelastringdisabled universal ringnum --dprintf( '* RefreshLastRing: ringnum = 'ringnum', savelastringdisabled = 'savelastringdisabled) do once = 1 to 1 -- Always enable it savelastringdisabled = 0 -- Check if globally disabled KeyPath = '\NEPMD\User\AutoRestore\Ring\SaveLast' Enabled = QueryConfigKey( KeyPath) if Enabled <> 1 then leave endif if ringnum = '' then -- ringnum is usually set at the first select event after all -- files are loaded. If not set, repeat that for all rings. 'SaveLastRing' else 'SaveLastRing 'ringnum endif enddo ; --------------------------------------------------------------------------- ; Open a new window with a specified size ; --------------------------------------------------------------------------- ; --------------------------------------------------------------------------- ; Write a global key to reg. That one is read at defmain. defc NextWindowPos -- Write NextWindowPos Key = '\NEPMD\Var\History\FileList\NextWindowPos' Val = strip( arg( 1)) if Val <> '' then parse value Val with x y cx cy . if IsNum( x) & IsNum( y) & IsNum( cx) & IsNum( cy) then call NepmdWriteConfigValue( -3, Key, Val) endif endif ; --------------------------------------------------------------------------- ; This is executed by defmain before the window is shown. It reads a (global) ; key from reg. If present, the pos. of the current window is set and the key ; is deleted. ; The key may be written by NextWindowPos, which is executed by LoadFileList. defc ApplyNextWindowPos Key = '\NEPMD\Var\History\FileList\NextWindowPos' Val = NepmdQueryConfigValue( -3, Key) --dprintf( 'ApplyNextWindowPos: Val = 'Val) call NepmdDeleteConfigValue( -3, Key) if Val <> '' then parse value Val with x y cx cy . if IsNum( x) & IsNum( y) & IsNum( cx) & IsNum( cy) then call NepmdSetFrameWindowPos( x, y, cx, cy) endif endif ; --------------------------------------------------------------------------- ; Save and load file lists ; --------------------------------------------------------------------------- ; --------------------------------------------------------------------------- ; Passes all lines of a FileList to Edit. ; Syntax: RestoreFileList( [FileSpec] [, SectionNum [, Cmd]]) ; SectionNum may be omitted, if empty. ; For other empty args, the empty string has to be specified. ; This is executed by 'Edit @', not directly, to set universals ; etc. correctly. defproc RestoreFileList universal edithistorydisabled do once = 1 to 1 EpmFile = arg( 1) SectionNum = arg( 2) CommonCmd = arg( 3) PrevWorkDir = directory() -- Load EpmFile 'xcom e /d 'EnquoteFilespec( EpmFile) if rc then leave endif getfileid listfid if listfid = '' then leave endif -- Change to dir of EpmFile Drive = GetFileSpec( 'D', EpmFile) Path = GetFileSpec( 'P', EpmFile) NewWorkDir = Drive''Path if Path <> '\' then NewWorkDir = strip( NewWorkDir, 'T', '\') endif call directory2( NewWorkDir) -- Don't process file if first line contains 'history' after a comment. fIsAFileList = 1 NumChecked = 0 do once2 = 1 to 1 do l = 1 to .last getline LineStr, l, listfid LineStr = strip( LineStr) --dprintf( 'Line 'l': LineStr = >'LineStr'<') -- Ignore blank lines if LineStr == '' then --dprintf( '1) Empty') iterate -- l endif FirstChar = leftstr( LineStr, 1) fComment = 0 if FirstChar = ';' then fComment = 1 endif -- Check line if fComment & NumChecked = 0 & wordpos( 'HISTORY', upcase( LineStr)) then --dprintf( '2) History list, not a filelist') fIsAFileList = 0 leave -- l elseif fComment then --dprintf( '3) Comment') iterate -- l elseif FirstChar = '[' then -- File list --dprintf( '4) [') -- nop elseif substr( LineStr, 2, 2) = ':\' then --dprintf( '5) :\') -- nop elseif substr( LineStr, 1, 2) = '\\' then --dprintf( '6) \\') -- nop elseif substr( LineStr, 2, 2) = ':/' then --dprintf( '7) :/') -- nop elseif pos( '//', leftstr( LineStr, 20)) then --dprintf( '8) //') -- nop else -- Get first word, eventually enquoted. -- This should recognize filenames and cmds to distinguish -- them from most normal sentences. BeforeCmd = '' if leftstr( LineStr, 1) = "'" then parse value LineStr with "'"ThisCmd"'" Rest elseif leftstr( LineStr, 1) = '"' then parse value LineStr with '"'ThisFile'"' "'"ThisCmd"'" Rest else parse value LineStr with BeforeCmd "'"ThisCmd"'" Rest if words( BeforeCmd) = 1 then ThisFile = strip( BeforeCmd) --dprintf( '9a) ThisFile = 'ThisFile', ThisCmd = 'ThisCmd', Rest = 'Rest) else ThisFile = '' --dprintf( '9b) ThisFile = 'ThisFile', ThisCmd = 'ThisCmd', Rest = 'Rest', not a filelist') fIsAFileList = 0 leave -- l endif endif Rest = strip( Rest) --dprintf( '10) ThisFile = 'ThisFile', ThisCmd = 'ThisCmd', Rest = 'Rest) if Rest = '' then --dprintf( '10a) Rest = empty') -- nop elseif leftstr( Rest, 1) = ',' then --dprintf( '10b) Rest = segment parser') -- nop else --dprintf( '10c) Rest = other, not a filelist') fIsAFileList = 0 leave -- l endif endif NumChecked = NumChecked + 1 --dprintf( 'NumChecked = 'NumChecked) -- Check max. 3 non-empty lines only if NumChecked >= 3 then -- This is most likely a filelist leave -- l endif enddo -- l enddo -- once2 if not fIsAFileList then 'xcom quit' -- Load file normally 'Edit 'EnquoteFilespec( EpmFile) leave endif -- Rename EpmFile to allow for loading it itself without error on close .filename = '.filelist' .modify = 0 .autosave = 0 .visible = 0 -- Find '['ThisSection']' in col 1 first and store it in -- SectionStartList as '['ThisSection']' l pairs SectionStartLineList = '' do l = 1 to listfid.last getline LineStr, l, listfid LineStr = strip( LineStr) -- Ignore comment lines: ';' if leftstr( LineStr, 1) = ';' then iterate endif -- Ignore trailing comments: '--' p = pos( '--', LineStr) if p > 0 then LineStr = leftstr( LineStr, p - 1) endif -- Strip spaces LineStr = strip( LineStr) -- Ignore empty lines if LineStr = '' then iterate endif -- Find ThisSection if leftstr( LineStr, 1) = '[' & rightstr( LineStr, 1) = ']' then next = substr( Linestr, 2, length( LineStr) - 2) if IsNum( next) then ThisSection = next if SectionStartLineList = '' then SectionStartLineList = '['ThisSection']' l else SectionStartLineList = SectionStartLineList' ['ThisSection']' l endif iterate endif endif enddo --dprintf( 'SectionStartLineList = 'SectionStartLineList) -- Find SectionNum in SectionStartLineList, if specified ThisSectionStartLine = 0 wp = 0 if SectionNum then wp = wordpos( '['SectionNum']', SectionStartLineList) if wp then ThisSectionStartLine = word( SectionStartLineList, wp + 1) endif endif -- If SectionNum not specified, start at last section if not ThisSectionStartLine then if SectionStartLineList then -- Sections found in list wp = words( SectionStartLineList) - 1 ThisSectionStartLine = word( SectionStartLineList, wp + 1) else -- No sections in list ThisSectionStartLine = 0 endif endif firstnewfid = '' erc = 0 do i = 1 to listfid.last -- Just an upper limit to prevent looping forever --if SectionStartLineList & wp then -- dprintf( 'wp = 'wp', ThisSection = 'word( SectionStartLineList, wp)', ThisSectionStartLine = 'ThisSectionStartLine) --else -- dprintf( 'wp = 'wp', ThisSectionStartLine = 'ThisSectionStartLine) --endif PrevSectionCmd = '' do l = ThisSectionStartLine + 1 to listfid.last -- Just an upper limit to provide looping forever -- Execute every line, e.g. filename 'cmd' getline LineStr, l, listfid LineStr = strip( LineStr) -- Ignore comment lines: ';' if leftstr( LineStr, 1) = ';' then iterate endif -- Ignore trailing comments: '--' p = pos( '--', LineStr) if p > 0 then LineStr = leftstr( LineStr, p - 1) endif -- Strip spaces LineStr = strip( LineStr) -- Ignore empty lines if LineStr = '' then iterate endif -- Stop at next section if leftstr( LineStr, 1) = '[' & rightstr( LineStr, 1) = ']' then leave endif if CommonCmd <> '' then -- Append CommonCmd if LineStr doesn't contain a Cmd RestParm = LineStr NextParm = '' -- Parse NextParm from RestParm. NextParm = filespec. ParseNextParm( NextParm, RestParm) -- RestParm may be a cmd RestParm = strip( RestParm) NoRest = '' ParseCmd( RestParm, NoRest, Cmd, fCmdFound, fIsAPosCmd) if not fCmdFound then LineStr = LineStr "'"CommonCmd"'" endif endif -- Avoid addition to the Edit history SavedEditHistoryDisabled = edithistorydisabled edithistorydisabled = 1 -- Execute line --dprintf( 'Edit 'LineStr) 'Edit 'LineStr -- Save first rc <> 0 or unset if rc & not erc then -- Save rc but continue. Edit already displayed the msg. erc = rc endif -- Restore universal edithistorydisabled = SavedEditHistoryDisabled -- Save first file if firstnewfid = '' then getfileid fid if fid <> listfid then firstnewfid = fid endif endif enddo if not SectionStartLineList then leave endif if wp <= 1 then leave endif wp = wp - 2 PrevSectionStartLine = word( SectionStartLineList, wp + 1) --dprintf( 'wp = 'wp', PrevSectionStartLine = 'PrevSectionStartLine) -- Read 'WindowPos in prev. section parse value word( SectionStartLineList, wp) with '['PrevSectionNum']' PrevSectionCmd = "Open 'RestoreNextFileList "PrevSectionNum EpmFile"'" --dprintf( 'PrevSectionCmd = 'PrevSectionCmd) do l = PrevSectionStartLine + 1 to listfid.last getline LineStr, l, listfid if leftstr( upcase( LineStr), 10) = "'WINDOWPOS" then NextPos = strip( substr( LineStr, 11)) parse value NextPos with NextPos"'" -- Write reg key for ApplyNextWindowPos, executed by defmain 'NextWindowPos 'NextPos --dprintf( 'NextWindowPos = 'NextPos) leave endif -- Stop at next section if leftstr( LineStr, 1) = '[' & rightstr( LineStr, 1) = ']' then leave endif enddo -- Execute the prev. section if PrevSectionCmd then 'PostMe 'PrevSectionCmd -- PostMe sometimes required endif leave enddo -- i = 1 to listfid.last if firstnewfid = '' then -- If no file loaded except the list file, load a new .Untitled -- one. Better add this to the list file, if required. 'NewUntitledFile' endif -- Note: File loading takes some time. Therefore many commands -- won't give reliable results at this time. PostMe helps. 'PostMe CloseHiddenFile' listfid firstnewfid -- PostMe required rc = erc enddo -- Change work dir back call directory2( PrevWorkDir) return ; --------------------------------------------------------------------------- defc RestoreNextFileList universal loadhistorydisabled parse arg SectionNum EpmFile SectionNum = strip( SectionNum) EpmFile = strip( EpmFile) -- Avoid addition to Load history -- Automatically reset in ProcessPostFilesLoaded loadhistorydisabled = 1 call RestoreFileList( EpmFile, SectionNum) ; --------------------------------------------------------------------------- ; Open a file dialog to select a file for RestoreFileList processing in a new ; edit window. No args. ; Executed by 'Load ring from file list' menu item. defc OpenFileListDlg Title = 'Select a list file' Command = 'Open @"%*"' Filemask = Get_Env( 'NEPMD_USERDIR')'\bin\*.epm' 'FileDlg 'Title', 'Command', 'Filemask ; --------------------------------------------------------------------------- ; Syntax: RestoreFileList [ [sectionnum>]] defc RestoreFileList, LoadFileList Args = strip( arg( 1)) --dprintf( 'RestoreFileList:, Args = 'Args) if leftstr( Args, 1) = '"' then parse value Args with '"'EpmFile'"' SectionNum else parse value Args with EpmFile SectionNum endif if EpmFile = '' then 'OpenFileListDlg' else 'Edit @'EnquoteFileSpec( EpmFile) endif ; --------------------------------------------------------------------------- ; Finds other EPM rings. Returns 1 if there exist other EPM windows, ; otherwise 0. Similar to IsOnlyEpmWindow, but finds also "epm /m" windows ; and inverted return value. defproc QueryMoreEpmWindows buf = leftstr( '', 128, \0) desktop = 1 -- (1 == HWND_DESKTOP) my_hwnd = getpminfo( EPMINFO_EDITFRAME) fMoreEpmWindows = 0 len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName GethWndC( EPMINFO_EDITFRAME) || atol( 128) || address( buf), 2) ClsFrame = leftstr( buf, len) -- Get ClsName (NewEditWndClass) of current edit client window len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName GethWndC( EPMINFO_EDITCLIENT) || atol( 128) || address( buf), 2) ClsName = leftstr( buf, len) -- Examine desktop windows for client of same edit class henum = atol( dynalink32( 'PMWIN', '#702', -- WinBeginEnumWindows atol( desktop), 2)) cnt = 0 do while cnt < 250 cnt = cnt + 1 hwnd = dynalink32( 'PMWIN', '#756', -- WinGetNextWindow henum, 2) if not hwnd then -- No more top-level windows leave elseif hwnd == my_hwnd then -- Just me, never mind iterate endif len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName atol( hwnd) || atol( 128) || address( buf), 2) ClsFrame = leftstr( buf, len) hwndClient = dynalink32( 'PMWIN', '#899', -- WinWindowFromId atol( hwnd) || atol( FID_CLIENT), 2) -- get client len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName atol( hwndClient) || atol( 128) || address( buf), 2) ClsClient = leftstr( buf, len) -- Same class as me? if ClsName = ClsClient then fMoreEpmWindows = 1 leave endif enddo call dynalink32( 'PMWIN', '#737', -- WinEndEnumWindows henum, 2) return fMoreEpmWindows ; --------------------------------------------------------------------------- ; Finds all EPM rings. Writes EpmWindows to Config. defproc WriteAllEpmWindows KeyPath = '\NEPMD\Var\Temp\EpmWindows' EpmWindows = '' -- This is a list of '['num'] 'hwndClient '['num'] 'hwndClient ... buf = leftstr( '', 128, \0) desktop = 1 -- (1 == HWND_DESKTOP) my_hwnd = getpminfo( EPMINFO_EDITFRAME) --dprintf( ' 0: my_hwnd = 'getpminfo( EPMINFO_EDITFRAME)) len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName GethWndC( EPMINFO_EDITFRAME) || atol( 128) || address( buf), 2) ClsFrame = leftstr( buf, len) -- Get ClsName (NewEditWndClass) of current edit client window len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName GethWndC( EPMINFO_EDITCLIENT) || atol( 128) || address( buf), 2) ClsName = leftstr( buf, len) --dprintf( ' 0: my_hwnd = F: 'ClsFrame', C: 'ClsName', hwndF = 'getpminfo( EPMINFO_EDITFRAME)', hwndC = 'getpminfo( EPMINFO_EDITCLIENT)) -- Examine desktop windows for client of same edit class henum = atol( dynalink32( 'PMWIN', '#702', -- WinBeginEnumWindows atol( desktop), 2)) cnt = 0 do while cnt < 250 cnt = cnt + 1 hwnd = dynalink32( 'PMWIN', '#756', -- WinGetNextWindow henum, 2) if not hwnd then -- No more top-level windows leave elseif hwnd == my_hwnd then -- Just me, never mind --dprintf( rightstr( cnt, 2)': 1) hwnd = F: 'ClsFrame', C: 'ClsName', hwndF = 'hwnd', hwndC = 'getpminfo( EPMINFO_EDITCLIENT)) -- Set this as first handle --dprintf( 'hwndClient = 'getpminfo( EPMINFO_EDITCLIENT)', hwndFrame = 'getpminfo( EPMINFO_EDITFRAME)) SectionNum = 1 EpmWindows = '['SectionNum'] 'getpminfo( EPMINFO_EDITCLIENT) iterate endif len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName atol( hwnd) || atol( 128) || address( buf), 2) ClsFrame = leftstr( buf, len) hwndClient = dynalink32( 'PMWIN', '#899', -- WinWindowFromId atol( hwnd) || atol( FID_CLIENT), 2) -- get client len = dynalink32( 'PMWIN', '#805', -- WinQueryClassName atol( hwndClient) || atol( 128) || address( buf), 2) ClsClient = leftstr( buf, len) --dprintf( rightstr( cnt, 2)': 1) hwnd = F: 'ClsFrame', C: 'ClsClient', hwndF = 'hwnd', hwndC = 'hwndClient) -- Same class as me? if ClsName = ClsClient then --dprintf( 'ClsName = 'ClsName) --dprintf( rightstr( cnt, 2)': 2) hwnd = F: 'ClsFrame', C: 'ClsClient', hwndF = 'hwnd', hwndC = 'hwndClient) -- Append this handle --dprintf( 'hwndClient = 'hwndClient', hwndFrame = 'hwnd) SectionNum = SectionNum + 1 EpmWindows = EpmWindows' ['SectionNum'] 'hwndClient endif enddo call dynalink32( 'PMWIN', '#737', -- WinEndEnumWindows henum, 2) -- Write EpmWindows WriteConfigKey( KeyPath, EpmWindows) ; --------------------------------------------------------------------------- defc WriteAllEpmWindows call WriteAllEpmWindows() ; --------------------------------------------------------------------------- defproc GetAllEpmWindows KeyPath = '\NEPMD\Var\Temp\EpmWindows' EpmWindows = QueryConfigKey( KeyPath) return EpmWindows ; --------------------------------------------------------------------------- ; Saves all rings to a file list. defproc SaveFileList do once = 1 to 1 EpmFile = arg( 1) SectionNum = arg( 2) fAllRings = 0 if not IsNum( SectionNum) then fAllRings = 1 SectionNum = 1 endif -- Check for an unnamed and modified file getfileid startfid 'VSyncCursor' --dprintf( 'RINGCMD', 'SaveFileList: Check if unnamed unsaved file in ring') do i = 1 to filesinring( 1) -- Provide an upper limit; prevent looping forever if .filename = GetUnnamedFilename() then if .last <> 1 or textline( 1) <> '' then activatefile startfid 'SayError An unnamed file exists in the ring;' || ' it must have a name to save the ring.' return endif endif nextfile getfileid curfid if curfid = startfid then leave endif enddo -- Get a filename DefaultFileListDir = Get_Env( 'NEPMD_USERDIR')'\bin' if EpmFile = '' then -- Enter a file List and start again Title = 'Enter a list file for export' Command = 'SaveFileList "%*"' parse value DateTime() with Date HH':'MM':'. FilemaskDateTime = Date'_'HH'_'MM Filemask = DefaultFileListDir'\rings_'FilemaskDateTime'.epm' 'PostMe FileDlg 'Title', 'Command', 'Filemask leave else -- Prepend path if not specified lp = pos( '\', EpmFile) if not lp then EpmFile = DefaultFileListDir'\'EpmFile endif endif if fAllRings then -- Create a hidden file listfid = LoadHiddenFile( '.filelist') if listfid = '' then leave endif -- Delete automatically created first line deleteline 1, listfid listfid.modify = 0 else 'xcom e /d 'EnquoteFileSpec( EpmFile) if rc then leave endif getfileid listfid .visible = 0 endif -- Save ring number call AppendHiddenFile( listfid, "["SectionNum"]") -- Save window pos and size Val = NepmdQueryWindowPos( EPMINFO_EDITFRAME) call AppendHiddenFile( listfid, "'WindowPos "Val"'") -- Save work dir if SectionNum = 1 then WorkDir = directory() call AppendHiddenFile( listfid, "'WorkDir "WorkDir"'") endif -- Save filenames and pos activatefile startfid n = 0 --dprintf( 'RINGCMD', 'SaveFileList: Save filenames and pos') do i = 1 to filesinring( 1) -- Provide an upper limit; prevent looping forever -- Skip temp. files if leftstr( .filename, 1) <> '.' then if Exist( .filename) then n = n + 1 pSave_Pos( SavedPos) SavedPos = subword( SavedPos, 1, 4) -- Omit the last two sizes Entry = EnquoteFileSpec( .filename)" 'RestorePos "SavedPos"'" call AppendHiddenFile( listfid, Entry) endif endif nextfile getfileid curfid if curfid = startfid then leave endif enddo activatefile startfid -- Save and quit hidden file if not validatefileid( listfid) then leave endif activatefile listfid 'xcom s 'EnquoteFileSpec( EpmFile) 'xcom q' if fAllRings then call WriteAllEpmWindows() endif EpmWindows = GetAllEpmWindows() NextSectionNum = SectionNum + 1 Nexthwnd = '' wp = wordpos( '['NextSectionNum']', EpmWindows) if wp then Nexthwnd = word( EpmWindows, wp + 1) endif --dprintf( 'NextSectionNum = 'NextSectionNum', Nexthwnd = 'Nexthwnd) if not Nexthwnd then 'SayError Saved file list to 'EpmFile'.' -- Cleanup KeyPath = '\NEPMD\Var\Temp\EpmWindows' DeleteConfigKey( KeyPath) endif if Nexthwnd then -- Execute 'PostTo 'Nexthwnd' SaveNextFileList 'NextSectionNum EpmFile endif enddo -- once return ; --------------------------------------------------------------------------- ; Syntax: SaveFileList [] defc SaveFileList EpmFile = strip( arg( 1)) call SaveFileList( EpmFile) ; --------------------------------------------------------------------------- ; Executed by PostTo in SaveFileList. defc SaveNextFileList parse arg SectionNum EpmFile SectionNum = strip( SectionNum) EpmFile = strip( EpmFile) call SaveFileList( EpmFile, SectionNum) ; --------------------------------------------------------------------------- defc ExportHistory universal nepmd_hini TypeList = arg( 1) -- Case as used in reg ValidTypes = 'Edit Load Save Last Search' if TypeList = '' then TypeList = ValidTypes else -- Check types and make it caseless FilteredList = '' do t = 1 to words( TypeList) ThisType = word( TypeList, t) wp = wordpos( upcase( ThisType), upcase( ValidTypes)) if wp then ThisWord = word( ValidTypes, wp) if FilteredList = '' then FilteredList = ThisWord else FilteredList = FilteredList ThisWord endif else 'SayError ExportHistory: Unknown type 'ThisType' specified.' return endif enddo TypeList = FilteredList endif getfileid startfid 'VSyncCursor' DefaultFileListDir = Get_Env( 'NEPMD_USERDIR')'\bin' do t = 1 to words( TypeList) ThisType = word( TypeList, t) --dprintf( 'ThisType = 'ThisType) -- Create a hidden file listfid = LoadHiddenFile( '.filelist') if listfid = '' then leave endif -- Delete automatically created first line deleteline 1, listfid listfid.modify = 0 -- Get a filename. Append a number if it exists. IsoDate = word( DateTime(), 1) Ext = 'epm' PathBaseName = DefaultFileListDir'\'ThisType'_'IsoDate CheckFile = PathBaseName'.'Ext n = 0 do forever if Exist( CheckFile) then n = n + 1 if n > 9 then leave endif CheckFile = PathBaseName'_'n'.'Ext else leave endif enddo FileList = CheckFile KeyPath = '\NEPMD\Var\History\'ThisType if ThisType = 'Last' then SectionContainer = queryprofile( nepmd_hini, 'RegContainer', KeyPath) rest = translate( SectionContainer, ' ', \0) -- Filter non-numbers out, can use the word functions here SectionNumList = '' do w = 1 to words( rest) ThisWrd = word( rest, w) if not IsNum( ThisWrd) then iterate endif if SectionNumList = '' then SectionNumList = ThisWrd else SectionNumList = SectionNumList ThisWrd endif enddo n = 0 do s = 1 to words( SectionNumList) ThisSection = word( SectionNumList, s) call AppendHiddenFile( listfid, '['ThisSection']') WindowPos = NepmdQueryConfigValue( -3, KeyPath'\'ThisSection'\WindowPos') if WindowPos then call AppendHiddenFile( listfid, "'WindowPos "WindowPos"'") endif WorkDir = NepmdQueryConfigValue( -3, KeyPath'\'ThisSection'\WorkDir') if WorkDir then call AppendHiddenFile( listfid, "'WorkDir "WorkDir"'") endif EntryContainer = queryprofile( nepmd_hini, 'RegContainer', KeyPath'\'ThisSection) rest = translate( EntryContainer, ' ', \0) -- Filter non-numbers out, can use the word functions here EntryNumList = '' do w = 1 to words( rest) ThisWrd = word( rest, w) if not IsNum( ThisWrd) then iterate endif if EntryNumList = '' then EntryNumList = ThisWrd else EntryNumList = EntryNumList ThisWrd endif enddo -- Write filenames do e = 1 to words( EntryNumList) ThisNum = word( EntryNumList, e) ThisEntry = NepmdQueryConfigValue( -3, KeyPath'\'ThisSection'\'ThisNum) n = n + 1 call AppendHiddenFile( listfid, ThisEntry) enddo enddo else -- Find filenames n = 0 Order = NepmdQueryConfigValue( -3, KeyPath'\Order') do o = 1 to words( Order) ThisNum = word( Order, o) ThisFile = NepmdQueryConfigValue( -3, KeyPath'\'ThisNum) if ThisFile = '' then iterate endif -- Write ThisFile n = n + 1 --dprintf( rightstr( ThisNum, 2)': 'ThisFile) call AppendHiddenFile( listfid, ThisFile) enddo endif -- Quit hidden file if nothing added if n = 0 then if not validatefileid( listfid) then iterate endif activatefile listfid .modify = 0 'xcom q' if validatefileid( startfid) then activatefile startfid endif iterate endif -- Prepend header LineStr = "; "ThisType" history - exported on "DateTime() insertline LineStr, 1, listfid LineStr = "; The word 'history' in the first line avoids file loading of the contents." insertline LineStr, 2, listfid LineStr = "; The word '"ThisType"' in the first line makes it replace the current '"ThisType"'" insertline LineStr, 3, listfid LineStr = "; history on import. Filename must contain '"ThisType"', too." insertline LineStr, 4, listfid -- Save and quit hidden file if not validatefileid( listfid) then iterate endif activatefile listfid 'xcom s 'EnquoteFileSpec( FileList) 'xcom q' if validatefileid( startfid) then activatefile startfid endif 'SayError 'n 'entries exported to 'FileList'.' --dprintf( n 'entries exported to 'FileList'.') enddo ; --------------------------------------------------------------------------- defc ImportHistory do once = 1 to 1 Args = strip( arg( 1)) if leftstr( Args, 1) = '"' then parse value Args with '"'Args'"' endif if Args = '' then Title = 'Select a history list for import' Command = 'ImportHistory "%*"' Filemask = Get_Env( 'NEPMD_USERDIR')'\bin\*.epm' 'PostMe FileDlg 'Title', 'Command', 'Filemask return endif FileList = Args getfileid startfid 'VSyncCursor' Msg = '' -- Load FileList 'xcom e /d 'EnquoteFilespec( FileList) if rc then leave endif getfileid listfid .autosave = 0 .visible = 0 do once2 = 1 to 1 -- Case as used in reg ValidTypes = 'Edit Load Save Last Search' -- Get type from comment in first line ListType = '' getline LineStr, 1, listfid if leftstr( LineStr, 1) = ';' then UpLineStr = upcase( LineStr) if wordpos( 'EDIT', UpLineStr) then ListType = 'Edit' elseif wordpos( 'LOAD', UpLineStr) then ListType = 'Load' elseif wordpos( 'SAVE', UpLineStr) then ListType = 'Save' elseif wordpos( 'LAST', UpLineStr) then ListType = 'Last' elseif wordpos( 'SEARCH', UpLineStr) then ListType = 'Search' endif endif if ListType = '' then Msg = 'ImportHistory: No list type specified. First line must have: ; history ( = one of 'ValidTypes').' leave endif -- Check if filename contains ListType Name = GetFileSpec( 'N', FileList) if not pos( upcase( ListType), upcase( ValidTypes)) then Msg = 'ImportHistory: Filename must contain 'ListType'.' leave endif -- Import lines SectionNum = 1 n = 0 e = 0 Order = '' fTreeDeleted = 0 do l = 1 to listfid.last getline LineStr, l, listfid -- Ignore comment lines: ';' if leftstr( LineStr, 1) = ';' then iterate endif -- Ignore trailing comments: '--' p = pos( '--', LineStr) if p > 0 then LineStr = leftstr( LineStr, p - 1) endif -- Strip spaces LineStr = strip( LineStr) -- Ignore empty lines if LineStr = '' then iterate endif -- Ensure that old tree is deleted if first entry found if not fTreeDeleted then -- Delete current history KeyPath = '\NEPMD\Var\History\'ListType --dprintf( 'ImportHistory: delete KeyPath = 'KeyPath) call NepmdDeleteConfigTree( -3, KeyPath) fTreeDeleted = 1 endif -- Write line if ListType = 'Last' then -- Parse next section if leftstr( LineStr, 1) = '[' & rightstr( LineStr, 1) = ']' then parse value LineStr with '['SectionNum']' --dprintf( 'ImportHistory: SectionNum = 'SectionNum) e = 0 iterate endif if leftstr( upcase( LineStr), 10) = "'WINDOWPOS" then WindowPos = strip( substr( LineStr, 11)) parse value WindowPos with WindowPos"'" call NepmdWriteConfigValue( -3, KeyPath'\'SectionNum'\WindowPos', WindowPos) --dprintf( 'ImportHistory: : WindowPos = 'WindowPos ) iterate endif if leftstr( upcase( LineStr), 8) = "'WORKDIR" then WorkDir = strip( substr( LineStr, 9)) parse value WorkDir with WorkDir"'" call NepmdWriteConfigValue( -3, KeyPath'\'SectionNum'\WorkDir', WorkDir) --dprintf( 'ImportHistory: : WorkDir = 'WorkDir ) iterate endif if leftstr( upcase( LineStr), 5) = "'HWND" then -- Ignore iterate endif n = n + 1 e = e + 1 call NepmdWriteConfigValue( -3, KeyPath'\'SectionNum'\'e, LineStr) --dprintf( 'ImportHistory: 'rightstr( n, 2)':' LineStr) else n = n + 1 call NepmdWriteConfigValue( -3, KeyPath'\'n, LineStr) --dprintf( 'ImportHistory: 'rightstr( n, 2)':' LineStr) if Order = '' then Order = n else Order = Order n endif endif enddo if ListType <> 'Last' then -- Write Order key call NepmdWriteConfigValue( -3, KeyPath'\Order', Order) --dprintf( 'ImportHistory: Order = 'Order) endif if n = 0 then Msg = 'No entry changed. For deletion use: DeleteConfigTree 'KeyPath'.' else Msg = n 'entries imported to 'KeyPath'.' endif enddo -- once2 -- Close hidden file and switch to startfid 'PostMe CloseHiddenFile' listfid startfid if Msg then 'SayError 'Msg endif enddo ; --------------------------------------------------------------------------- defc DeleteHistoryLists if AskOkCancel( 'Delete all history lists?'\n\n || 'Be sure to have them exported before.') then 'DeleteConfigTree \NEPMD\Var\History' endif ; --------------------------------------------------------------------------- defc GroupsToFileLists do once = 1 to 1 getfileid startfid 'VSyncCursor' DefaultFileListDir = Get_Env( 'NEPMD_USERDIR')'\bin' fEnsureAllGroupsRemoved = 1 f = 0 KeyPath = '\NEPMD\User\Groups' NextGroup = '' do while NepmdGetNextConfigKey( -3, KeyPath, 'C', NextGroup) --dprintf( 'NextGroup = 'NextGroup) -- Create a hidden file listfid = LoadHiddenFile( '.filelist') if listfid = '' then fEnsureAllGroupsRemoved = 0 leave endif -- Delete automatically created first line deleteline 1, listfid listfid.modify = 0 -- Get a filename FileList = DefaultFileListDir'\'NextGroup'.epm' -- Find File and Posn entries NextEntry = '' n = 0 do while NepmdGetNextConfigKey( -3, KeyPath'\'NextGroup, 'K', NextEntry) --dprintf( ' NextEntry = 'NextEntry) if leftstr( NextEntry, 4) = 'File' then -- Export this ThisNum = rightstr( NextEntry, 1) n = n + 1 -- Query File and Posn ThisFile = NepmdQueryConfigValue( -3, KeyPath'\'NextGroup'\File'ThisNum) ThisPosn = NepmdQueryConfigValue( -3, KeyPath'\'NextGroup'\Posn'ThisNum) -- Build and write export line if ThisPosn = '' then ExportLine = EnquoteFileSpec( ThisFile) else ExportLine = EnquoteFileSpec( ThisFile)" 'RestorePos "ThisPosn"'" endif --dprintf( ' 'n' 'ExportLine) call AppendHiddenFile( listfid, ExportLine) endif enddo -- Quit hidden file if nothing added if n = 0 then if not validatefileid( listfid) then iterate endif activatefile listfid .modify = 0 'xcom q' if validatefileid( startfid) then activatefile startfid endif iterate endif -- Save and quit hidden file if not validatefileid( listfid) then iterate endif activatefile listfid 'xcom s 'EnquoteFileSpec( FileList) 'xcom q' f = f + 1 if validatefileid( startfid) then activatefile startfid endif --dprintf( ' Exported to 'FileList) -- Remove group call NepmdDeleteConfigTree( -3, KeyPath'\'NextGroup) enddo if fEnsureAllGroupsRemoved then -- Ensure that all group entries are removed call NepmdDeleteConfigTree( -3, KeyPath) endif if f > 0 then 'SayError 'f 'group(s) exported to 'FileList'.' --dprintf( f 'group(s) exported to 'FileList'.') endif enddo ; --------------------------------------------------------------------------- defc ConvertHistory ListName = strip( arg( 1)) ListName = upcase( Listname) if ListName = 'EDIT' then ListNames = 'Edit' elseif ListName = 'LOAD' then ListNames = 'Load' elseif ListName = 'SAVE' then ListNames = 'Save' else ListNames = 'Edit Load Save' endif KeyPath = '\NEPMD\Var\History' KeyPath2 = '\NEPMD\User\History' do w = 1 to words( ListNames) -- Read old history key ListName = word( ListNames, w) History = QueryConfigKey( KeyPath'\'ListName) -- Don't overwrite new lists if length( strip( History, 'B', \0)) = 0 then iterate endif if QueryConfigKey( KeyPath'\'ListName'\Order') <> '' then iterate endif -- Read current MaxNum MaxNum = QueryConfigKey( KeyPath2'\'ListName'\Number', 50) -- Parse old history NewNum = 0 rest = History do while rest <> '' if NewNum >= MaxNum then leave else NewNum = NewNum + 1 endif parse value rest with next \0 rest if next = '' then iterate endif -- Remove surrounded double quotes if not required if leftstr( next, 1) = '"' & rightstr( next, 1) = '"' then Stripped = substr( next, 2, Max( 0, length( next) - 2)) Enquoted = EnquoteFileSpec( Stripped) if Stripped = Enquoted then next = Stripped endif endif -- Write new key WriteConfigKey( KeyPath'\'ListName'\'NewNum, next) enddo -- Delete keys with nums > MaxNum do n = NewNum + 1 to MaxNum DeleteConfigKey( KeyPath'\'ListName'\'n) enddo -- Order key NewOrder = '' do n = 1 to NewNum -- Last found NewNum NewOrder = NewOrder n enddo NewOrder = strip( NewOrder) WriteConfigKey( KeyPath'\'ListName'\Order', NewOrder) -- Delete old history key DeleteConfigKey( KeyPath'\'ListName) enddo ; --------------------------------------------------------------------------- ; Called by edit, load, save and search. defproc AddToHistory( ListName, NewItem) do once = 1 to 1 UpListName = upcase( ListName) if UpListName = 'COMMANDLINE' then call AddToCommandBox( NewItem) leave endif KeyPath = '\NEPMD\User\History' Enabled = QueryConfigKey( KeyPath) if Enabled <> 1 then leave endif if UpListName = 'EDIT' then ListName = 'Edit' elseif UpListName = 'LOAD' then ListName = 'Load' elseif UpListName = 'SAVE' then ListName = 'Save' elseif UpListName = 'SEARCH' then ListName = 'Search' endif -- Remove surrounded double quotes if not required if leftstr( NewItem, 1) = '"' & rightstr( NewItem, 1) = '"' then Stripped = substr( NewItem, 2, Max( 0, length( NewItem) - 2)) Enquoted = EnquoteFileSpec( Stripped) if Stripped = Enquoted then NewItem = Stripped endif endif MaxNum = QueryConfigKey( KeyPath'\'ListName'\Number', 50) KeyPath = '\NEPMD\Var\History' OrderList = QueryConfigKey( KeyPath'\'ListName'\Order') NewNum = 0 NewOrder = '' -- The history may have other numbers than OrderList. -- For a new OrderList, it must additionally checked if a number -- is contained in OrderList. -- Limit words of Order key to MaxNum NumOrderList = words( OrderList) if NumOrderList > MaxNum then NumOrderList = subword( OrderList, 1, MaxNum) endif -- Query number and list of saved entries NumSavedList = 0 SavedList = '' NextNum = '' do while NepmdGetNextConfigKey( -3, KeyPath'\'ListName, 'K', NextNum) if not IsNum( NextNum) then iterate endif NumSavedList = NumSavedList + 1 if SavedList = '' then SavedList = NextNum else SavedList = SavedList NextNum endif enddo -- Extend Order key if there are more saved entries than items in Order a = 0 do w = 1 to Max( MaxNum, NumSavedList) NumOrderList = words( OrderList) if NumOrderList >= NumSavedList | NumOrderList >= MaxNum then leave endif ThisNum = word( SavedList, w) if not wordpos( ThisNum, OrderList) then if OrderList = '' then OrderList = ThisNum else OrderList = OrderList ThisNum endif a = a + 1 endif enddo -- Check if NewItem is already in history FoundNum = HistoryFindEntry( ListName, NewItem) -- Determine NewNum and NewOrder if FoundNum > 0 then NewNum = FoundNum -- Found in history, search in OrderList wp = wordpos( NewNum, OrderList) if wp then NewOrder = MoveWord( OrderList, wp, 1) else NewOrder = strip( NewNum subword( OrderList, 1, MaxNum - 1)) endif else -- Check for next free num in history FreeNum = HistoryFindFreeNum( ListName, MaxNum) if FreeNum > 0 then NewNum = FreeNum -- FreeNum found, search in OrderList wp = wordpos( NewNum, OrderList) if wp then NewOrder = NewNum OrderList else NewOrder = strip( NewNum subword( OrderList, 1, MaxNum - 1)) endif else LastNum = word( OrderList, MaxNum) NewNum = LastNum -- No FreeNum, search in OrderList wp = wordpos( NewNum, OrderList) if wp then NewOrder = MoveWord( OrderList, wp, 1) else NewOrder = strip( NewNum subword( OrderList, 1, MaxNum - 1)) endif endif endif -- Save new values if NewNum then WriteConfigKey( KeyPath'\'ListName'\'NewNum, NewItem) WriteConfigKey( KeyPath'\'ListName'\Order', NewOrder) endif enddo ; --------------------------------------------------------------------------- ; For use with postme. defc AddToHistory parse arg ListName NewItem call AddToHistory( ListName, NewItem) ; --------------------------------------------------------------------------- defproc HistoryFindEntry( ListName, FindEntry) KeyPath = '\NEPMD\Var\History\'ListName FoundNum = 0 NextNum = '' do while NepmdGetNextConfigKey( -3, KeyPath, 'K', NextNum) if not IsNum( NextNum) then iterate endif NextEntry = QueryConfigKey( KeyPath'\'NextNum) if upcase( NextEntry) = upcase( FindEntry) then FoundNum = NextNum leave endif enddo return FoundNum ; --------------------------------------------------------------------------- defproc HistoryFindFreeNum( ListName, MaxNum) KeyPath = '\NEPMD\Var\History\'ListName FreeNum = 0 -- Use OrderList OrderList = QueryConfigKey( KeyPath'\Order') do n = 1 to MaxNum if not wordpos( n, OrderList) then FreeNum = n leave endif enddo return FreeNum ; --------------------------------------------------------------------------- defc History universal lastsearchpos do once = 1 to 1 KeyPath = '\NEPMD\Var\History' parse arg ListName Item ListName = strip( upcase( ListName)) if ListName = '' then ListName = 'LOAD' endif if ListName = 'EDIT' then ListName = 'Edit' elseif ListName = 'LOAD' then ListName = 'Load' elseif ListName = 'SAVE' then ListName = 'Save' elseif ListName = 'SEARCH' then ListName = 'Search' -- Open the search dialog, if not already open if not Item then 'SearchDlg' -- The item after the ListName is here used to indicate that -- dialog was opened before 'PostMe History SEARCH 1' return endif else rc = 13 'Sayerror "'ListName'" is not a valid arg for HISTORY. Specify one of LOAD, SAVE, EDIT or SEARCH.' leave endif DefaultItem = strip( Item) if DefaultItem = '' then DefaultItem = 1 endif 'VSyncCursor' getfileid startfid listfid = LoadHiddenFile( '.history') -- for ListBox if listfid = '' then rc = 2 leave endif MaxNum = QueryConfigKey( KeyPath'\'ListName'\Number', 50) OrderList = QueryConfigKey( KeyPath'\'ListName'\Order') do w = 1 to words( OrderList) n = word( OrderList, w) next = QueryConfigKey( KeyPath'\'ListName'\'n) if next <> '' then call AppendHiddenFile( listfid, next) endif enddo DefaultItem = strip( Item) if DefaultItem = '' then DefaultItem = 1 elseif not IsNum( DefaultItem) then DefaultItem = 1 elseif DefaultItem < 0 then DefaultItem = 1 elseif DefaultItem > MaxNum then DefaultItem = 1 endif activatefile listfid if ListBox_Buffer_From_File( startfid, bufhndl, noflines, usedsize) then leave endif -- Open Listbox if ListName = 'Search' then Title = 'Select an entry from 'upcase( ListName)' history' Text = '' Buttons = '/~Restore/~Exchange/~Delete.../'CANCEL__MSG Height = Min( 20, .windowheight) Width = Min( 60, .windowwidth) else Title = 'Select a file from 'upcase( ListName)' history' Text = CTRL_KEY__MSG' to open a new window' Buttons = '/~Open/O~pen.../Open ~folder/~Delete.../'CANCEL__MSG Height = Min( 20, .windowheight) Width = Min( 80, .windowwidth) endif DefaultButton = 1 HelpId = 0 ret = ListBox( Title, \0 || atol( usedsize) || atoi( 32) || atoi( bufhndl), Buttons, 0, 0, -- top, left, Height, Width, GethWndC( APP_HANDLE) || atoi( DefaultItem) || atoi( DefaultButton) || atoi( HelpId) || Text\0) call buffer( FREEBUF, bufhndl) -- Parse return string parse value ret with Button 2 Select \0 Button = asc( Button) if ListName = 'Search' then if Button = 1 then -- Restore NewSearchArgs = Select 'RestoreSearchHistory 'NewSearchArgs 'AddToHistory SEARCH 'NewSearchArgs -- Reset PrevFid to always start a new search parse value lastsearchpos with PrevFid'|'RestSearchPos lastsearchpos = 0'|'RestSearchPos elseif Button = 2 then -- Exchange 'ExchangeSearchStrings' elseif Button = 3 then -- Delete... 'DeleteHistoryEntry 'upcase( ListName) Select -- DeleteHistoryEntry starts this dialog again else rc = 31 -- Cancel leave endif else if Button = 1 then EditArgs = EnquoteFileSpec( Select) 'DialogLoadFile 'EditArgs elseif Button = 2 then 'OpenDlg EDIT' elseif Button = 3 then 'OpenFolderOf 'Select elseif Button = 4 then 'DeleteHistoryEntry 'upcase( ListName) Select -- DeleteHistoryEntry starts this dialog again else rc = 31 -- Cancel leave endif endif enddo ; --------------------------------------------------------------------------- defc DeleteHistoryEntry universal nepmd_hini parse arg ListName Item ListName = upcase( ListName) if ListName = 'EDIT' then ListName = 'Edit' elseif ListName = 'LOAD' then ListName = 'Load' elseif ListName = 'SAVE' then ListName = 'Save' elseif ListName = 'SEARCH' then ListName = 'Search' endif KeyPath = '\NEPMD\Var\History\'ListName NextDefaultItem = '' -- Find Item in history entries Container = queryprofile( nepmd_hini, 'RegContainer', KeyPath) rest = translate( Container, ' ', \0) do w = 1 to words( rest) ThisWrd = word( rest, w) if not IsNum( ThisWrd) then iterate endif next = QueryConfigKey( KeyPath'\'ThisWrd) if next = Item then -- Confirm delete if Ctrl isn't pressed if CtrlIsDown() then rcx = 0 else if AskOkCancel( Item\n\n || 'Delete entry?'\n\n || '('CTRL_KEY__MSG' to bypass confirmation.)') then rcx = 0 else rcx = -1 endif endif if not rcx then -- Delete Item call DeleteConfigKey( KeyPath'\'ThisWrd) -- Delete num in Order Order = QueryConfigKey( KeyPath'\Order') wp = wordpos( ThisWrd, Order) Order = delword( Order, wp, 1) -- Write new Order call WriteConfigKey( KeyPath'\Order', Order) NextDefaultItem = Min( words( Order), wp) 'SayError Deleted 'ListName' entry: 'Item leave endif endif enddo 'History 'upcase( ListName) NextDefaultItem -- Start dialog again ; --------------------------------------------------------------------------- defproc GetHistoryEntry( ListName, Item) Entry = '' KeyPath = '\NEPMD\Var\History' ListName = upcase( ListName) if ListName = 'EDIT' then ListName = 'Edit' elseif ListName = 'LOAD' then ListName = 'Load' elseif ListName = 'SAVE' then ListName = 'Save' elseif ListName = 'SEARCH' then ListName = 'Search' endif if IsUInt( Item) then Order = QueryConfigKey( KeyPath'\'ListName'\Order') Num = word( Order, Item) Entry = QueryConfigKey( KeyPath'\'ListName'\'Num) endif return Entry ; --------------------------------------------------------------------------- defc DisableEditHistory universal edithistorydisabled edithistorydisabled = 1 ; --------------------------------------------------------------------------- defc EnableEditHistory universal edithistorydisabled edithistorydisabled = 0 ; --------------------------------------------------------------------------- defc DisableLoadHistory universal loadhistorydisabled loadhistorydisabled = 1 ; --------------------------------------------------------------------------- defc EnableLoadHistory universal loadhistorydisabled loadhistorydisabled = 0 ; --------------------------------------------------------------------------- ; Command box ; --------------------------------------------------------------------------- ; --------------------------------------------------------------------------- ; This won't add an entry while the CommandLine is open. defproc AddToCommandBox( NewItem) universal app_hini universal appname MaxLength = 1600 -- for ETK strings Delim = \0 MarkupString = '.** CommandBox'\0 LenMarkup = length( MarkupString) -- History items are saved reversed, MarkupString''OldestItem -> NewestItem''MarkupString. History = queryprofile( app_hini, appname, 'CommandBox') LenHistory = length( History) if History = '' then -- nop -- Check presence of markup string elseif leftstr( History, LenMarkup) <> MarkupString | rightstr( History, LenMarkup) <> MarkupString then return else -- Strip MarkupString History = substr( History, LenMarkup + 1, LenHistory - (2 * LenMarkup)) endif -- Append NewItem to History History = History''NewItem''Delim -- Reverse history string. RevHistory = reverse( History) -- Limit string to MaxLength, separate at history entries rest = RevHistory NewHistory = '' do forever if rest = '' then leave endif -- Get next item parse value rest with next (Delim) rest if next = '' then iterate endif -- Check length if length( NewHistory) + 1 + length( next) > MaxLength - (2 * LenMarkup) then leave endif if next = '' then iterate endif -- Append delimiter and next item to reversed history NewHistory = NewHistory''Delim''next enddo RevHistory = NewHistory -- Reverse history string back History = reverse( RevHistory) -- Re-add MarkupString History = MarkupString''History''MarkupString -- Write to ini call setprofile( app_hini, appname, 'CommandBox', History) return ; --------------------------------------------------------------------------- ; File numbers ('File # of ##' or '#/##') ; --------------------------------------------------------------------------- ; --------------------------------------------------------------------------- ; RingSetFileNumber is called by ProcessFilesLoaded. ; The firstinringfid is checked. If not valid anymore (e.g. if file was ; quit), then it is set to the lowest FileNumber of all files in the ring. ; At the end all FileNumbers are rewritten, starting with firstinringfid. ; ; Note: FileNumbers are assigned according to the order in the ring, while ; every fileid is assigned after loading a file. The use of firstinringfid, ; set by the first edit command together with redertermining it, if not valid ; anymore by RingSetFileNumber, ensures that the first file in the ring gets ; the FileNumber 1 assigned. The 'ring_more' dialog is filled internally, ; its files are ordered according to their fileids. defproc RingSetFileNumber universal firstinringfid do once = 1 to 1 -- Process only, when a field is present KeyPath = '\NEPMD\User\Appearance\InfoLine\Title\Template' TitleFields = QueryConfigKey( KeyPath) if pos( '', TitleFields) = 0 then KeyPath = '\NEPMD\User\Appearance\InfoLine\Status\Template' StatusFields = QueryConfigKey( KeyPath) if pos( '', StatusFields) = 0 then leave endif endif getfileid startfid dprintf( 'SET_FILE_NUMBER', 'startfile = 'startfid.filename) 'VSyncCursor' display -1 if validatefileid( firstinringfid) then activatefile firstinringfid else -- If firstinringfid is not in ring anymore -- Redetermine first loaded file (file with lowest FileNumber, if any) dprintf( 'SET_FILE_NUMBER', 'startfid not found in ring, redetermining lowest file number.') firstinringfid = startfid if validatefileid( startfid) then activatefile startfid endif nextfile -- only useful in case no FileNumber exists in the ring getfileid firstfid -- start at the following file (usually the last loaded is on top) fid = firstfid firstinringfid = fid -- initialize to current file LowestFileNumber = filesinring() -- initialize to upper limit dprintf( 'RINGCMD', 'RingSetFileNumber 1, filesinring = 'filesinring()) do f = 1 to filesinring( 1) -- just as an upper limit -- Check if FileNumber was set by a previous call to RingSetFileNumber -- and get the lowest ThisFileNumber = GetAVar( fid'.filenumber') dprintf( 'SET_FILE_NUMBER', 'f = 'f', FileNumber = 'ThisFileNumber', FileName = '.filename) if ThisFileNumber <= LowestFileNumber & ThisFileNumber <> '' then LowestFileNumber = ThisFileNumber firstinringfid = fid endif nextfile getfileid fid if fid = firstfid then leave endif enddo endif dprintf( 'SET_FILE_NUMBER', 'firstinringfid = 'firstinringfid.filename) -- Set FileNumbers for all files in the ring, start with firstinringfid FileNumber = 0 fid = firstinringfid dprintf( 'RINGCMD', 'RingSetFileNumber 2, filesinring = 'filesinring()) do f = 1 to filesinring( 1) -- just as an upper limit FileNumber = FileNumber + 1 -- Save FileNumber in an array var call SetAVar( fid'.filenumber', FileNumber) -- Critical? If this would be processed only on defselect, the field for -- a file, selected by the internal ask-before-quit-if-modified routine -- is not updated, when it gets selected. -- (But the ring can be updated before the ring_more dialog is opened.) -- Maybe refreshing the ring should be processed on the next defselect. 'RefreshInfoLine FILELIST' nextfile getfileid fid if fid = firstinringfid then leave endif enddo if validatefileid( startfid) then activatefile startfid endif display 1 enddo return ; --------------------------------------------------------------------------- defc RingSetFileNumber call RingSetFileNumber() ; --------------------------------------------------------------------------- ; Called by defproc GetInfoFieldValue( 'FILE'). defproc GetFileNumber -- Get FileNumber for Filename by querying an array var getfileid fid FileNumber = GetAVar( fid'.filenumber') -- If array var is not set, just return '1'. An empty number looks -- strange in the titletext. It's been updated after maybe recompiling -- all user .e files. Until then the file numbers were not determined -- and the titlebar displays /1 for 1 file in the ring. Now -- it displays 1/1 or 1/5 , which is correct. -- if FileNumber = '' then FileNumber = 1 endif return FileNumber ; --------------------------------------------------------------------------- ; Views and ring lists ; --------------------------------------------------------------------------- ; --------------------------------------------------------------------------- ; Swap current and next views to advance the current file position in the ; ring. Original by Larry Margolis: ; http://groups.google.com/group/comp.os.os2.apps/browse_thread/thread/c88c425bd33fcf0a ; See also this message for an explanation why the Ring dialog shows the ; files in another order. defc SwapView universal firstinringfid getfileid fid this_view = fid.nextview_of_file prev_view = this_view.prevview next_view = this_view.nextview if this_view = prev_view | this_view = next_view | prev_view = next_view then 'SayError Not enough views in the ring to swap.' return endif nextnext_view = next_view.nextview prev_view.nextview = next_view nextnext_view.prevview = this_view next_view.prevview = prev_view next_view.nextview = this_view this_view.prevview = next_view this_view.nextview = nextnext_view -- Must handle the first and last views specially: -- change firstinringfid before calling RingSetFileNumber CurFileNumber = GetAVar( fid'.filenumber') MaxFileNumber = filesinring() if CurFileNumber >= MaxFileNumber then firstinringfid = fid elseif CurFileNumber = 1 then firstinringfid = next_view - 1 -- - 1 required endif -- Redetermine all file numbers call RingSetFileNumber() ; --------------------------------------------------------------------------- compile if not defined( RINGMORE_WORKAROUND_LEN_LIST) const -- Workaround: The RingMore dialog is empty if the sum of all titletext -- lengths has one of these values: RINGMORE_WORKAROUND_LEN_LIST = '236 241 247 414 477' compile endif /* 旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴커 � what's it called: Ring_More � � � � what does it do : This command is called when the More... selection on � � the ring menu is selected. (Or by the Ring action bar � � item if MENU_LIMIT = 0.) It generates a listbox � � containing all the filenames, and selects the � � appropriate fileid if a filename is selected. � � � 읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴켸 */ ; One more bug of this buggy ETK function: ; - If the ring contains many files, whose sum of filename lengths exceeds ; 1600, the dialog is also empty instead of truncated. ; Note: When the dialog is enpty, its size is also minimal. That one can't ; be closed with the Cancel button. It can be closed e.g. with a double ; click on the system menu icon or with Alt+F4. defc Ring_More, RingMore universal lastcommand lastcommand = 'RingMore' if filesinring() = 1 then 'SayError' ONLY_FILE__MSG return endif -- Workaround: This avoids unwanted window scrolling after closing the dialog. 'VSyncCursor' -- Workaround: The dialog is empty if the sum of all titletexts = 241 -- or 477. -- In that case append a space to the titletext of the current file. -- It appears in the dialog nearly unvisible. tlen = PreRingMore() call windowmessage( 0, getpminfo( APP_HANDLE), 5141, -- EPM_POPRINGDIALOG 0, 0) -- Workaround: Remove appended char from titletext -- This must be posted and moved to another command to make the dialog -- open first. if wordpos( tlen, RINGMORE_WORKAROUND_LEN_LIST) then 'PostMe PostRingMore 'tlen endif -- At this point the dialog window is about to open. -- Everything else is handled by the dialog window itself. -- E code here would be processed before the dialog window -- is closed. -- This is relevant, because canceling the dialog always makes -- the window scroll to the cursor. This can't be fixed here. -- Moreover, after scrolling the window, the cursor becomes invisible -- until it is moved. Therefore VSyncCursor was added. ; --------------------------------------------------------------------------- defproc PreRingMore tlen = CalcSumTitles() do once = 1 to 1 if not wordpos( tlen, RINGMORE_WORKAROUND_LEN_LIST) then leave else .titletext = .titletext' ' --dprintf( 'Appended 1 char to titletext of '.filename) endif enddo return tlen ; --------------------------------------------------------------------------- defc PostRingMore parse arg tlen if wordpos( tlen, RINGMORE_WORKAROUND_LEN_LIST) then .titletext = leftstr( .titletext, length( .titletext) - 1) endif --dprintf( 'Removed 1 char from titletext of '.filename) ; --------------------------------------------------------------------------- defproc CalcSumTitles do once = 1 to 1 getfileid startfid fnum = 0 tlen = 0 do f = 1 to filesinring( 1) -- Just an upper limit to prevent looping forever fnum = fnum + 1 tlen = tlen + length( .titletext) nextfile getfileid fid if fid = startfid then leave endif enddo pActivateFile( startfid) enddo return tlen ; --------------------------------------------------------------------------- defc SumTitles tlen = CalcSumTitles() 'SayError Length of titletexts = 'tlen ; --------------------------------------------------------------------------- ; Syntax: Ring ; Executes a cmd on all files of the ring. defc Ring if arg( 1) = '' then 'SayError Specify a command to be executed on all files in the ring.' return endif display -3 getfileid startfid dprintf( 'RINGCMD', 'Ring' arg( 1)) 'VSyncCursor' do f = 1 to filesinring( 1) -- just as an upper limit if .visible then arg( 1) -- execute arg( 1) endif nextfile getfileid fid if fid = startfid then leave endif enddo 'PostMe ActivateFile' startfid 'PostMe Display' 3