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;
Forms Library: PKG_ITEM
Current Record Visual Attribute problem

Leave a Reply

Your email address will not be published / Required fields are marked *