/*------------------------------------------------------------------------------
  tc11180d_false_steal.p

  Recreate for review point #1 on the #11180b fix
  (ThinClient.processProgressEvent, "stolen" predicate).

    boolean stolen = oldFocusGone
                  && redirected != null
                  && redirected != src            // <-- WRONG operand
                  && redirected.isDisplayed()
                  && UiUtils.locateFrame(redirected) != frame;

  The predicate is meant to detect a trigger-REDIRECTED focus (a genuine
  steal).  The correct test - the one FocusManager.handleFocusChange uses
  (curFocus != oldFocus) and the one both methods' comments describe - is
  "redirected != inFocus" (inFocus is the analog of oldFocus; src is the
  analog of newFocus).  Using "redirected != src" instead produces a FALSE
  POSITIVE in the legitimate frame-deletion-WITHOUT-steal case.

  Topology (no steal at all):
    - focus is on browse W in DYNAMIC frame A  (inFocus, oldFrame)
    - APPLY 'ENTRY' targets fill-in fB in a DIFFERENT, LIVE frame B (src/frame)
    - frame A's LEAVE trigger DELETEs frame A (oldFocusGone becomes true) but
      does NOT redirect focus anywhere - it does no APPLY.

  What happens in ThinClient.processProgressEvent:
    - tryFocusChange(src=fB, .., doEntry=false) returns before requestFocus
      (doEntry is false) -> focus is NOT moved, still on W.
    - sendLeave(oldFrame=A, frame=B) fires A's frame LEAVE -> A is deleted;
      sendLeave never calls requestFocus, so focus stays on W and
      destroyFrame() defers the hide -> getCurrentFocus() == W, W.isDisplayed().
    - redirected = getCurrentFocus() == W == inFocus.
        oldFocusGone      = true            (A deleted)
        redirected != src = W != fB = true  <-- FALSE POSITIVE
        (with the correct "redirected != inFocus": W != W = false -> not stolen)
        redirected.isDisplayed()          = true
        locateFrame(W)=A != frame=B        = true
      => stolen == true (wrongly) => evt.consume(); return;

  Result: the LEGITIMATE ENTRY into fB is silently dropped - fB's ENTRY
  trigger never runs - and FOCUS is left parked on the DELETED browse W
  (the invalid-focus outcome the fix was meant to prevent).

  W is a BROWSE only so that getCurrentFocus() reliably survives A's deletion
  (a read-only browse remains the focus widget after its frame is destroyed).
  fB is a plain fill-in, so the both-Browse gate on the spurious-LEAVE emit is
  NOT satisfied - this isolates the defect to the consume/return itself
  (point #1), independent of the spurious-LEAVE emit (point #2).

  Expected (OpenEdge / correctly-predicated FWD):
    fB ENTRY fires, FOCUS ends on fB.
  Bug (FWD 11180b as reviewed):
    fB ENTRY never fires; FOCUS parked on the deleted browse.

  FWD drives the whole path synchronously from APPLY "ENTRY", so this runs
  head-less: log to tc11180d.log, then QUIT.
------------------------------------------------------------------------------*/

DEFINE TEMP-TABLE tt NO-UNDO FIELD nm AS CHARACTER.
DEFINE QUERY qA FOR tt SCROLLING.

DEFINE VARIABLE fB  AS CHARACTER NO-UNDO FORMAT "x(8)" INITIAL "bbb".
DEFINE VARIABLE seq AS INTEGER   NO-UNDO.

DEFINE VARIABLE hFrmA AS HANDLE NO-UNDO.
DEFINE VARIABLE hBrw  AS HANDLE NO-UNDO.

DEFINE FRAME frmB fB WITH TITLE "FRAME-B (legitimate destination)" AT ROW 6 COLUMN 2 SIZE 40 BY 4.

PROCEDURE logit:
   DEFINE INPUT PARAMETER m AS CHARACTER NO-UNDO.
   seq = seq + 1.
   OUTPUT TO "tc11180d.log" APPEND.
   PUT UNFORMATTED STRING(seq, "99") " " m SKIP.
   OUTPUT CLOSE.
