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