chroma/lexers/testdata/openedgeabl.actual
2025-03-22 20:46:00 +13:00

5159 lines
No EOL
151 KiB
Text

//Source of this test file: https://github.com/patrickTingen/DataDigger/blob/master/DataDiggerLib.p
&ANALYZE-SUSPEND _VERSION-NUMBER AB_v10r12
&ANALYZE-RESUME
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _CUSTOM _DEFINITIONS Procedure
/*------------------------------------------------------------------------
Name: DataDiggerLib.p
Desc: Library for DataDigger functions
------------------------------------------------------------------------*/
/* This .W file was created with the Progress AppBuilder. */
/*----------------------------------------------------------------------*/
DEFINE VARIABLE gcSaveDatabaseList AS CHARACTER NO-UNDO.
DEFINE VARIABLE giDataserverNr AS INTEGER NO-UNDO. /* [JAG 01-11-2019] */
DEFINE VARIABLE glDirtyCache AS LOGICAL NO-UNDO.
/* Buildnr, temp-tables and forward defs */
{ DataDigger.i }
PROCEDURE GetUserNameA EXTERNAL "ADVAPI32.DLL":
DEFINE INPUT PARAMETER mUserId AS MEMPTR NO-UNDO.
DEFINE INPUT-OUTPUT PARAMETER intBufferSize AS LONG NO-UNDO.
DEFINE RETURN PARAMETER intResult AS SHORT NO-UNDO.
END PROCEDURE.
/* Detect bitness of running Progress version
* See Progress kb #54631
*/
&IF PROVERSION <= '8' &THEN /* OE 10+ */
&IF PROVERSION >= '11.3' &THEN /* PROCESS-ARCHITECTURE function is available */
&IF PROCESS-ARCHITECTURE = 32 &THEN /* 32-bit pointers */
&GLOBAL-DEFINE POINTERTYPE LONG
&GLOBAL-DEFINE POINTERBYTES 4
&ELSEIF PROCESS-ARCHITECTURE = 64 &THEN /* 64-bit pointers */
&GLOBAL-DEFINE POINTERTYPE INT64
&GLOBAL-DEFINE POINTERBYTES 8
&ENDIF /* PROCESS-ARCHITECTURE */
&ELSE /* Can't check architecture pre-11.3 so default to 32-bit */
&GLOBAL-DEFINE POINTERTYPE LONG
&GLOBAL-DEFINE POINTERBYTES 4
&ENDIF /* PROVERSION > 11.3 */
&ELSE /* pre-OE10 always 32-bit on Windows */
&GLOBAL-DEFINE POINTERTYPE LONG
&GLOBAL-DEFINE POINTERBYTES 4
&ENDIF /* PROVERSION < 8 */
PROCEDURE GetKeyboardState EXTERNAL "user32.dll":
DEFINE INPUT PARAMETER KBState AS {&POINTERTYPE}. /* memptr */
DEFINE RETURN PARAMETER RetVal AS LONG. /* bool */
END PROCEDURE.
/* Windows API entry point */
PROCEDURE ShowScrollBar EXTERNAL "user32.dll":
DEFINE INPUT PARAMETER hwnd AS LONG.
DEFINE INPUT PARAMETER fnBar AS LONG.
DEFINE INPUT PARAMETER fShow AS LONG.
DEFINE RETURN PARAMETER ReturnValue AS LONG.
END PROCEDURE.
PROCEDURE SendMessageA EXTERNAL "user32.dll":
DEFINE INPUT PARAMETER hwnd AS long NO-UNDO.
DEFINE INPUT PARAMETER wmsg AS long NO-UNDO.
DEFINE INPUT PARAMETER wparam AS long NO-UNDO.
DEFINE INPUT PARAMETER lparam AS long NO-UNDO.
DEFINE RETURN PARAMETER rc AS long NO-UNDO.
END PROCEDURE.
PROCEDURE RedrawWindow EXTERNAL "user32.dll":
DEFINE INPUT PARAMETER v-hwnd AS LONG NO-UNDO.
DEFINE INPUT PARAMETER v-rect AS LONG NO-UNDO.
DEFINE INPUT PARAMETER v-rgn AS LONG NO-UNDO.
DEFINE INPUT PARAMETER v-flags AS LONG NO-UNDO.
DEFINE RETURN PARAMETER v-ret AS LONG NO-UNDO.
END PROCEDURE.
PROCEDURE SetWindowTextA EXTERNAL "user32.dll":
DEFINE INPUT PARAMETER hwnd AS long.
DEFINE INPUT PARAMETER txt AS CHARACTER.
END PROCEDURE.
PROCEDURE GetWindow EXTERNAL "user32.dll" :
DEFINE INPUT PARAMETER hwnd AS LONG.
DEFINE INPUT PARAMETER uCmd AS LONG.
DEFINE RETURN PARAMETER hwndOther AS LONG.
END PROCEDURE.
PROCEDURE GetParent EXTERNAL "user32.dll" :
DEFINE INPUT PARAMETER hwndChild AS LONG.
DEFINE RETURN PARAMETER hwndParent AS LONG.
END PROCEDURE.
PROCEDURE GetCursorPos EXTERNAL "user32":
DEFINE INPUT PARAMETER lpPoint AS {&POINTERTYPE}. /* memptr */
DEFINE RETURN PARAMETER ReturnValue AS LONG.
END PROCEDURE.
PROCEDURE GetSysColor EXTERNAL "user32.dll":
DEFINE INPUT PARAMETER nDspElement AS LONG.
DEFINE RETURN PARAMETER COLORREF AS LONG.
END PROCEDURE.
PROCEDURE ScreenToClient EXTERNAL "user32.dll" :
DEFINE INPUT PARAMETER hWnd AS LONG.
DEFINE INPUT PARAMETER lpPoint AS MEMPTR.
END PROCEDURE.
/* Transparency */
PROCEDURE SetWindowLongA EXTERNAL "user32.dll":
DEFINE INPUT PARAMETER HWND AS LONG.
DEFINE INPUT PARAMETER nIndex AS LONG.
DEFINE INPUT PARAMETER dwNewLong AS LONG.
DEFINE RETURN PARAMETER stat AS LONG.
END PROCEDURE.
PROCEDURE SetLayeredWindowAttributes EXTERNAL "user32.dll":
DEFINE INPUT PARAMETER HWND AS LONG.
DEFINE INPUT PARAMETER crKey AS LONG.
DEFINE INPUT PARAMETER bAlpha AS SHORT.
DEFINE INPUT PARAMETER dwFlagsas AS LONG.
DEFINE RETURN PARAMETER stat AS SHORT.
END PROCEDURE.
/* Find out if a file is locked */
&GLOBAL-DEFINE GENERIC_WRITE 1073741824 /* &H40000000 */
&GLOBAL-DEFINE OPEN_EXISTING 3
&GLOBAL-DEFINE FILE_SHARE_READ 1 /* = &H1 */
&GLOBAL-DEFINE FILE_ATTRIBUTE_NORMAL 128 /* = &H80 */
PROCEDURE CreateFileA EXTERNAL "kernel32":
DEFINE INPUT PARAMETER lpFileName AS CHARACTER.
DEFINE INPUT PARAMETER dwDesiredAccess AS LONG.
DEFINE INPUT PARAMETER dwShareMode AS LONG.
DEFINE INPUT PARAMETER lpSecurityAttributes AS LONG.
DEFINE INPUT PARAMETER dwCreationDisposition AS LONG.
DEFINE INPUT PARAMETER dwFlagsAndAttributes AS LONG.
DEFINE INPUT PARAMETER hTemplateFile AS LONG.
DEFINE RETURN PARAMETER ReturnValue AS LONG.
END PROCEDURE.
PROCEDURE CloseHandle EXTERNAL "kernel32" :
DEFINE INPUT PARAMETER hObject AS LONG.
DEFINE RETURN PARAMETER ReturnValue AS LONG.
END PROCEDURE.
/* Used in update check / about window */
PROCEDURE URLDownloadToFileA EXTERNAL "URLMON.DLL" :
DEFINE INPUT PARAMETER pCaller AS LONG.
DEFINE INPUT PARAMETER szURL AS CHARACTER.
DEFINE INPUT PARAMETER szFilename AS CHARACTER.
DEFINE INPUT PARAMETER dwReserved AS LONG.
DEFINE INPUT PARAMETER lpfnCB AS LONG.
DEFINE RETURN PARAMETER ReturnValue AS LONG.
END PROCEDURE. /* URLDownloadToFileA */
PROCEDURE DeleteUrlCacheEntry EXTERNAL "WININET.DLL" :
DEFINE INPUT PARAMETER lbszUrlName AS CHARACTER.
END PROCEDURE. /* DeleteUrlCacheEntry */
DEFINE TEMP-TABLE ttColor NO-UNDO
FIELD cName AS CHARACTER
FIELD iColor AS INTEGER
INDEX iPrim AS PRIMARY cName.
DEFINE TEMP-TABLE ttFont NO-UNDO
FIELD cName AS CHARACTER
FIELD iFont AS INTEGER
INDEX iPrim AS PRIMARY cName.
/* If you have trouble with the cache, disable it in the settings screen */
DEFINE VARIABLE glCacheTableDefs AS LOGICAL NO-UNDO.
DEFINE VARIABLE glCacheFieldDefs AS LOGICAL NO-UNDO.
/* Vars for caching dirnames */
DEFINE VARIABLE gcProgramDir AS CHARACTER NO-UNDO.
DEFINE VARIABLE gcWorkFolder AS CHARACTER NO-UNDO.
/* Locking / unlocking windows */
&GLOBAL-DEFINE WM_SETREDRAW 11
&GLOBAL-DEFINE RDW_ALLCHILDREN 128
&GLOBAL-DEFINE RDW_ERASE 4
&GLOBAL-DEFINE RDW_INVALIDATE 1
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ANALYZE-SUSPEND _UIB-PREPROCESSOR-BLOCK
/* ******************** Preprocessor Definitions ******************** */
&Scoped-define PROCEDURE-TYPE Procedure
&Scoped-define DB-AWARE no
/* _UIB-PREPROCESSOR-BLOCK-END */
&ANALYZE-RESUME
/* ************************ Function Prototypes ********************** */
&IF DEFINED(EXCLUDE-addConnection) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD addConnection Procedure
FUNCTION addConnection RETURNS LOGICAL
( pcDatabase AS CHARACTER
, pcSection AS CHARACTER ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-formatQueryString) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD formatQueryString Procedure
FUNCTION formatQueryString RETURNS CHARACTER
( INPUT pcQueryString AS CHARACTER
, INPUT plExpanded AS LOGICAL ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getColor) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getColor Procedure
FUNCTION getColor RETURNS INTEGER
( pcName AS CHARACTER ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getColorByRGB) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getColorByRGB Procedure
FUNCTION getColorByRGB RETURNS INTEGER
( piRed AS INTEGER
, piGreen AS INTEGER
, piBlue AS INTEGER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getColumnLabel) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getColumnLabel Procedure
FUNCTION getColumnLabel RETURNS CHARACTER
( INPUT phFieldBuffer AS HANDLE ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getColumnWidthList) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getColumnWidthList Procedure
FUNCTION getColumnWidthList RETURNS CHARACTER
( INPUT phBrowse AS HANDLE ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getDatabaseList) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getDatabaseList Procedure
FUNCTION getDatabaseList RETURNS CHARACTER FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getEscapedData) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getEscapedData Procedure
FUNCTION getEscapedData RETURNS CHARACTER
( pcTarget AS CHARACTER
, pcString AS CHARACTER ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getFieldList) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getFieldList Procedure
FUNCTION getFieldList RETURNS CHARACTER
( pcDatabase AS CHARACTER
, pcFile AS CHARACTER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getFileCategory) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getFileCategory Procedure
FUNCTION getFileCategory RETURNS CHARACTER
( piFileNumber AS INTEGER
, pcFileName AS CHARACTER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getFont) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getFont Procedure
FUNCTION getFont RETURNS INTEGER
( pcName AS CHARACTER ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getImagePath) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getImagePath Procedure
FUNCTION getImagePath RETURNS CHARACTER
( pcImage AS CHARACTER ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getIndexFields) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getIndexFields Procedure
FUNCTION getIndexFields RETURNS CHARACTER
( INPUT pcDatabaseName AS CHARACTER
, INPUT pcTableName AS CHARACTER
, INPUT pcFlags AS CHARACTER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getKeyList) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getKeyList Procedure
FUNCTION getKeyList RETURNS CHARACTER
( /* parameter-definitions */ ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getLinkInfo) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getLinkInfo Procedure
FUNCTION getLinkInfo RETURNS CHARACTER
( INPUT pcFieldName AS CHARACTER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getMaxLength) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getMaxLength Procedure
FUNCTION getMaxLength RETURNS INTEGER
( cFieldList AS CHARACTER ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getOsErrorDesc) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getOsErrorDesc Procedure
FUNCTION getOsErrorDesc RETURNS CHARACTER
(INPUT piOsError AS INTEGER) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getProgramDir) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getProgramDir Procedure
FUNCTION getProgramDir RETURNS CHARACTER
( /* parameter-definitions */ ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getQuery) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getQuery Procedure
FUNCTION getQuery RETURNS CHARACTER
( INPUT pcDatabase AS CHARACTER
, INPUT pcTable AS CHARACTER
, INPUT piQuery AS INTEGER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getReadableQuery) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getReadableQuery Procedure
FUNCTION getReadableQuery RETURNS CHARACTER
( INPUT pcQuery AS CHARACTER ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getRegistry) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getRegistry Procedure
FUNCTION getRegistry RETURNS CHARACTER
( pcSection AS CHARACTER
, pcKey AS CHARACTER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getSchemaHolder) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getSchemaHolder Procedure
FUNCTION getSchemaHolder RETURNS CHARACTER
( INPUT pcDataSrNameOrDbName AS CHARACTER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getStackSize) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getStackSize Procedure
FUNCTION getStackSize RETURNS INTEGER() FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getTableDesc) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getTableDesc Procedure
FUNCTION getTableDesc RETURNS CHARACTER
( INPUT pcDatabase AS CHARACTER
, INPUT pcTable AS CHARACTER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getTableLabel) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getTableLabel Procedure
FUNCTION getTableLabel RETURNS CHARACTER
( INPUT pcDatabase AS CHARACTER
, INPUT pcTable AS CHARACTER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getTableList) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getTableList Procedure
FUNCTION getTableList RETURNS CHARACTER
( INPUT pcDatabaseFilter AS CHARACTER
, INPUT pcTableFilter AS CHARACTER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getUserName) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getUserName Procedure
FUNCTION getUserName RETURNS CHARACTER
( /* parameter-definitions */ ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getWidgetUnderMouse) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getWidgetUnderMouse Procedure
FUNCTION getWidgetUnderMouse RETURNS HANDLE
( phFrame AS HANDLE ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getWorkFolder) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getWorkFolder Procedure
FUNCTION getWorkFolder RETURNS CHARACTER
( /* parameter-definitions */ ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getXmlNodeName) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD getXmlNodeName Procedure
FUNCTION getXmlNodeName RETURNS CHARACTER
( pcFieldName AS CHARACTER ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-isDataServer) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD isDataServer Procedure
FUNCTION isDataServer RETURNS LOGICAL
( INPUT pcDataSrNameOrDbName AS CHARACTER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-isDefaultFontsChanged) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD isDefaultFontsChanged Procedure
FUNCTION isDefaultFontsChanged RETURNS LOGICAL
( /* parameter-definitions */ ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-isFileLocked) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD isFileLocked Procedure
FUNCTION isFileLocked RETURNS LOGICAL
( pcFileName AS CHARACTER ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-isMouseOver) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD isMouseOver Procedure
FUNCTION isMouseOver RETURNS LOGICAL
( phWidget AS HANDLE ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-isTableFilterUsed) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD isTableFilterUsed Procedure
FUNCTION isTableFilterUsed RETURNS LOGICAL
( INPUT TABLE ttTableFilter ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-isValidCodePage) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD isValidCodePage Procedure
FUNCTION isValidCodePage RETURNS LOGICAL
(pcCodepage AS CHARACTER) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-readFile) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD readFile Procedure
FUNCTION readFile RETURNS LONGCHAR
(pcFilename AS CHARACTER) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-removeConnection) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD removeConnection Procedure
FUNCTION removeConnection RETURNS LOGICAL
( pcDatabase AS CHARACTER ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-resolveOsVars) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD resolveOsVars Procedure
FUNCTION resolveOsVars RETURNS CHARACTER
( pcString AS CHARACTER ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-resolveSequence) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD resolveSequence Procedure
FUNCTION resolveSequence RETURNS CHARACTER
( pcString AS CHARACTER ) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setColor) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD setColor Procedure
FUNCTION setColor RETURNS INTEGER
( pcName AS CHARACTER
, piColor AS INTEGER) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setColumnWidthList) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD setColumnWidthList Procedure
FUNCTION setColumnWidthList RETURNS LOGICAL
( INPUT phBrowse AS HANDLE
, INPUT pcWidthList AS CHARACTER) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setLinkInfo) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD setLinkInfo Procedure
FUNCTION setLinkInfo RETURNS LOGICAL
( INPUT pcFieldName AS CHARACTER
, INPUT pcValue AS CHARACTER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setRegistry) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD setRegistry Procedure
FUNCTION setRegistry RETURNS CHARACTER
( pcSection AS CHARACTER
, pcKey AS CHARACTER
, pcValue AS CHARACTER
) FORWARD.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
/* *********************** Procedure Settings ************************ */
&ANALYZE-SUSPEND _PROCEDURE-SETTINGS
/* Settings for THIS-PROCEDURE
Type: Procedure
Allow:
Frames: 0
Add Fields to: Neither
Other Settings: CODE-ONLY COMPILE
*/
&ANALYZE-RESUME _END-PROCEDURE-SETTINGS
/* ************************* Create Window ************************** */
&ANALYZE-SUSPEND _CREATE-WINDOW
/* DESIGN Window definition (used by the UIB)
CREATE WINDOW Procedure ASSIGN
HEIGHT = 41
WIDTH = 57.4.
/* END WINDOW DEFINITION */
*/
&ANALYZE-RESUME
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _CUSTOM _MAIN-BLOCK Procedure
/* *************************** Main Block *************************** */
/* terminate it. */
ON CLOSE OF THIS-PROCEDURE
DO:
DEFINE VARIABLE cEnvironment AS CHARACTER NO-UNDO.
cEnvironment = SUBSTITUTE('DataDigger-&1', getUserName() ).
UNLOAD 'DataDiggerHelp' NO-ERROR.
UNLOAD 'DataDigger' NO-ERROR.
UNLOAD cEnvironment NO-ERROR.
END. /* CLOSE OF THIS-PROCEDURE */
/* Caching settings must be set from within UI.
* Since the library might be started from DataDigger.p
* we cannot rely on the registry being loaded yet
*/
glCacheTableDefs = TRUE.
glCacheFieldDefs = TRUE.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
/* ********************** Internal Procedures *********************** */
&IF DEFINED(EXCLUDE-applyChoose) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE applyChoose Procedure
PROCEDURE applyChoose :
/* Apply the choose event to a dynamically created widget
*/
DEFINE INPUT PARAMETER pihWidget AS HANDLE NO-UNDO.
IF VALID-HANDLE(pihWidget) THEN
DO:
PUBLISH "debugInfo" (3, SUBSTITUTE("Apply CHOOSE to &1 &2", pihWidget:TYPE, pihWidget:NAME)).
APPLY 'choose' TO pihWidget.
END.
END PROCEDURE. /* applyChoose */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-applyEvent) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE applyEvent Procedure
PROCEDURE applyEvent :
/* Apply an event to a dynamically created widget
*/
DEFINE INPUT PARAMETER pihWidget AS HANDLE NO-UNDO.
DEFINE INPUT PARAMETER pcEvent AS CHARACTER NO-UNDO.
IF VALID-HANDLE(pihWidget) THEN
DO:
PUBLISH "debugInfo" (3, SUBSTITUTE("Apply &1 to &2 &3", CAPS(pcEvent), pihWidget:TYPE, pihWidget:NAME)).
APPLY pcEvent TO pihWidget.
END.
END PROCEDURE. /* applyEvent */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-checkBackupFolder) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE checkBackupFolder Procedure
PROCEDURE checkBackupFolder :
/* If backup is on, create a folder for it
*/
DEFINE OUTPUT PARAMETER plFolderOk AS LOGICAL NO-UNDO.
DEFINE VARIABLE cFolder AS CHARACTER NO-UNDO.
IF LOGICAL(getRegistry("DataDigger:Backup","BackupOnCreate"))
OR LOGICAL(getRegistry("DataDigger:Backup","BackupOnDelete"))
OR LOGICAL(getRegistry("DataDigger:Backup","BackupOnDelete")) THEN
DO:
RUN getDumpFileName
( INPUT 'dump' /* action */
, INPUT '' /* database */
, INPUT '' /* table */
, INPUT '' /* extension */
, INPUT getRegistry("DataDigger:Backup", "BackupDir") /* template */
, OUTPUT cFolder
).
RUN createFolder(cFolder).
/* Now check if folder is actually created */
FILE-INFO:FILE-NAME = cFolder.
plFolderOk = (FILE-INFO:FULL-PATHNAME <> ?).
IF NOT plFolderOk THEN
DO:
RUN showHelp('CannotCreateBackupFolder', cFolder).
setRegistry("DataDigger:Backup","BackupOnCreate", "NO").
setRegistry("DataDigger:Backup","BackupOnUpdate", "NO").
setRegistry("DataDigger:Backup","BackupOnDelete", "NO").
END.
END.
ELSE
plFolderOk = TRUE.
END PROCEDURE. /* checkBackupFolder */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-checkDir) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE checkDir Procedure
PROCEDURE checkDir :
/* Check if a folder exists, is accessible etc
*/
DEFINE INPUT PARAMETER pcFileName AS CHARACTER NO-UNDO.
DEFINE OUTPUT PARAMETER pcError AS CHARACTER NO-UNDO.
DEFINE VARIABLE cDumpDir AS CHARACTER NO-UNDO.
DEFINE VARIABLE cDirToCreate AS CHARACTER NO-UNDO.
DEFINE VARIABLE iDir AS INTEGER NO-UNDO.
PUBLISH "debugInfo" (3, SUBSTITUTE("Check &1", pcFileName)).
/* If no path is given, use startup folder */
cDumpDir = SUBSTRING(pcFileName, 1, R-INDEX(pcFileName,"\")).
IF cDumpDir = '' THEN cDumpDir = '.'.
/* We cannot use the program dir itself */
FILE-INFO:FILE-NAME = cDumpDir.
IF TRIM(FILE-INFO:FULL-PATHNAME,'\/') = TRIM(getProgramDir(),"/\") THEN
DO:
pcError = getRegistry('DataDigger:Help', 'ExportToProgramdir:message').
RETURN.
END.
PUBLISH "debugInfo" (3, SUBSTITUTE("Dir = &1", cDumpDir)).
/* Ask to overwrite if it already exists */
FILE-INFO:FILE-NAME = pcFileName.
IF FILE-INFO:FULL-PATHNAME <> ? THEN
DO:
PUBLISH "debugInfo" (3, SUBSTITUTE("Already exists as &1 (&2)", FILE-INFO:FULL-PATHNAME, FILE-INFO:FILE-TYPE)).
IF FILE-INFO:FILE-TYPE MATCHES '*F*' THEN
DO:
RUN showHelp('OverwriteDumpFile', pcFileName).
IF getRegistry('DataDigger:Help', 'OverwriteDumpFile:answer') <> '1' THEN
DO:
/* Do not remember the answer "No" for this question, otherwise it will be
* confusing the next time the user encounters this situation
*/
setRegistry('DataDigger:Help', 'OverwriteDumpFile:answer',?).
pcError = 'Aborted by user.'.
RETURN.
END.
/* Write access to this file? */
IF NOT FILE-INFO:FILE-TYPE MATCHES '*W*' THEN
DO:
pcError = SUBSTITUTE('Cannot overwrite output file "&1"', pcFileName).
RETURN.
END.
END.
/* If a dir already exists with the same name as the output file, we cannot create it */
IF FILE-INFO:FILE-TYPE MATCHES '*D*' THEN
DO:
pcError = SUBSTITUTE('A directory named "&1" exists; cannot create a file with the same name.', pcFileName).
RETURN.
END.
END.
/* Check dir */
FILE-INFO:FILE-NAME = cDumpDir.
IF cDumpDir <> "" /* Don't complain about not using a dir */
AND FILE-INFO:FULL-PATHNAME = ? THEN
DO:
RUN showHelp('CreateDumpDir', cDumpDir).
IF getRegistry('DataDigger:Help', 'CreateDumpDir:answer') <> '1' THEN
DO:
pcError = 'Aborted by user.'.
RETURN.
END.
END.
/* Try to create path + file. Progress will not raise an error if it already exists */
cDirToCreate = ENTRY(1,cDumpDir,'\').
DO iDir = 2 TO NUM-ENTRIES(cDumpDir,'\').
/* In which dir do we want to create a subdir? */
IF iDir = 2 THEN
FILE-INFO:FILE-NAME = cDirToCreate + '\'.
ELSE
FILE-INFO:FILE-NAME = cDirToCreate.
/* Does it even exist? */
IF FILE-INFO:FULL-PATHNAME = ? THEN
DO:
pcError = SUBSTITUTE('Directory "&1" does not exist.', cDirToCreate).
PUBLISH "debugInfo" (3, SUBSTITUTE("Error: &1", pcError)).
RETURN.
END.
/* Check if the dir is writable */
IF FILE-INFO:FILE-TYPE MATCHES '*X*' /* Happens on CD-ROM drives */
OR ( FILE-INFO:FILE-TYPE MATCHES '*D*'
AND NOT FILE-INFO:FILE-TYPE MATCHES '*W*' ) THEN
DO:
pcError = SUBSTITUTE('No write-access to directory: "&1"', cDirToCreate).
PUBLISH "debugInfo" (3, SUBSTITUTE("Error: &1", pcError)).
RETURN.
END.
/* Seems to exist and to be writable. */
cDirToCreate = cDirToCreate + '\' + ENTRY(iDir,cDumpDir,'\').
/* If a file already exists with the same name, we cannot create a dir */
FILE-INFO:FILE-NAME = cDirToCreate.
IF FILE-INFO:FILE-TYPE MATCHES '*F*' THEN
DO:
pcError = SUBSTITUTE('A file named "&1" exists; cannot create a dir with the same name.', cDirToCreate).
PUBLISH "debugInfo" (3, SUBSTITUTE("Error: &1", pcError)).
RETURN.
END.
/* Create the dir. Creating an existing dir gives no error */
OS-CREATE-DIR value(cDirToCreate).
IF OS-ERROR <> 0 THEN
DO:
pcError = getOsErrorDesc(OS-ERROR).
PUBLISH "debugInfo" (3, SUBSTITUTE("Error: &1", pcError)).
RETURN.
END. /* error */
END. /* iDir */
END PROCEDURE. /* checkDir */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-clearColorCache) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE clearColorCache Procedure
PROCEDURE clearColorCache :
/* Clear the registry cache
*/
PUBLISH "debugInfo" (3, SUBSTITUTE("Clearing color cache")).
EMPTY TEMP-TABLE ttColor.
END PROCEDURE. /* clearColorCache */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-clearDiskCache) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE clearDiskCache Procedure
PROCEDURE clearDiskCache :
/* Clear the cache files on disk
*/
DEFINE VARIABLE cFile AS CHARACTER NO-UNDO EXTENT 3.
PUBLISH "debugInfo" (3, SUBSTITUTE("Clearing disk cache")).
FILE-INFORMATION:FILE-NAME = getWorkFolder() + "cache".
IF FILE-INFORMATION:FULL-PATHNAME = ? THEN RETURN.
INPUT FROM OS-DIR(FILE-INFORMATION:FULL-PATHNAME).
REPEAT:
IMPORT cFile.
IF cFile[1] MATCHES "*.xml" THEN OS-DELETE VALUE( cFile[2]).
END.
INPUT CLOSE.
END PROCEDURE. /* clearDiskCache */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-clearFontCache) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE clearFontCache Procedure
PROCEDURE clearFontCache :
/* Clear the font cache
*/
PUBLISH "debugInfo" (3, SUBSTITUTE("Clearing font cache")).
EMPTY TEMP-TABLE ttFont.
END PROCEDURE. /* clearFontCache */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-clearMemoryCache) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE clearMemoryCache Procedure
PROCEDURE clearMemoryCache :
/* Clear the memory cache
*/
PUBLISH "debugInfo" (3, SUBSTITUTE("Clearing memory cache")).
EMPTY TEMP-TABLE ttFieldCache.
END PROCEDURE. /* clearMemoryCache */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-clearRegistryCache) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE clearRegistryCache Procedure
PROCEDURE clearRegistryCache :
/* Clear the registry cache
*/
PUBLISH "debugInfo" (3, SUBSTITUTE("Clearing registry cache")).
EMPTY TEMP-TABLE ttConfig.
END PROCEDURE. /* clearRegistryCache */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-collectQueryInfo) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE collectQueryInfo Procedure
PROCEDURE collectQueryInfo :
/* Fill the query temp-table
*/
DEFINE INPUT PARAMETER pcDatabase AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcTable AS CHARACTER NO-UNDO.
DEFINE VARIABLE iMaxQueryHistory AS INTEGER NO-UNDO.
DEFINE VARIABLE iQueryNr AS INTEGER NO-UNDO.
DEFINE VARIABLE iLoop AS INTEGER NO-UNDO.
DEFINE VARIABLE cSetting AS CHARACTER NO-UNDO.
DEFINE BUFFER bQuery FOR ttQuery.
{&timerStart}
/* Delete all known queries in memory of this table */
FOR EACH bQuery
WHERE bQuery.cDatabase = pcDatabase
AND bQuery.cTable = pcTable:
DELETE bQuery.
END.
iMaxQueryHistory = INTEGER(getRegistry("DataDigger", "MaxQueryHistory" )).
IF iMaxQueryHistory = 0 THEN RETURN. /* no query history wanted */
/* If it is not defined use default setting */
IF iMaxQueryHistory = ? THEN iMaxQueryHistory = 10.
collectQueries:
DO iLoop = 1 TO iMaxQueryHistory:
cSetting = getRegistry( SUBSTITUTE("DB:&1", pcDatabase)
, SUBSTITUTE('&1:query:&2', pcTable, iLoop )).
IF cSetting = '<Empty>' THEN NEXT collectQueries.
IF cSetting <> ? THEN
DO:
CREATE bQuery.
ASSIGN
iQueryNr = iQueryNr + 1
bQuery.cDatabase = pcDatabase
bQuery.cTable = pcTable
bQuery.iQueryNr = iQueryNr
bQuery.cQueryTxt = cSetting.
END.
ELSE
LEAVE collectQueries.
END. /* 1 .. MaxQueryHistory */
{&timerStop}
END PROCEDURE. /* collectQueryInfo */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-correctFilterList) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE correctFilterList Procedure
PROCEDURE correctFilterList :
/* Move negative entries from positive list to negative
*/
DEFINE INPUT-OUTPUT PARAMETER pcPositive AS CHARACTER NO-UNDO.
DEFINE INPUT-OUTPUT PARAMETER pcNegative AS CHARACTER NO-UNDO.
DEFINE VARIABLE iWord AS INTEGER NO-UNDO.
/* Strip entries that start with a ! */
IF INDEX(pcPositive,"!") > 0 THEN
DO:
DO iWord = 1 TO NUM-ENTRIES(pcPositive):
IF ENTRY(iWord,pcPositive) BEGINS "!" THEN
DO:
/* Add this word to the negative-list */
pcNegative = TRIM(pcNegative + ',' + TRIM(ENTRY(iWord,pcPositive),'!'),',').
/* And wipe it from the positive-list */
ENTRY(iWord,pcPositive) = ''.
END.
END.
/* Remove empty elements */
pcPositive = TRIM(pcPositive,',').
REPEAT WHILE INDEX(pcPositive,',,') > 0:
pcPositive = REPLACE(pcPositive,',,',',').
END.
END.
END PROCEDURE. /* correctFilterList */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-createFolder) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE createFolder Procedure
PROCEDURE createFolder :
/* Create a folder structure
*/
DEFINE INPUT PARAMETER pcFolder AS CHARACTER NO-UNDO.
DEFINE VARIABLE iElement AS INTEGER NO-UNDO.
DEFINE VARIABLE cPath AS CHARACTER NO-UNDO.
/* c:\temp\somefolder\subfolder\ */
DO iElement = 1 TO NUM-ENTRIES(pcFolder,'\'):
cPath = SUBSTITUTE('&1\&2', cPath, ENTRY(iElement,pcFolder,'\')).
cPath = LEFT-TRIM(cPath,'\').
IF iElement > 1 THEN OS-CREATE-DIR VALUE(cPath).
END.
END PROCEDURE. /* createFolder */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-dumpRecord) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE dumpRecord Procedure
PROCEDURE dumpRecord :
/* Dump the record(s) to disk
*/
DEFINE INPUT PARAMETER pcAction AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER phSource AS HANDLE NO-UNDO.
DEFINE OUTPUT PARAMETER plContinue AS LOGICAL NO-UNDO.
DEFINE VARIABLE hExportTT AS HANDLE NO-UNDO.
DEFINE VARIABLE hExportTtBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE hBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE cFileName AS CHARACTER NO-UNDO.
DEFINE VARIABLE cError AS CHARACTER NO-UNDO.
DEFINE VARIABLE cMessage AS CHARACTER NO-UNDO.
DEFINE VARIABLE iRow AS INTEGER NO-UNDO.
DEFINE VARIABLE lDefaultDump AS LOGICAL NO-UNDO.
IF NOT VALID-HANDLE(phSource) THEN RETURN.
/* Protect against wrong input */
IF LOOKUP(pcAction,'Dump,Create,Update,Delete') = 0 THEN
DO:
MESSAGE 'Unknown action' pcAction VIEW-AS ALERT-BOX INFORMATION BUTTONS OK.
RETURN.
END.
/* Determine appropriate buffer and populate an intermediate tt
* with the data to export
*/
CASE phSource:TYPE:
WHEN 'buffer' THEN
DO:
hBuffer = phSource.
/* Create temptable-handle... */
CREATE TEMP-TABLE hExportTt.
hExportTt:CREATE-LIKE(SUBSTITUTE("&1.&2", hBuffer:DBNAME, hBuffer:TABLE)).
/* Prepare the TempTable... */
hExportTt:TEMP-TABLE-PREPARE(SUBSTITUTE("&1", hBuffer:TABLE)).
hExportTtBuffer = hExportTt:DEFAULT-BUFFER-HANDLE.
hExportTtBuffer:BUFFER-CREATE().
hExportTtBuffer:BUFFER-COPY(hBuffer).
END.
WHEN 'browse' THEN
DO:
hBuffer = phSource:QUERY:GET-BUFFER-HANDLE(1).
/* Create temptable-handle... */
CREATE TEMP-TABLE hExportTt.
hExportTt:CREATE-LIKE(SUBSTITUTE("&1.&2", hBuffer:DBNAME, hBuffer:TABLE)).
/* Prepare the TempTable... */
hExportTt:TEMP-TABLE-PREPARE(SUBSTITUTE("&1", hBuffer:TABLE)).
hExportTtBuffer = hExportTt:DEFAULT-BUFFER-HANDLE.
/* Copy the records */
DO iRow = 1 TO phSource:NUM-SELECTED-ROWS:
phSource:FETCH-SELECTED-ROW(iRow).
hExportTtBuffer:BUFFER-CREATE().
hExportTtBuffer:BUFFER-COPY(hBuffer).
END.
END.
OTHERWISE RETURN.
END CASE.
/* Do we need to dump at all?
* If the setting=NO or if no setting at all, then don't do any checks
*/
IF pcAction <> 'Dump'
AND ( getRegistry('DataDigger:Backup','BackupOn' + pcAction) = ?
OR logical(getRegistry('DataDigger:Backup','BackupOn' + pcAction)) = NO
) THEN
DO:
ASSIGN plContinue = YES.
RETURN.
END.
/* Determine the default name to save to */
RUN getDumpFileName
( INPUT pcAction /* Dump | Create | Update | Delete */
, INPUT hBuffer:DBNAME
, INPUT hBuffer:TABLE
, INPUT "XML"
, INPUT ""
, OUTPUT cFileName
).
RUN checkDir(INPUT cFileName, OUTPUT cError).
IF cError <> "" THEN
DO:
MESSAGE cError VIEW-AS ALERT-BOX INFORMATION BUTTONS OK.
RETURN.
END.
/* Fix XML Node Names for fields in the tt */
RUN setXmlNodeNames(INPUT hExportTt:DEFAULT-BUFFER-HANDLE).
/* See if the user has specified his own dump program
*/
plContinue = ?. /* To see if it ran or not */
PUBLISH "customDump"
( INPUT pcAction
, INPUT hBuffer:DBNAME
, INPUT hBuffer:TABLE
, INPUT hExportTt
, INPUT cFileName
, OUTPUT cMessage
, OUTPUT lDefaultDump
, OUTPUT plContinue
).
IF plContinue <> ? THEN
DO:
IF cMessage <> "" THEN MESSAGE cMessage VIEW-AS ALERT-BOX INFORMATION BUTTONS OK.
IF NOT lDefaultDump OR NOT plContinue THEN RETURN.
END.
plContinue = hExportTT:WRITE-XML
( 'file' /* TargetType */
, cFileName /* File */
, YES /* Formatted */
, ? /* Encoding */
, ? /* SchemaLocation */
, NO /* WriteSchema */
, NO /* MinSchema */
).
DELETE OBJECT hExportTt.
END PROCEDURE. /* dumpRecord */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-dynamicDump) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE dynamicDump Procedure
PROCEDURE dynamicDump :
/* Dump the data to a file that is similar to those of Progress self.
*/
DEFINE INPUT PARAMETER pihBrowse AS HANDLE NO-UNDO.
DEFINE INPUT PARAMETER picFile AS CHARACTER NO-UNDO.
DEFINE VARIABLE cTimeStamp AS CHARACTER NO-UNDO.
DEFINE VARIABLE hBuffer AS HANDLE NO-UNDO EXTENT 5.
DEFINE VARIABLE hColumn AS HANDLE NO-UNDO.
DEFINE VARIABLE hField AS HANDLE NO-UNDO.
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
DEFINE VARIABLE iBack AS INTEGER NO-UNDO.
DEFINE VARIABLE iBuffer AS INTEGER NO-UNDO.
DEFINE VARIABLE iColumn AS INTEGER NO-UNDO.
DEFINE VARIABLE iExtent AS INTEGER NO-UNDO.
DEFINE VARIABLE iRecords AS INTEGER NO-UNDO.
DEFINE VARIABLE iTrailer AS INTEGER NO-UNDO.
DEFINE VARIABLE lFirst AS LOGICAL NO-UNDO.
hQuery = pihBrowse:QUERY.
/* Accept max 5 buffers for a query */
DO iBuffer = 1 TO min(5, hQuery:NUM-BUFFERS):
hBuffer[iBuffer] = hQuery:GET-BUFFER-HANDLE(iBuffer).
END.
ASSIGN
iRecords = 0
cTimeStamp = STRING(YEAR( TODAY),"9999":u) + "/":u
+ string(MONTH(TODAY),"99":u ) + "/":u
+ string(DAY( TODAY),"99":u ) + "-":u
+ string(TIME,"HH:MM:SS":u).
hQuery:GET-FIRST.
/* Open outputfile */
OUTPUT to value(picFile) no-echo no-map.
EXPORT ?.
iBack = seek(output) - 1.
SEEK OUTPUT TO 0.
REPEAT WHILE NOT hQuery:QUERY-OFF-END
ON STOP UNDO, LEAVE:
ASSIGN
iRecords = iRecords + 1
lFirst = TRUE
.
PROCESS EVENTS.
browseColumn:
DO iColumn = 1 TO pihBrowse:NUM-COLUMNS:
/* Grab the handle */
hColumn = pihBrowse:GET-BROWSE-COLUMN(iColumn).
/* Skip invisible columns */
IF NOT hColumn:VISIBLE THEN NEXT browseColumn.
/* Find the buffer the column belongs to */
SearchLoop:
DO iBuffer = 1 TO 5:
ASSIGN hField = hBuffer[iBuffer]:BUFFER-FIELD(hColumn:NAME) NO-ERROR.
IF ERROR-STATUS:ERROR = FALSE
AND hField <> ? THEN
LEAVE SearchLoop.
END.
/* If no column found, something weird happened */
IF hField = ? THEN NEXT browseColumn.
IF hField:DATA-TYPE = "recid":u THEN NEXT browseColumn.
IF lFirst THEN
lFirst = FALSE.
ELSE
DO:
SEEK OUTPUT TO seek(output) - iBack.
PUT CONTROL ' ':u.
END.
IF hField:EXTENT > 1 THEN
DO iExtent = 1 TO hField:EXTENT:
IF iExtent > 1 THEN
DO:
SEEK OUTPUT TO SEEK(OUTPUT) - iBack.
PUT CONTROL ' ':u.
END.
EXPORT hField:BUFFER-VALUE(iExtent).
END.
ELSE
EXPORT hField:BUFFER-VALUE.
END.
hQuery:GET-NEXT().
END.
/* Add a checksum and nr of records at the end of the file.
*/
PUT UNFORMATTED ".":u SKIP.
iTrailer = SEEK(OUTPUT).
PUT UNFORMATTED
"PSC":u
SKIP "filename=":u hBuffer[1]:TABLE
SKIP "records=":u STRING(iRecords,"9999999999999":u)
SKIP "ldbname=":u hBuffer[1]:DBNAME
SKIP "timestamp=":u cTimeStamp
SKIP "numformat=":u ASC(SESSION:NUMERIC-SEPARATOR) ",":u ASC(SESSION:NUMERIC-DECIMAL-POINT)
SKIP "dateformat=":u SESSION:DATE-FORMAT "-":u SESSION:YEAR-OFFSET
SKIP "map=NO-MAP":u
SKIP "cpstream=":u SESSION:CPSTREAM
SKIP ".":u
SKIP STRING(iTrailer,"9999999999":u)
SKIP.
OUTPUT CLOSE.
END PROCEDURE. /* dynamicDump */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-flushRegistry) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE flushRegistry Procedure
PROCEDURE flushRegistry :
/* Flush all dirty registry settings to disk
*/
{&timerStart}
IF glDirtyCache THEN
RUN saveConfigFileSorted.
{&timerStop}
END PROCEDURE. /* flushRegistry */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getColumnSort) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE getColumnSort Procedure
PROCEDURE getColumnSort :
/* Return the column nr the browse is sorted on
*/
DEFINE INPUT PARAMETER phBrowse AS HANDLE NO-UNDO.
DEFINE OUTPUT PARAMETER pcColumn AS CHARACTER NO-UNDO.
DEFINE OUTPUT PARAMETER plAscending AS LOGICAL NO-UNDO.
DEFINE VARIABLE hColumn AS HANDLE NO-UNDO.
DEFINE VARIABLE iColumn AS INTEGER NO-UNDO.
{&timerStart}
#BrowseColumns:
DO iColumn = 1 TO phBrowse:NUM-COLUMNS:
hColumn = phBrowse:GET-BROWSE-COLUMN(iColumn).
IF hColumn:SORT-ASCENDING <> ? THEN
DO:
ASSIGN
pcColumn = hColumn:NAME
plAscending = hColumn:SORT-ASCENDING
.
LEAVE #BrowseColumns.
END.
END.
IF pcColumn = '' THEN
ASSIGN
pcColumn = phBrowse:GET-BROWSE-COLUMN(1):name
plAscending = TRUE.
PUBLISH "debugInfo" (3, SUBSTITUTE("Sorting &1 on &2", STRING(plAscending,"up/down"), pcColumn)).
{&timerStop}
END PROCEDURE. /* getColumnSort */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getDumpFileName) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE getDumpFileName Procedure
PROCEDURE getDumpFileName :
/* Return a file name based on a template
*/
DEFINE INPUT PARAMETER pcAction AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcDatabase AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcTable AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcExtension AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcTemplate AS CHARACTER NO-UNDO.
DEFINE OUTPUT PARAMETER pcFileName AS CHARACTER NO-UNDO.
DEFINE VARIABLE cLastDir AS CHARACTER NO-UNDO.
DEFINE VARIABLE cDayOfWeek AS CHARACTER NO-UNDO EXTENT 7 INITIAL ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].
DEFINE VARIABLE cDumpName AS CHARACTER NO-UNDO.
DEFINE VARIABLE cDumpDir AS CHARACTER NO-UNDO.
DEFINE VARIABLE cBackupDir AS CHARACTER NO-UNDO.
DEFINE VARIABLE hBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE cUserId AS CHARACTER NO-UNDO.
/* Checks */
IF LOOKUP(pcAction, "Dump,Create,Update,Delete") = 0 THEN
DO:
MESSAGE 'Unknown action' pcAction VIEW-AS ALERT-BOX.
RETURN.
END.
/* If not provided, find the template from the settings,
* depending on the action we want to perform.
*/
IF pcTemplate = ? OR pcTemplate = "" THEN
DO:
IF pcAction = 'Dump' THEN
pcFileName = "<DUMPDIR>" + getRegistry("DumpAndLoad", "DumpFileTemplate").
ELSE
pcFileName = "<BACKUPDIR>" + getRegistry("DataDigger:Backup", "BackupFileTemplate").
END.
ELSE
pcFileName = pcTemplate.
IF pcFileName = ? THEN pcFileName = "".
PUBLISH "debugInfo" (3, SUBSTITUTE("Dump to: &1", pcFileName)).
/* Dump dir / backup dir / last-used dir from settings */
cDumpDir = RIGHT-TRIM(getRegistry("DumpAndLoad", "DumpDir"),'/\') + '\'.
IF cDumpDir = ? OR cDumpDir = '' THEN cDumpDir = "<WORKDIR>dump\".
cBackupDir = RIGHT-TRIM(getRegistry("DataDigger:Backup", "BackupDir"),'/\') + '\'.
IF cBackupDir = ? OR cBackupDir = '' THEN cBackupDir = "<WORKDIR>backup\".
cLastDir = RIGHT-TRIM(getRegistry("DumpAndLoad", "DumpLastFileName"),'/\').
cLastDir = SUBSTRING(cLastDir,1,R-INDEX(cLastDir,"\")).
IF cLastDir = ? THEN cLastDir = "<WORKDIR>dump".
cLastDir = RIGHT-TRIM(cLastDir,'\').
/* Find _file for the dump-name */
CREATE BUFFER hBuffer FOR TABLE SUBSTITUTE('&1._file', pcDatabase) NO-ERROR.
IF VALID-HANDLE(hBuffer) THEN
DO:
hBuffer:FIND-UNIQUE(SUBSTITUTE('where _file-name = &1 and _File._File-Number < 32768', QUOTER(pcTable)),NO-LOCK).
IF hBuffer:AVAILABLE THEN
cDumpName = hBuffer::_dump-name.
ELSE
cDumpName = pcTable.
END.
ELSE
cDumpName = pcTable.
IF cDumpName = ? THEN cDumpName = pcTable.
/* If you have no db connected, userid gives back unknown value
* which misbehaves in a replace statement */
cUserId = USERID(LDBNAME(1)).
IF cUserId = ? THEN cUserId = ''.
PUBLISH "debugInfo" (3, SUBSTITUTE("DumpDir : &1", cDumpDir)).
PUBLISH "debugInfo" (3, SUBSTITUTE("BackupDir: &1", cBackupDir)).
PUBLISH "debugInfo" (3, SUBSTITUTE("LastDir : &1", cLastDir)).
PUBLISH "debugInfo" (3, SUBSTITUTE("DumpName : &1", cDumpName)).
/* Now resolve all tags */
pcFileName = REPLACE(pcFileName,"<DUMPDIR>" , cDumpDir ).
pcFileName = REPLACE(pcFileName,"<BACKUPDIR>", cBackupDir ).
pcFileName = REPLACE(pcFileName,"<LASTDIR>" , cLastDir ).
pcFileName = REPLACE(pcFileName,"<PROGDIR>" , getWorkFolder() ).
pcFileName = REPLACE(pcFileName,"<WORKDIR>" , getWorkFolder() ).
pcFileName = REPLACE(pcFileName,"<ACTION>" , pcAction ).
pcFileName = REPLACE(pcFileName,"<USERID>" , cUserId ).
pcFileName = REPLACE(pcFileName,"<DB>" , pcDatabase ).
pcFileName = REPLACE(pcFileName,"<TABLE>" , pcTable ).
pcFileName = REPLACE(pcFileName,"<DUMPNAME>" , cDumpName ).
pcFileName = REPLACE(pcFileName,"<EXT>" , pcExtension ).
pcFileName = REPLACE(pcFileName,"<TIMESTAMP>", "<YEAR><MONTH><DAY>.<HH><MM><SS>" ).
pcFileName = REPLACE(pcFileName,"<DATE>" , "<YEAR>-<MONTH>-<DAY>" ).
pcFileName = REPLACE(pcFileName,"<TIME>" , "<HH>:<MM>:<SS>" ).
pcFileName = REPLACE(pcFileName,"<WEEKDAY>" , STRING(WEEKDAY(TODAY)) ).
pcFileName = REPLACE(pcFileName,"<DAYNAME>" , cDayOfWeek[WEEKDAY(today)] ).
pcFileName = REPLACE(pcFileName,"<YEAR>" , STRING(YEAR (TODAY),"9999") ).
pcFileName = REPLACE(pcFileName,"<MONTH>" , STRING(MONTH(TODAY), "99") ).
pcFileName = REPLACE(pcFileName,"<DAY>" , STRING(DAY (TODAY), "99") ).
pcFileName = REPLACE(pcFileName,"<HH>" , ENTRY(1,STRING(TIME,"HH:MM:SS"),":" ) ).
pcFileName = REPLACE(pcFileName,"<MM>" , ENTRY(2,STRING(TIME,"HH:MM:SS"),":" ) ).
pcFileName = REPLACE(pcFileName,"<SS>" , ENTRY(3,STRING(TIME,"HH:MM:SS"),":" ) ).
/* Get rid of annoying slashes */
pcFileName = TRIM(pcFileName,'/\').
/* Get rid of double slashes (except at the beginning for UNC paths) */
pcFileName = SUBSTRING(pcFileName,1,1) + REPLACE(SUBSTRING(pcFileName,2),'\\','\').
/* Sequences */
pcFileName = resolveSequence(pcFileName).
/* OS-vars */
pcFileName = resolveOsVars(pcFileName).
/* Make lower */
pcFileName = LC(pcFileName).
PUBLISH "debugInfo" (3, SUBSTITUTE("Dump to: &1", pcFileName)).
END PROCEDURE. /* getDumpFileName */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getFavourites) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE getFavourites Procedure
PROCEDURE getFavourites :
/* Extract favourites from config table into own tt
*/
DEFINE OUTPUT PARAMETER TABLE FOR ttFavGroup.
DEFINE BUFFER bfConfig FOR ttConfig.
DEFINE BUFFER btFavGroup FOR ttFavGroup.
EMPTY TEMP-TABLE ttFavGroup.
FOR EACH bfConfig
WHERE bfConfig.cSection = 'DataDigger:Favourites'
AND bfConfig.cSetting > "":
CREATE btFavGroup.
ASSIGN
btFavGroup.cGroup = bfConfig.cSetting
btFavGroup.cTables = bfConfig.cValue.
END.
/* If no groups are found, create a default one */
IF NOT CAN-FIND(FIRST btFavGroup) THEN
DO:
CREATE btFavGroup.
ASSIGN btFavGroup.cGroup = 'MyFavourites'.
END.
END PROCEDURE. /* getFavourites */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getFields) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE getFields Procedure
PROCEDURE getFields :
/* Fill the fields temp-table
*/
DEFINE INPUT PARAMETER pcDatabase AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcTableName AS CHARACTER NO-UNDO.
DEFINE OUTPUT PARAMETER DATASET FOR dsFields.
DEFINE VARIABLE cCacheFile AS CHARACTER NO-UNDO.
DEFINE VARIABLE cPrimIndexFields AS CHARACTER NO-UNDO.
DEFINE VARIABLE cQuery AS CHARACTER NO-UNDO.
DEFINE VARIABLE cSelectedFields AS CHARACTER NO-UNDO.
DEFINE VARIABLE cUniqueIndexFields AS CHARACTER NO-UNDO.
DEFINE VARIABLE cSDBName AS CHARACTER NO-UNDO.
DEFINE VARIABLE hBufferField AS HANDLE NO-UNDO.
DEFINE VARIABLE hBufferFile AS HANDLE NO-UNDO.
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
DEFINE VARIABLE iFieldExtent AS INTEGER NO-UNDO.
DEFINE VARIABLE iFieldOrder AS INTEGER NO-UNDO.
DEFINE VARIABLE lDataField AS LOGICAL NO-UNDO.
DEFINE VARIABLE iDataOrder AS INTEGER NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE BUFFER bTable FOR ttTable.
DEFINE BUFFER bField FOR ttField.
DEFINE BUFFER bColumn FOR ttColumn.
DEFINE BUFFER bFieldCache FOR ttFieldCache.
DEFINE BUFFER bColumnCache FOR ttColumnCache.
DEFINE BUFFER bTableFilter FOR ttTableFilter.
{&timerStart}
/* Clean up first */
EMPTY TEMP-TABLE bField.
EMPTY TEMP-TABLE bColumn.
/* For dataservers, use the schema name [dataserver] */
ASSIGN cSDBName = SDBNAME(pcDatabase).
/* Return if no db connected */
IF NUM-DBS = 0 THEN RETURN.
/* caching */
IF glCacheFieldDefs THEN
DO:
/* Find the table. Should exist. */
FIND bTable WHERE bTable.cDatabase = pcDatabase AND bTable.cTableName = pcTableName NO-ERROR.
IF NOT AVAILABLE bTable THEN RETURN.
/* Verify whether the CRC is still the same. If not, kill the cache */
PUBLISH "DD:Timer" ("start", 'getFields - step 1: verify CRC').
CREATE BUFFER hBufferFile FOR TABLE cSDBName + "._File".
hBufferFile:FIND-UNIQUE(SUBSTITUTE('where _file-name = &1 and _File._File-Number < 32768', QUOTER(pcTableName)),NO-LOCK).
IF hBufferFile::_crc <> bTable.cCrc THEN
DO:
/* It seems that it is not possible to refresh the schema cache of the running
* session. You just have to restart your session.
*/
PUBLISH "debugInfo" (1, SUBSTITUTE("File CRC changed, kill cache and build new")).
FOR EACH bFieldCache WHERE bFieldCache.cTableCacheId = bTable.cCacheId:
DELETE bFieldCache.
END.
FOR EACH bColumnCache WHERE bColumnCache.cTableCacheId = bTable.cCacheId:
DELETE bColumnCache.
END.
/* Get a fresh list of tables */
RUN getTables(INPUT TABLE bTableFilter, OUTPUT TABLE bTable).
/* Find the table back. Should exist. */
FIND bTable WHERE bTable.cDatabase = pcDatabase AND bTable.cTableName = pcTableName NO-ERROR.
IF NOT AVAILABLE bTable THEN RETURN.
END.
PUBLISH "DD:Timer" ("stop", 'getFields - step 1: verify CRC').
/* First look in the memory-cache */
IF CAN-FIND(FIRST bFieldCache WHERE bFieldCache.cTableCacheId = bTable.cCacheId) THEN
DO:
PUBLISH "DD:Timer" ("start", 'getFields - step 2: check memory cache').
PUBLISH "debugInfo" (3, SUBSTITUTE("Get from memory-cache")).
FOR EACH bFieldCache WHERE bFieldCache.cTableCacheId = bTable.cCacheId:
CREATE bField.
BUFFER-COPY bFieldCache TO bField.
END.
FOR EACH bColumnCache WHERE bColumnCache.cTableCacheId = bTable.cCacheId:
CREATE bColumn.
BUFFER-COPY bColumnCache TO bColumn.
END.
/* Update with settings from registry */
RUN updateFields(INPUT pcDatabase, INPUT pcTableName, INPUT-OUTPUT TABLE bField).
PUBLISH "DD:Timer" ("stop", 'getFields - step 2: check memory cache').
RETURN.
END.
/* See if disk cache exists */
cCacheFile = SUBSTITUTE('&1cache\&2.xml', getWorkFolder(), bTable.cCacheId).
PUBLISH "debugInfo" (2, SUBSTITUTE("Cachefile: &1", cCacheFile)).
IF SEARCH(cCacheFile) <> ? THEN
DO:
PUBLISH "DD:Timer" ("start", 'getFields - step 3: get from disk cache').
PUBLISH "debugInfo" (3, SUBSTITUTE("Get from disk cache")).
DATASET dsFields:READ-XML("file", cCacheFile, "empty", ?, ?, ?, ?).
/* Add to memory cache, so the next time it's even faster */
IF TEMP-TABLE bField:HAS-RECORDS THEN
DO:
PUBLISH "debugInfo" (3, SUBSTITUTE("Add to first-level cache")).
FOR EACH bField {&TABLE-SCAN}:
CREATE bFieldCache.
BUFFER-COPY bField TO bFieldCache.
END.
FOR EACH bColumn {&TABLE-SCAN}:
CREATE bColumnCache.
BUFFER-COPY bColumn TO bColumnCache.
END.
END.
/* Update with settings from registry */
RUN updateFields(INPUT pcDatabase, INPUT pcTableName, INPUT-OUTPUT TABLE bField).
PUBLISH "DD:Timer" ("stop", 'getFields - step 3: get from disk cache').
RETURN.
END.
PUBLISH "debugInfo" (3, SUBSTITUTE("Not found in any cache, build tables...")).
END.
/*
* If we get here, the table either cannot be found in the cache
* or caching is disabled. Either way, fill the tt with fields
*/
PUBLISH "DD:Timer" ("start", 'getFields - step 4: build cache').
FIND bTable WHERE bTable.cDatabase = pcDatabase AND bTable.cTableName = pcTableName NO-ERROR.
IF NOT AVAILABLE bTable THEN RETURN.
CREATE BUFFER hBufferFile FOR TABLE cSDBName + "._File".
CREATE BUFFER hBufferField FOR TABLE cSDBName + "._Field".
CREATE QUERY hQuery.
hQuery:SET-BUFFERS(hBufferFile,hBufferField).
cQuery = SUBSTITUTE("FOR EACH &1._File WHERE &1._file._file-name = '&2' AND _File._File-Number < 32768 NO-LOCK, " +
" EACH &1._Field OF &1._File NO-LOCK BY _ORDER"
, cSDBName
, pcTableName
).
hQuery:QUERY-PREPARE(cQuery).
hQuery:QUERY-OPEN().
hQuery:GET-FIRST().
/* Get list of fields in primary index. */
cPrimIndexFields = getIndexFields(cSDBName, pcTableName, "P").
/* Get list of fields in all unique indexes. */
cUniqueIndexFields = getIndexFields(cSDBName, pcTableName, "U").
/* Get list of all previously selected fields */
cSelectedFields = getRegistry(SUBSTITUTE("DB:&1",pcDatabase), SUBSTITUTE("&1:Fields",pcTableName)).
/* If none selected, set mask to 'all' */
IF cSelectedFields = ? THEN cSelectedFields = '*'.
REPEAT WHILE NOT hQuery:QUERY-OFF-END:
CREATE bField.
ASSIGN
iFieldOrder = iFieldOrder + 1
bField.cTableCacheId = bTable.cCacheId
bField.cDatabase = pcDatabase
bField.cTablename = pcTableName
bField.cFieldName = hBufferField:BUFFER-FIELD('_field-name'):BUFFER-VALUE
bField.lShow = CAN-DO(cSelectedFields, hBufferField:BUFFER-FIELD('_field-name'):BUFFER-VALUE)
bField.iOrder = iFieldOrder
bField.iOrderOrg = iFieldOrder
bField.cFullName = hBufferField:BUFFER-FIELD('_field-name'):BUFFER-VALUE
bField.cDataType = hBufferField:BUFFER-FIELD('_data-type'):BUFFER-VALUE
bField.cInitial = hBufferField:BUFFER-FIELD('_initial'):BUFFER-VALUE
bField.cFormat = hBufferField:BUFFER-FIELD('_format'):BUFFER-VALUE
bField.cFormatOrg = hBufferField:BUFFER-FIELD('_format'):BUFFER-VALUE
bField.iWidth = hBufferField:BUFFER-FIELD('_width'):BUFFER-VALUE
bField.cLabel = hBufferField:BUFFER-FIELD('_label'):BUFFER-VALUE
bField.lPrimary = CAN-DO(cPrimIndexFields, bField.cFieldName)
bField.iExtent = hBufferField:BUFFER-FIELD('_Extent'):BUFFER-VALUE
bField.lMandatory = hBufferField:BUFFER-FIELD('_mandatory'):BUFFER-VALUE
bField.lUniqueIdx = CAN-DO(cUniqueIndexFields,bField.cFieldName)
/* New fields as per v19 */
bField.cColLabel = hBufferField:BUFFER-FIELD('_Col-label'):BUFFER-VALUE
bField.iDecimals = hBufferField:BUFFER-FIELD('_Decimals'):BUFFER-VALUE
bField.iFieldRpos = hBufferField:BUFFER-FIELD('_Field-rpos'):BUFFER-VALUE
bField.cValExp = hBufferField:BUFFER-FIELD('_ValExp'):BUFFER-VALUE
bField.cValMsg = hBufferField:BUFFER-FIELD('_ValMsg'):BUFFER-VALUE
bField.cHelp = hBufferField:BUFFER-FIELD('_Help'):BUFFER-VALUE
bField.cDesc = hBufferField:BUFFER-FIELD('_Desc'):BUFFER-VALUE
bField.cViewAs = hBufferField:BUFFER-FIELD('_View-as'):BUFFER-VALUE
.
ASSIGN
bField.cXmlNodeName = getXmlNodeName(bField.cFieldName)
.
/* Make a list of fields on table level */
bTable.cFields = bTable.cFields + "," + bField.cFieldName.
/* Some types should not be shown like CLOB BLOB and RAW */
lDataField = (LOOKUP(bField.cDataType, 'clob,blob,raw') = 0).
/* Create TT records for each column to show, except for CLOB / BLOB / RAW */
IF lDataField = TRUE THEN
DO iFieldExtent = (IF bField.iExtent = 0 THEN 0 ELSE 1) TO bField.iExtent:
iDataOrder = iDataOrder + 1.
CREATE bColumn.
ASSIGN
bColumn.cTableCacheId = bTable.cCacheId
bColumn.cDatabase = bField.cDatabase
bColumn.cTableName = bField.cTablename
bColumn.cFieldName = bField.cFieldName
bColumn.iExtent = iFieldExtent
bColumn.cFullName = bField.cFieldName + (IF iFieldExtent > 0 THEN SUBSTITUTE("[&1]", iFieldExtent) ELSE "")
bColumn.iColumnNr = iDataOrder
bColumn.iOrder = bField.iOrder
bColumn.cLabel = bField.cLabel
.
PUBLISH "debugInfo"(3,SUBSTITUTE("Field &1 created", bColumn.cFullName)).
END. /* For each extent nr */
hQuery:GET-NEXT().
END.
hQuery:QUERY-CLOSE().
DELETE OBJECT hQuery.
DELETE OBJECT hBufferField.
DELETE OBJECT hBufferFile.
/* Fieldlist */
bTable.cFields = SUBSTRING(bTable.cFields,2).
/* Add columns for recid/rowid */
DO i = 1 TO 2:
CREATE bField.
ASSIGN
iFieldOrder = iFieldOrder + 1
bField.cTableCacheId = bTable.cCacheId
bField.cDatabase = pcDatabase
bField.cTablename = pcTableName
bField.cFieldName = ENTRY(i,"RECID,ROWID")
bField.lShow = FALSE
bField.iOrder = iFieldOrder
bField.iOrderOrg = iFieldOrder
bField.cFieldName = bField.cFieldName
bField.cFullName = bField.cFieldName
bField.cDataType = 'character'
bField.cInitial = ''
bField.cFormat = ENTRY(i,"X(20),X(24)")
bField.cFormatOrg = bField.cFormat
bField.cLabel = bField.cFieldName
bField.lPrimary = NO
bField.iExtent = 0
.
iDataOrder = iDataOrder + 1.
CREATE bColumn.
ASSIGN
bColumn.cTableCacheId = bField.cTableCacheId
bColumn.cDatabase = bField.cDatabase
bColumn.cTableName = bField.cTablename
bColumn.cFieldName = bField.cFieldName
bColumn.iExtent = 0
bColumn.cFullName = bField.cFieldName
bColumn.iColumnNr = iDataOrder
bColumn.iOrder = bField.iOrder
bColumn.cLabel = bField.cLabel
.
END.
PUBLISH "DD:Timer" ("stop", 'getFields - step 4: build cache').
/* Update the cache */
IF glCacheFieldDefs THEN
DO:
/* Add to disk cache */
PUBLISH "DD:Timer" ("start", 'getFields - step 5: save to disk').
PUBLISH "debugInfo" (3, SUBSTITUTE("Add to second-level cache.")).
DATASET dsFields:WRITE-XML( "file", cCacheFile, YES, ?, ?, NO, NO).
/* Add to memory cache */
PUBLISH "debugInfo" (3, SUBSTITUTE("Add to first-level cache.")).
FOR EACH bField {&TABLE-SCAN}:
CREATE bFieldCache.
BUFFER-COPY bField TO bFieldCache.
END.
FOR EACH bColumn {&TABLE-SCAN}:
CREATE bColumnCache.
BUFFER-COPY bColumn TO bColumnCache.
END.
PUBLISH "DD:Timer" ("stop", 'getFields - step 5: save to disk').
END.
/* Update fields with settings from registry */
RUN updateFields(INPUT pcDatabase, INPUT pcTableName, INPUT-OUTPUT TABLE bField).
{&timerStop}
END PROCEDURE. /* getFields */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getMouseXY) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE getMouseXY Procedure
PROCEDURE getMouseXY :
/* Get the position of the mouse relative to the frame
*/
DEFINE INPUT PARAMETER phFrame AS HANDLE NO-UNDO.
DEFINE OUTPUT PARAMETER piMouseX AS INTEGER NO-UNDO.
DEFINE OUTPUT PARAMETER piMouseY AS INTEGER NO-UNDO.
DEFINE VARIABLE lp AS MEMPTR NO-UNDO.
{&_proparse_prolint-nowarn(varusage)}
DEFINE VARIABLE iRet AS INT64 NO-UNDO.
SET-SIZE( LP ) = 16.
{&_proparse_prolint-nowarn(varusage)}
RUN GetCursorPos(INPUT GET-POINTER-VALUE(lp), OUTPUT iRet).
RUN ScreenToClient ( INPUT phFrame:HWND, INPUT lp ).
piMouseX = GET-LONG( lp, 1 ).
piMouseY = GET-LONG( lp, 5 ).
SET-SIZE( LP ) = 0.
PUBLISH "debugInfo" (3, SUBSTITUTE("Mouse X/Y = &1 / &2", piMouseX, piMouseY)).
END PROCEDURE. /* getMouseXY */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getQueryTable) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE getQueryTable Procedure
PROCEDURE getQueryTable :
/* Get the ttQuery table
* Note: This procedure just returns the table, no further logic needed.
*/
DEFINE OUTPUT PARAMETER table FOR ttQuery.
END PROCEDURE. /* getQueryTable */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getRegistryTable) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE getRegistryTable Procedure
PROCEDURE getRegistryTable :
/* Return complete registry tt
*/
DEFINE OUTPUT PARAMETER TABLE FOR ttConfig.
END PROCEDURE. /* getRegistryTable */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getTables) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE getTables Procedure
PROCEDURE getTables :
/* Fill ttTable with all currently connected databases.
*/
DEFINE INPUT PARAMETER TABLE FOR ttTableFilter.
DEFINE OUTPUT PARAMETER TABLE FOR ttTable.
DEFINE VARIABLE cCacheFile AS CHARACTER NO-UNDO.
DEFINE VARIABLE hDbBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE hDbStatusBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE hDbQuery AS HANDLE NO-UNDO.
DEFINE VARIABLE iDatabase AS INTEGER NO-UNDO.
DEFINE VARIABLE cCacheTimeStamp AS CHARACTER NO-UNDO.
DEFINE VARIABLE cCacheDir AS CHARACTER NO-UNDO.
DEFINE VARIABLE cSchemaCacheFile AS CHARACTER NO-UNDO.
DEFINE VARIABLE cOneCacheFile AS CHARACTER NO-UNDO.
DEFINE BUFFER bTable FOR ttTable.
DEFINE BUFFER bTableXml FOR ttTableXml.
{&timerStart}
/* Dataserver support can be for:
*
* V9: "PROGRESS,AS400,ORACLE,MSS,ODBC"
* V10: "PROGRESS,ORACLE,MSS,ODBC" (from V10 no native support for AS400)
* V11: "PROGRESS,ORACLE,MSS,ODBC"
* V12: "PROGRESS,ORACLE,MSS" (from V12 no ODBC support anymore)
*
*/
EMPTY TEMP-TABLE ttTable.
CREATE WIDGET-POOL "metaInfo".
#Database:
DO iDatabase = 1 TO NUM-DBS:
IF DBTYPE(iDatabase) <> "PROGRESS" THEN NEXT #Database.
/* Compose name of the cache file. Use date/time of last schema change in the name */
IF glCacheTableDefs THEN
DO:
CREATE BUFFER hDbStatusBuffer FOR TABLE LDBNAME(iDatabase) + "._DbStatus" IN WIDGET-POOL "metaInfo".
hDbStatusBuffer:FIND-FIRST("",NO-LOCK).
ASSIGN
cCacheTimeStamp = REPLACE(REPLACE(hDbStatusBuffer::_dbstatus-cachestamp," ","_"),":","")
cCacheFile = SUBSTITUTE("&1cache\db.&2.&3.xml", getWorkFolder(), LDBNAME(iDatabase), cCacheTimeStamp ).
DELETE OBJECT hDbStatusBuffer.
END.
/* If caching enabled and there is a cache file, read it */
IF glCacheTableDefs AND SEARCH(cCacheFile) <> ? THEN
DO:
PUBLISH "debugInfo" (3, SUBSTITUTE("Get table list from cache file &1", cCacheFile)).
TEMP-TABLE ttTable:READ-XML("file", cCacheFile, "APPEND", ?, ?, ?, ?).
cCacheDir = SUBSTITUTE( "&1cache", getWorkFolder() ).
INPUT FROM OS-DIR(cCacheDir).
#ReadSchemaCache:
REPEAT:
IMPORT cSchemaCacheFile.
IF cSchemaCacheFile BEGINS SUBSTITUTE("db.&1;", LDBNAME(iDatabase))
AND ENTRY(NUM-ENTRIES(cSchemaCacheFile, ".") - 1, cSchemaCacheFile, ".") = ENTRY (NUM-ENTRIES(cCacheFile, ".") - 1, cCacheFile, ".") /* Check timestamp */
THEN
DO:
cOneCacheFile = SUBSTITUTE( "&1\&2", cCacheDir, cSchemaCacheFile).
TEMP-TABLE ttTable:READ-XML("file", cOneCacheFile, "APPEND", ?, ?, ?, ?).
END.
END.
INPUT CLOSE.
END.
/* Otherwise build it */
ELSE
DO:
CREATE ALIAS 'dictdb' FOR DATABASE VALUE(LDBNAME(iDatabase)).
RUN getSchema.p(INPUT TABLE ttTable BY-REFERENCE).
/* Save cache file for next time */
IF glCacheTableDefs THEN
DO:
/* Move the tables of the current db to a separate tt so we can dump it. */
EMPTY TEMP-TABLE ttTableXml.
CREATE QUERY hDbQuery IN WIDGET-POOL "metaInfo".
CREATE BUFFER hDbBuffer FOR TABLE LDBNAME(iDatabase) + "._Db" IN WIDGET-POOL "metaInfo".
hDbQuery:SET-BUFFERS(hDbBuffer).
hDbQuery:QUERY-PREPARE("FOR EACH _Db NO-LOCK WHERE _Db._Db-local = TRUE").
hDbQuery:QUERY-OPEN().
#DB:
REPEAT:
hDbQuery:GET-NEXT().
IF hDbQuery:QUERY-OFF-END THEN LEAVE #DB.
FOR EACH bTable
WHERE bTable.cDatabase = (IF hDbBuffer::_Db-slave THEN hDbBuffer::_Db-name ELSE LDBNAME(iDatabase)):
CREATE bTableXml.
BUFFER-COPY bTable TO bTableXml.
END.
END.
hDbQuery:QUERY-CLOSE().
DELETE OBJECT hDbQuery.
DELETE OBJECT hDbBuffer.
TEMP-TABLE ttTableXml:WRITE-XML("file", cCacheFile, YES, ?, ?, NO, NO).
EMPTY TEMP-TABLE ttTableXml.
/* Support Dataservers */
FOR EACH bTable
WHERE bTable.cSchemaHolder = LDBNAME(iDatabase)
BREAK BY bTable.cDatabase
BY bTable.cTableName:
IF FIRST-OF(bTable.cDatabase) THEN
DO:
cCacheFile = SUBSTITUTE( "&1cache\db.&2;&3.&4.xml"
, getWorkFolder()
, LDBNAME(iDatabase)
, bTable.cDatabase
, cCacheTimeStamp
).
EMPTY TEMP-TABLE bTableXml.
END.
CREATE bTableXml.
BUFFER-COPY bTable TO bTableXml.
IF LAST-OF(bTable.cDatabase) THEN
DO:
TEMP-TABLE bTableXml:WRITE-XML("file", cCacheFile, YES, ?, ?, NO, NO).
EMPTY TEMP-TABLE bTableXml.
END. /* IF LAST-OF */
END. /* FOR EACH bTable */
END. /* IF glCacheTableDefs THEN */
END. /* tt empty */
END. /* 1 to num-dbs */
DELETE WIDGET-POOL "metaInfo".
/* Apply filter to collection of tables */
RUN getTablesFiltered(INPUT TABLE ttTableFilter, OUTPUT TABLE ttTable).
/* Get table properties from the INI file */
RUN getTableStats(INPUT-OUTPUT TABLE ttTable).
{&timerStop}
END PROCEDURE. /* getTables */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getTablesFiltered) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE getTablesFiltered Procedure
PROCEDURE getTablesFiltered :
/* Determine whether tables in the ttTable are visible given a user defined filter
*/
{&timerStart}
DEFINE INPUT PARAMETER TABLE FOR ttTableFilter.
DEFINE OUTPUT PARAMETER TABLE FOR ttTable.
DEFINE VARIABLE cSearchFld AS CHARACTER NO-UNDO.
DEFINE VARIABLE cThisField AS CHARACTER NO-UNDO.
DEFINE VARIABLE iSearch AS INTEGER NO-UNDO.
DEFINE VARIABLE iField AS INTEGER NO-UNDO.
DEFINE VARIABLE lRejected AS LOGICAL NO-UNDO.
DEFINE VARIABLE lFieldFound AS LOGICAL NO-UNDO.
DEFINE VARIABLE lNormal AS LOGICAL NO-UNDO.
DEFINE VARIABLE lSchema AS LOGICAL NO-UNDO.
DEFINE VARIABLE lVst AS LOGICAL NO-UNDO.
DEFINE VARIABLE lSql AS LOGICAL NO-UNDO.
DEFINE VARIABLE lOther AS LOGICAL NO-UNDO.
DEFINE VARIABLE lHidden AS LOGICAL NO-UNDO.
DEFINE VARIABLE lFrozen AS LOGICAL NO-UNDO.
DEFINE VARIABLE cNameShow AS CHARACTER NO-UNDO.
DEFINE VARIABLE cNameHide AS CHARACTER NO-UNDO.
DEFINE VARIABLE cFieldShow AS CHARACTER NO-UNDO.
DEFINE VARIABLE cFieldHide AS CHARACTER NO-UNDO.
/* This table **SHOULD** exist and have exactly 1 record */
FIND ttTableFilter NO-ERROR.
IF NOT AVAILABLE ttTableFilter THEN RETURN.
ASSIGN
lNormal = ttTableFilter.lShowNormal
lSchema = ttTableFilter.lShowSchema
lVst = ttTableFilter.lShowVst
lSql = ttTableFilter.lShowSql
lOther = ttTableFilter.lShowOther
lHidden = ttTableFilter.lShowHidden
lFrozen = ttTableFilter.lShowFrozen
cNameShow = ttTableFilter.cTableNameShow
cNameHide = ttTableFilter.cTableNameHide
cFieldShow = ttTableFilter.cTableFieldShow
cFieldHide = ttTableFilter.cTableFieldHide
.
/* Reset the filters to sane values if needed */
IF cNameShow = '' OR cNameShow = ? THEN cNameShow = '*'.
IF cNameHide = '*' OR cNameHide = ? THEN cNameHide = '' .
IF cFieldShow = '*' OR cFieldShow = ? THEN cFieldShow = ''.
IF cFieldHide = '*' OR cFieldHide = ? THEN cFieldHide = ''.
/* Move elements starting with "!" from pos-list to neg-list */
RUN correctFilterList(INPUT-OUTPUT cNameShow, INPUT-OUTPUT cNameHide).
RUN correctFilterList(INPUT-OUTPUT cFieldShow, INPUT-OUTPUT cFieldHide).
#Table:
FOR EACH ttTable {&TABLE-SCAN}:
/* Init table to false until proven otherwise */
ASSIGN ttTable.lShowInList = FALSE.
/* Check against filter-to-hide */
IF CAN-DO(cNameHide,ttTable.cTableName) THEN NEXT #Table.
/* Check against filter-to-show */
IF NOT CAN-DO(cNameShow,ttTable.cTableName) THEN NEXT #Table.
/* User tables : _file-number > 0 AND _file-number < 32000
* Schema tables : _file-number > -80 AND _file-number < 0
* Virtual system tables: _file-number < -16384
* SQL catalog tables : _file-name BEGINS "_sys"
*/
IF NOT lNormal AND ttTable.cCategory = 'Normal' THEN NEXT #Table.
IF NOT lSchema AND ttTable.cCategory = 'Schema' THEN NEXT #Table.
IF NOT lVst AND ttTable.cCategory = 'VST' THEN NEXT #Table.
IF NOT lSql AND ttTable.cCategory = 'SQL' THEN NEXT #Table.
IF NOT lOther AND ttTable.cCategory = 'Other' THEN NEXT #Table.
/* Handling for Hidden and Frozen apply only to user tables otherwise it will be too confusing
* because Schema, VST and SQL tables are all by default hidden and frozen.
*/
IF NOT lHidden AND ttTable.cCategory = 'Application' AND ttTable.lHidden = TRUE THEN NEXT #Table.
IF NOT lFrozen AND ttTable.cCategory = 'Application' AND ttTable.lFrozen = TRUE THEN NEXT #Table.
/* Fields that must be in the list */
DO iSearch = 1 TO NUM-ENTRIES(cFieldShow):
cSearchFld = ENTRY(iSearch,cFieldShow).
/* If no wildcards used, we can simply CAN-DO */
IF INDEX(cSearchFld,"*") = 0 THEN
DO:
IF NOT CAN-DO(ttTable.cFields, cSearchFld) THEN NEXT #Table.
END.
ELSE
DO:
lFieldFound = FALSE.
#Field:
DO iField = 1 TO NUM-ENTRIES(ttTable.cFields):
cThisField = ENTRY(iField,ttTable.cFields).
IF CAN-DO(cSearchFld,cThisField) THEN
DO:
lFieldFound = TRUE.
LEAVE #Field.
END.
END.
IF NOT lFieldFound THEN NEXT #Table.
END.
END.
/* Fields that may not be in the list */
DO iSearch = 1 TO NUM-ENTRIES(cFieldHide):
cSearchFld = ENTRY(iSearch,cFieldHide).
/* If no wildcards used, we can simply CAN-DO */
IF INDEX(cSearchFld,"*") = 0 THEN
DO:
IF CAN-DO(ttTable.cFields, cSearchFld) THEN NEXT #Table.
END.
ELSE
DO:
lRejected = FALSE.
#Field:
DO iField = 1 TO NUM-ENTRIES(ttTable.cFields):
cThisField = ENTRY(iField,ttTable.cFields).
IF CAN-DO(cSearchFld,cThisField) THEN
DO:
lRejected = TRUE.
LEAVE #Field.
END.
END. /* do iField */
IF lRejected THEN NEXT #Table.
END. /* else */
END. /* do iSearch */
/* If we get here, we should add the table */
ASSIGN ttTable.lShowInList = TRUE.
END. /* for each ttTable */
{&timerStop}
END PROCEDURE. /* getTablesFiltered */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getTableStats) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE getTableStats Procedure
PROCEDURE getTableStats :
/* Get table statistics from the INI file
*/
DEFINE INPUT-OUTPUT PARAMETER table FOR ttTable.
DEFINE VARIABLE cIniFile AS CHARACTER NO-UNDO.
DEFINE VARIABLE cLine AS CHARACTER NO-UNDO.
DEFINE VARIABLE cSection AS CHARACTER NO-UNDO.
DEFINE VARIABLE cDatabase AS CHARACTER NO-UNDO.
/* Read the ini file as plain text and parse the lines.
*
* The normal way would be to do a FOR-EACH on the _file table and
* retrieve the information needed. But if you have a large database
* (or a lot of databases), this becomes VERY slow. Searching the
* other way around by parsing the INI is a lot faster.
*/
{&timerStart}
cIniFile = SUBSTITUTE('&1DataDigger-&2.ini', getWorkFolder(), getUserName() ).
IF SEARCH(cIniFile) = ? THEN RETURN.
INPUT FROM VALUE(cIniFile).
#ReadLine:
REPEAT:
/* Sometimes lines get screwed up and are waaaay too long
* for the import statement. So just ignore those.
*/
IMPORT UNFORMATTED cLine NO-ERROR.
IF ERROR-STATUS:ERROR THEN NEXT #ReadLine.
/* Find DB sections */
IF cLine MATCHES '[DB:*]' THEN
DO:
cSection = TRIM(cLine,'[]').
cDatabase = ENTRY(2,cSection,":").
END.
/* Only process lines of database-sections */
IF NOT cSection BEGINS "DB:" THEN NEXT #ReadLine.
/* Only process setting lines */
IF NOT cLine MATCHES '*:*=*' THEN NEXT #ReadLine.
/* Filter out some settings */
IF cLine MATCHES "*:QueriesServed=*" THEN
DO:
FIND FIRST ttTable
WHERE ttTable.cDatabase = cDatabase
AND ttTable.cTableName = ENTRY(1,cLine,':') NO-ERROR.
IF AVAILABLE ttTable THEN
DO:
ttTable.iNumQueries = INTEGER(ENTRY(2,cLine,'=')) NO-ERROR.
IF ttTable.iNumQueries = ? THEN ttTable.iNumQueries = 0.
END.
END. /* queriesServed */
ELSE
IF cLine MATCHES "*:LastUsed=*" THEN
DO:
FIND FIRST ttTable
WHERE ttTable.cDatabase = cDatabase
AND ttTable.cTableName = ENTRY(1,cLine,':') NO-ERROR.
IF AVAILABLE ttTable THEN
ttTable.tLastUsed = DATETIME(ENTRY(2,cLine,'=')) NO-ERROR.
END. /* lastUsed */
END. /* repeat */
INPUT CLOSE.
{&timerStop}
END PROCEDURE. /* getTableStats */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-initTableFilter) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE initTableFilter Procedure
PROCEDURE initTableFilter :
/* Set table filter values back to their initial values
*/
DEFINE INPUT-OUTPUT PARAMETER TABLE FOR ttTableFilter.
EMPTY TEMP-TABLE ttTableFilter.
CREATE ttTableFilter.
/* Set visibility of schema tables */
ttTableFilter.lShowSchema = LOGICAL(getRegistry('DataDigger','ShowHiddenTables')).
IF ttTableFilter.lShowSchema = ? THEN ttTableFilter.lShowSchema = NO.
END PROCEDURE. /* initTableFilter */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-loadSettings) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE loadSettings Procedure
PROCEDURE loadSettings :
/* Load settings from ini files
*/
DEFINE VARIABLE lValue AS LOGICAL NO-UNDO.
/* Help file is least important, so read that first */
RUN readConfigFile( SUBSTITUTE("&1DataDiggerHelp.ini", getProgramDir() ), FALSE).
/* General DD settings (always in program folder) */
RUN readConfigFile( SUBSTITUTE("&1DataDigger.ini", getProgramDir() ), FALSE).
/* Per-user settings */
RUN readConfigFile( SUBSTITUTE("&1DataDigger-&2.ini", getWorkFolder(), getUserName() ), TRUE).
/* When all ini-files have been read, we can determine whether
* caching needs to be enabled
*/
lValue = LOGICAL(getRegistry("DataDigger:Cache","TableDefs")) NO-ERROR.
IF lValue <> ? THEN ASSIGN glCacheTableDefs = lValue.
END PROCEDURE. /* loadSettings */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-lockWindow) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE lockWindow Procedure
PROCEDURE lockWindow :
/* Lock / unlock updates that Windows does to windows.
*/
DEFINE INPUT PARAMETER phWindow AS HANDLE NO-UNDO.
DEFINE INPUT PARAMETER plLock AS LOGICAL NO-UNDO.
{&_proparse_prolint-nowarn(varusage)}
DEFINE VARIABLE iRet AS INTEGER NO-UNDO.
DEFINE BUFFER ttWindowLock FOR ttWindowLock.
{&timerStart}
PUBLISH "debugInfo" (3, SUBSTITUTE("Window &1, lock: &2", phWindow:TITLE, STRING(plLock,"ON/OFF"))).
IF NOT VALID-HANDLE(phWindow) THEN RETURN.
/* Find window in our tt of locked windows */
FIND ttWindowLock WHERE ttWindowLock.hWindow = phWindow NO-ERROR.
IF NOT AVAILABLE ttWindowLock THEN
DO:
/* If we try to unlock a window thats not in the tt, just go back */
IF NOT plLock THEN RETURN.
/* Otherwise create a tt record for it */
CREATE ttWindowLock.
ttWindowLock.hWindow = phWindow.
END.
/* Because commands to lock or unlock may be nested, keep track
* of the number of locks/unlocks using a semaphore.
*
* The order of commands may be:
* lockWindow(yes). -> actually lock the window
* lockWindow(yes). -> do nothing
* lockWindow(yes). -> do nothing
* lockWindow(no). -> do nothing
* lockWindow(no). -> do nothing
* lockWindow(yes). -> do nothing
* lockWindow(no). -> do nothing
* lockWindow(no). -> actually unlock the window
*/
IF plLock THEN
ttWindowLock.iLockCounter = ttWindowLock.iLockCounter + 1.
ELSE
ttWindowLock.iLockCounter = ttWindowLock.iLockCounter - 1.
PUBLISH "debugInfo" (3, SUBSTITUTE("Lock counter: &1", ttWindowLock.iLockCounter)).
/* Now, only lock when the semaphore is increased to 1 */
IF plLock AND ttWindowLock.iLockCounter = 1 THEN
DO:
{&_proparse_prolint-nowarn(varusage)}
RUN SendMessageA( phWindow:HWND /* {&window-name}:hwnd */
, {&WM_SETREDRAW}
, 0
, 0
, OUTPUT iRet
).
END.
/* And only unlock after the last unlock command */
ELSE IF ttWindowLock.iLockCounter <= 0 THEN
DO:
{&_proparse_prolint-nowarn(varusage)}
RUN SendMessageA( phWindow:HWND /* {&window-name}:hwnd */
, {&WM_SETREDRAW}
, 1
, 0
, OUTPUT iRet
).
{&_proparse_prolint-nowarn(varusage)}
RUN RedrawWindow( phWindow:HWND /* {&window-name}:hwnd */
, 0
, 0
, {&RDW_ALLCHILDREN} + {&RDW_ERASE} + {&RDW_INVALIDATE}
, OUTPUT iRet
).
/* Don't delete, creating records is more expensive than re-use, so just reset */
ttWindowLock.iLockCounter = 0.
END.
{&timerStop}
END PROCEDURE. /* lockWindow */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-readConfigFile) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE readConfigFile Procedure
PROCEDURE readConfigFile :
/* Read the ini-file and create tt records for it
*/
DEFINE INPUT PARAMETER pcConfigFile AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER plUserSettings AS LOGICAL NO-UNDO.
DEFINE VARIABLE cFile AS LONGCHAR NO-UNDO.
DEFINE VARIABLE cLine AS CHARACTER NO-UNDO.
DEFINE VARIABLE cChunk AS LONGCHAR NO-UNDO.
DEFINE VARIABLE cSection AS CHARACTER NO-UNDO.
DEFINE VARIABLE cTrimChars AS CHARACTER NO-UNDO.
DEFINE VARIABLE iLine AS INTEGER NO-UNDO.
{&timerStart}
DEFINE BUFFER bfConfig FOR ttConfig.
/* Read file in 1 pass to memory */
IF SEARCH(pcConfigFile) = ? THEN RETURN.
COPY-LOB FILE pcConfigFile TO cFile NO-CONVERT NO-ERROR.
IF ERROR-STATUS:ERROR THEN cFile = readFile(pcConfigFile).
cTrimChars = " " + CHR(1) + "~r". /* space / chr-1 / LF */
/* Process line by line */
#LineLoop:
DO iLine = 1 TO NUM-ENTRIES(cFile,"~n"):
cChunk = ENTRY(iLine,cFile,"~n").
cChunk = SUBSTRING(cChunk, 1,20000). /* trim very long lines */
cLine = TRIM(cChunk, cTrimChars). /* remove junk */
/* Section line */
IF cLine MATCHES "[*]" THEN
DO:
cSection = TRIM(cLine,"[]").
NEXT #LineLoop.
END.
/* Ignore weird settings within [DB:xxxx] sections */
IF cSection BEGINS 'DB:'
AND NUM-ENTRIES( TRIM(ENTRY(1,cLine,"=")), ':') = 1 THEN NEXT #LineLoop.
/* Config line */
FIND bfConfig
WHERE bfConfig.cSection = cSection
AND bfConfig.cSetting = TRIM(ENTRY(1,cLine,"=")) NO-ERROR.
IF NOT AVAILABLE bfConfig THEN
DO:
CREATE bfConfig.
ASSIGN
bfConfig.cSection = cSection
bfConfig.cSetting = TRIM(ENTRY(1,cLine,"="))
.
END.
/* Config line /might/ already exist. This can happen if you have
* the same setting in multiple .ini files.
*/
ASSIGN
bfConfig.cValue = TRIM(SUBSTRING(cLine, INDEX(cLine,"=") + 1))
bfConfig.lUser = plUserSettings.
END.
{&timerStop}
END PROCEDURE. /* readConfigFile */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-resetAnswers) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE resetAnswers Procedure
PROCEDURE resetAnswers :
/* Reset answers to all 'do not ask again' questions
*/
{&timerStart}
DEFINE BUFFER bfConfig FOR ttConfig.
FOR EACH bfConfig
WHERE bfConfig.cSection = 'DataDigger:Help'
AND (bfConfig.cSetting MATCHES '*:hidden' OR bfConfig.cSetting MATCHES '*:answer'):
setRegistry(bfConfig.cSection, bfConfig.cSetting, ?).
END. /* for each bfConfig */
RUN flushRegistry.
{&timerStop}
END PROCEDURE. /* resetAnswers */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-resizeFilterFields) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE resizeFilterFields Procedure
PROCEDURE resizeFilterFields :
/* Redraw the browse filter fields
*/
DEFINE INPUT PARAMETER phLeadButton AS HANDLE NO-UNDO.
DEFINE INPUT PARAMETER pcFilterFields AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcButtons AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER phBrowse AS HANDLE NO-UNDO.
DEFINE VARIABLE iField AS INTEGER NO-UNDO.
DEFINE VARIABLE iButton AS INTEGER NO-UNDO.
DEFINE VARIABLE iCurrentPos AS INTEGER NO-UNDO.
DEFINE VARIABLE iRightEdge AS INTEGER NO-UNDO.
DEFINE VARIABLE iWidth AS INTEGER NO-UNDO.
DEFINE VARIABLE hColumn AS HANDLE NO-UNDO.
DEFINE VARIABLE hButton AS HANDLE NO-UNDO.
DEFINE VARIABLE hFilterField AS HANDLE NO-UNDO.
DEFINE VARIABLE iFilter AS INTEGER NO-UNDO.
{&timerStart}
/* To prevent drawing error, make all fields small */
PUBLISH "DD:Timer" ("start", "resizeFilterFields:makeSmall").
DO iField = 1 TO NUM-ENTRIES(pcFilterFields):
hFilterField = HANDLE(ENTRY(iField,pcFilterFields)).
hFilterField:VISIBLE = NO.
hFilterField:X = phBrowse:X.
hFilterField:Y = phBrowse:Y - 23.
hFilterField:WIDTH-PIXELS = 1.
END.
PUBLISH "DD:Timer" ("stop", "resizeFilterFields:makeSmall").
/* Start by setting the buttons at the proper place. Do this right to left */
PUBLISH "DD:Timer" ("start", "resizeFilterFields:reposition").
ASSIGN iRightEdge = phBrowse:X + phBrowse:WIDTH-PIXELS.
DO iButton = NUM-ENTRIES(pcButtons) TO 1 BY -1:
hButton = HANDLE(ENTRY(iButton,pcButtons)).
hButton:X = iRightEdge - hButton:WIDTH-PIXELS.
hButton:Y = phBrowse:Y - 23. /* filter buttons close to the browse */
iRightEdge = hButton:X + 0. /* A little margin between buttons */
END.
PUBLISH "DD:Timer" ("stop", "resizeFilterFields:reposition").
/* The left side of the left button is the maximum point
* Fortunately, this value is already in iRightEdge.
* Resize and reposition the fields from left to right,
* use the space between browse:x and iRightEdge
*/
/* Take the left side of the first visible column as a starting point. */
PUBLISH "DD:Timer" ("start", "resizeFilterFields:firstVisibleColumn").
firstVisibleColumn:
DO iField = 1 TO phBrowse:NUM-COLUMNS:
hColumn = phBrowse:GET-BROWSE-COLUMN(iField):HANDLE.
IF hColumn:X > 0 AND hColumn:VISIBLE THEN
DO:
iCurrentPos = phBrowse:X + hColumn:X.
LEAVE firstVisibleColumn.
END.
END.
PUBLISH "DD:Timer" ("stop", "resizeFilterFields:firstVisibleColumn").
PUBLISH "DD:Timer" ("start", "resizeFilterFields:#Field").
#Field:
DO iField = 1 TO phBrowse:NUM-COLUMNS:
hColumn = phBrowse:GET-BROWSE-COLUMN(iField):handle.
/* Some types cannot have a filter */
IF hColumn:DATA-TYPE = 'raw' THEN NEXT #Field.
iFilter = iFilter + 1.
IF iFilter > NUM-ENTRIES(pcFilterFields) THEN LEAVE #Field.
/* Determine the handle of the filterfield */
hFilterField = HANDLE(ENTRY(iFilter, pcFilterFields)).
/* If the column is hidden, make the filter hidden and go to the next */
IF NOT hColumn:VISIBLE THEN
DO:
hFilterField:VISIBLE = NO.
NEXT #Field.
END.
/* Where *are* we ?? */
iCurrentPos = phBrowse:X + hColumn:X.
/* If the columns have been resized, some columns might have fallen off the screen */
IF hColumn:X < 1 THEN NEXT #Field.
/* Does it fit on the screen? */
IF iCurrentPos >= iRightEdge - 5 THEN LEAVE #Field. /* accept some margin */
/* Where will this field end? And does it fit? */
iWidth = hColumn:WIDTH-PIXELS + 4.
IF iCurrentPos + iWidth > iRightEdge THEN iWidth = iRightEdge - iCurrentPos.
/* Ok, seems to fit */
hFilterField:X = iCurrentPos.
hFilterField:WIDTH-PIXELS = iWidth.
iCurrentPos = iCurrentPos + iWidth.
hFilterField:VISIBLE = phBrowse:VISIBLE. /* take over the visibility of the browse */
END.
PUBLISH "DD:Timer" ("stop", "resizeFilterFields:#Field").
/* Place lead-button at the utmost left */
IF VALID-HANDLE(phLeadButton) THEN
ASSIGN
phLeadButton:X = phBrowse:X
phLeadButton:Y = phBrowse:Y - 23.
{&timerStop}
END PROCEDURE. /* resizeFilterFields */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-restoreWindowPos) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE restoreWindowPos Procedure
PROCEDURE restoreWindowPos :
/* Restore position / size of a window
*/
DEFINE INPUT PARAMETER phWindow AS HANDLE NO-UNDO.
DEFINE INPUT PARAMETER pcWindowName AS CHARACTER NO-UNDO.
DEFINE VARIABLE iValue AS INTEGER NO-UNDO.
iValue = INTEGER(getRegistry(pcWindowName, 'Window:x' )).
IF iValue = ? THEN iValue = INTEGER(getRegistry('DataDigger', 'Window:x' )) + 50.
ASSIGN phWindow:X = iValue NO-ERROR.
iValue = INTEGER(getRegistry(pcWindowName, 'Window:y' )).
IF iValue = ? THEN iValue = INTEGER(getRegistry('DataDigger', 'Window:y' )) + 50.
IF iValue <> ? THEN ASSIGN phWindow:Y = iValue NO-ERROR.
iValue = INTEGER(getRegistry(pcWindowName, 'Window:height' )).
IF iValue = ? OR iValue = 0 THEN iValue = INTEGER(getRegistry('DataDigger', 'Window:height' )) - 100.
ASSIGN phWindow:HEIGHT-PIXELS = iValue NO-ERROR.
iValue = INTEGER(getRegistry(pcWindowName, 'Window:width' )).
IF iValue = ? OR iValue = 0 THEN iValue = INTEGER(getRegistry('DataDigger', 'Window:width' )) - 100.
ASSIGN phWindow:WIDTH-PIXELS = iValue NO-ERROR.
/* Force a redraw */
APPLY 'window-resized' TO phWindow.
END PROCEDURE. /* restoreWindowPos */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-saveConfigFileSorted) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE saveConfigFileSorted Procedure
PROCEDURE saveConfigFileSorted :
/* Save settings file sorted
*/
DEFINE VARIABLE cUserConfigFile AS CHARACTER NO-UNDO.
DEFINE BUFFER bfConfig FOR ttConfig.
{&timerStart}
/* Clean up rubbish settings data */
FOR EACH bfConfig
WHERE bfConfig.cSetting = '' OR bfConfig.cSetting = ?
OR bfConfig.cValue = '' OR bfConfig.cValue = ?:
DELETE bfConfig.
END.
cUserConfigFile = SUBSTITUTE("&1DataDigger-&2.ini", getWorkFolder(), getUserName() ).
OUTPUT TO VALUE(cUserConfigFile).
FOR EACH bfConfig
WHERE bfConfig.lUser = TRUE
BREAK BY (bfConfig.cSection BEGINS "DataDigger") DESCENDING
BY bfConfig.cSection
BY bfConfig.cSetting:
IF FIRST-OF(bfConfig.cSection) THEN PUT UNFORMATTED SUBSTITUTE("[&1]",bfConfig.cSection) SKIP.
PUT UNFORMATTED SUBSTITUTE("&1=&2",bfConfig.cSetting, bfConfig.cValue) SKIP.
IF LAST-OF(bfConfig.cSection) THEN PUT UNFORMATTED SKIP(1).
END.
OUTPUT CLOSE.
glDirtyCache = FALSE.
{&timerStop}
END PROCEDURE. /* saveConfigFileSorted */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-saveQuery) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE saveQuery Procedure
PROCEDURE saveQuery :
/* Save a single query to the INI file.
*/
DEFINE INPUT PARAMETER pcDatabase AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcTable AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcQuery AS CHARACTER NO-UNDO.
DEFINE VARIABLE cQuery AS CHARACTER NO-UNDO.
DEFINE VARIABLE iNewNr AS INTEGER NO-UNDO.
DEFINE BUFFER bQuery FOR ttQuery.
{&timerStart}
/* Prepare query for saving in ini-file */
cQuery = pcQuery.
cQuery = REPLACE(cQuery,'~n',CHR(1)).
cQuery = REPLACE(cQuery,{&QUERYSEP},CHR(1)).
IF cQuery = '' THEN RETURN.
/* Get the table with queries again, because they might be
* changed if the user has more than one window open.
*/
RUN collectQueryInfo(pcDatabase, pcTable).
/* Save current query in the tt. If it already is in the
* TT then just move it to the top
*/
FIND bQuery
WHERE bQuery.cDatabase = pcDatabase
AND bQuery.cTable = pcTable
AND bQuery.cQueryTxt = cQuery NO-ERROR.
IF AVAILABLE bQuery THEN
DO:
ASSIGN bQuery.iQueryNr = 0.
END.
ELSE
DO:
CREATE bQuery.
ASSIGN bQuery.cDatabase = pcDatabase
bQuery.cTable = pcTable
bQuery.iQueryNr = 0
bQuery.cQueryTxt = cQuery.
END.
/* The ttQuery temp-table is already filled, renumber it */
#QueryLoop:
REPEAT PRESELECT EACH bQuery
WHERE bQuery.cDatabase = pcDatabase
AND bQuery.cTable = pcTable
BY bQuery.iQueryNr:
FIND NEXT bQuery NO-ERROR.
IF NOT AVAILABLE bQuery THEN LEAVE #QueryLoop.
ASSIGN
iNewNr = iNewNr + 1
bQuery.iQueryNr = iNewNr.
END.
/* And save it to the INI-file */
RUN saveQueryTable(table bQuery, pcDatabase, pcTable).
{&timerStop}
END PROCEDURE. /* saveQuery */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-saveQueryTable) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE saveQueryTable Procedure
PROCEDURE saveQueryTable :
/* Save the queries in the TT to the INI file with a max of MaxQueryHistory
*/
DEFINE INPUT PARAMETER table FOR ttQuery.
DEFINE INPUT PARAMETER pcDatabase AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcTable AS CHARACTER NO-UNDO.
DEFINE VARIABLE iMaxQueryHistory AS INTEGER NO-UNDO.
DEFINE VARIABLE iQuery AS INTEGER NO-UNDO.
DEFINE VARIABLE cSetting AS CHARACTER NO-UNDO.
DEFINE BUFFER bQuery FOR ttQuery.
{&timerStart}
iMaxQueryHistory = INTEGER(getRegistry("DataDigger", "MaxQueryHistory" )).
IF iMaxQueryHistory = 0 THEN RETURN. /* no query history wanted */
/* If it is not defined use default setting */
IF iMaxQueryHistory = ? THEN iMaxQueryHistory = 10.
iQuery = 1.
#SaveQuery:
FOR EACH bQuery
WHERE bQuery.cDatabase = pcDatabase
AND bQuery.cTable = pcTable
BY bQuery.iQueryNr:
cSetting = bQuery.cQueryTxt.
IF cSetting = '' THEN NEXT #SaveQuery.
setRegistry( SUBSTITUTE("DB:&1", pcDatabase)
, SUBSTITUTE('&1:query:&2', pcTable, iQuery)
, cSetting).
iQuery = iQuery + 1.
IF iQuery > iMaxQueryHistory THEN LEAVE #SaveQuery.
END.
/* Delete higher nrs than MaxQueryHistory */
DO WHILE iQuery <= iMaxQueryHistory:
setRegistry( SUBSTITUTE("DB:&1", pcDatabase)
, SUBSTITUTE('&1:query:&2', pcTable, iQuery)
, ?).
iQuery = iQuery + 1.
END. /* iQuery .. MaxQueryHistory */
{&timerStop}
END PROCEDURE. /* saveQueryTable */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-saveWindowPos) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE saveWindowPos Procedure
PROCEDURE saveWindowPos :
/* Save position / size of a window
*/
DEFINE INPUT PARAMETER phWindow AS HANDLE NO-UNDO.
DEFINE INPUT PARAMETER pcWindowName AS CHARACTER NO-UNDO.
setRegistry(pcWindowName, "Window:x" , STRING(phWindow:X) ).
setRegistry(pcWindowName, "Window:y" , STRING(phWindow:Y) ).
setRegistry(pcWindowName, "Window:height", STRING(phWindow:HEIGHT-PIXELS) ).
setRegistry(pcWindowName, "Window:width" , STRING(phWindow:WIDTH-PIXELS) ).
END PROCEDURE. /* saveWindowPos */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setCaching) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE setCaching Procedure
PROCEDURE setCaching :
/* Set the cache vars for the library
*/
glCacheTableDefs = LOGICAL( getRegistry("DataDigger:Cache","TableDefs") ).
glCacheFieldDefs = LOGICAL( getRegistry("DataDigger:Cache","FieldDefs") ).
END PROCEDURE. /* setCaching */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setFavourite) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE setFavourite Procedure
PROCEDURE setFavourite :
/* Set / unset / toggle a table as favourite
*/
DEFINE INPUT PARAMETER pcTable AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcGroupName AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER plFavourite AS LOGICAL NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE cList AS CHARACTER NO-UNDO.
cList = getRegistry("DataDigger:Favourites", pcGroupName).
IF cList = ? THEN cList = ''.
i = LOOKUP(pcTable, cList).
/* Toggle setting? */
IF plFavourite = ? THEN plFavourite = (i = 0).
/* Add to favourites */
IF NOT plFavourite AND i > 0 THEN
DO:
ENTRY(i, cList) = ''.
cList = REPLACE(cList,',,',',').
cList = TRIM(cList,',').
END.
/* Remove from favourites */
IF plFavourite AND i = 0 THEN
cList = TRIM(SUBSTITUTE('&1,&2', cList, pcTable),',').
setRegistry("DataDigger:Favourites", pcGroupName, cList).
END PROCEDURE. /* setFavourite */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setLabelPosition) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE setLabelPosition Procedure
PROCEDURE setLabelPosition :
/* Correct the position of the label for larger fonts
*/
DEFINE INPUT PARAMETER phWidget AS HANDLE NO-UNDO.
/* Move horizontally far enough from the widget */
phWidget:SIDE-LABEL-HANDLE:X = phWidget:X
- FONT-TABLE:GET-TEXT-WIDTH-PIXELS(phWidget:SIDE-LABEL-HANDLE:SCREEN-VALUE, phWidget:FRAME:FONT)
- (IF phWidget:TYPE = 'fill-in' THEN 5 ELSE 0)
.
END PROCEDURE. /* setLabelPosition */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setSortArrow) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE setSortArrow Procedure
PROCEDURE setSortArrow :
/* Set the sorting arrow on a browse
*/
DEFINE INPUT PARAMETER phBrowse AS HANDLE NO-UNDO.
DEFINE INPUT PARAMETER pcSortField AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER plAscending AS LOGICAL NO-UNDO.
DEFINE VARIABLE iColumn AS INTEGER NO-UNDO.
DEFINE VARIABLE hColumn AS HANDLE NO-UNDO.
DEFINE VARIABLE lSortFound AS LOGICAL NO-UNDO.
{&timerStart}
DO iColumn = 1 TO phBrowse:NUM-COLUMNS:
hColumn = phBrowse:GET-BROWSE-COLUMN(iColumn).
/* If you apply the sort to the same column, the order
* of sorting is inverted.
*/
IF hColumn:NAME = pcSortField THEN
DO:
phBrowse:SET-SORT-ARROW(iColumn, plAscending ).
lSortFound = TRUE.
/* Setting is one of: ColumnSortFields | ColumnSortIndexes | ColumnSortTables */
setRegistry( 'DataDigger'
, SUBSTITUTE('ColumnSort&1', SUBSTRING(phBrowse:NAME,3))
, SUBSTITUTE('&1,&2',iColumn, plAscending)
).
END.
ELSE
phBrowse:SET-SORT-ARROW(iColumn, ? ). /* erase existing arrow */
END.
/* If no sort is found, delete setting */
IF NOT lSortFound THEN
setRegistry( 'DataDigger', SUBSTITUTE('ColumnSort&1', SUBSTRING(phBrowse:NAME,3)), ?).
{&timerStop}
END PROCEDURE. /* setSortArrow */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setTransparency) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE setTransparency Procedure
PROCEDURE setTransparency :
/* Set transparency level for a frame, using Windows api
*/
DEFINE INPUT PARAMETER phFrame AS HANDLE NO-UNDO.
DEFINE INPUT PARAMETER piLevel AS INTEGER NO-UNDO.
&SCOPED-DEFINE GWL_EXSTYLE -20
&SCOPED-DEFINE WS_EX_LAYERED 524288
&SCOPED-DEFINE LWA_ALPHA 2
&SCOPED-DEFINE WS_EX_TRANSPARENT 32
{&_proparse_prolint-nowarn(varusage)}
DEFINE VARIABLE stat AS INTEGER NO-UNDO.
/* Set WS_EX_LAYERED on this window */
{&_proparse_prolint-nowarn(varusage)}
RUN SetWindowLongA(phFrame:HWND, {&GWL_EXSTYLE}, {&WS_EX_LAYERED}, OUTPUT stat).
/* Make this window transparent (0 - 255) */
{&_proparse_prolint-nowarn(varusage)}
RUN SetLayeredWindowAttributes(phFrame:HWND, 0, piLevel, {&LWA_ALPHA}, OUTPUT stat).
END PROCEDURE. /* setTransparency */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setXmlNodeNames) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE setXmlNodeNames Procedure
PROCEDURE setXmlNodeNames :
/* Set the XML-NODE-NAMES of all fields in a buffer
*/
DEFINE INPUT PARAMETER phTable AS HANDLE NO-UNDO.
DEFINE VARIABLE iField AS INTEGER NO-UNDO.
DO iField = 1 TO phTable:NUM-FIELDS:
phTable:BUFFER-FIELD(iField):XML-NODE-NAME = getXmlNodeName(phTable:BUFFER-FIELD(iField):NAME).
END.
END PROCEDURE. /* setXmlNodeNames */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-showHelp) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE showHelp Procedure
PROCEDURE showHelp :
/* Show a help message and save answer to ini
*/
DEFINE INPUT PARAMETER pcTopic AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcStrings AS CHARACTER NO-UNDO.
DEFINE VARIABLE cButtons AS CHARACTER NO-UNDO.
DEFINE VARIABLE cMessage AS CHARACTER NO-UNDO.
DEFINE VARIABLE cPrg AS CHARACTER NO-UNDO.
DEFINE VARIABLE cTitle AS CHARACTER NO-UNDO.
DEFINE VARIABLE cType AS CHARACTER NO-UNDO.
DEFINE VARIABLE cUrl AS CHARACTER NO-UNDO.
DEFINE VARIABLE cCanHide AS CHARACTER NO-UNDO.
DEFINE VARIABLE iButtonPressed AS INTEGER NO-UNDO.
DEFINE VARIABLE lDontShowAgain AS LOGICAL NO-UNDO.
DEFINE VARIABLE lCanHide AS LOGICAL NO-UNDO.
DEFINE VARIABLE lHidden AS LOGICAL NO-UNDO.
DEFINE VARIABLE iString AS INTEGER NO-UNDO.
DEFINE VARIABLE cUserString AS CHARACTER NO-UNDO EXTENT 9.
/* If no message, then just return */
cMessage = getRegistry('DataDigger:Help', pcTopic + ':message').
/* What to start? */
cUrl = getRegistry('DataDigger:Help', pcTopic + ':url').
cPrg = getRegistry('DataDigger:Help', pcTopic + ':program').
cCanHide = getRegistry('DataDigger:Help', pcTopic + ':canHide').
cCanHide = TRIM(cCanHide).
lCanHide = LOGICAL(cCanHide) NO-ERROR.
IF lCanHide = ? THEN lCanHide = TRUE.
IF cMessage = ? THEN
DO:
IF cUrl = ? AND cPrg = ? THEN RETURN.
lHidden = YES. /* suppress empty text window */
iButtonPressed = 1. /* forces to start the url or prog */
END.
/* If type is unknown, set to QUESTION if there is a question mark in the message */
cType = getRegistry('DataDigger:Help', pcTopic + ':type').
IF cType = ? THEN cType = (IF cMessage MATCHES '*?*' THEN 'Question' ELSE 'Message').
/* If no button labels defined, set them based on message type */
cButtons = getRegistry('DataDigger:Help', pcTopic + ':buttons').
IF cButtons = ? THEN cButtons = (IF cType = 'Question' THEN '&Yes,&No,&Cancel' ELSE '&Ok').
/* If title is empty, set it to the type of the message */
cTitle = getRegistry('DataDigger:Help', pcTopic + ':title').
IF cTitle = ? THEN cTitle = cType.
/* If hidden has strange value, set it to NO */
lHidden = LOGICAL(getRegistry('DataDigger:Help', pcTopic + ':hidden')) NO-ERROR.
IF lHidden = ? THEN lHidden = NO.
/* If ButtonPressed has strange value, set hidden to NO */
iButtonPressed = INTEGER( getRegistry('DataDigger:Help',pcTopic + ':answer') ) NO-ERROR.
IF iButtonPressed = ? THEN lHidden = NO.
/* if we have no message, but we do have an URL or prog, then
* dont show an empty message box.
*/
IF cMessage = ? THEN
ASSIGN
lHidden = YES /* suppress empty text window */
iButtonPressed = 1. /* forces to start the url or prog */
/* Fill in strings in message */
DO iString = 1 TO NUM-ENTRIES(pcStrings):
cUserString[iString] = ENTRY(iString,pcStrings).
END.
cMessage = SUBSTITUTE( cMessage
, cUserString[1]
, cUserString[2]
, cUserString[3]
, cUserString[4]
, cUserString[5]
, cUserString[6]
, cUserString[7]
, cUserString[8]
, cUserString[9]
).
/* If not hidden, show the message and let the user choose an answer */
IF NOT lHidden THEN
DO:
RUN VALUE( getProgramDir() + 'dQuestion.w')
( INPUT cTitle
, INPUT cMessage
, INPUT cButtons
, INPUT lCanHide
, OUTPUT iButtonPressed
, OUTPUT lDontShowAgain
).
IF lDontShowAgain THEN
setRegistry('DataDigger:Help', pcTopic + ':hidden', 'yes').
END.
/* Start external things if needed */
IF iButtonPressed = 1 THEN
DO:
IF cUrl <> ? THEN OS-COMMAND NO-WAIT START (cUrl).
IF cPrg <> ? THEN RUN VALUE(cPrg) NO-ERROR.
END.
/* Save answer */
setRegistry('DataDigger:Help',pcTopic + ':answer', STRING(iButtonPressed)).
END PROCEDURE. /* showHelp */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-showScrollbars) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE showScrollbars Procedure
PROCEDURE showScrollbars :
/* Hide or show scrollbars the hard way
*/
DEFINE INPUT PARAMETER ip-Frame AS HANDLE NO-UNDO.
DEFINE INPUT PARAMETER ip-horizontal AS LOGICAL NO-UNDO.
DEFINE INPUT PARAMETER ip-vertical AS LOGICAL NO-UNDO.
{&_proparse_prolint-nowarn(varusage)}
DEFINE VARIABLE iv-retint AS INTEGER NO-UNDO.
{&timerStart}
IF NOT VALID-HANDLE(ip-Frame) OR ip-Frame:HWND = ? THEN RETURN.
&scoped-define SB_HORZ 0
&scoped-define SB_VERT 1
&scoped-define SB_BOTH 3
&scoped-define SB_THUMBPOSITION 4
{&_proparse_prolint-nowarn(varusage)}
RUN ShowScrollBar ( ip-Frame:HWND,
{&SB_HORZ},
IF ip-horizontal THEN -1 ELSE 0,
OUTPUT iv-retint ).
{&_proparse_prolint-nowarn(varusage)}
RUN ShowScrollBar ( ip-Frame:HWND,
{&SB_VERT},
IF ip-vertical THEN -1 ELSE 0,
OUTPUT iv-retint ).
&undefine SB_HORZ
&undefine SB_VERT
&undefine SB_BOTH
&undefine SB_THUMBPOSITION
{&timerStop}
END PROCEDURE. /* ShowScrollbars */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-unlockWindow) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE unlockWindow Procedure
PROCEDURE unlockWindow :
/* Force a window to unlock
*/
DEFINE INPUT PARAMETER phWindow AS HANDLE NO-UNDO.
{&_proparse_prolint-nowarn(varusage)}
DEFINE VARIABLE iRet AS INTEGER NO-UNDO.
DEFINE BUFFER ttWindowLock FOR ttWindowLock.
PUBLISH "debugInfo" (3, SUBSTITUTE("Window &1, force to unlock", phWindow:TITLE)).
/* Find window in our tt of locked windows */
FIND ttWindowLock WHERE ttWindowLock.hWindow = phWindow NO-ERROR.
IF NOT AVAILABLE ttWindowLock THEN RETURN.
IF ttWindowLock.iLockCounter > 0 THEN
DO:
{&_proparse_prolint-nowarn(varusage)}
RUN SendMessageA(phWindow:HWND, {&WM_SETREDRAW}, 1, 0, OUTPUT iRet).
{&_proparse_prolint-nowarn(varusage)}
RUN RedrawWindow(phWindow:HWND, 0, 0, {&RDW_ALLCHILDREN} + {&RDW_ERASE} + {&RDW_INVALIDATE}, OUTPUT iRet).
DELETE ttWindowLock.
END.
END PROCEDURE. /* unlockWindow */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-updateFields) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE updateFields Procedure
PROCEDURE updateFields :
/* Update the fields temp-table with settings from registry
*/
DEFINE INPUT PARAMETER pcDatabase AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcTableName AS CHARACTER NO-UNDO.
DEFINE INPUT-OUTPUT PARAMETER TABLE FOR ttField.
DEFINE VARIABLE cCustomFormat AS CHARACTER NO-UNDO.
DEFINE VARIABLE cSelectedFields AS CHARACTER NO-UNDO.
DEFINE VARIABLE cFieldOrder AS CHARACTER NO-UNDO.
DEFINE VARIABLE iColumnOrder AS INTEGER NO-UNDO.
DEFINE VARIABLE iFieldOrder AS INTEGER NO-UNDO.
DEFINE VARIABLE iMaxExtent AS INTEGER NO-UNDO.
DEFINE VARIABLE lRecRowAtEnd AS LOGICAL NO-UNDO.
DEFINE BUFFER bField FOR ttField.
DEFINE BUFFER bColumn FOR ttColumn.
{&timerStart}
PUBLISH "debugInfo" (1, SUBSTITUTE("Update field definitions for &1.&2", pcDatabase, pcTableName)).
/* Get list of all previously selected fields */
cSelectedFields = getRegistry(SUBSTITUTE("DB:&1",pcDatabase), SUBSTITUTE("&1:fields",pcTableName)).
IF cSelectedFields = ? THEN cSelectedFields = '!RECID,!ROWID,*'.
/* Get field ordering */
cFieldOrder = getRegistry(SUBSTITUTE('DB:&1',pcDatabase), SUBSTITUTE('&1:fieldOrder',pcTableName)).
/* RECID and ROWID at the end? */
IF cFieldOrder <> ? THEN
DO:
lRecRowAtEnd = LOOKUP("ROWID", cFieldOrder) > NUM-ENTRIES(cFieldOrder) - 2 AND LOOKUP("RECID", cFieldOrder) > NUM-ENTRIES(cFieldOrder) - 2.
PUBLISH "debugInfo" (2, SUBSTITUTE("Field order for table &1: &2", pcTableName, cFieldOrder)).
PUBLISH "debugInfo" (3, SUBSTITUTE("Rowid/recid at the end for table &1: &2", pcTableName, lRecRowAtEnd)).
END.
FOR EACH bField {&TABLE-SCAN}:
/* Due to a bug the nr of decimals may be set on non-decimal fields
* See PKB P185263 (article 18087) for more information
* http://knowledgebase.progress.com/articles/Article/P185263
*/
IF bField.cDataType <> 'DECIMAL' THEN bField.iDecimals = ?.
/* Was this field selected? */
bField.lShow = CAN-DO(cSelectedFields, bField.cFullName).
/* Customization option for the user to show/hide certain fields */
PUBLISH "DD:Timer" ("start", 'customShowField').
PUBLISH 'customShowField' (pcDatabase, pcTableName, bField.cFieldName, INPUT-OUTPUT bField.lShow).
PUBLISH "DD:Timer" ("stop", 'customShowField').
/* Customization option for the user to adjust the format */
PUBLISH "DD:Timer" ("start", 'customFormat').
PUBLISH 'customFormat' (pcDatabase, pcTableName, bField.cFieldName, bField.cDatatype, INPUT-OUTPUT bField.cFormat).
PUBLISH "DD:Timer" ("stop", 'customFormat').
/* Restore changed field format. */
cCustomFormat = getRegistry(SUBSTITUTE("DB:&1",pcDatabase), SUBSTITUTE("&1.&2:format",pcTableName,bField.cFieldName) ).
IF cCustomFormat <> ? THEN bField.cFormat = cCustomFormat.
/* Restore changed field order. */
bField.iOrder = LOOKUP(bField.cFullName,cFieldOrder).
IF bField.iOrder = ? THEN bField.iOrder = bField.iOrderOrg.
/* Keep track of highest nr */
iFieldOrder = MAXIMUM(iFieldOrder,bField.iOrder).
END. /* f/e bField */
/* Only show first X of an extent */
iMaxExtent = INTEGER(getRegistry("DataDigger","MaxExtent")) NO-ERROR.
IF iMaxExtent = ? THEN iMaxExtent = 100.
IF iMaxExtent > 0 THEN
FOR EACH bColumn WHERE bColumn.iExtent > iMaxExtent:
DELETE bColumn.
END.
IF CAN-FIND(FIRST bField WHERE bField.iOrder = 0) THEN
DO:
/* Set new fields (no order assigned) at the end */
FOR EACH bField WHERE bField.iOrder = 0 BY bField.iFieldRpos:
ASSIGN
iFieldOrder = iFieldOrder + 1
bField.iOrder = iFieldOrder.
END.
/* If RECID+ROWID should be at the end then re-assign them */
IF lRecRowAtEnd THEN
FOR EACH bField
WHERE bField.cFieldName = "RECID" OR bField.cFieldName = "ROWID" BY bField.iOrder:
ASSIGN
iFieldOrder = iFieldOrder + 1
bField.iOrder = iFieldOrder.
END.
END.
/* Reorder fields to get rid of gaps */
iFieldOrder = 0.
#FieldLoop:
REPEAT PRESELECT EACH bField BY bField.iOrder:
FIND NEXT bField NO-ERROR.
IF NOT AVAILABLE bField THEN LEAVE #FieldLoop.
ASSIGN
iFieldOrder = iFieldOrder + 1
bField.iOrder = iFieldOrder.
END.
/* Assign order nrs to columns to handle extents */
iColumnOrder = 0.
FOR EACH bField BY bField.iOrder:
FOR EACH bColumn WHERE bColumn.cFieldName = bField.cFieldName BY bColumn.cFieldName:
iColumnOrder = iColumnOrder + 1.
bColumn.iColumnNr = iColumnOrder.
END.
END.
{&timerStop}
END PROCEDURE. /* updateFields */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-updateMemoryCache) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE updateMemoryCache Procedure
PROCEDURE updateMemoryCache :
/* Update the memory cache with current settings
*/
DEFINE INPUT PARAMETER pcDatabase AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcTableName AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER TABLE FOR ttField.
DEFINE INPUT PARAMETER TABLE FOR ttColumn.
DEFINE BUFFER bField FOR ttField.
DEFINE BUFFER bColumn FOR ttColumn.
DEFINE BUFFER bFieldCache FOR ttFieldCache.
DEFINE BUFFER bColumnCache FOR ttColumnCache.
PUBLISH "debugInfo" (2, SUBSTITUTE("Update first-level cache for &1.&2", pcDatabase, pcTableName)).
/* Delete old */
FOR EACH bFieldCache
WHERE bFieldCache.cDatabase = pcDatabase
AND bFieldCache.cTableName = pcTableName:
DELETE bFieldCache.
END.
FOR EACH bColumnCache
WHERE bColumnCache.cDatabase = pcDatabase
AND bColumnCache.cTableName = pcTableName:
DELETE bColumnCache.
END.
/* Create new */
FOR EACH bField {&TABLE-SCAN}:
CREATE bFieldCache.
BUFFER-COPY bField TO bFieldCache.
END.
FOR EACH bColumn {&TABLE-SCAN}:
CREATE bColumnCache.
BUFFER-COPY bColumn TO bColumnCache.
END.
END PROCEDURE. /* updateMemoryCache */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
/* ************************ Function Implementations ***************** */
&IF DEFINED(EXCLUDE-addConnection) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION addConnection Procedure
FUNCTION addConnection RETURNS LOGICAL
( pcDatabase AS CHARACTER
, pcSection AS CHARACTER ) :
/* Add a connection to the temp-table
*/
IF NOT CAN-FIND(ttDatabase WHERE ttDatabase.cLogicalName = pcDatabase) THEN
DO:
CREATE ttDatabase.
ASSIGN
ttDatabase.cLogicalName = pcDatabase
ttDatabase.cSection = pcSection
.
END.
RETURN TRUE.
END FUNCTION.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-formatQueryString) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION formatQueryString Procedure
FUNCTION formatQueryString RETURNS CHARACTER
( INPUT pcQueryString AS CHARACTER
, INPUT plExpanded AS LOGICAL ) :
/* Return a properly formatted query string
*/
DEFINE VARIABLE cReturnValue AS CHARACTER NO-UNDO.
{&timerStart}
cReturnValue = pcQueryString.
IF cReturnValue <> '' AND cReturnValue <> ? THEN
DO:
/* There might be chr(1) chars in the text (if read from ini, for example)
* Replace these with normal CRLF, then proceed
*/
cReturnValue = REPLACE(cReturnValue,CHR(1),'~n').
IF plExpanded THEN
cReturnValue = REPLACE(cReturnValue, {&QUERYSEP}, '~n').
ELSE
cReturnValue = REPLACE(cReturnValue, '~n', {&QUERYSEP}).
END.
RETURN cReturnValue.
{&timerStop}
END FUNCTION. /* formatQueryString */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getColor) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getColor Procedure
FUNCTION getColor RETURNS INTEGER
( pcName AS CHARACTER ) :
/* Return the color number for a color name
*/
DEFINE BUFFER bColor FOR ttColor.
FIND bColor WHERE bColor.cName = pcName NO-ERROR.
IF NOT AVAILABLE bColor THEN
RETURN setColor(pcName,?).
ELSE
RETURN bColor.iColor. /* Function return value. */
END FUNCTION. /* getColor */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getColorByRGB) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getColorByRGB Procedure
FUNCTION getColorByRGB RETURNS INTEGER
( piRed AS INTEGER
, piGreen AS INTEGER
, piBlue AS INTEGER
):
/* Return the color number for a RGB combination
* if needed, add color to color table.
*/
DEFINE VARIABLE i AS INTEGER NO-UNDO.
/* See if already exists */
DO i = 0 TO COLOR-TABLE:NUM-ENTRIES - 1:
IF COLOR-TABLE:GET-RED-VALUE(i) = piRed
AND COLOR-TABLE:GET-GREEN-VALUE(i) = piGreen
AND COLOR-TABLE:GET-BLUE-VALUE(i) = piBlue THEN RETURN i.
END.
/* Define new color */
i = COLOR-TABLE:NUM-ENTRIES.
COLOR-TABLE:NUM-ENTRIES = COLOR-TABLE:NUM-ENTRIES + 1.
COLOR-TABLE:SET-DYNAMIC(i, TRUE).
COLOR-TABLE:SET-RED-VALUE (i, piRed ).
COLOR-TABLE:SET-GREEN-VALUE(i, piGreen).
COLOR-TABLE:SET-BLUE-VALUE (i, piBlue ).
RETURN i.
END FUNCTION. /* getColorByRGB */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getColumnLabel) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getColumnLabel Procedure
FUNCTION getColumnLabel RETURNS CHARACTER
( INPUT phFieldBuffer AS HANDLE ):
/* Return column label, based on settings
*/
DEFINE VARIABLE cColumnLabel AS CHARACTER NO-UNDO.
DEFINE VARIABLE cTemplate AS CHARACTER NO-UNDO.
{&timerStart}
cTemplate = getRegistry("DataDigger","ColumnLabelTemplate").
IF cTemplate = ? OR cTemplate = "" THEN cTemplate = "&1".
cColumnLabel = SUBSTITUTE(cTemplate
, phFieldBuffer::cFullName
, phFieldBuffer::iOrder
, phFieldBuffer::cLabel
).
RETURN cColumnLabel.
{&timerStop}
END FUNCTION. /* getColumnLabel */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getColumnWidthList) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getColumnWidthList Procedure
FUNCTION getColumnWidthList RETURNS CHARACTER
( INPUT phBrowse AS HANDLE ):
/* returns a list of all fields and their width like:
* custnum:12,custname:20,city:12
*/
DEFINE VARIABLE cWidthList AS CHARACTER NO-UNDO.
DEFINE VARIABLE hColumn AS HANDLE NO-UNDO.
DEFINE VARIABLE iColumn AS INTEGER NO-UNDO.
{&timerStart}
DO iColumn = 1 TO phBrowse:NUM-COLUMNS:
hColumn = phBrowse:GET-BROWSE-COLUMN(iColumn).
cWidthList = SUBSTITUTE('&1,&2:&3'
, cWidthList
, hColumn:NAME
, hColumn:WIDTH-PIXELS
).
END.
RETURN TRIM(cWidthList,',').
{&timerStop}
END FUNCTION. /* getColumnWidthList */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getDatabaseList) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getDatabaseList Procedure
FUNCTION getDatabaseList RETURNS CHARACTER:
/* Return a comma separated list of all connected databases
*/
DEFINE VARIABLE cDatabaseList AS CHARACTER NO-UNDO.
DEFINE VARIABLE cSchemaHolders AS CHARACTER NO-UNDO.
DEFINE VARIABLE iCount AS INTEGER NO-UNDO.
DEFINE VARIABLE cDbType AS CHARACTER NO-UNDO.
DEFINE VARIABLE cLogicalDbName AS CHARACTER NO-UNDO.
DEFINE VARIABLE iPos AS INTEGER NO-UNDO.
DEFINE BUFFER bDataserver FOR ttDataserver.
{&timerStart}
/* Support Dataservers */
IF gcSaveDatabaseList <> ""
AND PROGRAM-NAME(2) BEGINS "initializeObjects " THEN RETURN gcSaveDatabaseList.
/* Make a list of schema holders */
#Db:
DO iCount = 1 TO NUM-DBS:
ASSIGN
cDbType = DBTYPE(iCount)
cLogicalDbName = LDBNAME(iCount).
IF cDbType <> 'PROGRESS' THEN
cSchemaHolders = cSchemaHolders + ',' + SDBNAME(iCount).
cDbType = DBTYPE(iCount).
IF cDbType <> "PROGRESS" THEN NEXT #Db.
cDatabaseList = cDatabaseList + ',' + cLogicalDbName.
END.
/* Build list of all databases. Skip if already in the list of schemaholders */
#Db:
DO iCount = 1 TO NUM-DBS:
ASSIGN
cDbType = DBTYPE(iCount)
cLogicalDbName = LDBNAME(iCount).
IF LOOKUP(LDBNAME(iCount), cSchemaHolders) > 0 OR cDbType <> "PROGRESS" THEN NEXT #Db.
CREATE ALIAS dictdb FOR DATABASE VALUE(cLogicalDbName).
RUN getDataserver.p
( INPUT cLogicalDbName
, INPUT-OUTPUT giDataserverNr
, INPUT-OUTPUT TABLE bDataserver
).
DELETE ALIAS dictdb.
END.
/* Support dataservers */
FOR EACH bDataserver BY bDataserver.cLDbNameSchema:
/* Remove schemaholder from database list */
IF bDataserver.lDontShowSchemaHr THEN
DO:
iPos = LOOKUP(bDataserver.cLDbNameSchema, cDatabaseList).
IF iPos > 0
AND NOT CAN-FIND(FIRST ttTable WHERE ttTable.cDatabase = bDataserver.cLDbNameSchema
AND ttTable.lHidden = NO) THEN
DO:
ENTRY(iPos, cDatabaseList) = "".
cDatabaseList = TRIM(REPLACE(cDatabaseList, ",,", ","), ",").
END.
END.
/* Add dataserver to database list */
iPos = LOOKUP(bDataserver.cLDbNameDataserver, cDatabaseList).
IF bDataserver.lConnected THEN
DO:
IF iPos = 0 THEN cDatabaseList = TRIM(cDatabaseList + "," + bDataserver.cLDbNameDataserver, ",").
END. /* IF bDataserver.lConnected */
ELSE
DO:
IF iPos > 0 THEN
DO:
ENTRY(iPos, cDatabaseList) = "".
cDatabaseList = TRIM(REPLACE(cDatabaseList, ",,", ","), ",").
END. /* IF iPos > 0 */
END. /* else */
END. /* FOR EACH bDataserver */
ASSIGN
cDatabaseList = TRIM(cDatabaseList, ',')
gcSaveDatabaseList = cDatabaseList.
RETURN cDatabaseList.
{&timerStop}
END FUNCTION. /* getDatabaseList */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getEscapedData) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getEscapedData Procedure
FUNCTION getEscapedData RETURNS CHARACTER
( pcTarget AS CHARACTER
, pcString AS CHARACTER ) :
/* Return html- or 4gl-safe string
*/
DEFINE VARIABLE cOutput AS CHARACTER NO-UNDO.
DEFINE VARIABLE iTmp AS INTEGER NO-UNDO.
{&timerStart}
/* Garbage in, garbage out */
cOutput = pcString.
CASE pcTarget:
WHEN "HTML" THEN
DO:
cOutput = REPLACE(cOutput,"<","&lt;").
cOutput = REPLACE(cOutput,">","&gt;").
END.
WHEN "4GL" THEN
DO:
/* Replace single quotes because we are using them for 4GL separating too */
cOutput = REPLACE(cOutput, "'", "~~'").
/* Replace CHR's 1 till 13 */
DO iTmp = 1 TO 13:
cOutput = REPLACE(cOutput, CHR(iTmp), "' + chr(" + string(iTmp) + ") + '").
END.
END.
END CASE.
RETURN cOutput.
{&timerStop}
END FUNCTION. /* getEscapedData */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getFieldList) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getFieldList Procedure
FUNCTION getFieldList RETURNS CHARACTER
( pcDatabase AS CHARACTER
, pcFile AS CHARACTER
):
/* Return a comma separated list of all fields of a table
*/
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
DEFINE VARIABLE hFile AS HANDLE NO-UNDO.
DEFINE VARIABLE hField AS HANDLE NO-UNDO.
DEFINE VARIABLE cFields AS CHARACTER NO-UNDO.
CREATE BUFFER hFile FOR TABLE pcDatabase + "._file".
CREATE BUFFER hField FOR TABLE pcDatabase + "._field".
CREATE QUERY hQuery.
hQuery:SET-BUFFERS(hFile,hField).
hQuery:QUERY-PREPARE(SUBSTITUTE('FOR EACH _File WHERE _File-name = &1, EACH _Field OF _File', QUOTER(pcFile))).
hQuery:QUERY-OPEN().
#CollectFields:
REPEAT:
hQuery:GET-NEXT().
IF hQuery:QUERY-OFF-END THEN LEAVE #CollectFields.
cFields = cFields + "," + hField::_Field-name.
END. /* #CollectFields */
hQuery:QUERY-CLOSE().
DELETE OBJECT hField.
DELETE OBJECT hFile.
DELETE OBJECT hQuery.
RETURN TRIM(cFields, ",").
END FUNCTION. /* getFieldList */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getFileCategory) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getFileCategory Procedure
FUNCTION getFileCategory RETURNS CHARACTER
( piFileNumber AS INTEGER
, pcFileName AS CHARACTER
) :
/* Based on table name and -number, return the category for a table
*
* Application tables : _file-number > 0 AND _file-number < 32000
* Schema tables : _file-number > -80 AND _file-number < 0
* Virtual system tables: _file-number < -16384
* SQL catalog tables : _file-name BEGINS "_sys"
* Other tables : _file-number >= -16384 AND _file-number <= -80
*/
IF piFileNumber > 0 AND piFileNumber < 32000 THEN RETURN 'Normal'.
IF piFileNumber > -80 AND piFileNumber < 0 THEN RETURN 'Schema'.
IF piFileNumber < -16384 THEN RETURN 'VST'.
IF pcFileName BEGINS '_sys' THEN RETURN 'SQL'.
IF piFileNumber >= -16384 AND piFileNumber <= -80 THEN RETURN 'Other'.
RETURN ''. /* Function return value. */
END FUNCTION. /* getFileCategory */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getFont) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getFont Procedure
FUNCTION getFont RETURNS INTEGER
( pcName AS CHARACTER ) :
/* Return the fontnumber for the type given
*/
DEFINE BUFFER bFont FOR ttFont.
{&timerStart}
FIND bFont WHERE bFont.cName = pcName NO-ERROR.
IF AVAILABLE bFont THEN RETURN bFont.iFont.
CREATE bFont.
ASSIGN bFont.cName = pcName.
bFont.iFont = INTEGER(getRegistry('DataDigger:Fonts',pcName)) NO-ERROR.
IF bFont.iFont = ? OR bFont.iFont > 23 THEN
CASE pcName:
WHEN 'Default' THEN bFont.iFont = 4.
WHEN 'Fixed' THEN bFont.iFont = 0.
END CASE.
RETURN bFont.iFont. /* Function return value. */
{&timerStop}
END FUNCTION. /* getFont */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getImagePath) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getImagePath Procedure
FUNCTION getImagePath RETURNS CHARACTER
( pcImage AS CHARACTER ) :
/* Return the image path + icon set name
*/
{&timerStart}
RETURN SUBSTITUTE('&1Image/default_&2', getProgramDir(), pcImage).
{&timerStop}
END FUNCTION. /* getImagePath */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getIndexFields) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getIndexFields Procedure
FUNCTION getIndexFields RETURNS CHARACTER
( INPUT pcDatabaseName AS CHARACTER
, INPUT pcTableName AS CHARACTER
, INPUT pcFlags AS CHARACTER
) :
/* Return the index fields of a table.
*/
DEFINE VARIABLE cWhere AS CHARACTER NO-UNDO.
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
DEFINE VARIABLE hFieldBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE hFileBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE hIndexBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE hIndexFieldBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE cFieldList AS CHARACTER NO-UNDO.
{&timerStart}
CREATE BUFFER hFileBuffer FOR TABLE pcDatabaseName + "._File".
CREATE BUFFER hIndexBuffer FOR TABLE pcDatabaseName + "._Index".
CREATE BUFFER hIndexFieldBuffer FOR TABLE pcDatabaseName + "._Index-Field".
CREATE BUFFER hFieldBuffer FOR TABLE pcDatabaseName + "._Field".
CREATE QUERY hQuery.
hQuery:SET-BUFFERS(hFileBuffer,hIndexBuffer,hIndexFieldBuffer,hFieldBuffer).
{&_proparse_ prolint-nowarn(longstrings)}
cWhere = SUBSTITUTE("FOR EACH &1._file WHERE &1._file._file-name = &2 AND _File._File-Number < 32768, ~
EACH &1._index OF &1._file WHERE TRUE &3 &4, ~
EACH &1._index-field OF &1._index, ~
EACH &1._field OF &1._index-field"
, pcDatabaseName
, QUOTER(pcTableName)
, (IF CAN-DO(pcFlags,"U") THEN "AND _index._unique = true" ELSE "")
, (IF CAN-DO(pcFlags,"P") THEN "AND recid(_index) = _file._prime-index" ELSE "")
).
IF hQuery:QUERY-PREPARE (cWhere) THEN
DO:
hQuery:QUERY-OPEN().
hQuery:GET-FIRST(NO-LOCK).
REPEAT WHILE NOT hQuery:QUERY-OFF-END:
cFieldList = cFieldList + "," + trim(hFieldBuffer:BUFFER-FIELD("_field-name"):string-value).
hQuery:GET-NEXT(NO-LOCK).
END.
END.
cFieldList = TRIM(cFieldList, ",").
hQuery:QUERY-CLOSE.
DELETE OBJECT hFileBuffer.
DELETE OBJECT hIndexBuffer.
DELETE OBJECT hIndexFieldBuffer.
DELETE OBJECT hFieldBuffer.
DELETE OBJECT hQuery.
RETURN cFieldList. /* Function return value. */
{&timerStop}
END FUNCTION. /* getIndexFields */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getKeyList) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getKeyList Procedure
FUNCTION getKeyList RETURNS CHARACTER
( /* parameter-definitions */ ) :
/* Return a list of special keys pressed
*/
DEFINE VARIABLE mKeyboardState AS MEMPTR NO-UNDO.
{&_proparse_prolint-nowarn(varusage)}
DEFINE VARIABLE iReturnValue AS INT64 NO-UNDO.
DEFINE VARIABLE cKeyList AS CHARACTER NO-UNDO.
SET-SIZE(mKeyboardState) = 256.
/* Get the current state of the keyboard */
{&_proparse_prolint-nowarn(varusage)}
RUN GetKeyboardState(GET-POINTER-VALUE(mKeyboardState), OUTPUT iReturnValue) NO-ERROR.
/* try to suppress error: 'C' Call Stack has been compromised after calling in (6069) */
IF NOT ERROR-STATUS:ERROR THEN
DO:
IF GET-BITS(GET-BYTE(mKeyboardState, 1 + 16), 8, 1) = 1 THEN cKeyList = TRIM(cKeyList + ",SHIFT",",").
IF GET-BITS(GET-BYTE(mKeyboardState, 1 + 17), 8, 1) = 1 THEN cKeyList = TRIM(cKeyList + ",CTRL",",").
IF GET-BITS(GET-BYTE(mKeyboardState, 1 + 18), 8, 1) = 1 THEN cKeyList = TRIM(cKeyList + ",ALT",",").
END.
SET-SIZE(mKeyboardState) = 0.
RETURN cKeyList. /* Function return value. */
END FUNCTION. /* getKeyList */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getLinkInfo) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getLinkInfo Procedure
FUNCTION getLinkInfo RETURNS CHARACTER
( INPUT pcFieldName AS CHARACTER
):
/* Save name/value of a field.
*/
DEFINE BUFFER bLinkInfo FOR ttLinkInfo.
{&timerStart}
FIND bLinkInfo WHERE bLinkInfo.cField = pcFieldName NO-ERROR.
RETURN (IF AVAILABLE bLinkInfo THEN bLinkInfo.cValue ELSE "").
{&timerStop}
END FUNCTION. /* getLinkInfo */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getMaxLength) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getMaxLength Procedure
FUNCTION getMaxLength RETURNS INTEGER
( cFieldList AS CHARACTER ) :
/* Return the length of the longest element in a comma separated list
*/
DEFINE VARIABLE iField AS INTEGER NO-UNDO.
DEFINE VARIABLE iMaxLength AS INTEGER NO-UNDO.
{&timerStart}
/* Get max field length */
DO iField = 1 TO NUM-ENTRIES(cFieldList):
iMaxLength = MAXIMUM(iMaxLength,LENGTH(ENTRY(iField,cFieldList))).
END.
RETURN iMaxLength. /* Function return value. */
{&timerStop}
END FUNCTION. /* getMaxLength */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getOsErrorDesc) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getOsErrorDesc Procedure
FUNCTION getOsErrorDesc RETURNS CHARACTER
(INPUT piOsError AS INTEGER):
/* Return string for os-error
*/
CASE piOsError:
WHEN 0 THEN RETURN "No error ".
WHEN 1 THEN RETURN "Not owner ".
WHEN 2 THEN RETURN "No such file or directory".
WHEN 3 THEN RETURN "Interrupted system call ".
WHEN 4 THEN RETURN "I/O error ".
WHEN 5 THEN RETURN "Bad file number ".
WHEN 6 THEN RETURN "No more processes ".
WHEN 7 THEN RETURN "Not enough core memory ".
WHEN 8 THEN RETURN "Permission denied ".
WHEN 9 THEN RETURN "Bad address ".
WHEN 10 THEN RETURN "File exists ".
WHEN 11 THEN RETURN "No such device ".
WHEN 12 THEN RETURN "Not a directory ".
WHEN 13 THEN RETURN "Is a directory ".
WHEN 14 THEN RETURN "File table overflow ".
WHEN 15 THEN RETURN "Too many open files ".
WHEN 16 THEN RETURN "File too large ".
WHEN 17 THEN RETURN "No space left on device ".
WHEN 18 THEN RETURN "Directory not empty ".
OTHERWISE RETURN "Unmapped error ".
END CASE.
END FUNCTION. /* getOsErrorDesc */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getProgramDir) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getProgramDir Procedure
FUNCTION getProgramDir RETURNS CHARACTER
( /* parameter-definitions */ ) :
/* Return the DataDigger install dir, including a backslash
*/
/* Cached the value in a global var (about 100x as fast) */
IF gcProgramDir = '' THEN
DO:
/* this-procedure:file-name will return the .p name without path when the
* procedure us run without full path. We need to seek it in the propath.
*/
FILE-INFO:FILE-NAME = THIS-PROCEDURE:FILE-NAME.
IF FILE-INFO:FULL-PATHNAME = ? THEN
DO:
IF SUBSTRING(THIS-PROCEDURE:FILE-NAME,LENGTH(THIS-PROCEDURE:FILE-NAME) - 1, 2) = ".p" THEN
FILE-INFO:FILE-NAME = SUBSTRING(THIS-PROCEDURE:FILE-NAME,1,LENGTH(THIS-PROCEDURE:FILE-NAME) - 2) + ".r".
END.
gcProgramDir = SUBSTRING(FILE-INFO:FULL-PATHNAME,1,R-INDEX(FILE-INFO:FULL-PATHNAME,'\')).
PUBLISH "message"(50,gcProgramDir).
END.
RETURN gcProgramDir.
END FUNCTION. /* getProgramDir */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getQuery) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getQuery Procedure
FUNCTION getQuery RETURNS CHARACTER
( INPUT pcDatabase AS CHARACTER
, INPUT pcTable AS CHARACTER
, INPUT piQuery AS INTEGER
) :
/* Get previously used query nr <piQuery>
*/
DEFINE BUFFER bQuery FOR ttQuery.
FIND bQuery
WHERE bQuery.cDatabase = pcDatabase
AND bQuery.cTable = pcTable
AND bQuery.iQueryNr = piQuery NO-ERROR.
IF AVAILABLE bQuery THEN
RETURN bQuery.cQueryTxt.
ELSE
RETURN ?.
END FUNCTION. /* getQuery */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getReadableQuery) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getReadableQuery Procedure
FUNCTION getReadableQuery RETURNS CHARACTER
( INPUT pcQuery AS CHARACTER ):
/* Return a query as a string that is readable for humans.
*/
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
/* Accept query or query-handle */
hQuery = WIDGET-HANDLE(pcQuery) NO-ERROR.
IF VALID-HANDLE( hQuery ) THEN
DO:
hQuery = WIDGET-HANDLE(pcQuery).
pcQuery = hQuery:PREPARE-STRING.
END.
pcQuery = REPLACE(pcQuery,' EACH ' ,' EACH ').
pcQuery = REPLACE(pcQuery,' FIRST ',' FIRST ').
pcQuery = REPLACE(pcQuery,' WHERE ', '~n WHERE ').
pcQuery = REPLACE(pcQuery,' AND ' , '~n AND ').
pcQuery = REPLACE(pcQuery,' BY ' , '~n BY ').
pcQuery = REPLACE(pcQuery,' FIELDS ()','').
pcQuery = REPLACE(pcQuery,'FOR EACH ' ,'FOR EACH ').
pcQuery = REPLACE(pcQuery,' NO-LOCK', ' NO-LOCK').
pcQuery = REPLACE(pcQuery,' INDEXED-REPOSITION', '').
pcQuery = pcQuery + '~n'.
RETURN pcQuery.
END FUNCTION. /* getReadableQuery */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getRegistry) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getRegistry Procedure
FUNCTION getRegistry RETURNS CHARACTER
( pcSection AS CHARACTER
, pcKey AS CHARACTER
) :
/* Get a value from the registry.
*/
{&timerStart}
DEFINE BUFFER bDatabase FOR ttDatabase.
DEFINE BUFFER bConfig FOR ttConfig.
/* If this is a DB-specific section then replace db name if needed */
IF pcSection BEGINS "DB:" THEN
DO:
FIND bDatabase WHERE bDatabase.cLogicalName = ENTRY(2,pcSection,":") NO-ERROR.
IF AVAILABLE bDatabase THEN pcSection = "DB:" + bDatabase.cSection.
END.
/* Load settings if there is nothing in the config table */
IF NOT TEMP-TABLE ttConfig:HAS-RECORDS THEN
RUN loadSettings.
/* Search in settings tt */
FIND bConfig WHERE bConfig.cSection = pcSection AND bConfig.cSetting = pcKey NO-ERROR.
RETURN ( IF AVAILABLE bConfig THEN bConfig.cValue ELSE ? ).
{&timerStop}
END FUNCTION. /* getRegistry */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getSchemaHolder) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getSchemaHolder Procedure
FUNCTION getSchemaHolder RETURNS CHARACTER
( INPUT pcDataSrNameOrDbName AS CHARACTER
):
DEFINE BUFFER bDataserver FOR ttDataserver.
FIND bDataserver WHERE bDataserver.cLDBNameDataserver = pcDataSrNameOrDbName NO-ERROR.
RETURN (IF AVAILABLE bDataserver THEN bDataserver.cLDBNameSchema ELSE pcDataSrNameOrDbName).
END FUNCTION. /* getSchemaHolder */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getStackSize) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getStackSize Procedure
FUNCTION getStackSize RETURNS INTEGER():
/* Return value of the -s session setting
*/
DEFINE VARIABLE cList AS CHARACTER NO-UNDO.
DEFINE VARIABLE cParm AS CHARACTER CASE-SENSITIVE NO-UNDO.
DEFINE VARIABLE cSetting AS CHARACTER NO-UNDO.
DEFINE VARIABLE cValue AS CHARACTER NO-UNDO.
DEFINE VARIABLE iParm AS INTEGER NO-UNDO.
DEFINE VARIABLE iStackSize AS INTEGER NO-UNDO.
cList = SESSION:STARTUP-PARAMETERS.
DO iParm = 1 TO NUM-ENTRIES(cList):
cSetting = ENTRY(iParm,cList) + " ".
cParm = ENTRY(1,cSetting," ").
cValue = ENTRY(2,cSetting," ").
IF cParm = "-s" THEN
DO:
iStackSize = INTEGER(cValue) NO-ERROR.
IF ERROR-STATUS:ERROR THEN iStackSize = 0.
END.
END.
/* If not defined, report the default */
IF iStackSize = 0 THEN iStackSize = 40.
RETURN iStackSize.
END FUNCTION. /* getStackSize */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getTableDesc) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getTableDesc Procedure
FUNCTION getTableDesc RETURNS CHARACTER
( INPUT pcDatabase AS CHARACTER
, INPUT pcTable AS CHARACTER
) :
DEFINE BUFFER bTable FOR ttTable.
FIND bTable
WHERE bTable.cDatabase = pcDatabase
AND bTable.cTableName = pcTable NO-ERROR.
RETURN (IF AVAILABLE bTable THEN bTable.cTableDesc ELSE '').
END FUNCTION. /* getTableDesc */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getTableLabel) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getTableLabel Procedure
FUNCTION getTableLabel RETURNS CHARACTER
( INPUT pcDatabase AS CHARACTER
, INPUT pcTable AS CHARACTER
) :
DEFINE BUFFER bTable FOR ttTable.
FIND bTable
WHERE bTable.cDatabase = pcDatabase
AND bTable.cTableName = pcTable NO-ERROR.
RETURN (IF AVAILABLE bTable AND bTable.cTableLabel <> ? THEN bTable.cTableLabel ELSE '').
END FUNCTION. /* getTableLabel */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getTableList) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getTableList Procedure
FUNCTION getTableList RETURNS CHARACTER
( INPUT pcDatabaseFilter AS CHARACTER
, INPUT pcTableFilter AS CHARACTER
) :
/* Get a filtered list of all tables in the current database
*/
DEFINE VARIABLE cTableList AS CHARACTER NO-UNDO.
DEFINE VARIABLE cQuery AS CHARACTER NO-UNDO.
DEFINE BUFFER bTable FOR ttTable.
DEFINE QUERY qTable FOR bTable.
{&timerStart}
IF pcDatabaseFilter = '' OR pcDatabaseFilter = ? THEN pcDatabaseFilter = '*'.
/* Build query */
cQuery = SUBSTITUTE('for each bTable where cDatabase matches &1', QUOTER(pcDatabaseFilter)).
cQuery = SUBSTITUTE("&1 and cTableName matches &2", cQuery, QUOTER(pcTableFilter )).
QUERY qTable:QUERY-PREPARE( SUBSTITUTE('&1 by cTableName', cQuery)).
QUERY qTable:QUERY-OPEN.
QUERY qTable:GET-FIRST.
/* All fields */
REPEAT WHILE NOT QUERY qTable:QUERY-OFF-END:
cTableList = cTableList + "," + bTable.cTableName.
QUERY qTable:GET-NEXT.
END.
QUERY qTable:QUERY-CLOSE.
cTableList = LEFT-TRIM(cTableList, ",").
RETURN cTableList. /* Function return value. */
{&timerStop}
END FUNCTION. /* getTableList */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getUserName) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getUserName Procedure
FUNCTION getUserName RETURNS CHARACTER
( /* parameter-definitions */ ) :
/* Return login name of user
*/
DEFINE VARIABLE cUserName AS LONGCHAR NO-UNDO.
DEFINE VARIABLE intResult AS INTEGER NO-UNDO.
DEFINE VARIABLE intSize AS INTEGER NO-UNDO.
DEFINE VARIABLE mUserId AS MEMPTR NO-UNDO.
{&startTimer}
/* Otherwise determine the value */
SET-SIZE(mUserId) = 256.
intSize = 255.
RUN GetUserNameA(INPUT mUserId, INPUT-OUTPUT intSize, OUTPUT intResult).
COPY-LOB mUserId FOR (intSize - 1) TO cUserName NO-CONVERT.
IF intResult <> 1 OR cUserName = "" OR cUserName = ? THEN
cUserName = "default".
ELSE
cUserName = REPLACE(cUserName,".","").
RETURN STRING(cUserName). /* Function return value. */
{&stopTimer}
END FUNCTION. /* getUserName */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getWidgetUnderMouse) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getWidgetUnderMouse Procedure
FUNCTION getWidgetUnderMouse RETURNS HANDLE
( phFrame AS HANDLE ) :
/* Return the handle of the widget that is currently under the mouse cursor
*/
DEFINE VARIABLE hWidget AS HANDLE NO-UNDO.
DEFINE VARIABLE iMouseX AS INTEGER NO-UNDO.
DEFINE VARIABLE iMouseY AS INTEGER NO-UNDO.
{&timerStart}
hWidget = phFrame:FIRST-CHILD:first-child.
RUN getMouseXY(INPUT phFrame, OUTPUT iMouseX, OUTPUT iMouseY).
REPEAT WHILE VALID-HANDLE(hWidget):
IF hWidget:TYPE <> "RECTANGLE"
AND iMouseX >= hWidget:X
AND iMouseX <= hWidget:X + hWidget:WIDTH-PIXELS
AND iMouseY >= hWidget:Y
AND iMouseY <= hWidget:Y + hWidget:HEIGHT-PIXELS THEN RETURN hWidget.
hWidget = hWidget:NEXT-SIBLING.
END.
RETURN ?.
{&timerStop}
END FUNCTION. /* getWidgetUnderMouse */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getWorkFolder) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getWorkFolder Procedure
FUNCTION getWorkFolder RETURNS CHARACTER
( /* parameter-definitions */ ) :
/* Cached the value in a global var */
IF gcWorkFolder = '' THEN
DO:
gcWorkFolder = getRegistry("DataDigger", "WorkFolder").
/* Possibility to specify where DD files are created */
IF gcWorkFolder = ? OR gcWorkFolder = '' THEN
gcWorkFolder = getProgramDir().
ELSE
DO:
gcWorkFolder = RIGHT-TRIM(gcWorkFolder,'/\') + '\'.
gcWorkFolder = resolveOsVars(gcWorkFolder).
RUN createFolder(gcWorkFolder).
FILE-INFO:FILE-NAME = gcWorkFolder.
IF FILE-INFO:FULL-PATHNAME = ? THEN gcWorkFolder = getProgramDir().
END.
END.
RETURN gcWorkFolder.
END FUNCTION. /* getWorkFolder */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-getXmlNodeName) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION getXmlNodeName Procedure
FUNCTION getXmlNodeName RETURNS CHARACTER
( pcFieldName AS CHARACTER ) :
/* Return a name that is safe to use in XML output
*/
pcFieldName = REPLACE(pcFieldName,'%', '_').
pcFieldName = REPLACE(pcFieldName,'#', '_').
RETURN pcFieldName.
END FUNCTION. /* getXmlNodeName */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-isDataServer) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION isDataServer Procedure
FUNCTION isDataServer RETURNS LOGICAL
( INPUT pcDataSrNameOrDbName AS CHARACTER
):
RETURN CAN-FIND(ttDataserver WHERE ttDataserver.cLDBNameDataserver = pcDataSrNameOrDbName).
END FUNCTION. /* isDataServer */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-isDefaultFontsChanged) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION isDefaultFontsChanged Procedure
FUNCTION isDefaultFontsChanged RETURNS LOGICAL
( /* parameter-definitions */ ) :
/* Returns whether the default fonts 0-7 were changed.
*/
DEFINE VARIABLE cFontSize AS CHARACTER NO-UNDO EXTENT 8.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
/* These are the expected fontsizes of the text 'DataDigger' */
cFontSize[1] = '70/14'. /* font0 */
cFontSize[2] = '54/13'. /* font1 */
cFontSize[3] = '70/14'. /* font2 */
cFontSize[4] = '70/14'. /* font3 */
cFontSize[5] = '54/13'. /* font4 */
cFontSize[6] = '70/16'. /* font5 */
cFontSize[7] = '65/13'. /* font6 */
cFontSize[8] = '54/13'. /* font7 */
checkFont:
DO i = 0 TO 7:
IF cFontSize[i + 1] <> SUBSTITUTE('&1/&2'
, FONT-TABLE:GET-TEXT-WIDTH-PIXELS('DataDigger',i)
, FONT-TABLE:GET-TEXT-HEIGHT-PIXELS(i)
) THEN RETURN TRUE.
END. /* checkFont */
RETURN FALSE.
END FUNCTION. /* isDefaultFontsChanged */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-isFileLocked) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION isFileLocked Procedure
FUNCTION isFileLocked RETURNS LOGICAL
( pcFileName AS CHARACTER ) :
/* Check whether a file is locked on the file system
*/
DEFINE VARIABLE iFileHandle AS INTEGER NO-UNDO.
{&_proparse_prolint-nowarn(varusage)}
DEFINE VARIABLE nReturn AS INTEGER NO-UNDO.
/* Try to lock the file agains writing */
RUN CreateFileA ( INPUT pcFileName
, INPUT {&GENERIC_WRITE}
, {&FILE_SHARE_READ}
, 0
, {&OPEN_EXISTING}
, {&FILE_ATTRIBUTE_NORMAL}
, 0
, OUTPUT iFileHandle
).
/* Release file handle */
{&_proparse_prolint-nowarn(varusage)}
RUN CloseHandle (INPUT iFileHandle, OUTPUT nReturn).
RETURN (iFileHandle = -1).
END FUNCTION. /* isFileLocked */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-isMouseOver) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION isMouseOver Procedure
FUNCTION isMouseOver RETURNS LOGICAL
( phWidget AS HANDLE ) :
/* Return whether the mouse is currently over a certain widget
*/
DEFINE VARIABLE iMouseX AS INTEGER NO-UNDO.
DEFINE VARIABLE iMouseY AS INTEGER NO-UNDO.
IF NOT VALID-HANDLE(phWidget) THEN RETURN FALSE.
RUN getMouseXY(INPUT phWidget:FRAME, OUTPUT iMouseX, OUTPUT iMouseY).
RETURN ( iMouseX >= phWidget:X
AND iMouseX <= phWidget:X + phWidget:WIDTH-PIXELS
AND iMouseY >= phWidget:Y
AND iMouseY <= phWidget:Y + phWidget:HEIGHT-PIXELS ).
END FUNCTION. /* isMouseOver */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-isTableFilterUsed) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION isTableFilterUsed Procedure
FUNCTION isTableFilterUsed RETURNS LOGICAL
( INPUT TABLE ttTableFilter ) :
/* Returns whether any setting is used for table filtering
*/
FIND ttTableFilter NO-ERROR.
IF NOT AVAILABLE ttTableFilter THEN RETURN FALSE.
/* Main toggles */
IF ttTableFilter.lShowNormal = FALSE
OR ttTableFilter.lShowSchema <> LOGICAL(getRegistry('DataDigger','ShowHiddenTables'))
OR ttTableFilter.lShowVst = TRUE
OR ttTableFilter.lShowSql = TRUE
OR ttTableFilter.lShowOther = TRUE
OR ttTableFilter.lShowHidden = TRUE
OR ttTableFilter.lShowFrozen = TRUE THEN RETURN TRUE.
/* Show these tables */
IF ttTableFilter.cTableNameShow <> ?
AND ttTableFilter.cTableNameShow <> ''
AND ttTableFilter.cTableNameShow <> '*' THEN RETURN TRUE.
/* But hide these */
IF ttTableFilter.cTableNameHide <> ?
AND ttTableFilter.cTableNameHide <> '' THEN RETURN TRUE.
/* Show only tables that contain all of these fields */
IF ttTableFilter.cTableFieldShow <> ?
AND ttTableFilter.cTableFieldShow <> ''
AND ttTableFilter.cTableFieldShow <> '*' THEN RETURN TRUE.
/* But hide tables that contain any of these */
IF ttTableFilter.cTableFieldHide <> ?
AND ttTableFilter.cTableFieldHide <> '' THEN RETURN TRUE.
/* else */
RETURN FALSE.
END FUNCTION. /* isTableFilterUsed */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-isValidCodePage) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION isValidCodePage Procedure
FUNCTION isValidCodePage RETURNS LOGICAL
(pcCodepage AS CHARACTER):
/* Returns whether pcCodePage is valid
*/
{&_proparse_prolint-nowarn(varusage)}
DEFINE VARIABLE cDummy AS LONGCHAR NO-UNDO.
IF pcCodePage = '' THEN RETURN TRUE.
FIX-CODEPAGE(cDummy) = pcCodepage NO-ERROR.
RETURN NOT ERROR-STATUS:ERROR.
END FUNCTION. /* isValidCodePage */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-readFile) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION readFile Procedure
FUNCTION readFile RETURNS LONGCHAR
(pcFilename AS CHARACTER):
/* Read contents of a file as a longchar.
*/
DEFINE VARIABLE cContent AS LONGCHAR NO-UNDO.
DEFINE VARIABLE cLine AS CHARACTER NO-UNDO.
IF SEARCH(pcFilename) <> ? THEN
DO:
INPUT FROM VALUE(pcFilename).
REPEAT:
IMPORT UNFORMATTED cLine.
cContent = cContent + "~n" + cLine.
END.
INPUT CLOSE.
END.
RETURN cContent.
END FUNCTION. /* readFile */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-removeConnection) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION removeConnection Procedure
FUNCTION removeConnection RETURNS LOGICAL
( pcDatabase AS CHARACTER ) :
/* Remove record from connection temp-table
*/
DEFINE BUFFER bfDatabase FOR ttDatabase.
FIND bfDatabase WHERE bfDatabase.cLogicalName = pcDatabase NO-ERROR.
IF AVAILABLE bfDatabase THEN DELETE bfDatabase.
RETURN TRUE.
END FUNCTION. /* removeConnection */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-resolveOsVars) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION resolveOsVars Procedure
FUNCTION resolveOsVars RETURNS CHARACTER
( pcString AS CHARACTER ) :
/* Return a string with OS vars resolved
*/
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DO i = 1 TO NUM-ENTRIES(pcString,'%'):
IF i MODULO 2 = 0
AND OS-GETENV(ENTRY(i,pcString,'%')) <> ? THEN
ENTRY(i,pcString,'%') = OS-GETENV(ENTRY(i,pcString,'%')).
END.
pcString = REPLACE(pcString,'%','').
RETURN pcString.
END FUNCTION. /* resolveOsVars */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-resolveSequence) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION resolveSequence Procedure
FUNCTION resolveSequence RETURNS CHARACTER
( pcString AS CHARACTER ) :
/* Return a string where sequence nr for file is resolved
*/
DEFINE VARIABLE iFileNr AS INTEGER NO-UNDO.
DEFINE VARIABLE cSeqMask AS CHARACTER NO-UNDO .
DEFINE VARIABLE cSeqFormat AS CHARACTER NO-UNDO .
DEFINE VARIABLE cFileName AS CHARACTER NO-UNDO.
cFileName = pcString.
/* User can specify a sequence for the file. The length of
* the tag sets the format: <###> translates to a 3-digit nr
* Special case is <#> which translates to no leading zeros
*/
IF INDEX(cFileName,'<#') > 0
AND index(cFileName,'#>') > 0 THEN
DO:
cSeqMask = SUBSTRING(cFileName,INDEX(cFileName,'<#')). /* <#####>tralalala */
cSeqMask = SUBSTRING(cSeqMask,1,INDEX(cSeqMask,'>')). /* <#####> */
cSeqFormat = TRIM(cSeqMask,'<>'). /* ##### */
cSeqFormat = REPLACE(cSeqFormat,'#','9').
IF cSeqFormat = '9' THEN cSeqFormat = '>>>>>>>>>9'.
setFileNr:
REPEAT:
iFileNr = iFileNr + 1.
IF SEARCH(REPLACE(cFileName,cSeqMask,TRIM(STRING(iFileNr,cSeqFormat)))) = ? THEN
DO:
cFileName = REPLACE(cFileName,cSeqMask,TRIM(STRING(iFileNr,cSeqFormat))).
LEAVE setFileNr.
END.
END.
END.
RETURN cFileName.
END FUNCTION. /* resolveSequence */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setColor) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION setColor Procedure
FUNCTION setColor RETURNS INTEGER
( pcName AS CHARACTER
, piColor AS INTEGER) :
/* Set color nr in the color tt
*/
DEFINE BUFFER bColor FOR ttColor.
FIND bColor WHERE bColor.cName = pcName NO-ERROR.
IF NOT AVAILABLE bColor THEN
DO:
CREATE bColor.
ASSIGN bColor.cName = pcName.
END.
/* Set to default value from settings */
IF piColor = ? THEN
DO:
piColor = INTEGER(getRegistry('DataDigger:Colors', pcName)) NO-ERROR.
IF ERROR-STATUS:ERROR THEN piColor = ?.
END.
bColor.iColor = piColor.
RETURN bColor.iColor.
END FUNCTION. /* setColor */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setColumnWidthList) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION setColumnWidthList Procedure
FUNCTION setColumnWidthList RETURNS LOGICAL
( INPUT phBrowse AS HANDLE
, INPUT pcWidthList AS CHARACTER):
/* Set all specified columns in pcWidthList to a specified width
*/
DEFINE VARIABLE cColumnName AS CHARACTER NO-UNDO.
DEFINE VARIABLE cListItem AS CHARACTER NO-UNDO.
DEFINE VARIABLE hColumn AS HANDLE NO-UNDO.
DEFINE VARIABLE iColumnWidth AS INTEGER NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE j AS INTEGER NO-UNDO.
DO i = 1 TO NUM-ENTRIES(pcWidthList):
cListItem = ENTRY(i,pcWidthList).
cColumnName = ENTRY(1,cListItem,':') NO-ERROR.
iColumnWidth = INTEGER(ENTRY(2,cListItem,':')) NO-ERROR.
DO j = 1 TO phBrowse:NUM-COLUMNS:
hColumn = phBrowse:GET-BROWSE-COLUMN(j).
IF hColumn:NAME = cColumnName THEN
hColumn:WIDTH-PIXELS = iColumnWidth.
END. /* j */
END. /* i */
RETURN TRUE.
END FUNCTION. /* setColumnWidthList */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setLinkInfo) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION setLinkInfo Procedure
FUNCTION setLinkInfo RETURNS LOGICAL
( INPUT pcFieldName AS CHARACTER
, INPUT pcValue AS CHARACTER
):
/* Save name/value of a field.
*/
DEFINE BUFFER bLinkInfo FOR ttLinkInfo.
{&timerStart}
PUBLISH "debugInfo" (2, SUBSTITUTE("Set linkinfo for field &1 to &2", pcFieldName, pcValue)).
FIND bLinkInfo WHERE bLinkInfo.cField = pcFieldName NO-ERROR.
IF NOT AVAILABLE bLinkInfo THEN
DO:
CREATE bLinkInfo.
ASSIGN bLinkInfo.cField = pcFieldName.
END.
bLinkInfo.cValue = TRIM(pcValue).
RETURN TRUE. /* Function return value. */
{&timerStop}
END FUNCTION. /* setLinkInfo */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF
&IF DEFINED(EXCLUDE-setRegistry) = 0 &THEN
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION setRegistry Procedure
FUNCTION setRegistry RETURNS CHARACTER
( pcSection AS CHARACTER
, pcKey AS CHARACTER
, pcValue AS CHARACTER
) :
/* Set a value in the registry.
*/
{&timerStart}
DEFINE BUFFER bfConfig FOR ttConfig.
FIND bfConfig
WHERE bfConfig.cSection = pcSection
AND bfConfig.cSetting = pcKey NO-ERROR.
IF NOT AVAILABLE bfConfig THEN
DO:
CREATE bfConfig.
ASSIGN
bfConfig.cSection = pcSection
bfConfig.cSetting = pcKey.
glDirtyCache = TRUE.
END.
IF pcValue = ? OR TRIM(pcValue) = '' THEN
DO:
DELETE bfConfig.
glDirtyCache = TRUE.
END.
ELSE
DO:
ASSIGN
bfConfig.lUser = TRUE
bfConfig.cValue = pcValue.
IF bfConfig.cValue <> pcValue THEN glDirtyCache = TRUE.
END.
RETURN "". /* Function return value. */
{&timerStop}
END FUNCTION. /* setRegistry */
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
&ENDIF