END PROCEDURE.

/* Frame A's LEAVE: destroy A synchronously while its own LEAVE runs.
   CRUCIALLY there is NO APPLY here - focus is NOT redirected/stolen.
   This is the legitimate frame-deletion-without-steal case. */
PROCEDURE aLeave:
   RUN logit("frmA  LEAVE  (begin - delete frame A, NO focus steal)").
   IF VALID-HANDLE(hFrmA) THEN DELETE WIDGET hFrmA.
   RUN logit("frmA  LEAVE  (end - no APPLY performed)").
END PROCEDURE.

/* ---- destination frame B (the legitimate ENTRY target that MUST fire) ---- */
ON ENTRY OF FRAME frmB
   RUN logit("frmB  ENTRY  <== destination FRAME ENTRY (MUST fire)").
ON LEAVE OF FRAME frmB
   RUN logit("frmB  LEAVE").
ON ENTRY OF fB IN FRAME frmB
   RUN logit("fB    ENTRY  <== LEGITIMATE destination ENTRY (MUST fire; dropped by bug)").
ON LEAVE OF fB IN FRAME frmB
   RUN logit("fB    LEAVE").

/* ---- main ---- */
OUTPUT TO "tc11180d.log".
PUT UNFORMATTED "=== tc11180d_false_steal start ===" SKIP.
OUTPUT CLOSE.

CREATE tt. tt.nm = "row1".
CREATE tt. tt.nm = "row2".
CREATE tt. tt.nm = "row3".

ENABLE fB WITH FRAME frmB.
VIEW FRAME frmB.

/* dynamic frame A holding a read-only browse (the source W) */
CREATE FRAME hFrmA
   ASSIGN TITLE = "FRAME-A (browse source)"
          ROW = 2 COLUMN = 2 WIDTH = 34 HEIGHT = 5
          BOX = TRUE VISIBLE = FALSE.

OPEN QUERY qA FOR EACH tt.

CREATE BROWSE hBrw
   ASSIGN FRAME = hFrmA
          QUERY = QUERY qA:HANDLE
          X = 4 Y = 4 WIDTH = 30 DOWN = 2
          SEPARATORS = TRUE ROW-MARKERS = FALSE
          SENSITIVE = TRUE VISIBLE = TRUE.
hBrw:ADD-COLUMNS-FROM(BUFFER tt:HANDLE).
hBrw:READ-ONLY = TRUE.

hFrmA:VISIBLE = TRUE.

/* Register the source-FRAME LEAVE trigger that deletes A (no steal).
   Hooked on the FRAME (not the browse) so it fires from the fix's
   sendLeave(oldFrame) at ThinClient ~line 23244, AFTER tryFocusChange -
   this is what reaches the "stolen" branch. */
ON "LEAVE":U OF hFrmA PERSISTENT RUN aLeave.

RUN logit("--- APPLY ENTRY to browse (land focus in browse source W) ---").
APPLY "ENTRY" TO hBrw.

IF VALID-HANDLE(FOCUS) THEN
   RUN logit("--- FOCUS before move: TYPE=" + STRING(FOCUS:TYPE)
             + " is-browse=" + STRING(FOCUS:TYPE = "BROWSE") + " ---").
ELSE
   RUN logit("--- FOCUS before move: <none> ---").

RUN logit("--- APPLY ENTRY to fB (legitimate move browse-A -> destination B) ---").
APPLY "ENTRY" TO fB IN FRAME frmB.

RUN logit("--- done; FOCUS is now: "
          + (IF VALID-HANDLE(FOCUS) THEN STRING(FOCUS:TYPE) + "/" + FOCUS:NAME
             ELSE "<none/invalid>") + " ---").
RUN logit("--- EXPECT (OE/fixed): fB ENTRY fired, FOCUS=FILL-IN/fB ---").
RUN logit("--- BUG   (11180b):    fB ENTRY absent, FOCUS on deleted browse ---").
QUIT.
