Project

General

Profile

6764.03.patch

Marian Edu, 10/03/2022 07:40 AM

Download (49.9 KB)

View differences:

new/src/com/goldencode/p2j/ui/EventDefinition.java 2022-10-03 06:35:42 +0000
63 63
**     CA  20210917          Javadoc fixes.
64 64
**     CA  20211005          Set the matchedWidgetId when lookup is performed.
65 65
**     SBI 20211024          Added containsWidget(int) method.
66
**     ME  20220928          Rewrite trigger lookup, move some of the logic in EventList.
67
**         20221003          Remove 'global anywhere' (derived), use scope self/anywhere on lookup.
66 68
**/
67 69

  
68 70
/*
......
125 127
import java.util.*;
126 128
import java.util.function.Consumer;
127 129

  
128
import com.goldencode.p2j.ui.chui.*;
129 130
import org.roaringbitmap.*;
130 131
import org.roaringbitmap.longlong.*;
131 132

  
132 133
import com.goldencode.p2j.util.*;
133
import com.goldencode.p2j.ui.client.*;
134
import com.goldencode.p2j.ui.client.widget.*;
135 134
import com.goldencode.p2j.util.Utils;
136 135

  
137 136
/**
......
177 176
public class EventDefinition
178 177
implements Externalizable
179 178
{
179
   /** SELF event scope */
180
   public static final int SCOPE_SELF = 1;
181

  
182
   /** ANYWHERE event scope */
183
   public static final int SCOPE_ANYWHERE = 2;
184
   
180 185
   /** Bitwise mask to mark if there are events in the stream.  */
181 186
   private static final byte MASK_HAS_EVENT = (byte) 0x01;
182 187
   
......
198 203
   /** Bitwise mask for the anywhere flag.  */
199 204
   private static final byte MASK_ANYWHERE  = (byte) 0x40;
200 205
   
201
   /** Bitwise mask for the global anywhere flag.  */
202
   private static final byte MASK_GLOBAL_ANYWHERE = (byte) 0x80;
203
   
204 206
   /** The event ID associated with this instance IF and ONLY IF there is only 1 event. */
205 207
   private Integer event = null;   
206 208
   
......
222 224
   /** Widget-specific ANYWHERE option, if given. */
223 225
   private boolean anywhere = false;
224 226

  
225
   /** Global ANYWHERE option, if given. */
226
   private boolean globalAnywhere = false;
227
   
228 227
   /** Trigger assigned to the event definition or -1 if this is an exit condition. */
229 228
   private int triggerId = -1;
230 229

  
......
253 252
      this.widgets        = widgets;
254 253
      this.resources      = resources;
255 254
      this.anywhere       = anywhere;
256
      this.globalAnywhere = (widgets == null && resources == null);
257 255
      
258 256
      events.forEach(evt -> this.events.add(EventList.eventCode(evt).intValue()));
259 257
   }
......
276 274
      this.widgets        = widgets;
277 275
      this.resources      = resources;
278 276
      this.anywhere       = anywhere;
279
      this.globalAnywhere = (widgets == null && resources == null);
280 277
   }
281 278
   
282 279
   /**
......
305 302
      
306 303
      this.event          = event;
307 304
      this.anywhere       = anywhere;
308
      this.globalAnywhere = ((widget == null || widget == WidgetId.INVALID_WIDGET_ID) &&
309
                             (resource == null || resource == ResourceIdHelper.INVALID_RESOURCE));
310 305
   }
311 306
   
312 307
   /**
......
335 330
      
336 331
      this.events         = events;
337 332
      this.anywhere       = anywhere;
338
      this.globalAnywhere = ((widget == null || widget == WidgetId.INVALID_WIDGET_ID) &&
339
                             (resource == null || resource == ResourceIdHelper.INVALID_RESOURCE));
340 333
   }
341 334
   
342 335
   /**
......
357 350
      this.widgets        = widgets;
358 351
      this.resources      = resources;
359 352
      this.anywhere       = anywhere;
360
      this.globalAnywhere = (widgets == null && resources == null);
361 353
   }
362 354
   
363 355
   /**
......
373 365
      copyResources(ed);
374 366
      
375 367
      this.anywhere       = ed.anywhere;
376
      this.globalAnywhere = ed.globalAnywhere;
377 368
      this.triggerId      = ed.triggerId;
378 369
   }
379 370
   
......
390 381
   EventDefinition(boolean anywhere, Integer widgetId, Integer event)
391 382
   {
392 383
      this.event   = event;
393
      this.widget  = widgetId;
384
      if (widgetId != null)
385
      {
386
         this.widget = widgetId;
387
      }
394 388
      this.anywhere = anywhere;
395 389
   }
396 390

  
......
407 401
   EventDefinition(boolean anywhere, Long resId, Integer event)
408 402
   {
409 403
      this.event    = event;
410
      this.resource = resId;
404
      if (resId != null)
405
      {
406
         this.resource = resId;
407
      }
411 408
      this.anywhere = anywhere;
412 409
   }
413 410

  
......
419 416
    */
420 417
   EventDefinition(Integer event)
421 418
   {
422
      this.event          = event;
423
      this.globalAnywhere = true;
419
      this.event    = event;
420
      this.anywhere = true;
424 421
   }
425 422
   
426 423
   /**
......
537 534
      if (anywhere != other.anywhere)
538 535
         return false;
539 536
         
540
      if (globalAnywhere != other.globalAnywhere)
541
         return false;
542
         
543 537
      return hasSameEvents(other) && hasSameWidgets(other) && hasSameResources(other);
544 538
   }
545 539
   
......
689 683
    */
690 684
   public boolean isAnywhereGlobally()
691 685
   {
692
      return globalAnywhere;
686
      return isAnywhere() && !hasResource() && !hasWidget();
693 687
   }
694 688

  
695 689
   /**
......
706 700
   }
707 701

  
708 702
   /**
709
    * Check if the given event name is part of this instance.
703
    * Check if the given event id is part of this instance.
710 704
    *
711
    * @param    name
705
    * @param    id
712 706
    *           The event ID to test.
713 707
    *
714
    * @return   <code>true</code> if the event has been defined for particular event name.
708
    * @return   <code>true</code> if the event has been defined for particular event id.
715 709
    */
716
   public boolean isEventMatch(Integer name)
710
   public boolean isEventMatch(Integer id)
717 711
   {
718
      if (name == null)
712
      if (id == null)
719 713
         return false;
720 714
      
721
      return (events != null && !events.isEmpty()) ? events.contains(name)
722
                                                   : event.equals(name);
715
      return (events != null && !events.isEmpty()) ? events.contains(id)
716
                                                   : event.equals(id);
723 717
   }
724 718

  
725 719
   /**
......
742 736
    */
743 737
   public boolean hasEvent()
