17
17
18
18
package stroom .xmlschema .client .presenter ;
19
19
20
+ import stroom .alert .client .event .AlertEvent ;
21
+ import stroom .alert .client .event .ConfirmEvent ;
22
+ import stroom .dispatch .client .RestFactory ;
20
23
import stroom .docref .DocRef ;
21
24
import stroom .editor .client .presenter .EditorPresenter ;
22
25
import stroom .entity .client .presenter .AbstractTabProvider ;
26
29
import stroom .entity .client .presenter .MarkdownEditPresenter ;
27
30
import stroom .entity .client .presenter .MarkdownTabProvider ;
28
31
import stroom .security .client .presenter .DocumentUserPermissionsTabProvider ;
32
+ import stroom .svg .client .SvgPresets ;
33
+ import stroom .svg .shared .SvgImage ;
34
+ import stroom .widget .button .client .SvgButton ;
29
35
import stroom .widget .tab .client .presenter .TabData ;
30
36
import stroom .widget .tab .client .presenter .TabDataImpl ;
31
37
import stroom .widget .xsdbrowser .client .presenter .XSDBrowserPresenter ;
32
38
import stroom .widget .xsdbrowser .client .view .XSDModel ;
33
39
import stroom .xmlschema .shared .XmlSchemaDoc ;
40
+ import stroom .xmlschema .shared .XmlSchemaResource ;
41
+ import stroom .xmlschema .shared .XmlSchemaValidationResponse ;
34
42
43
+ import com .google .gwt .core .client .GWT ;
44
+ import com .google .gwt .user .client .Timer ;
35
45
import com .google .inject .Inject ;
36
46
import com .google .web .bindery .event .shared .EventBus ;
37
47
import com .gwtplatform .mvp .client .PresenterWidget ;
38
48
import edu .ycp .cs .dh .acegwt .client .ace .AceEditorMode ;
39
49
50
+ import java .util .function .Consumer ;
40
51
import javax .inject .Provider ;
41
52
42
53
public class XMLSchemaPresenter extends DocumentEditTabPresenter <LinkTabPanelView , XmlSchemaDoc > {
43
54
55
+ private static final XmlSchemaResource XML_SCHEMA_RESOURCE = GWT .create (XmlSchemaResource .class );
56
+
57
+ private static final String VALID = "Schema is valid" ;
58
+ private static final String INVALID = "Schema is invalid" ;
59
+
60
+ private static final int VALIDATION_DEBOUNCE_MS = 300 ;
44
61
private static final TabData SETTINGS = new TabDataImpl ("Settings" );
45
62
private static final TabData GRAPHICAL = new TabDataImpl ("Graphical" );
46
63
private static final TabData TEXT = new TabDataImpl ("Text" );
47
64
private static final TabData DOCUMENTATION = new TabDataImpl ("Documentation" );
48
65
private static final TabData PERMISSIONS = new TabDataImpl ("Permissions" );
49
66
67
+ private final RestFactory restFactory ;
50
68
private XSDBrowserPresenter xsdBrowserPresenter ;
51
69
private EditorPresenter codePresenter ;
52
70
private final XSDModel data = new XSDModel ();
53
71
private boolean updateDiagram ;
72
+ private XmlSchemaValidationResponse validationResponse =
73
+ new XmlSchemaValidationResponse (true , null );
74
+ private final SvgButton validationIndicator ;
75
+ private final Timer validationDebounceTimer ;
54
76
55
77
@ Inject
56
78
public XMLSchemaPresenter (final EventBus eventBus ,
@@ -59,9 +81,27 @@ public XMLSchemaPresenter(final EventBus eventBus,
59
81
final Provider <XSDBrowserPresenter > xsdBrowserPresenterProvider ,
60
82
final Provider <EditorPresenter > codePresenterProvider ,
61
83
final Provider <MarkdownEditPresenter > markdownEditPresenterProvider ,
62
- final DocumentUserPermissionsTabProvider <XmlSchemaDoc >
63
- documentUserPermissionsTabProvider ) {
84
+ final DocumentUserPermissionsTabProvider <XmlSchemaDoc > documentUserPermissionsTabProvider ,
85
+ final RestFactory restFactory ) {
64
86
super (eventBus , view );
87
+ this .restFactory = restFactory ;
88
+
89
+ validationIndicator = SvgButton .create (SvgPresets .ALERT );
90
+ validationIndicator .setSvg (SvgImage .OK );
91
+ validationIndicator .setTitle (VALID );
92
+ toolbar .addButton (this .validationIndicator );
93
+
94
+ this .validationDebounceTimer = new Timer () {
95
+ @ Override
96
+ public void run () {
97
+ // Call the server validation endpoint. The result consumer runs on success.
98
+ validateSchema (result -> {
99
+ validationResponse = result ;
100
+ // Update state and UI on the UI thread.
101
+ updateValidationIndicator ();
102
+ });
103
+ }
104
+ };
65
105
66
106
addTab (GRAPHICAL , new AbstractTabProvider <XmlSchemaDoc , XSDBrowserPresenter >(eventBus ) {
67
107
@ Override
@@ -85,11 +125,6 @@ protected EditorPresenter createPresenter() {
85
125
return codePresenter ;
86
126
}
87
127
88
- @ Override
89
- protected void onBind () {
90
- super .onBind ();
91
- }
92
-
93
128
@ Override
94
129
public void onRead (final EditorPresenter presenter ,
95
130
final DocRef docRef ,
@@ -101,6 +136,10 @@ public void onRead(final EditorPresenter presenter,
101
136
registerHandler (presenter .addValueChangeHandler (event -> {
102
137
setDirty (true );
103
138
updateDiagram = true ;
139
+
140
+ // Kick off debounce validation
141
+ validationDebounceTimer .cancel ();
142
+ validationDebounceTimer .schedule (VALIDATION_DEBOUNCE_MS );
104
143
}));
105
144
}
106
145
}
@@ -133,6 +172,40 @@ public XmlSchemaDoc onWrite(final MarkdownEditPresenter presenter,
133
172
selectTab (GRAPHICAL );
134
173
}
135
174
175
+ @ Override
176
+ protected void onBind () {
177
+ super .onBind ();
178
+ registerHandler (validationIndicator .addClickHandler (e -> {
179
+ if (validationResponse .isOk ()) {
180
+ AlertEvent .fireInfo (this , VALID , null );
181
+ } else {
182
+ AlertEvent .fireWarn (this , validationResponse .getError (), null );
183
+ }
184
+ }));
185
+ }
186
+
187
+ private void validateSchema (final Consumer <XmlSchemaValidationResponse > consumer ) {
188
+ final String schemaText ;
189
+ if (codePresenter != null ) {
190
+ schemaText = codePresenter .getText ();
191
+ } else if (getEntity () != null ) {
192
+ schemaText = getEntity ().getData ();
193
+ } else {
194
+ schemaText = "" ;
195
+ }
196
+
197
+ final String payload = schemaText == null
198
+ ? ""
199
+ : schemaText .trim ();
200
+
201
+ restFactory
202
+ .create (XML_SCHEMA_RESOURCE )
203
+ .method (res -> res .validate (payload ))
204
+ .onSuccess (consumer )
205
+ .taskMonitorFactory (this )
206
+ .exec ();
207
+ }
208
+
136
209
@ Override
137
210
protected void afterSelectTab (final PresenterWidget <?> content ) {
138
211
if (content != null ) {
@@ -149,10 +222,24 @@ protected void afterSelectTab(final PresenterWidget<?> content) {
149
222
}
150
223
}
151
224
225
+ private void updateValidationIndicator () {
226
+ if (validationResponse .isOk ()) {
227
+ validationIndicator .setTitle (VALID );
228
+ validationIndicator .setSvg (SvgImage .OK );
229
+ } else {
230
+ validationIndicator .setTitle (INVALID );
231
+ validationIndicator .setSvg (SvgImage .ALERT );
232
+ }
233
+ }
234
+
152
235
@ Override
153
236
protected void onRead (final DocRef docRef , final XmlSchemaDoc doc , final boolean readOnly ) {
154
237
super .onRead (docRef , doc , readOnly );
155
238
data .setContents (doc .getData ());
239
+
240
+ // Even for read-only, validate once so the indicator is correct.
241
+ validationDebounceTimer .cancel ();
242
+ validationDebounceTimer .schedule (0 );
156
243
}
157
244
158
245
@ Override
@@ -169,4 +256,22 @@ protected TabData getPermissionsTab() {
169
256
protected TabData getDocumentationTab () {
170
257
return DOCUMENTATION ;
171
258
}
259
+
260
+ @ Override
261
+ public void save () {
262
+ validateSchema (result -> {
263
+ if (!result .isOk ()) {
264
+ ConfirmEvent .fire (this ,
265
+ "The XML schema appears to be invalid. Are you sure you want to save?" ,
266
+ confirmed -> {
267
+ if (confirmed ) {
268
+ super .save ();
269
+ }
270
+ }
271
+ );
272
+ } else {
273
+ super .save ();
274
+ }
275
+ });
276
+ }
172
277
}
0 commit comments