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