744 738
   {
745
      return (events != null && !events.isEmpty()) || event != null;
739
      return event != null || (events != null && !events.isEmpty());
746 740
   }
747 741

  
748 742
   /**
......
752 746
    */
753 747
   public boolean hasWidget()
754 748
   {
755
      return (widgets != null && !widgets.isEmpty()) || widget != WidgetId.INVALID_WIDGET_ID;
749
      return widget != WidgetId.INVALID_WIDGET_ID || (widgets != null && !widgets.isEmpty());
756 750
   }
757 751

  
758 752
   /**
......
762 756
    */
763 757
   public boolean hasResource()
764 758
   {
765
      return (resources != null && !resources.isEmpty()) || resource != ResourceIdHelper.INVALID_RESOURCE;
759
      return resource != ResourceIdHelper.INVALID_RESOURCE || (resources != null && !resources.isEmpty());
766 760
   }
767 761

  
768 762
   /**
......
855 849
    * Checks whether this event matches any event defined in this <code>EventDefinition</code>
856 850
    * instance.
857 851
    *
858
    * @param    frameId
859
    *           Frame ID, can be <code>-1</code>.
860 852
    * @param    widgetId
861 853
    *           Widget ID to check or -1 if this is a global anywhere event.
862 854
    * @param    event
......
864 856
    * @param    isTrigger
865 857
    *           <code>true</code> if the search is for a trigger or <code>false</code> to 
866 858
    *           seach for an exit condition.
867
    * @param    specific
868
    *           <code>true</code> if an exact match is to be returned.
869
    * @param    universal
870
    *           <code>true</code> if the event is of the universal class.
871
    * @param    result
872
    *           On output both trigger ID and matched widget ID may be modified.  If no match
873
    *           was found, then the trigger ID will be set to -1.
859
    * @param    scope
860
    *           include only triggers without ANYWHERE (SELF), only ANYWHERE or both.
861
    * @return   returns trigger ID or -1 if no match was found.
874 862
    */
875
   public void lookup(int     frameId,
876
                      int     widgetId,
863
   public int lookup(int     widgetId,
877 864
                      Integer event,
878 865
                      boolean isTrigger,
879
                      boolean specific,
880
                      boolean universal,
881
                      TriggerMatch result)
866
                      int     scope)
