patch.6016.patch
new/src/com/goldencode/p2j/ui/ControlSetEntity.java 2022-02-01 14:31:53 +0000 | ||
---|---|---|
95 | 95 |
** RFB 20211022 Additional documentation to point out the empty string condition. Ref #4710. |
96 | 96 |
** HC 20211102 Implemented i18n support. |
97 | 97 |
** AL2 20220124 Make all control set entities to check for screen-value validity. |
98 |
** ME 20220201 Allow for multiple values list when setting screen-value (delimiter is used). |
|
98 | 99 |
*/ |
99 | 100 |
/* |
100 | 101 |
** This program is free software: you can redistribute it and/or modify |
... | ... | |
154 | 155 |
import java.util.*; |
155 | 156 |
import java.util.function.*; |
156 | 157 |
import java.util.regex.*; |
158 |
import java.util.stream.Collectors; |
|
159 |
import java.util.stream.Stream; |
|
157 | 160 | |
158 | 161 |
import com.goldencode.p2j.util.*; |
159 | 162 |
import com.goldencode.p2j.ui.client.format.*; |
... | ... | |
2853 | 2856 |
{ |
2854 | 2857 |
if (inUIStmt || !internalScreenValueUsage) |
2855 | 2858 |
{ |
2856 |
if (value instanceof character && !isValidScreenValue((character) value))
|
|
2859 |
if (value instanceof character && !validateScreenValue((character) value))
|
|
2857 | 2860 |
{ |
2858 |
if (_isRealized() && frame != null && |
|
2859 |
getAttr("wasRealized", () -> frame.getFrameWidget().config().wasRealized, true)) |
|
2860 |
{ |
|
2861 |
ErrorManager.recordOrShowError(4058, String.format( |
|
2862 |
"Attribute SCREEN-VALUE for the %s %s has an invalid value of %s", type(), |
|
2863 |
widgetName(), ((BaseDataType) value).isUnknown() ? "UNKNOWN" : value), false); |
|
2864 |
} |
|
2865 |
|
|
2866 | 2861 |
return false; |
2867 | 2862 |
} |
2868 | 2863 |
} |
... | ... | |
2870 | 2865 |
return super.setScreenValue(frameBuf, value, inUIStmt); |
2871 | 2866 |
} |
2872 | 2867 |
|
2868 |
/** |
|
2869 |
* Validate the value(s) for SCREEN-VALUE attribute, the delimiter is used |
|
2870 |
* to split it into an array. |
|
2871 |
* |
|
2872 |
* @param value |
|
2873 |
* The to be validated as SCREEN-VALUE attribute. |
|
2874 |
* |
|
2875 |
* @return <code>true</code> if the value is a valid screen-value. |
|
2876 |
*/ |
|
2877 |
boolean validateScreenValue(character value) |
|
2878 |
{ |
|
2879 |
if (!value.isUnknown()) |
|
2880 |
{ |
|
2881 |
char delimiter = getAttr("delimiter", () -> config.delimiter); |
|
2882 |
character[] values = TextOps.entries(character.class, value.getValue(), |
|
2883 |
String.valueOf(delimiter)); |
|
2884 | ||
2885 |
if (!isValidScreenValue(values)) |
|
2886 |
{ |
|
2887 |
if (_isRealized()) |
|
2888 |
{ |
|
2889 |
ErrorManager.recordOrShowWarning(4058, String.format( |
|
2890 |
"Attribute SCREEN-VALUE for the %s %s has an invalid value of %s", type(), |
|
2891 |
widgetName(), (value.isUnknown() ? "UNKNOWN" : value.getValue())), true, |
|
2892 |
false, false, true); |
|
2893 |
} |
|
2894 | ||
2895 |
return false; |
|
2896 |
} |
|
2897 |
} |
|
2898 | ||
2899 |
return true; |
|
2900 |
} |
|
2873 | 2901 |
|
2874 | 2902 |
/** |
2875 | 2903 |
* Check if the tested value is in the control-set values. |
... | ... | |
2881 | 2909 |
*/ |
2882 | 2910 |
protected boolean isValidScreenValue(character value) |
2883 | 2911 |
{ |
2884 |
if (value.isUnknown() || getAttr("items", () -> config.items) == null) |
|
2885 |
{ |
|
2886 |
return false; |
|
2887 |
} |
|
2888 |
|
|
2889 |
// test value |
|
2890 |
return Arrays.stream(getAttr("items", () -> config.items)).anyMatch(item -> item.getCharacterValue().equals(value)); |
|
2912 |
return isValidScreenValue(new character[] { value }); |
|
2913 |
} |
|
2914 |
|
|
2915 |
/** |
|
2916 |
* Check if the tested value(s) is in the control-set values. |
|
2917 |
* |
|
2918 |
* @param value |
|
2919 |
* The tested value(s) |
|
2920 |
* |
|
2921 |
* @return True if the tested value(s) is in the control-set values, otherwise false. |
|
2922 |
*/ |
|
2923 |
protected boolean isValidScreenValue(character... values) |
|
2924 |
{ |
|
2925 |
if (values == null || values.length == 0) |
|
2926 |
{ |
|
2927 |
return false; |
|
2928 |
} |
|
2929 |
|
|
2930 |
ControlSetItem[] items = getAttr("items", () -> config.items); |
|
2931 |
|
|
2932 |
if (items == null) |
|
2933 |
{ |
|
2934 |
return false; |
|
2935 |
} |
|
2936 |
|
|
2937 |
for (character value : values) |
|
2938 |
{ |
|
2939 |
if (!value.isUnknown() && !Arrays.stream(items).anyMatch(item -> CompareOps._isEqual(item.getCharacterValue(), value))) |
|
2940 |
{ |
|
2941 |
return false; |
|
2942 |
} |
|
2943 |
} |
|
2944 | ||
2945 |
return true; |
|
2891 | 2946 |
} |
2892 | 2947 |
|
2893 | 2948 |
/** |
new/src/com/goldencode/p2j/ui/SelectionListWidget.java 2022-02-02 06:52:36 +0000 | ||
---|---|---|
56 | 56 |
** VVT 20220120 Fixed: setting SCROLLBAR-HORIZONTAL and/or SCROLLBAR-VERTICAL for a realized |
57 | 57 |
** widget must be rejected with the warning 4053. See #5937-53. |
58 | 58 |
** AL2 20220124 Check screen-value validity through ControlSetEntity. |
59 |
** ME 20220201 Handle multiple values list in set screen-value. |
|
59 | 60 |
*/ |
60 | 61 |
/* |
61 | 62 |
** This program is free software: you can redistribute it and/or modify |
... | ... | |
112 | 113 | |
113 | 114 |
package com.goldencode.p2j.ui; |
114 | 115 | |
116 |
import java.util.Arrays; |
|
117 |
import java.util.Set; |
|
118 |
import java.util.stream.Collectors; |
|
119 | ||
115 | 120 |
import com.goldencode.p2j.util.*; |
116 | 121 | |
117 | 122 |
/** |
... | ... | |
908 | 913 |
@Override |
909 | 914 |
boolean setScreenValue(ScreenBuffer frameBuf, Object value, boolean inUIStmt) |
910 | 915 |
{ |
911 |
if (inUIStmt && frameBuf.getWidgetValue(getId()) != null) |
|
912 |
{ |
|
913 |
if (value == null || ( |
|
914 |
value instanceof BaseDataType && |
|
915 |
!(value instanceof character) && |
|
916 |
((BaseDataType) value).isUnknown())) |
|
916 |
if (!(value instanceof character)) |
|
917 |
{ |
|
918 |
// we can't set non-character value to selection list |
|
919 |
return false; |
|
920 |
} |
|
921 | ||
922 |
character cvalue = (character) value; |
|
923 | ||
924 |
if (!cvalue.isUnknown() && cvalue.toJavaType().length() == 0) |
|
925 |
{ |
|
926 |
cvalue.setUnknown(); |
|
927 |
} |
|
928 | ||
929 |
return super.setScreenValue(frameBuf, cvalue, inUIStmt); |
|
930 |
} |
|
931 |
|
|
932 |
/** |
|
933 |
* Validate the value(s) for SCREEN-VALUE attribute, the delimiter is used |
|
934 |
* to split it into an array. |
|
935 |
* |
|
936 |
* If valid the SCREEN-VALUE will be updated to reflect the resulting value. |
|
937 |
* |
|
938 |
* @param value |
|
939 |
* The to be validated as SCREEN-VALUE attribute. |
|
940 |
* |
|
941 |
* @return <code>true</code> if the value is a valid screen-value. |
|
942 |
*/ |
|
943 |
@Override |
|
944 |
boolean validateScreenValue(character value) |
|
945 |
{ |
|
946 |
if (super.validateScreenValue(value)) |
|
947 |
{ |
|
948 |
// if valid update the screen-value |
|
949 |
if (!value.isUnknown()) |
|
917 | 950 |
{ |
918 |
// we can set unknown value to character selection list |
|
919 |
return false; |
|
951 |
String delimiter = String.valueOf(getAttr("delimiter", () -> config.delimiter)); |
|
952 |
character[] values = TextOps.entries(character.class, value.getValue(), delimiter); |
|
953 |
ControlSetItem[] items = getAttr("items", () -> config.items); |
|
954 | ||
955 |
// resulting screen-value might be different due to: |
|
956 |
// - reorder based on item's index |
|
957 |
// - only first item with given value is selected (case insensitive) |
|
958 |
if (getAttr("multiple", () -> config.multiple)) |
|
959 |
{ |
|
960 |
// for multiple selection existing selection is kept (append) |
|
961 |
Set<Integer> selection = Arrays.stream(frame.getSelection(this)).map(i -> i + 1) |
|
962 |
.boxed().collect(Collectors.toSet()); |
|
963 | ||
964 |
for (character val : values) |
|
965 |
{ |
|
966 |
for (ControlSetItem item : items) |
|
967 |
{ |
|
968 |
if (CompareOps._isEqual(val, item.getCharacterValue())) |
|
969 |
{ |
|
970 |
selection.add(item.getItemId()); |
|
971 |
break; |
|
972 |
} |
|
973 |
} |
|
974 |
} |
|
975 | ||
976 |
character newValue = new character( |
|
977 |
Arrays.stream(items).filter(item -> selection.contains(item.getItemId())) |
|
978 |
.map(item -> item.getCharacterValue().getValue()) |
|
979 |
.collect(Collectors.joining(delimiter))); |
|
980 | ||
981 |
value.assign(newValue); |
|
982 |
} |
|
983 |
else |
|
984 |
{ |
|
985 |
// last value from the list win |
|
986 |
for (ControlSetItem item : items) |
|
987 |
{ |
|
988 |
if (CompareOps._isEqual(values[values.length - 1], item.getCharacterValue())) |
|
989 |
{ |
|
990 |
value.assign(item.getCharacterValue()); |
|
991 |
break; |
|
992 |
} |
|
993 |
} |
|
994 |
} |
|
920 | 995 |
} |
921 | 996 |
|
922 |
if (value instanceof character && |
|
923 |
((character) value).toJavaType().length() == 0) |
|
924 |
{ |
|
925 |
return false; |
|
926 |
} |
|
927 |
} |
|
928 |
|
|
929 |
if (!inUIStmt && |
|
930 |
value instanceof character && |
|
931 |
!((character) value).isUnknown() && |
|
932 |
((character) value).toJavaType().length() == 0) |
|
933 |
{ |
|
934 |
((character) value).setUnknown(); |
|
935 |
} |
|
936 |
|
|
937 |
return super.setScreenValue(frameBuf, value, inUIStmt); |
|
997 |
return true; |
|
998 |
} |
|
999 |
|
|
1000 |
return false; |
|
938 | 1001 |
} |
939 |
|
|
940 |
|
|
1002 | ||
941 | 1003 |
/** |
942 | 1004 |
* Check if the tested value is valid for screen-value. |
1005 |
* Unknown is a valid option as it will clear the selection. |
|
943 | 1006 |
* |
944 | 1007 |
* @param value |
945 | 1008 |
* The tested value |
946 | 1009 |
* |
947 | 1010 |
* @return True if the tested value is valid for screen-value, otherwise false. |
948 | 1011 |
*/ |
1012 |
@Override |
|
949 | 1013 |
protected boolean isValidScreenValue(character value) |
950 | 1014 |
{ |
951 | 1015 |
// it is valid to assign unknown to screen-value of a selection list widget |
new/src/com/goldencode/p2j/ui/client/SelectionList.java 2022-02-01 13:19:56 +0000 | ||
---|---|---|
72 | 72 |
** VVT 20220119 Minor annotation and javadoc fixes. |
73 | 73 |
** VVT 20220126 setSelectionMode() now returns boolean indicating any change was done |
74 | 74 |
** by the method call. See #5937. |
75 |
** ME 20220201 Force refresh on <code>afterConfigUpdate</code> if model is empty |
|
76 |
** (configuration items needs to be parsed during initialization). |
|
75 | 77 |
*/ |
76 | 78 |
/* |
77 | 79 |
** This program is free software: you can redistribute it and/or modify |
... | ... | |
480 | 482 | |
481 | 483 |
// 4gl API does allows only to replace all list items at once, which regenerates *all* item IDs. |
482 | 484 |
// As the result, it is sufficient to compare only the first item IDs here. |
483 |
needToResetView |= newItems[0].getItemId() != oldItems[0].getItemId(); |
|
485 |
needToResetView |= newItems[0].getItemId() != oldItems[0].getItemId() || list.model().size() == 0;
|
|
484 | 486 |
} |
485 | 487 | |
486 | 488 |
if (needToResetView) |
new/src/com/goldencode/p2j/ui/client/SelectionListBody.java 2022-02-01 13:17:24 +0000 | ||
---|---|---|
127 | 127 |
** toggleCurrentRowSelection(). selectItem() method is now unused and |
128 | 128 |
** removed. Method getDefaultEvent() overloaded. Several #5937 issues fixed. |
129 | 129 |
** Class members sorted. |
130 |
** ME 20220201 Handle multiple values list in set screen-value. |
|
130 | 131 |
*/ |
131 | 132 |
/* |
132 | 133 |
** This program is free software: you can redistribute it and/or modify |
... | ... | |
801 | 802 |
public void setValue(BaseDataType value) |
802 | 803 |
{ |
803 | 804 |
selected = false; |
804 |
initValue = new character(); |
|
805 |
|
|
806 | 805 |
boolean doRepaint = false; |
807 | 806 |
|
808 | 807 |
if (value.isUnknown()) |
809 |
return; |
|
810 |
|
|
811 |
selectionClear(); |
|
812 |
|
|
813 |
if (value instanceof character) |
|
814 | 808 |
{ |
815 |
String itemList = ((character) value).getValue(); |
|
816 |
|
|
817 |
char[] delim = new char[1]; |
|
818 |
delim[0] = config.delimiter; |
|
819 |
String d = new String(delim); |
|
820 |
|
|
821 |
String[] elem = itemList.split(d); |
|
822 |
|
|
823 |
boolean isChui = ThinClient.getInstance().isChui(); |
|
824 |
|
|
825 |
for (String element : elem) |
|
826 |
{ |
|
827 |
BaseDataType val = |
|
828 |
DisplayFormat.instanceOfType(isChui, config.dataType, element); |
|
829 |
|
|
830 |
if (setSingleValue(val)) |
|
831 |
doRepaint = true; |
|
832 |
} |
|
809 |
selectionClear(); |
|
810 |
doRepaint = true; |
|
833 | 811 |
} |
834 | 812 |
else |
835 |
doRepaint = setSingleValue(value); |
|
836 | ||
813 |
{ |
|
814 |
if (value instanceof character) |
|
815 |
{ |
|
816 |
String itemList = ((character) value).getValue(); |
|
817 |
|
|
818 |
char[] delim = new char[1]; |
|
819 |
delim[0] = config.delimiter; |
|
820 |
String d = new String(delim); |
|
821 |
|
|
822 |
String[] elem = itemList.split(d); |
|
823 |
|
|
824 |
boolean isChui = ThinClient.getInstance().isChui(); |
|
825 |
|
|
826 |
for (String element : elem) |
|
827 |
{ |
|
828 |
BaseDataType val = |
|
829 |
DisplayFormat.instanceOfType(isChui, config.dataType, element); |
|
830 |
|
|
831 |
if (setSingleValue(val)) |
|
832 |
doRepaint = true; |
|
833 |
} |
|
834 |
} |
|
835 |
else |
|
836 |
{ |
|
837 |
doRepaint = setSingleValue(value); |
|
838 |
} |
|
839 |
} |
|
840 |
|
|
837 | 841 |
if (doRepaint) |
838 | 842 |
{ |
839 | 843 |
repaint(); |
840 |
initValue = value;
|
|
844 |
initValue = getScreenValue();
|
|
841 | 845 |
} |
842 | 846 |
} |
843 | 847 |
|
... | ... | |
1105 | 1109 |
return false; |
1106 | 1110 |
} |
1107 | 1111 |
|
1108 |
boolean doRepaint = false; |
|
1112 |
if (selectionMode() == ListSelectionModel.SINGLE_SELECTION) |
|
1113 |
{ |
|
1114 |
selectionClear(); |
|
1115 |
} |
|
1109 | 1116 |
|
1110 | 1117 |
for (int i = 0; i < items.length; i++) |
1111 | 1118 |
{ |
... | ... | |
1113 | 1120 |
{ |
1114 | 1121 |
select(i,i); |
1115 | 1122 |
|
1116 |
if (first() >= 0)
|
|
1117 |
ensureRowVisible(first());
|
|
1123 |
if (i >= 0)
|
|
1124 |
ensureRowVisible(i);
|
|
1118 | 1125 |
|
1119 |
doRepaint = true; |
|
1126 |
// only first entry that matches the value is selected |
|
1127 |
return true; |
|
1120 | 1128 |
} |
1121 | 1129 |
} |
1122 | 1130 |
|
1123 |
return doRepaint;
|
|
1131 |
return false;
|
|
1124 | 1132 |
} |
1125 |
} |
|
1133 |
} |