GSI Object Oriented Online Offline (Go4) GO4-6.4.0
Loading...
Searching...
No Matches
analysiseditor.mjs
Go to the documentation of this file.
1// $Id$
2
3import { httpRequest, BasePainter, createMenu, getHPainter, clone, d3_select } from 'jsroot';
4import { source_dir, executeMethod, GO4 } from './core.mjs';
5
6const EvIOType = {
7 GO4EV_NULL: 0, // no event store/source
8 GO4EV_FILE: 1, // root file with own tree
9 GO4EV_TREE: 2, // branch of singleton tree
10 GO4EV_MBS_FILE: 3, // mbs listmode file (input only)
11 GO4EV_MBS_STREAM: 4, // mbs stream server (input only)
12 GO4EV_MBS_TRANSPORT: 5, // mbs transport server (input only)
13 GO4EV_MBS_EVENTSERVER: 6, // mbs event server (input only)
14 GO4EV_MBS_REVSERV: 7, // remote event server (input only)
15 GO4EV_BACK: 8, // backstore in memory (pseudo-ringbuffer?)
16 GO4EV_USER: 9, // user defined source class
17 GO4EV_MBS_RANDOM: 10, // random generated mbs event
18 GO4EV_HDF5: 11 // HDF5 file format
19 };
20
21class AnalysisStatusEditor extends BasePainter {
22 constructor(dom, stat) {
23 super(dom);
24 this.stat = stat;
25 this.changes = [["dummy0", "init0"],["dummy1","init1"]]; // changes array stepwise, index 0 = no step, index = stepindex+1
26 this.clearChanges();
27 }
28
29 markChanged(key, step) {
30 // first avoid duplicate keys:
31 for (let index = 0; index < this.changes[step].length; index++) {
32 if (this.changes[step][index]== key) return;
33 }
34 this.changes[step].push(key);
35 console.log("Mark changed :%s at step %d", key, step);
36
37 this.selectDom().select(".buttonAnaChangeLabel").style('display', null); // show warning sign
38 }
39
40 // clear changed elements' list, make warning sign invisible
41 clearChanges() {
42 let numsteps = this.changes.length;
43 for (let step = 0; step < numsteps ; step++)
44 this.changes[step] = [];
45 this.selectDom().select(".buttonAnaChangeLabel").style('display', 'none'); // hide warning sign
46 }
47
48 /** @summary scan changed value list and return optionstring to be send to server */
49 evaluateChanges(optionstring) {
50 let editor = this;
51 let numsteps = this.changes.length;
52 for (let step = 0; step < numsteps ; step++) {
53 let theElement = editor.stat.fxStepArray.arr[step],
54 stepoptions = "",
55 len = this.changes[step].length;
56
57 for (let index = 0; index < len ; index++) {
58
59 let key = this.changes[step][index],
60 preifx = `&${key}=`,
61 step_prefix = `&${key}_${step}=`;
62
63 // here mapping of key to editor field:
64 if (key == "stepenabled") {
65 stepoptions += step_prefix + theElement.fbProcessEnabled;
66 } else if (key == "sourceenabled") {
67 stepoptions += step_prefix + theElement.fbSourceEnabled;
68 } else if (key == "storeenabled") {
69 stepoptions += step_prefix + theElement.fbStoreEnabled;
70 } else if (key == "sourcesel") {
71 stepoptions += step_prefix + theElement.fxSourceType.fiID;
72 } else if (key == "sourcename") {
73 stepoptions += step_prefix + theElement.fxSourceType.fName;
74 } else if (key == "sourcetag") {
75 stepoptions += step_prefix + theElement.fxSourceType.fxTagFile;
76 } else if (key == "sourceport") {
77 stepoptions += step_prefix + theElement.fxSourceType.fiPort;
78 } else if (key == "sourcetmout") {
79 stepoptions += step_prefix + theElement.fxSourceType.fiTimeout;
80 } else if (key == "sourceretry") {
81 stepoptions += step_prefix + theElement.fxSourceType.fiRetryCnt;
82 } else if (key == "sourcefirst") {
83 stepoptions += step_prefix + theElement.fxSourceType.fuStartEvent;
84 } else if (key == "sourcelast") {
85 stepoptions += step_prefix + theElement.fxSourceType.fuStopEvent;
86 } else if (key == "sourceskip") {
87 stepoptions += step_prefix + theElement.fxSourceType.fuEventInterval;
88 } else if (key == "storesel") {
89 stepoptions += step_prefix + theElement.fxStoreType.fiID;
90 } else if (key == "storename") {
91 stepoptions += step_prefix + theElement.fxStoreType.fName;
92 } else if (key == "storesplit") {
93 stepoptions += step_prefix + theElement.fxStoreType.fiSplit;
94 } else if (key == "storebuf") {
95 stepoptions += step_prefix + theElement.fxStoreType.fiBufsize;
96 } else if (key == "storecomp") {
97 stepoptions += step_prefix + theElement.fxStoreType.fiCompression;
98 } else if (key == "storeasf") {
99 stepoptions += step_prefix + theElement.fxStoreType.fiAutosavesize;
100 } else if (key == "storeover") {
101 stepoptions += step_prefix + theElement.fxStoreType.fbOverwrite;
102 }
103 // non step specific options are in step 0 options too:
104 else if (key == "asfname") {
105 stepoptions += preifx + editor.stat.fxAutoFileName;
106 } else if (key == "asfenabled") {
107 stepoptions += preifx + editor.stat.fbAutoSaveOn;
108 } else if (key == "asftime") {
109 stepoptions += preifx + editor.stat.fiAutoSaveInterval;
110 } else if (key == "asfcomp") {
111 stepoptions += preifx + editor.stat.fiAutoSaveCompression;
112 } else if (key == "asfoverwrite") {
113 stepoptions += preifx + editor.stat.fbAutoSaveOverwrite;
114 } else if (key == "anaprefsname") {
115 stepoptions += preifx + editor.stat.fxConfigFileName;
116 } else {
117 console.log(`Warning: evaluateChanges found unknown key: ${key}`);
118 }
119
120 }// for index
121
122 optionstring += stepoptions;
123 } // for step
124 console.log("Resulting option string:%s", optionstring);
125 return optionstring;
126 }
127
128 showStepEditor(tab, theElement, theIndex) {
129
130 let sourcebox = tab.select(".step_box_source_enab"),
131 storebox = tab.select(".step_box_store_enab"),
132 step_source = tab.select(".step_source"),
133 step_store = tab.select(".step_store"),
134 sourcemore = tab.select(".step_source_expand");
135
136 // here step control checkboxes and source/store visibility:
137 if (theElement.fbProcessEnabled) {
138 sourcebox.attr('disabled', null);
139 storebox.attr('disabled', null);
140 step_source.attr('disabled', theElement.fbSourceEnabled ? null : "true");
141 step_store.style('display', theElement.fbStoreEnabled ? null : "none");
142 } else {
143 sourcebox.attr('disabled', "true");
144 storebox.attr('disabled', "true");
145 step_source.attr('disabled', "true");
146 step_store.style('display', "none");
147 }
148
149 let show_tag = false, show_ports = false, show_args = false, show_more = sourcemore.property("checked");
150
151 switch (theElement.fxSourceType.fiID) {
152 case EvIOType.GO4EV_MBS_FILE:
153 show_tag = show_args = show_more; break;
154 case EvIOType.GO4EV_MBS_STREAM:
155 case EvIOType.GO4EV_MBS_TRANSPORT:
156 case EvIOType.GO4EV_MBS_EVENTSERVER:
157 case EvIOType.GO4EV_MBS_REVSERV:
158 show_ports = show_args = show_more; break;
159 case EvIOType.GO4EV_USER:
160 show_ports = show_more; break;
161 case EvIOType.GO4EV_FILE:
162 case EvIOType.GO4EV_MBS_RANDOM:
163 default:
164 // show no extra parameters
165 break;
166 };
167
168 tab.select(".step_source_tagfile_args").style('display', show_tag ? null : 'none');
169 tab.select(".step_source_port_args").style('display', show_ports ? null : 'none');
170 tab.select(".step_source_number_args").style('display', show_args ? 'inline' : 'none');
171
172 let enbale_store_pars = false, enbale_store_name = true;
173 switch (theElement.fxStoreType.fiID) {
174 case EvIOType.GO4EV_FILE:
175 enbale_store_pars = true;
176 break;
177 case EvIOType.GO4EV_BACK:
178 enbale_store_pars = true;
179 enbale_store_name = false;
180 break;
181 case EvIOType.GO4EV_USER:
182 break;
183 default:
184 break;
185 };
186
187 tab.select(".step_store_pars").selectAll("input").each(function() {
188 d3_select(this).attr("disabled", enbale_store_pars ? null : "true");
189 });
190
191 tab.select(".step_store_name").attr("disabled", enbale_store_name ? null : "true");
192 }
193
194 fillEditor() {
195 let dom = this.selectDom(),
196 stat = this.stat;
197
198 let head_html = "", step_html = "";
199 stat.fxStepArray.arr.forEach((step, indx) => {
200 head_html += `<button for="go4_analysis_step_${indx}">${step.fName}</button>`;
201 step_html += `<div class="go4_analysis_step_${indx}" style="display:none">${this.stepPageHtml}</div>`;
202 });
203
204 dom.select(".ana_step_tabs_header").html(head_html);
205
206 dom.select(".ana_step_tabs_body").html(step_html);
207
208 // assign tabs buttons handlers
209 dom.select('.ana_step_tabs_header').selectAll("button").on("click", function() {
210 let btn = d3_select(this);
211
212 dom.select('.ana_step_tabs_header').selectAll("button").each(function() {
213 d3_select(this).classed("active_btn", false);
214 });
215
216 btn.classed("active_btn", true);
217
218 dom.selectAll('.ana_step_tabs_body>div').each(function() {
219 let tab = d3_select(this);
220 tab.style('display', tab.classed(btn.attr("for")) ? null : "none");
221 });
222 });
223
224 // activate first step
225 dom.select(".ana_step_tabs_body").select(".go4_analysis_step_0").style('display', null);
226 dom.select('.ana_step_tabs_header').select("button").classed("active_btn", true);
227
228 stat.fxStepArray.arr.forEach((theElement, theIndex) => {
229 let tab = dom.select(".ana_step_tabs_body").select(`.go4_analysis_step_${theIndex}`);
230
231 let enablebox = tab.select(".step_box_step_enab"),
232 sourcebox = tab.select(".step_box_source_enab"),
233 storebox = tab.select(".step_box_store_enab"),
234 sourcesel = tab.select(".step_source_select"),
235 sourcemore = tab.select(".step_source_expand"),
236 sourcename = tab.select(".step_source_name"),
237 sourcetag = tab.select(".step_source_tagfile"),
238 sourceport = tab.select(".step_source_port"),
239 sourcetmout = tab.select(".step_source_tmout"),
240 sourceretry = tab.select(".step_source_retry"),
241 sourcefirst = tab.select(".step_source_firstev"),
242 sourcelast = tab.select(".step_source_lastev"),
243 sourceskip = tab.select(".step_source_stepev"),
244 storesel = tab.select(".step_store_select"),
245 storename = tab.select(".step_store_name"),
246 storesplit = tab.select(".step_store_split"),
247 storebuf = tab.select(".step_store_buf"),
248 storecomp = tab.select(".step_store_comp"),
249 storetreeasf = tab.select(".step_store_asf"),
250 storeover = tab.select(" .step_store_overwrite");
251
252 enablebox.property('checked', theElement.fbProcessEnabled)
253 .on("click", () => {
254 this.markChanged("stepenabled", theIndex);
255 theElement.fbProcessEnabled = enablebox.property('checked');
256 this.showStepEditor(tab, theElement, theIndex);
257 }); // clickfunction
258
259 sourcebox.property('checked', theElement.fbSourceEnabled)
260 .on("click", () => {
261 this.markChanged("sourceenabled", theIndex);
262 theElement.fbSourceEnabled = sourcebox.property('checked');
263 this.showStepEditor(tab, theElement, theIndex);
264 }); // clickfunction
265
266 storebox.property('checked', theElement.fbStoreEnabled)
267 .on("click", () => {
268 this.markChanged("storeenabled", theIndex);
269 theElement.fbStoreEnabled = storebox.property('checked');
270 this.showStepEditor(tab, theElement, theIndex);
271 }); // clickfunction
272
273 //// EVENT SOURCE: /////////////////////////////////////////////////
274 sourcesel.property("value", theElement.fxSourceType.fiID).on("change", () => {
275 this.markChanged("sourcesel", theIndex);
276
277 theElement.fxSourceType.fiID = parseInt(sourcesel.property("value"));
278
279 this.showStepEditor(tab, theElement, theIndex);
280 }); // source selectmenu change
281
282 sourcemore.on("click", () => {
283 this.showStepEditor(tab, theElement, theIndex);
284 });
285
286 sourcename.property("value", theElement.fxSourceType.fName)
287 .on("change", () => {
288 this.markChanged("sourcename", theIndex);
289 theElement.fxSourceType.fName = sourcename.property("value").trim();
290 });
291
292 sourcetag.property("value", theElement.fxSourceType.fxTagFile || "")
293 .on("change", () => {
294 this.markChanged("sourcetag", theIndex);
295 theElement.fxSourceType.fxTagFile = sourcetag.property("value").trim();
296 });
297
298 sourceport.property("value", theElement.fxSourceType.fiPort || 0)
299 .on("change", () => {
300 this.markChanged("sourceport", theIndex);
301 theElement.fxSourceType.fiPort = parseInt(sourceport.property("value"));
302 });
303
304 sourcetmout.property("value", theElement.fxSourceType.fiTimeout || 100)
305 .on("change", () => {
306 this.markChanged("sourcetmout", theIndex);
307 theElement.fxSourceType.fiTimeout = parseInt(sourcetmout.property("value"));
308 });
309
310 sourceretry.property("value", theElement.fxSourceType.fiRetryCnt || 0)
311 .on("change", () => {
312 this.markChanged("sourceretry", theIndex);
313 theElement.fxSourceType.fiRetryCnt = parseInt(sourceretry.property("value"));
314 });
315
316 sourcefirst.property("value", theElement.fxSourceType.fuStartEvent || 0)
317 .on("change", () => {
318 this.markChanged("sourcefirst", theIndex);
319 theElement.fxSourceType.fuStartEvent = parseInt(sourcefirst.property("value"));
320 });
321
322 sourcelast.property("value", theElement.fxSourceType.fuStopEvent || 0)
323 .on("change", () => {
324 this.markChanged("sourcelast", theIndex);
325 theElement.fxSourceType.fuStopEvent = parseInt(sourcelast.property("value"));
326 });
327
328 sourceskip.property("value", theElement.fxSourceType.fuEventInterval || 0)
329 .on("change", () => {
330 this.markChanged("sourceskip", theIndex);
331 theElement.fxSourceType.fuEventInterval = parseInt(sourceskip.property("value"));
332 });
333
334 storesel.property("value", theElement.fxStoreType.fiID).on("change", () => {
335 this.markChanged("storesel", theIndex);
336 theElement.fxStoreType.fiID = parseInt(storesel.property("value"));
337 this.showStepEditor(tab, theElement, theIndex);
338 });
339
340 storename.property("value", theElement.fxStoreType.fName)
341 .on("change", () => {
342 this.markChanged("storename", theIndex);
343 theElement.fxStoreType.fName = storename.property("value").trim();
344 });
345
346 storesplit.property("value", theElement.fxStoreType.fiSplit || 1)
347 .on("change", () => {
348 theElement.fxStoreType.fiSplit = parseInt(storesplit.property("value"));
349 this.markChanged("storesplit", theIndex);
350 });
351
352 storebuf.property("value", Math.round((theElement.fxStoreType.fiBufsize || 16*1024) / 1024))
353 .on("change", () => {
354 theElement.fxStoreType.fiBufsize = parseInt(storebuf.property("value")) * 1024;
355 this.markChanged("storebuf", theIndex);
356 });
357
358 storecomp.property("value", theElement.fxStoreType.fiCompression || 0)
359 .on("change", () => {
360 theElement.fxStoreType.fiCompression = parseInt(storecomp.property("value"));
361 this.markChanged("storecomp", theIndex);
362 });
363
364 storetreeasf.property("value", theElement.fxStoreType.fiAutosavesize || 0)
365 .on("change", () => {
366 theElement.fxStoreType.fiAutosavesize = parseInt(storetreeasf.property("value"));
367 this.markChanged("storeasf", theIndex);
368 });
369
370 storeover.property("checked", theElement.fxStoreType.fbOverwrite || true)
371 .on("click", () => {
372 theElement.fxStoreType.fbOverwrite = storeover.property("checked");
373 this.markChanged("storeover", theIndex);
374 });
375
376 this.showStepEditor(tab, theElement, theIndex); // handle all visibility issues here, also refresh tabs
377
378 }); // steps loop
379
380 dom.select(".buttonGetAnalysis")
381 .style('background-image', `url(${source_dir}icons/right.png)`)
382 .on("click", () => {
383 getHPainter()?.display(this.getItemName());
384 });
385
386 dom.select(".buttonSetAnalysis")
387 .style('background-image', `url(${source_dir}icons/left.png)`)
388 .on("click", () => {
389 let options = this.evaluateChanges(""); // complete option string from all changed elements
390 console.log("submit analysis " + this.getItemName() + ", options=" + options);
391 executeMethod(this, "UpdateFromUrl", options).then(() => {
392 console.log("setting analyis configuration done.");
393 this.clearChanges();
394 getHPainter()?.reload();
395 });
396 });
397
398 dom.select(".buttonAnaChangeLabel")
399 .style('background-image', `url(${source_dir}icons/info1.png)`)
400 .style('display', 'none'); // do not show at the begin
401
402 dom.select(".buttonSetStartAnalysis")
403 .style('background-image', `url(${source_dir}icons/restart.png)`)
404 .on("click", () => {
405 let options = this.evaluateChanges(""); // complete option string from all changed elements
406 options += "&start";
407 console.log("submit and start analysis " + this.getItemName() + ", options=" + options);
408 executeMethod(this, "UpdateFromUrl", options).then(() => {
409 console.log("submit and start analyis configuration done. ");
410 this.clearChanges();
411 getHPainter()?.reload();
412 });
413 });
414
415 dom.select(".buttonCloseAnalysis")
416 .style('background-image', `url(${source_dir}icons/close.png)`)
417 .on("click", () => {
418 console.log("close analysis " + this.getItemName());
419 executeMethod(this, "UpdateFromUrl", "&close").then(() => {
420 console.log("closing down analyis done. ");
421 });
422 });
423
424 dom.select(".buttonSaveAnaASF")
425 .style('background-image', `url(${source_dir}icons/filesave.png)`);
426
427 dom.select(".anaASF_name").property("value", stat.fxAutoFileName);
428 dom.select(".anaASF_enabled")
429 .property('checked', stat.fbAutoSaveOn)
430 .on("click", () => {
431 this.markChanged("asfenabled",0);
432 this.stat.fbAutoSaveOn = dom.select(".anaASF_enabled").property('checked');
433 });
434
435 dom.select(".anaASF_time")
436 .property("value", stat.fiAutoSaveInterval)
437 .on("change", () => {
438 this.markChanged("asftime", 0);
439 this.stat.fiAutoSaveInterval = dom.select(".anaASF_time").property("value");
440 });
441
442 dom.select(".anaASF_compression")
443 .property("value", stat.fiAutoSaveCompression)
444 .on("change", () => {
445 this.markChanged("asfcomp", 0);
446 this.stat.fiAutoSaveCompression = dom.select(".anaASF_compression").property("value");
447 });
448
449 dom.select(".anaASF_overwrite")
450 .property('checked', stat.fbAutoSaveOverwrite)
451 .on("click", () => {
452 this.markChanged("asfoverwrite",0);
453 this.stat.fbAutoSaveOverwrite = dom.select(".anaASF_overwrite").property('checked');
454 });
455
456 ////////////////// PREFS FILE:
457 dom.select(".anaprefs_name").property("value", stat.fxConfigFileName);
458
459 dom.select(".anaASF_form").on("submit", event => {
460 event.preventDefault(); // do not send automatic request to server!
461 let content = dom.select(".anaASF_name").property("value");
462 content = content.trim();
463 // before we write immediately, mark name as changed in setup:
464 this.markChanged("asfname", 0);
465 this.stat.fxAutoFileName = content;
466
467 createMenu(event, this)
468 .then(menu => menu.confirm("Save auto save file", content))
469 .then(ok => (ok ? executeMethod(this, "UpdateFromUrl", "&saveasf=" + content) : null))
470 .then(res => console.log(res ? "Writing autosave file done." : "Ignore or failed"));
471 });
472
473
474 dom.select(".buttonSaveAnaConf")
475 .style('background-image', `url(${source_dir}icons/filesave.png)`)
476 .on("click", event => {
477 let content = dom.select(".anaprefs_name").property("value").trim(),
478 requestmsg = "Really save analysis preferences: " + content;
479 createMenu(event, this)
480 .then(menu => menu.confirm("Saving analysis preferences", requestmsg))
481 .then(ok => {
482 if (!ok) return null;
483 this.markChanged("anaprefsname", 0);
484 this.stat.fxConfigFileName = content;
485 return executeMethod(this, "UpdateFromUrl", "&saveprefs=" + content);
486 }).then(res => console.log(res !== null ? "Loading Saving preferences done. " : "Saving preferences FAILED."));
487 });
488
489 dom.select(".buttonLoadAnaConf")
490 .style('background-image', `url(${source_dir}icons/fileopen.png)`)
491 .on("click", event => {
492 let content = dom.select(".anaprefs_name").property("value").trim(),
493 requestmsg = "Really load analysis preferences: " + content;
494 createMenu(event, this)
495 .then(menu => menu.confirm("Loading analysis preferences", requestmsg))
496 .then(ok => (ok ? executeMethod(this, "UpdateFromUrl", "&loadprefs=" + content) : null))
497 .then(res => { if (res !== null) getHPainter()?.display(this.getItemName()); });
498 });
499 }
500
501 redrawObject(obj /*, opt */) {
502 if (obj._typename != this.stat._typename) return false;
503 this.stat = clone(obj);
504 this.clearChanges();
505 this.fillEditor();
506 return true;
507 }
508
509 static async draw(domarg, stat) {
510 let editor = new AnalysisStatusEditor(domarg, stat),
511 dom = editor.selectDom(),
512 h = dom.node().clientHeight,
513 w = dom.node().clientWidth;
514
515 if ((h < 10) && (w > 10)) dom.style("height", Math.round(w * 0.7)+"px");
516
517 return httpRequest(`${source_dir}html5/analysiseditor.htm`, 'text').then(code => {
518 dom.html(code);
519
520 return httpRequest(`${source_dir}html5/stepeditor.html`, 'text');
521
522 }).then(step_code => {
523
524 editor.stepPageHtml = step_code;
525
526 editor.fillEditor();
527
528 editor.setTopPainter();
529 return editor;
530 });
531 }
532}
533
534export { AnalysisStatusEditor };