882 867
   {
883
      result.matchedWidgetId = -1;
884

  
885 868
      // check the search type
886 869
      if (isTrigger && triggerId == -1)
887 870
      {
888 871
         // no match; not a trigger
889
         result.triggerId = -1;
890
         return;
872
         return -1;
891 873
      }
892 874

  
893 875
      if (!isTrigger && triggerId != -1)
894 876
      {
895 877
         // no match; not an exit condition
896
         result.triggerId = -1;
897
         return;
878
         return -1;
898 879
      }
899 880

  
900 881
      // check if the event is listed
901 882
      if (!isEventMatch(event))
902 883
      {
903
         result.triggerId = -1;
904
         return;
884
         return -1;
885
      }
886
      
887
      // check if anywhere scope is valid
888
      if ((scope & SCOPE_ANYWHERE) != SCOPE_ANYWHERE && anywhere) {
889
         return -1;
890
      }
891
      
892
      // check if widget only scope is valid
893
      if ((scope & SCOPE_SELF) != SCOPE_SELF && !anywhere) {
894
         return -1;
905 895
      }
906 896

  
907 897
      // check global anywhere case
908
      if (globalAnywhere && widgetId == -1)
909
      {
910
         result.triggerId = isTrigger ? triggerId : 0;
911
         return;
912
      }
913

  
914
      if (!hasWidget() && widgetId != -1)
915
      {
916
         // no match; only global anywhere
917
         result.triggerId = -1;
918
         return;
919
      }
920

  
921
      if (widgetId == -1)
922
      {
923
         // no match; only specific widgets
924
         result.triggerId = -1;
925
         return;
898
      if (widgetId == -1 && anywhere && !hasWidget())
899
      {
900
         return isTrigger ? triggerId : 0;
926 901
      }
927 902

  
928 903
      // check specific widget
929
      if (isWidgetMatch(widgetId))
930
      {
931
         result.triggerId = isTrigger ? triggerId : 0;
932
         result.matchedWidgetId = widgetId;
933
         return;
934
      }
935

  
936
      if (specific && !anywhere) // exact match but if not anywhere
937
      {
938
         result.triggerId = -1;
939
         return;
940
      }
941

  
942
      // check anywhere within the frame
943
      if (!anywhere && !universal)
944
      {
945
         result.triggerId = -1;
946
         return;
947
      }
948

  
949
      // WARNING: This code can currently only run on the client due to direct references to ThinClient,
950
      //          Browse, TitledWindow, Window and Widget.
951
      Widget<?> w = ThinClient.getInstance().registry().getComponent(widgetId);
952
      Browse<?> parentBrowse = w != null ? (Browse<?>) w.parent(Browse.class) : null;
953
      if (parentBrowse != null)
954
      {
955
         // If an event occurs for an in-browse editor, and there is a trigger for the browse column, it
956
         // should be fired. But if there is not column trigger and there is an OF BROWSE br ANYWHERE trigger,
957
         // it should be fired instead. This case is handled here.
958
         int browseId = parentBrowse.getId().asInt();
959
         if (isWidgetMatch(browseId))
960
         {
961
            result.triggerId = isTrigger ? triggerId : 0;
962
            result.matchedWidgetId = browseId;
963
            return;
964
         }
965
      }
966

  
967
      if (frameId != -1)
968
      {
969
         if (isWidgetMatch(frameId))
970
         {
971
            result.triggerId = isTrigger ? triggerId : 0;
972
            result.matchedWidgetId = frameId;
973
            return;
974
         }
975
      }
976
      else
977
      {
978
         TitledWindow<?> winInFocus = UiUtils.getCurrentFocusWindow();
979
         if (winInFocus instanceof Window && winInFocus.getId().asInt() == widgetId)
980
         {
981
            // added events propagation from window to its frames
982
            Widget<?>[] topComps = UiUtils.getTopLevelComponents((Window<?>) winInFocus);
983
            
984
            for (Widget<?> widget : topComps)
985
            {
986
               if (widget.getId() != null && isWidgetMatch(widget.getId().asInt()))
987
               {
988
                  result.triggerId = isTrigger ? triggerId : 0;
989
                  result.matchedWidgetId = widget.getId().asInt();
990
                  return;
991
               }
992
            }
993
         }
994
         else
995
         {
996
            // determine the frame ID based on given widget ID, consider parent frames as well
997
            for (Integer parentFrameId : UiUtils.getParentFrames(widgetId))
998
            {
999
               if (isWidgetMatch(parentFrameId))
1000
               {
1001
                  result.triggerId = isTrigger ? triggerId : 0;
1002
                  result.matchedWidgetId = parentFrameId;
1003
                  return;
1004
               }
1005
            }
1006
         }
1007
      }
1008

  
1009
      result.triggerId = -1;
904
      if (widgetId != -1 && isWidgetMatch(widgetId))
905
      {
906
         return isTrigger ? triggerId : 0;
907
      }
908

  
909
      return -1;
1010 910
   }
1011 911

  
1012 912
   /**
......
1065 965
         return false;                      // not an exit condition
1066 966
      }
1067 967

  
1068
      // check global anywhere case
1069
      if (globalAnywhere)
1070
      {
1071
         return false;                      // not an exit condition
1072
      }
1073

  
1074 968
      // check specific widget
1075 969
      return isWidgetMatch(widgetId);
1076 970
   }
......
1385 1279
      EventDefinition ned = new EventDefinition();
1386 1280
      ned.anywhere        = anywhere;
1387 1281
      ned.triggerId       = triggerId;
1388
      ned.globalAnywhere  = globalAnywhere;
1389 1282
      
1390 1283
      eventsIntersection(ed, ned);
1391 1284
      widgetsIntersection(ed, ned);
......
1606 1499
      if (ned1.hasEvent())
1607 1500
      {
1608 1501
         ned1.anywhere       = anywhere;
1609
         ned1.globalAnywhere = globalAnywhere;
1610 1502
         ned1.triggerId      = triggerId;
1611 1503
      
1612 1504
         widgetsIntersection(ed, ned1);
......
1622 1514
      if (ned2.hasWidget() || ned2.hasResource())
1623 1515
      {
1624 1516
         ned2.anywhere       = anywhere;
1625
         ned2.globalAnywhere = globalAnywhere;
1626 1517
         ned2.triggerId      = triggerId;
1627 1518
      
1628 1519
         ned2.copyEvents(this);
......
1723 1614
      boolean resourceSet  = (state & MASK_RESOURCE_SET) == MASK_RESOURCE_SET;
1724 1615
      
1725 1616
      anywhere             = (state & MASK_ANYWHERE) == MASK_ANYWHERE;
1726
      globalAnywhere       = (state & MASK_GLOBAL_ANYWHERE) == MASK_GLOBAL_ANYWHERE;
1727 1617
      
1728 1618
      triggerId = in.readInt();
1729 1619
      
......
1796 1686
      if (hasResources)   state |= MASK_HAS_RESOURCE;
1797 1687
      if (resourceSet)    state |= MASK_RESOURCE_SET;
1798 1688
      if (anywhere)       state |= MASK_ANYWHERE;
1799
      if (globalAnywhere) state |= MASK_GLOBAL_ANYWHERE;
1800 1689
      
1801 1690
      out.writeByte(state);
1802 1691
      out.writeInt(triggerId);
......
1847 1736
   public String toString()
1848 1737
   {
1849 1738
      return String.format("EventDefinition { events %s; widgets %s; resources %s; anywhere %b;" +
1850
                           " globalAnywhere %b; trigger id %d }",
1739
                           " trigger id %d }",
1851 1740
                           events != null && !events.isEmpty() ? toString(events) : "[" + toString(event) + "]",
1852 1741
                           widgets != null && !widgets.isEmpty()
1853 1742
                              ? widgets.toString()
......
1860 1749
                                 ? "[]" 
1861 1750
                                 : "[" + Long.toString(resource) + "]",
1862 1751
                           anywhere,
1863
                           globalAnywhere,
1864 1752
                           triggerId);
1865 1753
   }
1866 1754
   
......
2040 1928
         }
2041 1929
      }
2042 1930
         
2043
      if (globalAnywhere)
1931
      if (isAnywhereGlobally())
2044 1932
      {
2045 1933
         atoms.add(new EventDefinition(name));
2046 1934
      }
new/src/com/goldencode/p2j/ui/EventList.java 2022-10-03 06:41:28 +0000
165 165
**     ME  20220907          Rework lookupEventHelper to consider function key, any-printable, any-key for key
166 166
**                           events (in that order), first for specific widget then anywhere and last the frame.
167 167
**     CA  20220907          Added isEventMatchForWidget.
168
**     ME  20220928          Clean-up lookupEventHandler, reduce recursive calls.
169
**         20221003          Build events bitmap and resolve function key code in lookupWorker, avoid looping 
170
**                           through widget's parents chain if there is no event registered for the code.
168 171
*/
169 172

  
170 173
/*
......
233 236

  
234 237
import com.goldencode.p2j.ui.chui.ThinClient;
235 238
import com.goldencode.p2j.ui.client.*;
236
import com.goldencode.p2j.ui.client.event.*;
237 239
import com.goldencode.p2j.ui.client.widget.*;
238 240
import com.goldencode.p2j.util.*;
239 241

  
......
291 293
   /** List of event definitions */
292 294
   private List<EventDefinition> events = new ArrayList<>();
293 295

  
294
   /** The new order of events according to EventsPriorityComparator built on the client side*/
295
   private EventIndex[] order;
296
   
297 296
   /** Chain of event lists (not transferred via network).  */
298 297
   private EventList chain = null;
299 298
   
......
739 738
   }
740 739
   
741 740
   /**
742
    * Calculates new order of events according to EventsPriorityComparator.
743
    * 
744
    * @param    events
745
    *           The original list of event definition.
746
    * 
747
    * @return   The new order of events.
748
    */
749
   public static EventIndex[] calculatesEventsPriority(List<EventDefinition> events)
750
   {
751
      // The first commented method approximately performs 2*events.size()*log(events.size()) comparisons
752
      
753
//      PriorityQueue<EventIndex> copy = new PriorityQueue<EventList.EventIndex>(new EventsPriorityComparator(events));
754
//      for (int i = 0; i < events.size(); i++)
755
//      {
756
//         EventIndex eventIndex = new EventIndex();
757
//         eventIndex.id = i;
758
//         copy.add(eventIndex);
759
//      }
760
//      
761
//      EventIndex[] order = new EventIndex[copy.size()];
762
//      int i = 0;
763
//      while (!copy.isEmpty())
764
//      {
765
//         order[i++] = copy.poll();
766
//      }
767
      // The second method can be faster according to the java doc because it takes advantages of the almost sorted array.
768
      EventIndex[] order = new EventIndex[events.size()];
769
      for (int k = 0; k < events.size(); k++)
770
      {
771
         EventIndex eventIndex = new EventIndex();
772
         eventIndex.id = k;
773
         order[k] = eventIndex;
774
      }
775
     
776
      Arrays.sort(order, new EventsPriorityComparator(events));
777
      
778
      return order;
779
   }
