5159 lines
No EOL
151 KiB
Text
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,"<","<").
|
|
cOutput = REPLACE(cOutput,">",">").
|
|
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 |