6764.04.patch
new/src/com/goldencode/p2j/ui/EventDefinition.java 2022-10-11 10:02:22 +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 && isAnywhereGlobally()) |
|
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-11 10:02:22 +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 |
... | ... | |
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-10-11 10:02:22 +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-11 10:02:22 +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 |
* |