780

  
781
   /**
782 741
    * Calculate the event or key code for this event name.
783 742
    * 
784 743
    * @param    name
......
1859 1818
    * {@link #lookup(int, int, boolean, boolean, boolean, TriggerMatch)} with
1860 1819
    * <code>specificWidget</code> set to <code>false</code>.
1861 1820
    *
1862
    * @param    fid
1863
    *           Frame ID, can be <code>-1</code>
1821
    * @param    cid
1822
    *           Parent container ID, can be <code>-1</code>
1864 1823
    * @param    wid
1865 1824
    *           widget ID, can't be <code>-1</code>, but can be <code>SESSION_WINDOW_ID</code>.
1866 1825
    * @param    trigger
......
1874 1833
    *           For more information see
1875 1834
    *           {@link #lookup(int, int, boolean, boolean, boolean, TriggerMatch)}.
1876 1835
    */
1877
   public void lookup(int fid, int wid, boolean trigger, boolean isKey, TriggerMatch result)
1836
   public void lookup(int cid, int wid, boolean trigger, boolean isKey, TriggerMatch result)
1878 1837
   {
1879
      lookup(fid, wid, trigger, isKey, false, result);
1838
      lookup(cid, wid, trigger, isKey, false, result);
1880 1839
   }
1881 1840

  
1882 1841
   /**
......
1924 1883
    * <br>
1925 1884
    * If the widget is the session window, only the first step is taken.
1926 1885
    *
1927
    * @param    fid
1928
    *           Frame ID, can be <code>-1</code>
1886
    * @param    cid
1887
    *           Parent container ID, can be <code>-1</code>
1929 1888
    * @param    wid
1930 1889
    *           widget ID, can't be <code>-1</code>, but can be <code>SESSION_WINDOW_ID</code>.
1931 1890
    * @param    trigger
......
1934 1893
    * @param    isKey
1935 1894
    *           Marks real key pressed by user.
1936 1895
    * @param    specificWidget
1937
    *           When <code>true</code> only the specific widget events are lsearched, i.e.
1896
    *           When <code>true</code> only the specific widget events are searched, i.e.
1938 1897
    *           anywhere, session window, etc. are ignored.
1939 1898
    * @param    result
1940 1899
    *           On input this contains the numeric event code that is the subject of the search.
......
1944 1903
    *           given event code in the case of ANY-KEY or ANY-PRINTABLE).  For exit conditions,
1945 1904
    *           the trigger ID will be the found event index when it is found.
1946 1905
    */
