Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RBrowser.cxx
Go to the documentation of this file.
1// Authors: Bertrand Bellenot <bertrand.bellenot@cern.ch> Sergey Linev <S.Linev@gsi.de>
2// Date: 2019-02-28
3// Warning: This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome!
4
5/*************************************************************************
6 * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#include <ROOT/RBrowser.hxx>
14
18
19#include <ROOT/RLogger.hxx>
20#include <ROOT/RFileDialog.hxx>
22
23#include "RBrowserWidget.hxx"
24
25#include "TString.h"
26#include "TSystem.h"
27#include "TError.h"
28#include "TROOT.h"
29#include "TBufferJSON.h"
30#include "TApplication.h"
31#include "TRint.h"
32#include "Getline.h"
33
34#include <sstream>
35#include <iostream>
36#include <algorithm>
37#include <memory>
38#include <mutex>
39#include <thread>
40#include <fstream>
41
42using namespace std::string_literals;
43
44using namespace ROOT::Experimental;
45
46
48public:
49
50 bool fIsEditor{true}; ///<! either editor or image viewer
51 std::string fTitle;
52 std::string fFileName;
53 std::string fContent;
54 bool fFirstSend{false}; ///<! if editor content was send at least once
55 std::string fItemPath; ///<! item path in the browser
56
57 RBrowserEditorWidget(const std::string &name, bool is_editor = true) : RBrowserWidget(name), fIsEditor(is_editor) {}
58 virtual ~RBrowserEditorWidget() = default;
59
60 void ResetConn() override { fFirstSend = false; }
61
62 std::string GetKind() const override { return fIsEditor ? "editor"s : "image"s; }
63 std::string GetTitle() override { return fTitle; }
64 std::string GetUrl() override { return ""s; }
65
66 void Show(const std::string &) override {}
67
68 bool DrawElement(std::shared_ptr<Browsable::RElement> &elem, const std::string & = "") override
69 {
70 if (fIsEditor && elem->IsCapable(Browsable::RElement::kActEdit)) {
71 auto code = elem->GetContent("text");
72 if (!code.empty()) {
73 fFirstSend = false;
74 fContent = code;
75 fTitle = elem->GetName();
76 fFileName = elem->GetContent("filename");
77 } else {
78 auto json = elem->GetContent("json");
79 if (!json.empty()) {
80 fFirstSend = false;
81 fContent = json;
82 fTitle = elem->GetName() + ".json";
83 fFileName = "";
84 }
85 }
86 if (!fContent.empty()) {
87 // page->fItemPath = item_path;
88 return true;
89 }
90 }
91
92 if (!fIsEditor && elem->IsCapable(Browsable::RElement::kActImage)) {
93 auto img = elem->GetContent("image64");
94 if (!img.empty()) {
95 fFirstSend = false;
96 fContent = img;
97 fTitle = elem->GetName();
98 fFileName = elem->GetContent("filename");
99 // fItemPath = item_path;
100
101 return true;
102 }
103 }
104
105 return false;
106 }
107
108 std::string SendWidgetContent() override
109 {
110 if (fFirstSend) return ""s;
111
112 fFirstSend = true;
113 std::vector<std::string> args = { GetName(), fTitle, fFileName, fContent };
114
115 std::string msg = fIsEditor ? "EDITOR:"s : "IMAGE:"s;
116 msg += TBufferJSON::ToJSON(&args).Data();
117 return msg;
118 }
119
120};
121
122
124public:
125
126 enum { kMaxContentLen = 10000000 };
127
128 std::string fTitle;
129 std::string fContent;
130 bool fFirstSend{false}; ///<! if editor content was send at least once
131
133 {
134 fTitle = "Cling info"s;
135 Refresh();
136 }
137
138 virtual ~RBrowserInfoWidget() = default;
139
140 void ResetConn() override { fFirstSend = false; }
141
142 std::string GetKind() const override { return "info"s; }
143 std::string GetTitle() override { return fTitle; }
144 std::string GetUrl() override { return ""s; }
145
146 void Show(const std::string &) override {}
147
148 bool DrawElement(std::shared_ptr<Browsable::RElement> &, const std::string & = "") override { return false; }
149
150 void Refresh()
151 {
152 fFirstSend = false;
153 fContent = "";
154
155 std::ostringstream pathtmp;
156 pathtmp << gSystem->TempDirectory() << "/info." << gSystem->GetPid() << ".log";
157
158 std::ofstream ofs(pathtmp.str(), std::ofstream::out | std::ofstream::app);
159 ofs << "";
160 ofs.close();
161
162 gSystem->RedirectOutput(pathtmp.str().c_str(), "a");
163 gROOT->ProcessLine(".g");
164 gSystem->RedirectOutput(nullptr);
165
166 std::ifstream infile(pathtmp.str());
167 if (infile) {
168 std::string line;
169 while (std::getline(infile, line) && (fContent.length() < kMaxContentLen)) {
170 fContent.append(line);
171 fContent.append("\n");
172 }
173 }
174
175 gSystem->Unlink(pathtmp.str().c_str());
176 }
177
178 void RefreshFromLogs(const std::string &promt, const std::vector<std::string> &logs)
179 {
180 int indx = 0, last_prompt = -1;
181 for (auto &line : logs) {
182 if (line == promt)
183 last_prompt = indx;
184 indx++;
185 }
186
187 if (last_prompt < 0) {
188 Refresh();
189 return;
190 }
191
192 fFirstSend = false;
193 fContent = "";
194
195 indx = 0;
196 for (auto &line : logs) {
197 if ((indx++ > last_prompt) && (fContent.length() < kMaxContentLen)) {
198 fContent.append(line);
199 fContent.append("\n");
200 }
201 }
202 }
203
204
205 std::string SendWidgetContent() override
206 {
207 if (fFirstSend)
208 return ""s;
209
210 if (fContent.empty())
211 Refresh();
212
213 fFirstSend = true;
214 std::vector<std::string> args = { GetName(), fTitle, fContent };
215
216 return "INFO:"s + TBufferJSON::ToJSON(&args).Data();
217 }
218
219};
220
221
223public:
224
225 std::string fUrl; // url of catched widget
226 std::string fCatchedKind; // kind of catched widget
227
228 void Show(const std::string &) override {}
229
230 std::string GetKind() const override { return "catched"s; }
231
232 std::string GetUrl() override { return fUrl; }
233
234 std::string GetTitle() override { return fCatchedKind; }
235
236 RBrowserCatchedWidget(const std::string &name, const std::string &url, const std::string &kind) :
238 fUrl(url),
239 fCatchedKind(kind)
240 {
241 }
242};
243
244
245/** \class ROOT::Experimental::RBrowser
246\ingroup rbrowser
247\brief Web-based %ROOT files and objects browser
248
249\image html v7_rbrowser.png
250
251*/
252
253//////////////////////////////////////////////////////////////////////////////////////////////
254/// constructor
255
256RBrowser::RBrowser(bool use_rcanvas)
257{
258 if (gROOT->IsWebDisplayBatch()) {
259 ::Warning("RBrowser::RBrowser", "The RBrowser cannot run in web batch mode");
260 return;
261 }
262
263 std::ostringstream pathtmp;
264 pathtmp << gSystem->TempDirectory() << "/command." << gSystem->GetPid() << ".log";
265 fPromptFileOutput = pathtmp.str();
266
267 SetUseRCanvas(use_rcanvas);
268
270
272 fWebWindow->SetDefaultPage("file:rootui5sys/browser/browser.html");
273
274 // this is call-back, invoked when message received via websocket
275 fWebWindow->SetCallBacks([this](unsigned connid) { if (!fConnId) { fConnId = connid; SendInitMsg(connid); } else fConnId = 0xffffff; },
276 [this](unsigned connid, const std::string &arg) { if ((connid == fConnId) && (fConnId != 0xffffff)) ProcessMsg(connid, arg); });
277 fWebWindow->SetGeometry(1200, 700); // configure predefined window geometry
278 fWebWindow->SetConnLimit(1); // the only connection is allowed
279 fWebWindow->SetMaxQueueLength(30); // number of allowed entries in the window queue
280
281 fWebWindow->GetManager()->SetShowCallback([this](RWebWindow &win, const RWebDisplayArgs &args) -> bool {
282
283 std::string kind;
284
285 if (args.GetWidgetKind() == "RCanvas")
286 kind = "rcanvas";
287 else if (args.GetWidgetKind() == "TCanvas")
288 kind = "tcanvas";
289 else if (args.GetWidgetKind() == "RGeomViewer")
290 kind = "geom";
291 else if (args.GetWidgetKind() == "RTreeViewer")
292 kind = "tree";
293
294 if (!fWebWindow || !fCatchWindowShow || kind.empty()) return false;
295
296 std::string url = fWebWindow->GetRelativeAddr(win);
297
298 auto widget = AddCatchedWidget(url, kind);
299
300 if (widget && fWebWindow && (fWebWindow->NumConnections() > 0))
301 fWebWindow->Send(0, NewWidgetMsg(widget));
302
303 return widget ? true : false;
304 });
305
306 Show();
307
308 // add first canvas by default
309
310 //if (GetUseRCanvas())
311 // AddWidget("rcanvas");
312 //else
313 // AddWidget("tcanvas");
314
315 // AddWidget("geom"); // add geometry viewer at the beginning
316
317 // AddWidget("editor"); // one can add empty editor if necessary
318}
319
320//////////////////////////////////////////////////////////////////////////////////////////////
321/// destructor
322
324{
325 if (fWebWindow)
326 fWebWindow->GetManager()->SetShowCallback(nullptr);
327}
328
329//////////////////////////////////////////////////////////////////////////////////////////////
330/// Process browser request
331
332std::string RBrowser::ProcessBrowserRequest(const std::string &msg)
333{
334 std::unique_ptr<RBrowserRequest> request;
335
336 if (msg.empty()) {
337 request = std::make_unique<RBrowserRequest>();
338 request->first = 0;
339 request->number = 100;
340 } else {
341 request = TBufferJSON::FromJSON<RBrowserRequest>(msg);
342 }
343
344 if (!request)
345 return ""s;
346
347 if (request->path.empty() && fWidgets.empty() && fBrowsable.GetWorkingPath().empty())
349
350 return "BREPL:"s + fBrowsable.ProcessRequest(*request.get());
351}
352
353/////////////////////////////////////////////////////////////////////////////////
354/// Process file save command in the editor
355
356void RBrowser::ProcessSaveFile(const std::string &fname, const std::string &content)
357{
358 if (fname.empty()) return;
359 R__LOG_DEBUG(0, BrowserLog()) << "SaveFile " << fname << " content length " << content.length();
360 std::ofstream f(fname);
361 f << content;
362}
363
364/////////////////////////////////////////////////////////////////////////////////
365/// Process run macro command in the editor
366
367void RBrowser::ProcessRunMacro(const std::string &file_path)
368{
369 if (file_path.rfind(".py") == file_path.length() - 3) {
370 TString exec;
371 exec.Form("TPython::ExecScript(\"%s\");", file_path.c_str());
372 gROOT->ProcessLine(exec.Data());
373 } else {
374 gInterpreter->ExecuteMacro(file_path.c_str());
375 }
376}
377
378/////////////////////////////////////////////////////////////////////////////////
379/// Process dbl click on browser item
380
381std::string RBrowser::ProcessDblClick(std::vector<std::string> &args)
382{
383 args.pop_back(); // remove exec string, not used now
384
385 std::string opt = args.back();
386 args.pop_back(); // remove option
387
388 auto path = fBrowsable.GetWorkingPath();
389 path.insert(path.end(), args.begin(), args.end());
390
391 R__LOG_DEBUG(0, BrowserLog()) << "DoubleClick " << Browsable::RElement::GetPathAsString(path);
392
393 auto elem = fBrowsable.GetSubElement(path);
394 if (!elem) return ""s;
395
396 auto dflt_action = elem->GetDefaultAction();
397
398 // special case when canvas is clicked - always start new widget
399 if (dflt_action == Browsable::RElement::kActCanvas) {
400 std::string widget_kind;
401
402 if (elem->IsCapable(Browsable::RElement::kActDraw7))
403 widget_kind = "rcanvas";
404 else
405 widget_kind = "tcanvas";
406
407 std::string name = widget_kind + std::to_string(++fWidgetCnt);
408
409 auto new_widget = RBrowserWidgetProvider::CreateWidgetFor(widget_kind, name, elem);
410
411 if (!new_widget)
412 return ""s;
413
414 // assign back pointer
415 new_widget->fBrowser = this;
416
417 new_widget->Show("embed");
418 fWidgets.emplace_back(new_widget);
419 fActiveWidgetName = new_widget->GetName();
420
421 return NewWidgetMsg(new_widget);
422 }
423
424 // before display tree or geometry ensure that they read and cached inside element
425 if (elem->IsCapable(Browsable::RElement::kActGeom) || elem->IsCapable(Browsable::RElement::kActTree)) {
426 elem->GetChildsIter();
427 }
428
429 auto widget = GetActiveWidget();
430 if (widget && widget->DrawElement(elem, opt)) {
431 widget->SetPath(path);
432 return widget->SendWidgetContent();
433 }
434
435 // check if element was drawn in other widget and just activate that widget
436 auto iter = std::find_if(fWidgets.begin(), fWidgets.end(),
437 [path](const std::shared_ptr<RBrowserWidget> &wg) { return path == wg->GetPath(); });
438
439 if (iter != fWidgets.end())
440 return "SELECT_WIDGET:"s + (*iter)->GetName();
441
442 // check if object can be drawn in RCanvas even when default action is drawing in TCanvas
443 if ((dflt_action == Browsable::RElement::kActDraw6) && GetUseRCanvas() && elem->IsCapable(Browsable::RElement::kActDraw7))
444 dflt_action = Browsable::RElement::kActDraw7;
445
446 std::string widget_kind;
447 switch(dflt_action) {
448 case Browsable::RElement::kActDraw6: widget_kind = "tcanvas"; break;
449 case Browsable::RElement::kActDraw7: widget_kind = "rcanvas"; break;
450 case Browsable::RElement::kActEdit: widget_kind = "editor"; break;
451 case Browsable::RElement::kActImage: widget_kind = "image"; break;
452 case Browsable::RElement::kActTree: widget_kind = "tree"; break;
453 case Browsable::RElement::kActGeom: widget_kind = "geom"; break;
454 default: widget_kind.clear();
455 }
456
457 if (!widget_kind.empty()) {
458 auto new_widget = AddWidget(widget_kind);
459 if (new_widget) {
460 // draw object before client side is created - should not be a problem
461 // after widget add in browser, connection will be established and data provided
462 if (new_widget->DrawElement(elem, opt))
463 new_widget->SetPath(path);
464 return NewWidgetMsg(new_widget);
465 }
466 }
467
468 if (elem->IsCapable(Browsable::RElement::kActBrowse) && (elem->GetNumChilds() > 0)) {
469 // remove extra index in subitems name
470 for (auto &pathelem : path)
474 }
475
476 return ""s;
477}
478
479/////////////////////////////////////////////////////////////////////////////////
480/// Show or update RBrowser in web window
481/// If web window already started - just refresh it like "reload" button does
482/// If no web window exists or \param always_start_new_browser configured, starts new window
483/// \param args display arguments
484
485void RBrowser::Show(const RWebDisplayArgs &args, bool always_start_new_browser)
486{
487 if (!fWebWindow->NumConnections() || always_start_new_browser) {
488 fWebWindow->Show(args);
489 } else {
490 SendInitMsg(0);
491 }
492}
493
494///////////////////////////////////////////////////////////////////////////////////////////////////////
495/// Hide ROOT Browser
496
498{
499 if (fWebWindow)
500 fWebWindow->CloseConnections();
501}
502
503
504//////////////////////////////////////////////////////////////////////////////////////////////
505/// Creates new widget
506
507std::shared_ptr<RBrowserWidget> RBrowser::AddWidget(const std::string &kind)
508{
509 std::string name = kind + std::to_string(++fWidgetCnt);
510
511 std::shared_ptr<RBrowserWidget> widget;
512
513 if (kind == "editor"s)
514 widget = std::make_shared<RBrowserEditorWidget>(name, true);
515 else if (kind == "image"s)
516 widget = std::make_shared<RBrowserEditorWidget>(name, false);
517 else if (kind == "info"s)
518 widget = std::make_shared<RBrowserInfoWidget>(name);
519 else
521
522 if (!widget) {
523 R__LOG_ERROR(BrowserLog()) << "Fail to create widget of kind " << kind;
524 return nullptr;
525 }
526
527 widget->fBrowser = this;
528 widget->Show("embed");
529 fWidgets.emplace_back(widget);
530
532
533 return widget;
534}
535
536//////////////////////////////////////////////////////////////////////////////////////////////
537/// Add widget catched from external scripts
538
539std::shared_ptr<RBrowserWidget> RBrowser::AddCatchedWidget(const std::string &url, const std::string &kind)
540{
541 if (url.empty()) return nullptr;
542
543 std::string name = "catched"s + std::to_string(++fWidgetCnt);
544
545 auto widget = std::make_shared<RBrowserCatchedWidget>(name, url, kind);
546
547 fWidgets.emplace_back(widget);
548
550
551 return widget;
552}
553
554
555//////////////////////////////////////////////////////////////////////////////////////////////
556/// Create new widget and send init message to the client
557
558void RBrowser::AddInitWidget(const std::string &kind)
559{
560 auto widget = AddWidget(kind);
561 if (widget && fWebWindow && (fWebWindow->NumConnections() > 0))
562 fWebWindow->Send(0, NewWidgetMsg(widget));
563}
564
565//////////////////////////////////////////////////////////////////////////////////////////////
566/// Find widget by name or kind
567
568std::shared_ptr<RBrowserWidget> RBrowser::FindWidget(const std::string &name, const std::string &kind) const
569{
570 auto iter = std::find_if(fWidgets.begin(), fWidgets.end(),
571 [name, kind](const std::shared_ptr<RBrowserWidget> &widget) {
572 return kind.empty() ? name == widget->GetName() : kind == widget->GetKind();
573 });
574
575 if (iter != fWidgets.end())
576 return *iter;
577
578 return nullptr;
579}
580
581//////////////////////////////////////////////////////////////////////////////////////////////
582/// Close and delete specified widget
583
584void RBrowser::CloseTab(const std::string &name)
585{
586 auto iter = std::find_if(fWidgets.begin(), fWidgets.end(), [name](std::shared_ptr<RBrowserWidget> &widget) { return name == widget->GetName(); });
587 if (iter != fWidgets.end())
588 fWidgets.erase(iter);
589
590 if (fActiveWidgetName == name)
591 fActiveWidgetName.clear();
592}
593
594//////////////////////////////////////////////////////////////////////////////////////////////
595/// Get content of history file
596
597std::vector<std::string> RBrowser::GetRootHistory()
598{
599 std::vector<std::string> arr;
600
601 std::string path = gSystem->UnixPathName(gSystem->HomeDirectory());
602 path += "/.root_hist" ;
603 std::ifstream infile(path);
604
605 if (infile) {
606 std::string line;
607 while (std::getline(infile, line) && (arr.size() < 1000)) {
608 if(!(std::find(arr.begin(), arr.end(), line) != arr.end())) {
609 arr.emplace_back(line);
610 }
611 }
612 }
613
614 return arr;
615}
616
617//////////////////////////////////////////////////////////////////////////////////////////////
618/// Get content of log file
619
620std::vector<std::string> RBrowser::GetRootLogs()
621{
622 std::vector<std::string> arr;
623
624 std::ifstream infile(fPromptFileOutput);
625 if (infile) {
626 std::string line;
627 while (std::getline(infile, line) && (arr.size() < 10000)) {
628 arr.emplace_back(line);
629 }
630 }
631
632 return arr;
633}
634
635//////////////////////////////////////////////////////////////////////////////////////////////
636/// Process client connect
637
638void RBrowser::SendInitMsg(unsigned connid)
639{
640 std::vector<std::vector<std::string>> reply;
641
642 reply.emplace_back(fBrowsable.GetWorkingPath()); // first element is current path
643
644 for (auto &widget : fWidgets) {
645 widget->ResetConn();
646 reply.emplace_back(std::vector<std::string>({ widget->GetKind(), widget->GetUrl(), widget->GetName(), widget->GetTitle() }));
647 }
648
649 if (!fActiveWidgetName.empty())
650 reply.emplace_back(std::vector<std::string>({ "active"s, fActiveWidgetName }));
651
652 auto history = GetRootHistory();
653 if (history.size() > 0) {
654 history.insert(history.begin(), "history"s);
655 reply.emplace_back(history);
656 }
657
658 auto logs = GetRootLogs();
659 if (logs.size() > 0) {
660 logs.insert(logs.begin(), "logs"s);
661 reply.emplace_back(logs);
662 }
663
664 reply.emplace_back(std::vector<std::string>({
665 "drawoptions"s,
669 }));
670
671 std::string msg = "INMSG:";
672 msg.append(TBufferJSON::ToJSON(&reply, TBufferJSON::kNoSpaces).Data());
673
674 fWebWindow->Send(connid, msg);
675}
676
677//////////////////////////////////////////////////////////////////////////////////////////////
678/// Return the current directory of ROOT
679
681{
682 return "WORKPATH:"s + TBufferJSON::ToJSON(&fBrowsable.GetWorkingPath()).Data();
683}
684
685//////////////////////////////////////////////////////////////////////////////////////////////
686/// Create message which send to client to create new widget
687
688std::string RBrowser::NewWidgetMsg(std::shared_ptr<RBrowserWidget> &widget)
689{
690 std::vector<std::string> arr = { widget->GetKind(), widget->GetUrl(), widget->GetName(), widget->GetTitle(),
691 Browsable::RElement::GetPathAsString(widget->GetPath()) };
692 return "NEWWIDGET:"s + TBufferJSON::ToJSON(&arr, TBufferJSON::kNoSpaces).Data();
693}
694
695//////////////////////////////////////////////////////////////////////////////////////////////
696/// Check if any widget was modified and update if necessary
697
699{
700 for (auto &widget : fWidgets)
701 widget->CheckModified();
702}
703
704//////////////////////////////////////////////////////////////////////////////////////////////
705/// Process received message from the client
706
707void RBrowser::ProcessMsg(unsigned connid, const std::string &arg0)
708{
709 R__LOG_DEBUG(0, BrowserLog()) << "ProcessMsg len " << arg0.length() << " substr(30) " << arg0.substr(0, 30);
710
711 std::string kind, msg;
712 auto pos = arg0.find(":");
713 if (pos == std::string::npos) {
714 kind = arg0;
715 } else {
716 kind = arg0.substr(0, pos);
717 msg = arg0.substr(pos+1);
718 }
719
720 if (kind == "QUIT_ROOT") {
721
722 fWebWindow->TerminateROOT();
723
724 } else if (kind == "BRREQ") {
725 // central place for processing browser requests
726 auto json = ProcessBrowserRequest(msg);
727 if (!json.empty()) fWebWindow->Send(connid, json);
728
729 } else if (kind == "DBLCLK") {
730
731 std::string reply;
732
733 auto arr = TBufferJSON::FromJSON<std::vector<std::string>>(msg);
734 if (arr && (arr->size() > 2))
735 reply = ProcessDblClick(*arr);
736
737 if (reply.empty())
738 reply = "NOPE";
739
740 fWebWindow->Send(connid, reply);
741
742 } else if (kind == "WIDGET_SELECTED") {
743 fActiveWidgetName = msg;
744 auto widget = GetActiveWidget();
745 if (widget) {
746 auto reply = widget->SendWidgetContent();
747 if (!reply.empty()) fWebWindow->Send(connid, reply);
748 }
749 } else if (kind == "CLOSE_TAB") {
750 CloseTab(msg);
751 } else if (kind == "GETWORKPATH") {
752 fWebWindow->Send(connid, GetCurrentWorkingDirectory());
753 } else if (kind == "CHPATH") {
754 auto path = TBufferJSON::FromJSON<Browsable::RElementPath_t>(msg);
755 if (path) fBrowsable.SetWorkingPath(*path);
756 fWebWindow->Send(connid, GetCurrentWorkingDirectory());
757 } else if (kind == "CMD") {
758 std::string sPrompt = "root []";
759 TApplication *app = gROOT->GetApplication();
760 if (app->InheritsFrom("TRint")) {
761 sPrompt = ((TRint*)gROOT->GetApplication())->GetPrompt();
762 Gl_histadd((char *)msg.c_str());
763 }
764
765 std::ofstream ofs(fPromptFileOutput, std::ofstream::out | std::ofstream::app);
766 ofs << sPrompt << msg << std::endl;
767 ofs.close();
768
770 gROOT->ProcessLine(msg.c_str());
771 gSystem->RedirectOutput(nullptr);
772
773 if (msg == ".g"s) {
774 auto widget = std::dynamic_pointer_cast<RBrowserInfoWidget>(FindWidget(""s, "info"s));
775 if (!widget) {
776 auto new_widget = AddWidget("info"s);
777 fWebWindow->Send(connid, NewWidgetMsg(new_widget));
778 widget = std::dynamic_pointer_cast<RBrowserInfoWidget>(new_widget);
779 } else if (fActiveWidgetName != widget->GetName()) {
780 fWebWindow->Send(connid, "SELECT_WIDGET:"s + widget->GetName());
781 fActiveWidgetName = widget->GetName();
782 }
783
784 if (widget)
785 widget->RefreshFromLogs(sPrompt + msg, GetRootLogs());
786 }
787
789 } else if (kind == "GETHISTORY") {
790
791 auto history = GetRootHistory();
792
793 fWebWindow->Send(connid, "HISTORY:"s + TBufferJSON::ToJSON(&history, TBufferJSON::kNoSpaces).Data());
794 } else if (kind == "GETLOGS") {
795
796 auto logs = GetRootLogs();
797 fWebWindow->Send(connid, "LOGS:"s + TBufferJSON::ToJSON(&logs, TBufferJSON::kNoSpaces).Data());
798
799 } else if (kind == "FILEDIALOG") {
801 } else if (kind == "SYNCEDITOR") {
802 auto arr = TBufferJSON::FromJSON<std::vector<std::string>>(msg);
803 if (arr && (arr->size() > 4)) {
804 auto editor = std::dynamic_pointer_cast<RBrowserEditorWidget>(FindWidget(arr->at(0)));
805 if (editor) {
806 editor->fFirstSend = true;
807 editor->fTitle = arr->at(1);
808 editor->fFileName = arr->at(2);
809 if (!arr->at(3).empty()) editor->fContent = arr->at(4);
810 if ((arr->size() == 6) && (arr->at(5) == "SAVE"))
811 ProcessSaveFile(editor->fFileName, editor->fContent);
812 if ((arr->size() == 6) && (arr->at(5) == "RUN")) {
813 ProcessSaveFile(editor->fFileName, editor->fContent);
814 ProcessRunMacro(editor->fFileName);
815 }
816 }
817 }
818 } else if (kind == "GETINFO") {
819 auto info = std::dynamic_pointer_cast<RBrowserInfoWidget>(FindWidget(msg));
820 if (info) {
821 info->Refresh();
822 fWebWindow->Send(connid, info->SendWidgetContent());
823 }
824 } else if (kind == "NEWWIDGET") {
825 auto widget = AddWidget(msg);
826 if (widget)
827 fWebWindow->Send(connid, NewWidgetMsg(widget));
828 } else if (kind == "CDWORKDIR") {
830 if (fBrowsable.GetWorkingPath() != wrkdir) {
832 } else {
834 }
835 fWebWindow->Send(connid, GetCurrentWorkingDirectory());
836 } else if (kind == "OPTIONS") {
837 auto arr = TBufferJSON::FromJSON<std::vector<std::string>>(msg);
838 if (arr && (arr->size() == 3)) {
841 Browsable::RProvider::SetClassDrawOption("TProfile", (*arr)[2]);
842 }
843 }
844}
845
846//////////////////////////////////////////////////////////////////////////////////////////////
847/// Set working path in the browser
848
849void RBrowser::SetWorkingPath(const std::string &path)
850{
852 auto elem = fBrowsable.GetSubElement(p);
853 if (elem) {
855 if (fWebWindow && (fWebWindow->NumConnections() > 0))
857 }
858}
859
860//////////////////////////////////////////////////////////////////////////////////////////////
861/// Activate widget in RBrowser
862/// One should specify title and (optionally) kind of widget like "tcanvas" or "geom"
863
864bool RBrowser::ActivateWidget(const std::string &title, const std::string &kind)
865{
866 if (title.empty())
867 return false;
868
869 for (auto &widget : fWidgets) {
870
871 if (widget->GetTitle() != title)
872 continue;
873
874 if (!kind.empty() && (widget->GetKind() != kind))
875 continue;
876
877 if (fWebWindow)
878 fWebWindow->Send(0, "SELECT_WIDGET:"s + widget->GetName());
879 else
880 fActiveWidgetName = widget->GetName();
881 return true;
882 }
883
884 return false;
885}
886
887
nlohmann::json json
#define R__LOG_ERROR(...)
Definition RLogger.hxx:362
#define R__LOG_DEBUG(DEBUGLEVEL,...)
Definition RLogger.hxx:365
#define f(i)
Definition RSha256.hxx:104
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:241
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t win
char name[80]
Definition TGX11.cxx:110
#define gInterpreter
#define gROOT
Definition TROOT.h:405
R__EXTERN TSystem * gSystem
Definition TSystem.h:560
void Show(const std::string &) override
Definition RBrowser.cxx:228
RBrowserCatchedWidget(const std::string &name, const std::string &url, const std::string &kind)
Definition RBrowser.cxx:236
std::string fCatchedKind
Definition RBrowser.cxx:226
std::string GetTitle() override
Definition RBrowser.cxx:234
std::string GetUrl() override
Definition RBrowser.cxx:232
std::string GetKind() const override
Definition RBrowser.cxx:230
bool fIsEditor
! either editor or image viewer
Definition RBrowser.cxx:50
void ResetConn() override
Definition RBrowser.cxx:60
std::string GetTitle() override
Definition RBrowser.cxx:63
bool DrawElement(std::shared_ptr< Browsable::RElement > &elem, const std::string &="") override
Definition RBrowser.cxx:68
std::string GetUrl() override
Definition RBrowser.cxx:64
std::string SendWidgetContent() override
Definition RBrowser.cxx:108
RBrowserEditorWidget(const std::string &name, bool is_editor=true)
Definition RBrowser.cxx:57
std::string fContent
Definition RBrowser.cxx:53
std::string fItemPath
! item path in the browser
Definition RBrowser.cxx:55
std::string GetKind() const override
Definition RBrowser.cxx:62
bool fFirstSend
! if editor content was send at least once
Definition RBrowser.cxx:54
void Show(const std::string &) override
Definition RBrowser.cxx:66
std::string fTitle
Definition RBrowser.cxx:51
std::string fFileName
Definition RBrowser.cxx:52
virtual ~RBrowserEditorWidget()=default
std::string fContent
Definition RBrowser.cxx:129
void RefreshFromLogs(const std::string &promt, const std::vector< std::string > &logs)
Definition RBrowser.cxx:178
std::string fTitle
Definition RBrowser.cxx:128
bool DrawElement(std::shared_ptr< Browsable::RElement > &, const std::string &="") override
Definition RBrowser.cxx:148
void ResetConn() override
Definition RBrowser.cxx:140
std::string GetKind() const override
Definition RBrowser.cxx:142
std::string GetTitle() override
Definition RBrowser.cxx:143
bool fFirstSend
! if editor content was send at least once
Definition RBrowser.cxx:130
std::string GetUrl() override
Definition RBrowser.cxx:144
void Show(const std::string &) override
Definition RBrowser.cxx:146
std::string SendWidgetContent() override
Definition RBrowser.cxx:205
virtual ~RBrowserInfoWidget()=default
RBrowserInfoWidget(const std::string &name)
Definition RBrowser.cxx:132
static int ExtractItemIndex(std::string &name)
Extract index from name Index coded by client with ###<indx>$$$ suffix Such coding used by browser to...
Definition RElement.cxx:177
static std::string GetPathAsString(const RElementPath_t &path)
Converts element path back to string.
Definition RElement.cxx:159
@ kActEdit
can provide data for text editor
Definition RElement.hxx:54
@ kActCanvas
indicate that it is canvas and should be drawn directly
Definition RElement.hxx:58
@ kActBrowse
just browse (expand) item
Definition RElement.hxx:53
@ kActGeom
can be shown in geometry viewer
Definition RElement.hxx:60
@ kActDraw7
can be drawn inside ROOT7 canvas
Definition RElement.hxx:57
@ kActTree
can be shown in tree viewer
Definition RElement.hxx:59
@ kActImage
can be shown in image viewer, can provide image
Definition RElement.hxx:55
@ kActDraw6
can be drawn inside ROOT6 canvas
Definition RElement.hxx:56
static RElementPath_t ParsePath(const std::string &str)
Parse string path to produce RElementPath_t One should avoid to use string pathes as much as possible...
Definition RElement.cxx:115
static bool SetClassDrawOption(const ClassArg &, const std::string &)
Set draw option for the class Return true if entry for the class exists.
static std::string GetClassDrawOption(const ClassArg &)
Return configured draw option for the class.
static RElementPath_t GetWorkingPath(const std::string &workdir="")
Return working path in browser hierarchy.
Definition RSysFile.cxx:573
std::shared_ptr< Browsable::RElement > GetSubElement(const Browsable::RElementPath_t &path)
Returns sub-element starting from top, using cached data.
const Browsable::RElementPath_t & GetWorkingPath() const
void ClearCache()
Clear internal objects cache.
std::string ProcessRequest(const RBrowserRequest &request)
Process browser request, returns string with JSON of RBrowserReply data.
void SetWorkingPath(const Browsable::RElementPath_t &path)
set working directory relative to top element
void CreateDefaultElements()
Create default elements shown in the RBrowser.
static std::shared_ptr< RBrowserWidget > CreateWidgetFor(const std::string &kind, const std::string &name, std::shared_ptr< Browsable::RElement > &element)
Create specified widget for existing object.
static std::shared_ptr< RBrowserWidget > CreateWidget(const std::string &kind, const std::string &name)
Create specified widget.
Abstract Web-based widget, which can be used in the RBrowser Used to embed canvas,...
const std::string & GetName() const
std::shared_ptr< RBrowserWidget > AddWidget(const std::string &kind)
Creates new widget.
Definition RBrowser.cxx:507
std::vector< std::string > GetRootHistory()
Get content of history file.
Definition RBrowser.cxx:597
void AddInitWidget(const std::string &kind)
Create new widget and send init message to the client.
Definition RBrowser.cxx:558
void SetWorkingPath(const std::string &path)
Set working path in the browser.
Definition RBrowser.cxx:849
void Hide()
hide Browser
Definition RBrowser.cxx:497
std::string NewWidgetMsg(std::shared_ptr< RBrowserWidget > &widget)
Create message which send to client to create new widget.
Definition RBrowser.cxx:688
std::shared_ptr< RWebWindow > fWebWindow
! web window to browser
Definition RBrowser.hxx:41
std::shared_ptr< RBrowserWidget > GetActiveWidget() const
Definition RBrowser.hxx:48
void Show(const RWebDisplayArgs &args="", bool always_start_new_browser=false)
show Browser in specified place
Definition RBrowser.cxx:485
std::string GetCurrentWorkingDirectory()
Return the current directory of ROOT.
Definition RBrowser.cxx:680
std::shared_ptr< RBrowserWidget > AddCatchedWidget(const std::string &url, const std::string &kind)
Add widget catched from external scripts.
Definition RBrowser.cxx:539
std::shared_ptr< RBrowserWidget > FindWidget(const std::string &name, const std::string &kind="") const
Find widget by name or kind.
Definition RBrowser.cxx:568
virtual ~RBrowser()
destructor
Definition RBrowser.cxx:323
int fWidgetCnt
! counter for created widgets
Definition RBrowser.hxx:38
RBrowserData fBrowsable
! central browsing element
Definition RBrowser.hxx:43
void ProcessSaveFile(const std::string &fname, const std::string &content)
Process file save command in the editor.
Definition RBrowser.cxx:356
void CheckWidgtesModified()
Check if any widget was modified and update if necessary.
Definition RBrowser.cxx:698
std::string ProcessBrowserRequest(const std::string &msg)
Process browser request.
Definition RBrowser.cxx:332
std::string fActiveWidgetName
! name of active widget
Definition RBrowser.hxx:36
std::vector< std::string > GetRootLogs()
Get content of log file.
Definition RBrowser.cxx:620
void ProcessMsg(unsigned connid, const std::string &arg)
Process received message from the client.
Definition RBrowser.cxx:707
bool fCatchWindowShow
! if arbitrary RWebWindow::Show calls should be catched by browser
Definition RBrowser.hxx:35
RBrowser(bool use_rcanvas=true)
constructor
Definition RBrowser.cxx:256
void CloseTab(const std::string &name)
Close and delete specified widget.
Definition RBrowser.cxx:584
void SetUseRCanvas(bool on=true)
Definition RBrowser.hxx:74
bool ActivateWidget(const std::string &title, const std::string &kind="")
Activate widget in RBrowser One should specify title and (optionally) kind of widget like "tcanvas" o...
Definition RBrowser.cxx:864
void SendInitMsg(unsigned connid)
Process client connect.
Definition RBrowser.cxx:638
std::string ProcessDblClick(std::vector< std::string > &args)
Process dbl click on browser item.
Definition RBrowser.cxx:381
unsigned fConnId
! default connection id
Definition RBrowser.hxx:32
void ProcessRunMacro(const std::string &file_path)
Process run macro command in the editor.
Definition RBrowser.cxx:367
std::string fPromptFileOutput
! file name for prompt output
Definition RBrowser.hxx:39
std::vector< std::shared_ptr< RBrowserWidget > > fWidgets
! all browser widgets
Definition RBrowser.hxx:37
static std::shared_ptr< RFileDialog > Embedded(const std::shared_ptr< RWebWindow > &window, const std::string &args)
Create dialog instance to use as embedded dialog inside other widget Embedded dialog started on the c...
Holds different arguments for starting browser with RWebDisplayHandle::Display() method.
const std::string & GetWidgetKind() const
returns widget kind
Represents web window, which can be shown in web browser or any other supported environment.
static std::shared_ptr< RWebWindow > Create()
Create new RWebWindow Using default RWebWindowsManager.
This class creates the ROOT Application Environment that interfaces to the windowing system eventloop...
static TString ToJSON(const T *obj, Int_t compact=0, const char *member_name=nullptr)
Definition TBufferJSON.h:75
@ kNoSpaces
no new lines plus remove all spaces around "," and ":" symbols
Definition TBufferJSON.h:39
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:525
Definition TRint.h:31
Basic string class.
Definition TString.h:139
const char * Data() const
Definition TString.h:380
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2334
virtual Int_t RedirectOutput(const char *name, const char *mode="a", RedirectHandle_t *h=nullptr)
Redirect standard output (stdout, stderr) to the specified file.
Definition TSystem.cxx:1716
virtual int GetPid()
Get process id.
Definition TSystem.cxx:710
virtual const char * UnixPathName(const char *unixpathname)
Convert from a local pathname to a Unix pathname.
Definition TSystem.cxx:1066
virtual const char * HomeDirectory(const char *userName=nullptr)
Return the user's home directory.
Definition TSystem.cxx:890
virtual int Unlink(const char *name)
Unlink, i.e.
Definition TSystem.cxx:1384
virtual const char * TempDirectory() const
Return a user configured or systemwide directory to create temporary files in.
Definition TSystem.cxx:1485
TLine * line
RLogChannel & BrowserLog()
Log channel for Browser diagnostics.