Forms Library: PKG_FORM
This is just a post to document a standard library that I like to create in Oracle Forms, if equivalents are not already available. Suggestions or critiques are welcome.
“No warranty is express or implied about the suitability of this code for any purpose.”
Specification
PACKAGE PKG_FORM IS PROCEDURE centre_window (windown IN VARCHAR2); PROCEDURE check_record_is_saved; PROCEDURE commit; FUNCTION current_record (blockn IN VARCHAR2) RETURN INTEGER; FUNCTION current_record_status (blockn IN VARCHAR2) RETURN VARCHAR2; PROCEDURE delay_action (timern IN VARCHAR2); PROCEDURE set_current_record_status (blockn IN VARCHAR2 ,istatus IN NUMBER); PROCEDURE set_mdi_window_title (clock IN BOOLEAN := TRUE); -- gets the date/time from the app server FUNCTION system_datetime RETURN DATE; END PKG_FORM;
Package Body
PACKAGE PKG_FORM IS cAPP_TITLE CONSTANT VARCHAR2(100) := '[insert app title here]'; PROCEDURE centre_window (windown IN VARCHAR2) IS cMAIN_WINDOW CONSTANT VARCHAR2(100) := '[insert main window name here]'; x NUMBER; y NUMBER; main_win WINDOW := FIND_WINDOW(cMAIN_WINDOW); window_id WINDOW := FIND_WINDOW(windown); BEGIN x := GET_WINDOW_PROPERTY(main_win,X_POS) + (GET_WINDOW_PROPERTY(main_win,WIDTH ) - GET_WINDOW_PROPERTY(window_id,WIDTH )) / 2; y := GET_WINDOW_PROPERTY(main_win,Y_POS) + (GET_WINDOW_PROPERTY(main_win,HEIGHT) - GET_WINDOW_PROPERTY(window_id,HEIGHT)) / 2; SHOW_WINDOW(window_id, x, y); END centre_window; PROCEDURE check_record_is_saved IS BEGIN IF :SYSTEM.FORM_STATUS = 'CHANGED' THEN PKG_MESSAGE.error('Please save or cancel your changes first.'); END IF; END check_record_is_saved; PROCEDURE commit IS msglevel VARCHAR2(2) := :SYSTEM.MESSAGE_LEVEL; BEGIN msg('PKG_FORM.commit'); -- set message level to avoid FRM-40401 "No changes to save." :SYSTEM.MESSAGE_LEVEL := '5'; COMMIT_FORM; :SYSTEM.MESSAGE_LEVEL := msglevel; IF :SYSTEM.FORM_STATUS != 'QUERY' THEN PKG_MESSAGE.error('Unable to save changes.'); END IF; END commit; FUNCTION current_record (blockn IN VARCHAR2) RETURN INTEGER IS BEGIN RETURN GET_BLOCK_PROPERTY(blockn, CURRENT_RECORD); END current_record; FUNCTION current_record_status (blockn IN VARCHAR2) RETURN VARCHAR2 IS BEGIN RETURN GET_RECORD_PROPERTY( GET_BLOCK_PROPERTY(blockn, CURRENT_RECORD), blockn, STATUS); END current_record_status; PROCEDURE delay_action (timern IN VARCHAR2) IS -- requires a suitable WHEN-TIMER-EXPIRED form-level trigger timer_id TIMER; BEGIN IF ID_NULL(FIND_TIMER(timern)) THEN msg('CREATE_TIMER('||timern||')'); timer_id := CREATE_TIMER(timern,1,NO_REPEAT); END IF; END delay_action; PROCEDURE set_current_record_status (blockn IN VARCHAR2 ,istatus IN NUMBER) IS BEGIN SET_RECORD_PROPERTY( GET_BLOCK_PROPERTY(blockn, CURRENT_RECORD), blockn, STATUS, istatus); END set_current_record_status; PROCEDURE set_mdi_window_title (clock IN BOOLEAN := TRUE) IS --scaling factor is the number of milliseconds in a second cSCALING_FACTOR CONSTANT NUMBER := 1000; --don't update the time more than once every 10 seconds cMIN_UPDATE_FREQUENCY CONSTANT NUMBER := 10; date_time DATE; timer_id TIMER; seconds PLS_INTEGER; ms PLS_INTEGER; BEGIN IF clock THEN date_time := system_datetime; SET_WINDOW_PROPERTY(FORMS_MDI_WINDOW, TITLE, cAPP_TITLE || ' - ' || TO_CHAR(date_time,'Dy FMDD Mon YYYY HHFM:MIpm')); IF ID_NULL(FIND_TIMER('CLOCK')) THEN --get the seconds portion of the current time seconds := (date_time - TRUNC(date_time,'MI')) * 86400; --update the time at the end of the minute (or thereabouts) ms := GREATEST((61 - seconds) * cSCALING_FACTOR ,cMIN_UPDATE_FREQUENCY * cSCALING_FACTOR); timer_id := CREATE_TIMER('CLOCK', ms, NO_REPEAT); END IF; ELSE SET_WINDOW_PROPERTY(FORMS_MDI_WINDOW, TITLE, cAPP_TITLE); END IF; END set_mdi_window_title; FUNCTION system_datetime RETURN DATE IS -- gets the date/time from the app server -- should perform better than calling SYSDATE all the time -- WARNING: this assumes that the builtin date format includes the time component! BEGIN RETURN TO_DATE(:SYSTEM.EFFECTIVE_DATE, GET_APPLICATION_PROPERTY(BUILTIN_DATE_FORMAT)); END system_datetime; END PKG_FORM;
Example form-level trigger: when-timer-expired
DECLARE timern VARCHAR2(100) := GET_APPLICATION_PROPERTY(TIMER_NAME); BEGIN msg('when-timer-expired ' || timern); CASE timern WHEN 'CLOCK' THEN PKG_FORM.set_mdi_window_title; WHEN 'PKGNAME_XYZ' THEN PKGNAME.xyz; -- ... etc. ... ELSE PKG_MESSAGE.error('Unexpected timer name: ' || timern, 'System Error'); END CASE; END;