1947
   public void lookup(int fid, int wid, boolean trigger, boolean isKey,
1906
   public void lookup(int cid, int wid, boolean trigger, boolean isKey,
1948 1907
                      boolean specificWidget, TriggerMatch result)
1949 1908
   {
1950
      lookupWorker(fid, wid, trigger, isKey, specificWidget, result);
1909
      lookupWorker(cid, wid, trigger, isKey, specificWidget, result);
1951 1910

  
1952 1911
      if (result.triggerId == -1 && chain != null)
1953 1912
      {
1954
         chain.lookup(fid, wid, trigger, isKey, result);
1913
         chain.lookup(cid, wid, trigger, isKey, result);
1955 1914
      }
1956 1915
   }
1957 1916

  
......
2576 2535
   /**
2577 2536
    * Worker routine for {@link #lookup(int, int, boolean, boolean, TriggerMatch)}.
2578 2537
    * 
2579
    * @param    fid
2580
    *           Frame ID, can be <code>-1</code>.
2538
    * @param    cid
2539
    *           Parent container ID, can be <code>-1</code>.
2581 2540
    * @param    wid
2582 2541
    *           Widget ID, can't be <code>-1</code>, but can be <code>SESSION_WINDOW_ID</code>.
2583 2542
    * @param    trig
......
2596 2555
    *           given event code in the case of ANY-KEY or ANY-PRINTABLE).  For exit conditions,
2597 2556
    *           the trigger ID will be the found event index when it is found.
2598 2557
    */
2599
   private void lookupWorker(int fid, int wid, boolean trig, boolean isKey,
2558
   private void lookupWorker(int cid, int wid, boolean trig, boolean isKey,
2600 2559
                             boolean specificWidget, TriggerMatch result)
2601 2560
   {
2602
      LookupWidgetKey key = new LookupWidgetKey(fid, wid, trig, isKey, specificWidget, result.eventId);
2561
      LookupWidgetKey key = new LookupWidgetKey(cid, wid, trig, isKey, specificWidget, result.eventId);
2603 2562
      if (lookupWidgets == null)
2604 2563
      {
2605 2564
         lookupWidgets = new HashMap<>();
......
2616 2575
      {
2617 2576
         // obtain the event name and class
2618 2577
         String event = Keyboard.eventName(result.eventId);
2619
         boolean universal = EventDefinition.isEventUniversal(result.eventId);
2620 2578
         
2621 2579
         // convert the event name to the proper case
2622 2580
         String ev = setCase(event);
2623 2581
         // convert the label to a key code, alternate labels are honored here 
2624 2582
         int code = Keyboard.keyCode(ev);
2625 2583
         
2626
         //calculates new priority order of events
2627
         order = calculatesEventsPriority(events);
2628
         
2629 2584
         // is this a valid label?
2630
         if (code != -1)
2585
         if (code != -1 && code != result.eventId)
2631 2586
         {
2632 2587
            // yes, it was a label so now convert the common code to the primary label name
2633 2588
            String primary = Keyboard.keyLabel(code); 
......
2641 2596
                                           " could not be resolved!");
2642 2597
         }
2643 2598
         
2644
         // lookup event for a specific widget and honor any-printable/any-key if needed
2645
         lookupEventHelper(-1, wid, evCode, trig, true, false, isKey, result);
2646
         
2647
         if (result.triggerId != -1)
2648
         {
2649
            return;
2650
         }
2651
   
2652
         if (specificWidget)
2653
         {
2654
            return;
2655
         }
2656
   
2657
         // lookup event for a anywhere in the frame and honor any-printable/any-key if needed
2658
         lookupEventHelper(fid, wid, evCode, trig, false, universal, isKey, result);
2659
         
2660
         if (result.triggerId != -1)
2599
         int functionCode = isKey ? Keyboard.eventCode(Keyboard.keyFunction(evCode)) : -1;
2600
         boolean isPrintable = isKey && Keyboard.isPrintable(ev);
2601
         
2602
         if (eventCodes == null)
2603
         {
2604
            eventCodes = new RoaringBitmap();
2605
            events.forEach(evt -> evt.gatherEventCodes(eventCodes));
2606
         }
2607

  
2608
         // avoid looking-up the same event for all parent's chain if none defined
2609
         if (!eventCodes.contains(evCode)
2610
                  && (!isKey || !hasEventForKey(evCode, functionCode, isPrintable)))
2611
         {
2612
            return;
2613
         }
2614

  
2615
         // lookup event for the widget and honor any-printable/any-key if needed (specific or anywhere)
2616
         if (lookupEventHelper(wid, evCode, functionCode, trig,
2617
                  EventDefinition.SCOPE_SELF | EventDefinition.SCOPE_ANYWHERE, isKey, isPrintable,
2618
                  result) != -1 || specificWidget)
2619
         {
2620
            return;
2621
         }
2622

  
2623
         // lookup event for the parent container and honor any-printable/any-key if needed (anywhere only)
2624
         if (cid != -1 && lookupEventHelper(cid, evCode, functionCode, trig,
2625
                  EventDefinition.SCOPE_ANYWHERE, isKey, isPrintable, result) != -1)
2661 2626
         {
2662 2627
            result.matchedWidgetId = wid;
2663 2628
            return;
2664 2629
         }
2665 2630
         
2666
         // look the list up for the specified event and the containing frame
2667
         if (!trig || universal)
2668
         {
2669
            for (EventDefinition ed : events)
2670
            {
2671
               ed.lookup(-1, fid, evCode, trig, true, false, result);
2672
               if (result.triggerId != -1)
2673
               {
2674
                  result.matchedWidgetId = fid;
2675
                  return;
2676
               }
2677
            }
2678
         }
2679

  
2680 2631
         ThinClient tc = ThinClient.getInstance();
2681 2632
         Widget<?> widget = tc.getWidget(wid);
2682 2633
         
......
2685 2636
            List<Frame<?>> parentFrames = UiUtils.getParentFrames(widget);
2686 2637
            
2687 2638
            // search the target trigger through parent frames
2688
            for (Frame<?> frame  : parentFrames)
2639
            Frame<?> rootFrame = null;
2640
            for (Frame<?> frame : parentFrames)
2689 2641
            {
2690 2642
               int id = frame.getId().asInt();
2691
               
2692
               if (id != wid && id != fid && frame.isVisible() && !frame.hidden())
2693
               {
2694
                  lookupEventHelper(id, wid, evCode, trig, true, false, isKey, result);
2695
               }
2696
               
2697
               if (result.triggerId != -1)
2643

  
2644
               if (id != wid && id != cid && frame.isVisible() && !frame.hidden()
2645
                        && lookupEventHelper(id, evCode, functionCode, trig,
2646
                                 EventDefinition.SCOPE_ANYWHERE, isKey, isPrintable,
2647
                                 result) != -1)
2698 2648
               {
2699 2649
                  result.matchedWidgetId = wid;
2700 2650
                  return;
2701 2651
               }
2652
               
2653
               if (frame.isRootFrame()) 
2654
               {
2655
                  rootFrame = frame;
2656
               }
2702 2657
            }
2703
            
2704
            TopLevelWindow<?> win = null;
2705
            Frame<?> rootFrame =  UiUtils.locateRootFrame(widget);
2658

  
2706 2659
            if (rootFrame != null)
2707 2660
            {
2661
               TopLevelWindow<?> win = null;
2662
               
2708 2663
               if (rootFrame.isDialog())
2709 2664
               {
2710 2665
                  // for dialog-box, consider parent windows only if its top-level window is not visible
......
2714 2669
                     int parentId = rootFrame.config().parentId;
2715 2670
                     if (WidgetId.INVALID_WIDGET_ID != parentId)
2716 2671
                     {
2717
                        Widget parent = tc.getWidget(parentId);
2672
                        Widget parent = ThinClient.getInstance().getWidget(parentId);
2718 2673
                        if (parent instanceof TopLevelWindow)
2719 2674
                        {
2720 2675
                           win = (TopLevelWindow<?>) parent;
......
2726 2681
               {
2727 2682
                  win = rootFrame.topLevelWindow();
2728 2683
               }
2729
            }
2730
            else if (widget instanceof TopLevelWindow)
2731
            {
2732
               win = (TopLevelWindow<?>) widget;
2733
            }
2734

  
2735
            // search the target trigger in the window parent hierarchy up recursively
2736
            while (win != null && win.config() != null)
2737
            {
2738
               // note that the target window doesn't need to be visible (except dialog-box, but visible
2739
               // dialog-box should not reach this code block)
2740
               int winid = win.getId().asInt();
2741
               // lookup event for a specific widget and honor any-printable/any-key if needed
2742
               lookupEventHelper(rootFrame == null ? -1 : rootFrame.getId().asInt(),
2743
                                 winid, evCode, trig, true, false, isKey, result);
2744

  
2745
               if (result.triggerId != -1)
2684
               
2685
               // search the target trigger in the window parent hierarchy up recursively
2686
               while (win != null && win.config() != null)
2746 2687
               {
2747
                  result.matchedWidgetId = winid;
2748
                  break;
2688
                  // note that the target window doesn't need to be visible (except dialog-box, but visible
2689
                  // dialog-box should not reach this code block)
2690
                  int id = win.getId().asInt();
2691
                  if (id != wid && id != cid
2692
                           && lookupEventHelper(win.getId().asInt(), evCode, functionCode, trig,
2693
                                    EventDefinition.SCOPE_ANYWHERE, isKey, isPrintable,
2694
                                    result) != -1)
2695
                  {
2696
                     return;
2697
                  }
2698

  
2699
                  BaseConfig c = win.config();
2700
                  win = (TopLevelWindow<?>) tc.getWidget(c.parentId);
2749 2701
               }
2750

  
2751
               BaseConfig c = win.config();
2752
               win = (TopLevelWindow<?>) tc.getWidget(c.parentId);
2753 2702
            }
2703
            
2754 2704
         }
2755
         
2756
         if (result.triggerId != -1)
2757
            return;
2758
         
2759 2705
         // lookup event for a anywhere globally and honor any-printable/any-key if needed
2760
         lookupEventHelper(-1, -1, evCode, trig, false, false, isKey, result);
2761
         
2762
         if (result.triggerId != -1)
2763
            return;
2706
         lookupEventHelper(-1, evCode, functionCode, trig, EventDefinition.SCOPE_ANYWHERE, isKey,
2707
                  isPrintable, result);
2764 2708
      }
2765 2709
      finally
2766 2710
      {
......
2862 2806
    * and then upon an ANY-PRINTABLE event and finally upon an ANY-KEY event. The first
2863 2807
    * match aborts further checking.
2864 2808
    *
2865
    * @param    fid
2866
    *           Frame ID, can be <code>-1</code>.
2867 2809
    * @param    wid
2868 2810
    *           Widget ID to check or -1 if this is a global anywhere event.
2869 2811
    * @param    evCode
......
2871 2813
    * @param    trigger  
2872 2814
    *           <code>true</code> if the search is for a trigger or <code>false</code> to 
2873 2815
    *           search for an exit condition.
2874
    * @param    specific
2875
    *           <code>true</code> if an exact match is to be returned.
2876
    * @param    universal
2877
    *           <code>true</code> if the event is of the universal class.
2816
    * @param    scope
2817
    *           include only triggers without ANYWHERE (SELF), only ANYWHERE or both.
2878 2818
    * @param    isKey
2879 2819
    *           <code>true</code> if the event was generated from the keyboard, which will
2880
    *           cause the ANY-PRINTABLE/ANY-KEY events to be checked.
2820
    *           cause the ANY-KEY events to be checked.
2821
    *  @param   isPrintable
2822
    *           <code>true</code> if the event was generated by a printable keyboard, which will
2823
    *           cause the ANY-PRINTABLE events to be checked.
2881 2824
    * @param    result
2882 2825
    *           On input this contains the numeric event code that is the subject of the search.
2883 2826
    *           On output both the event code and the trigger id may be modified.  If no match
......
2886 2829
    *           given event code in the case of ANY-KEY or ANY-PRINTABLE).  For exit conditions,
2887 2830
    *           the trigger ID will be the found event index when it is found.
2888 2831
    */
2889
   private void lookupEventHelper(int          fid,
2890
                                  int          wid,
2891
                                  Integer      evCode,
2892
                                  boolean      trigger,
2893
                                  boolean      specific,
2894
                                  boolean      universal,
2895
                                  boolean      isKey,
2896
                                  TriggerMatch result)
2832
   private int lookupEventHelper(int            wid,
2833
                                 int            evCode,
2834
                                 int            functionCode,
2835
                                 boolean        trigger,
2836
                                 int            scope,
2837
                                 boolean        isKey,
2838
                                 boolean        isPrintable,
2839
                                 TriggerMatch   result)
2897 2840
   {
2898
      lookupEventHelper(fid, wid, evCode, trigger, specific, universal, isKey, false, result);
2841
      // array for trigger ids matching in order: 
2842
      // 0 - key function
2843
      // 1 - any-printable
2844
      // 2 - any-key
2845
      // 3 - key label anywhere
2846
      // 4 - key function anywhere
2847
      // 5 - any-printable anywhere
2848
      // 6 - any-key anywhere
2849
      int[] matches = new int[] { -1, -1, -1, -1, -1, -1, -1};
2850
      
2851
      // look the list up for the specified event and widget 
2852
      for (EventDefinition ed: events)
2853
      {
2854
         int triggerId = ed.lookup(wid, evCode, trigger, scope);
2855
         
2856
         if (triggerId != -1) {
2857
            if (!ed.isAnywhere()) 
2858
            {
2859
               // exact match
2860
               result.triggerId = triggerId;
2861
               
2862
               return triggerId;
2863
            }
2864
            else 
2865
            {
2866
               matches[3] = triggerId; // key label anywhere
2867
            }
2868
         }
2869
         else if (isKey)
2870
         {
2871
            // key function: 0 - widget, 4 - anywhere
2872
            // if already have a match for widget no point on testing further
2873
            if (functionCode != -1 && functionCode != evCode && matches[0] == -1)
2874
            {
2875
               triggerId = ed.lookup(wid, functionCode, trigger, scope);
2876
               
2877
               if (triggerId != -1) {
2878
                  matches[ed.isAnywhere() ? 4 : 0] = triggerId;
2879
               }
2880
            }
2881

  
2882
            // any-printable: 1 - widget, 5 - anywhere
2883
            // if already have a match for widget no point on testing further
2884
            if (isPrintable && evCode != Keyboard.SE_ANY_PRINTABLE && matches[0] == -1
2885
                     && matches[1] == -1 && (matches[5] == -1 || !ed.isAnywhere()))
2886
            {
2887
               triggerId = ed.lookup(wid, Keyboard.SE_ANY_PRINTABLE, trigger, scope);
2888

  
2889
               if (triggerId != -1)
2890
               {
2891
                  matches[ed.isAnywhere() ? 5 : 1] = triggerId;
2892
               }
2893
            }
2894

  
2895
            // any-key: 2 - widget, 6 - anywhere
2896
            // if already have a match for widget no point on testing further
2897
            if (evCode != Keyboard.SE_ANY_KEY && matches[0] == -1 && matches[1] == -1
2898
                     && matches[2] == -1 && (matches[6] == -1 || !ed.isAnywhere()))
2899
            {
2900
               triggerId = ed.lookup(wid, Keyboard.SE_ANY_KEY, trigger, scope);
2901

  
2902
               if (triggerId != -1)
2903
               {
2904
                  matches[ed.isAnywhere() ? 6 : 2] = triggerId;
2905
               }
2906
            }
2907
         }
2908
      }
2909
               
2910
      
2911
      // no exact match
2912
      for (int i = 0; i < matches.length; i++)
2913
      {
2914
         if (matches[i] != -1) {
2915
            result.triggerId = matches[i];
2916
            return matches[i];
2917
         }
2918
      }
2919
      
2920
      return -1;
2899 2921
   }
2900 2922
   
2901 2923
   /**
2902
    * Handles an event definition lookup for all known events and then it may also try the
2903
    * same lookup for ANY-PRINTABLE and ANY-KEY events, depending on the properties of the
2904
    * original event.  This will match first on a specific event match (e.g. the letter "A"
2905
    * and then upon an ANY-PRINTABLE event and finally upon an ANY-KEY event. The first
2906
    * match aborts further checking.
2907
    *
2908
    * @param    fid
2909
    *           Frame ID, can be <code>-1</code>.
2910
    * @param    wid
2911
    *           Widget ID to check or -1 if this is a global anywhere event.
2912
    * @param    evCode
2913
    *           The event ID.
2914
    * @param    trigger  
2915
    *           <code>true</code> if the search is for a trigger or <code>false</code> to 
2916
    *           search for an exit condition.
2917
    * @param    specific
2918
    *           <code>true</code> if an exact match is to be returned.
2919
    * @param    universal
2920
    *           <code>true</code> if the event is of the universal class.
2921
    * @param    isKey
2922
    *           <code>true</code> if the event was generated from the keyboard, which will
2923
    *           cause the ANY-PRINTABLE/ANY-KEY events to be checked.
2924
    * @param    isKeyFunction
2925
    *           <code>true</code> if the event is for a key function, as opposed to key label.
2926
    * @param    result
2927
    *           On input this contains the numeric event code that is the subject of the search.
2928
    *           On output both the event code and the trigger id may be modified.  If no match
2929
    *           was found, then the trigger ID will be set to -1.  For trigger searches, this is
2930
    *           the matching trigger ID and matched event code (which may be different from the
2931
    *           given event code in the case of ANY-KEY or ANY-PRINTABLE).  For exit conditions,
2932
    *           the trigger ID will be the found event index when it is found.
2924
    * Check if there is any event definition for a specific keyboard key.
2925
    * 
2926
    * @param evCode  the key label code
2927
    * @param functionCode the key function code
2928
    * @param isPrintable flag for printable key
2929
    * @return <code>true</code> if an event for the keyboard key is registered
2933 2930
    */
2934
   private void lookupEventHelper(int          fid,
2935
                                  int          wid,
2936
                                  Integer      evCode,
2937
                                  boolean      trigger,
2938
                                  boolean      specific,
2939
                                  boolean      universal,
2940
                                  boolean      isKey,
2941
                                  boolean      isKeyFunction,
2942
                                  TriggerMatch result)
2931
   private boolean hasEventForKey(int evCode, int functionCode, boolean isPrintable)
2943 2932
   {
2944 2933
      if (eventCodes == null)
2945 2934
      {
......
2947 2936
         events.forEach(evt -> evt.gatherEventCodes(eventCodes));
2948 2937
      }
2949 2938

  
2950
      if (!eventCodes.contains(evCode)
2951
               && (!isKey || (!eventCodes.contains(Keyboard.SE_ANY_PRINTABLE)
2952
                        && !eventCodes.contains(Keyboard.SE_ANY_KEY))))
2953
      {
2954
         return;
2955
      }
2956

  
2957
      // look the list up for the specified event and widget 
2958
      for (EventDefinition ed: events)
2959
      {
2960
         // do not use parent frame here, instead use the same widget id
2961
         ed.lookup(wid, wid, evCode, trigger, specific, universal, result);
2962
         
2963
         // if found check for widget match or default trigger
2964
         if (result.triggerId != -1 && (!specific || !ed.isAnywhere())
2965
                  && (wid == -1 || ed.isWidgetMatch(wid)))
2966
         {
2967
            return;
2968
         }
2969
      }
2970
               
2971
      
2972
      // keyboard only, look for "function key" then "any printable" and "any key" as needed
2973
      if (isKey && evCode != Keyboard.SE_ANY_KEY) {
2974
         // honor "function key" event (must be before ANY-PRINTABLE)
2975
         if (!isKeyFunction && evCode != Keyboard.SE_ANY_PRINTABLE)
2976
         {
2977
            int functionCode = Keyboard.eventCode(Keyboard.keyFunction(evCode));
2978
            
2979
            if (functionCode != -1 && !evCode.equals(functionCode))
2980
            {
2981
               lookupEventHelper(fid, wid, functionCode, trigger, specific, universal, isKey, true, result);
2982
               
2983
               if (result.triggerId != -1)
2984
               {
2985
                  result.eventId = functionCode;
2986
                  
2987
                  return;
2988
               }
2989
            }
2990
         }
2991

  
2992
         // honor ANY-PRINTABLE event (must be before ANY-KEY)
2993
         if (evCode != Keyboard.SE_ANY_PRINTABLE)
2994
         {
2995
            if (Keyboard.isPrintable(Keyboard.eventName(evCode)))
2996
            {
2997
               lookupEventHelper(fid, wid, Keyboard.SE_ANY_PRINTABLE, trigger, specific, universal, isKey, true, result);
2998
               
2999
               if (result.triggerId != -1)
3000
               {
3001
                  result.eventId = Keyboard.SE_ANY_PRINTABLE;
3002
                  
3003
                  return;
3004
               }
3005
            }
3006
            
3007
            // look for ANY-KEY
3008
            if (result.eventId != Key.VK_ALT && result.eventId != Key.VK_CTRL
3009
                     && result.eventId != Key.VK_SHIFT)
3010
            {
3011
               
3012
               lookupEventHelper(fid, wid, Keyboard.SE_ANY_KEY, trigger, specific, universal, isKey, true, result);
3013
               
3014
               if (result.triggerId != -1)
3015
               {
3016
                  result.eventId = Keyboard.SE_ANY_KEY;
3017
                  
3018
                  return;
3019
               }
3020
            }
3021
         }
3022
      }
3023
      
3024
      // if specific trigger wasn't found fallback to anywhere for the widget
3025
      if (specific)
3026
      {
3027
         lookupEventHelper(fid, wid, evCode, trigger, false /* anywhere */, universal, isKey, isKeyFunction, result);
3028
      }
3029
      else
3030
      {
3031
         // lookup for parent frame triggers
3032
         if (fid != -1 && fid != wid)
3033
         {
3034
            lookupEventHelper(fid, fid, evCode, trigger, false /* anywhere */, universal, isKey, isKeyFunction, result);
3035
            
3036
            // reset back the widget id
3037
            if (result.triggerId != -1)
3038
            {
3039
               result.matchedWidgetId = wid;
3040
            }
3041
         }
3042
      }
3043
      
2939
      return eventCodes.contains(evCode)
2940
               || (functionCode != -1 && eventCodes.contains(functionCode))
2941
               || (isPrintable && eventCodes.contains(Keyboard.SE_ANY_PRINTABLE))
2942
               || eventCodes.contains(Keyboard.SE_ANY_KEY);
3044 2943
   }
3045 2944
   
3046 2945
   /**
......
3053 2952
      this.lookupWidgets = null;
3054 2953
      this.eventCodes = null;
3055 2954
   }
3056
   
3057
   /**
3058
    * Defines new priority event order based on the natural linear order of events. EventList 1 and EventList 2 are
3059
    * always comparable. If they have the different events, then their order positions are not changed.
3060
    * If they have the same events, then their order positions are swapped if each associated widget from the first list
3061
    * have at least one of its parents in the second event list. This new order is also a linear order. 
3062
    */
3063
   private static class EventsPriorityComparator
3064
   implements Comparator<EventIndex>
3065
   {
3066
      private final List<EventDefinition> events;
3067
      
3068
      public EventsPriorityComparator(List<EventDefinition> events)
3069
      {
3070
         this.events = events;
3071
      }
3072
      
3073
      @Override
3074
      public int compare(EventIndex o1, EventIndex o2)
3075
      {
3076
         if (o1.id != o2.id)
3077
         {
3078
            EventDefinition o1Event = events.get(o1.id);
3079
            EventDefinition o2Event = events.get(o2.id);
3080
            if (o1Event != null && !o1Event.isSame(o2Event) && o1Event.hasSameEvents(o2Event))
3081
            {
3082
               final boolean[] collector = new boolean[] {true, false}; 
3083
               o1Event.processWidgets((Integer wid) ->
3084
               {
3085
                  if (o2Event != null && collector[0])
3086
                  {
3087
                     Iterator<Integer> parentFramesIter = new ClientFrameIterator(wid.intValue());
3088
                     boolean contains = false;
3089
                     while(parentFramesIter.hasNext())
3090
                     {
3091
                        Integer pfid = parentFramesIter.next();
3092
                        if (o2Event.containsWidget(pfid))
3093
                        {
3094
                           contains = true;
3095
                           break;
3096
                        }
3097
                     };
3098
                     collector[0] = collector[0] && contains;
3099
                     collector[1] = collector[0];
3100
                  }
3101
               });
3102
               if (collector[1])
3103
               {
3104
                  if (o2.id <= o1.id) // swap if o2.id before o1.id 
3105
                  {
3106
                     return o2.id - o1.id;
3107
                  }
3108
               }
3109
            }
3110
         }
3111
         
3112
         return o1.id - o2.id;
3113
      }
3114
   }
3115
   
3116
   /**
3117
    * Defines the client side frame iterator.
3118
    */
3119
   public static class ClientFrameIterator
3120
   implements Iterator<Integer>
3121
   {     
3122
      private Widget curr;
3123
      private Frame frame;
3124
      
3125
      /**
3126
       * Creates this iterator over the parent's hierarchy of the given widget.
3127
       * 
3128
       * @param    wid
3129
       *           The given widget id
3130
       */
3131
      public ClientFrameIterator(int wid)
3132
      {
3133
         curr = ThinClient.getInstance().getWidget(wid);
3134
      }
3135
      
3136
      /**
3137
       * Returns true if the iteration has more elements.
3138
       *
3139
       * @return   True if the iteration has more elements, otherwise false.
3140
       */
3141
      @Override
3142
      public boolean hasNext()
3143
      {
3144
         frame = UiUtils.locateFrame(curr);
3145
         
3146
         return (frame != null);
3147
      }
3148

  
3149
      /**
3150
       * Returns the next element in the iteration.
3151
       *
3152
       * @return   The next element in the iteration, or WidgetId.INVALID_WIDGET_ID if there is no 
3153
       *           such element.
3154
       */
3155
      @Override
3156
      public Integer next()
3157
      {
3158
         if (frame == null)
3159
         {
3160
            frame = UiUtils.locateFrame(curr);
3161
         }
3162
         
3163
         if (curr != null)
3164
         {
3165
            curr = curr.parent();
3166
         }
3167
         
3168
         if (frame != null)
3169
         {
3170
            return frame.getId().asInt();
3171
         }
3172
         else
3173
         {
3174
            return WidgetId.INVALID_WIDGET_ID;
3175
         }
3176
      }
3177
   }
3178
   
2955
      
3179 2956
   /**
3180 2957
    * Defines the index of the original event definition within its events list.
3181 2958
    */
new/src/com/goldencode/p2j/ui/chui/ThinClient.java 2022-09-30 08:12:59 +0000
2856 2856
**     EVL 20220913          Fix for regression in non date fill-ins with screen value getting.
2857 2857
**      HC 20220915          Performance: Eliminated integer auto-boxing when enqueuing widget attributes.
2858 2858
**      CA 20220918          Allow legacy client sockets to be ran on FWD server instead of FWD client.
2859
**      ME 20220920          Use widget parent 'container' when looking up triggers.
2859 2860
*/
2860 2861

  
2861 2862
/*
......
17253 17254
         // assume no trigger is found
17254 17255
         moreKeys = true;
17255 17256

  
17256
         Frame frame = UiUtils.locateFrame(focused);
17257
         Widget container = UiUtils.locateContainer(focused);
17257 17258
         int focusId = UiUtils.lookupWidgetIdAsInt(focused);
17258
         int frameId = UiUtils.lookupWidgetIdAsInt(frame);
17259
         int containerId = UiUtils.lookupWidgetIdAsInt(container);
17259 17260
         
17260 17261
         TriggerMatch result = new TriggerMatch(key.keyCode());
17261 17262

  
17262 17263
         // check if there is a trigger for this specific key
17263
         currentEventList.lookup(frameId, focusId, true, true, result);
17264
         currentEventList.lookup(containerId, focusId, true, true, result);
17264 17265
         
17265 17266
         if (result.triggerId == -1)
17266 17267
         {
......
17272 17273
               result = new TriggerMatch(defaultEvent);
17273 17274
               
17274 17275
               // check if there is a trigger for this default event
17275
               currentEventList.lookup(frameId, focusId, true, true, result);
17276
               currentEventList.lookup(containerId, focusId, true, true, result);
17276 17277
               
17277 17278
               // only if there is no other more specific match AND there is a match to 
17278 17279
               // a system event, do we call invoke
......
20606 20607
      // in the event list for an active user interface trigger
20607 20608
      if (key > 0 && key != KeyInput.CHAR_UNDEFINED && evt.id() != EventType.KEY_RELEASED)
20608 20609
      {
20609
         tr = invokeTriggers(src, key, false);
20610
         tr = invokeTriggers(src, key, evt.isRealKey());
20610 20611

  
20611 20612
         if (tr.executed)
20612 20613
         {
......
21626 21627
      }
21627 21628
      else if (!WidgetId.virtualWidget(widgetId))
21628 21629
      {
21629
         currentEventList.lookup(frameId, widgetId, true, isKey, result);
21630
         Widget container = UiUtils.locateContainer(widget);
21631
         
21632
         currentEventList.lookup(container != null && container != frame ? UiUtils.getWidgetIdAsInt(container) : frameId, widgetId, true, isKey, result);
21630 21633
      }
21631 21634

  
21632 21635
      // activate trigger
......
26153 26156
   /**
26154 26157
    * Applies widget attributes in the widget tree.
26155 26158
    *
26156
    * @param   widgetAttrs
26159
    * @param   widgetAttrsIds
26157 26160
    *          Flat array of widget attribute ids.
26158 26161
    * @param   widgetAttrValues
26159 26162
    *          Flat array of widget attribute values.
new/src/com/goldencode/p2j/ui/client/UiUtils.java 2022-10-01 18:01:08 +0000
110 110
**         20220527 Improved error logging.
111 111
**     IAS 20220803 Fixed loop condition in 'resolveLocalFileResource'.
112 112
**     EVL 20220809 Fixed issue with buildCanonicalUrl() on Windows server installation.
113
**     ME  20220928 Added two methods to get widget container and top level window.
113 114
*/
114 115

  
115 116
/*
......
807 808
   }
808 809

  
809 810
   /**
811
    * Return the widget which contains the specified widget. Most of the time this going to be the 
812
    * frame containing the widget except for the browse column where the container is the browse. 
813
    *
814
    * @param    widget
815
    *           Widget for which to find the container.
816
    *
817
    * @return   The container widget which contains specified widget, or <code>null</code>
818
    *           if <code>null</code> is passed as the parameter or the widget 
819
    *           is not placed in a container. 
820
    */
821
   public static Widget<?> locateContainer(Widget<?> widget)
822
   {
823
      if (widget == null)
824
      {
825
         return null;
826
      }
827

  
828
      if (!(widget instanceof Frame))
829
      {
830
         // check if parent is a browse (browse column)
831
         Browse<?> browse = widget.parent(Browse.class);
832
         
833
         if (browse != null)
834
         {
835
            return browse;
836
         }
837
      }
838
      
839
      return locateFrame(widget);
840
   }
841
   
842
   /**
810 843
    * Return the root frame which contains the specified widget. If the given 
811 844
    * widget is itself a root frame, then it will be returned.
812 845
    *