Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGFileBrowser.cxx
Go to the documentation of this file.
1 // @(#)root/gui:$Id$
2 // Author: Bertrand Bellenot 26/09/2007
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TROOT.h"
13 #include "TSystem.h"
14 #include "TApplication.h"
15 #include "TGClient.h"
16 #include "TGListTree.h"
17 #include "TGLayout.h"
18 #include "TGComboBox.h"
19 #include "TContextMenu.h"
20 #include "TGTextEntry.h"
21 #include "TGTab.h"
22 #include "TGLabel.h"
23 #include "TSystemDirectory.h"
24 #include "TGMimeTypes.h"
25 #include "TClass.h"
26 #include "TQClass.h"
27 #include "TInterpreter.h"
28 #include "TRegexp.h"
29 #include "TEnv.h"
30 #include "TImage.h"
31 #include "TBrowser.h"
32 #include "TRemoteObject.h"
33 #include "TKey.h"
34 #include "TKeyMapFile.h"
35 #include "TVirtualPad.h"
36 #include "Getline.h"
37 #include <time.h>
38 #include <string.h>
39 #include <stdlib.h>
40 
41 #include "TGFileBrowser.h"
42 #include "TRootBrowser.h"
43 #include "TGInputDialog.h"
44 
45 #include "TVirtualPadEditor.h"
46 #include "TGedEditor.h"
47 #include "TBaseClass.h"
48 
49 #include "RConfigure.h"
50 
51 #ifdef WIN32
52 const char rootdir[] = "\\";
53 #else
54 const char rootdir[] = "/";
55 #endif
56 
57 const char *filters[] = {
58  "",
59  "*.*",
60  "*.[C|c|h]*",
61  "*.root",
62  "*.txt"
63 };
64 
65 //_____________________________________________________________________________
66 //
67 // TCursorSwitcher
68 //
69 // Helper class used to change the cursor in a method and restore the
70 // original one when going out of the method scope.
71 //_____________________________________________________________________________
72 
73 ///////////////////////////////////////////////////////////////////////////////
74 class TCursorSwitcher {
75 private:
76  TGWindow *fW1;
77  TGWindow *fW2;
78 public:
79  TCursorSwitcher(TGWindow *w1, TGWindow *w2) : fW1(w1), fW2(w2) {
80  if (w1) gVirtualX->SetCursor(w1->GetId(), gVirtualX->CreateCursor(kWatch));
81  if (w2) gVirtualX->SetCursor(w2->GetId(), gVirtualX->CreateCursor(kWatch));
82  }
83  ~TCursorSwitcher() {
84  if (fW1) gVirtualX->SetCursor(fW1->GetId(), gVirtualX->CreateCursor(kPointer));
85  if (fW2) gVirtualX->SetCursor(fW2->GetId(), gVirtualX->CreateCursor(kPointer));
86  }
87 };
88 
89 //_____________________________________________________________________________
90 //
91 // TGFileBrowser
92 //
93 // System file browser, used as TRootBrowser plug-in.
94 // This class is the real core of the ROOT browser.
95 //_____________________________________________________________________________
96 
97 ClassImp(TGFileBrowser);
98 
99 ////////////////////////////////////////////////////////////////////////////////
100 /// TGFileBrowser constructor.
101 
102 TGFileBrowser::TGFileBrowser(const TGWindow *p, TBrowser* b, UInt_t w, UInt_t h)
103  : TGMainFrame(p, w, h), TBrowserImp(b), fNewBrowser(0)
104 {
105  if (p && p != gClient->GetDefaultRoot())
106  fNewBrowser = (TRootBrowser *)p->GetMainFrame();
107  if (fNewBrowser)
108  fNewBrowser->SetActBrowser(this);
109  CreateBrowser();
110  Resize(w, h);
111  if (fBrowser) Show();
112 }
113 
114 ////////////////////////////////////////////////////////////////////////////////
115 /// Create the actual file browser.
116 
117 void TGFileBrowser::CreateBrowser()
118 {
119  fCachedPic = 0;
120  SetCleanup(kDeepCleanup);
121 
122  fTopFrame = new TGHorizontalFrame(this, 100, 30);
123  fDrawOption = new TGComboBox(fTopFrame, "");
124  TGTextEntry *dropt_entry = fDrawOption->GetTextEntry();
125  dropt_entry->SetToolTipText("Object Draw Option", 300);
126  fDrawOption->Resize(80, 20);
127  TGListBox *lb = fDrawOption->GetListBox();
128  lb->Resize(lb->GetWidth(), 120);
129  Int_t dropt = 1;
130  fDrawOption->AddEntry("", dropt++);
131  fDrawOption->AddEntry("box", dropt++);
132  fDrawOption->AddEntry("colz", dropt++);
133  fDrawOption->AddEntry("lego", dropt++);
134  fDrawOption->AddEntry("lego1", dropt++);
135  fDrawOption->AddEntry("lego2", dropt++);
136  fDrawOption->AddEntry("same", dropt++);
137  fDrawOption->AddEntry("surf", dropt++);
138  fDrawOption->AddEntry("surf1", dropt++);
139  fDrawOption->AddEntry("surf2", dropt++);
140  fDrawOption->AddEntry("surf3", dropt++);
141  fDrawOption->AddEntry("surf4", dropt++);
142  fDrawOption->AddEntry("surf5", dropt++);
143  fDrawOption->AddEntry("text", dropt++);
144  fTopFrame->AddFrame(fDrawOption, new TGLayoutHints(kLHintsCenterY |
145  kLHintsRight, 2, 2, 2, 2));
146  fTopFrame->AddFrame(new TGLabel(fTopFrame, "Draw Option:"),
147  new TGLayoutHints(kLHintsCenterY | kLHintsRight,
148  5, 2, 2, 2));
149 
150  fSortButton = new TGPictureButton(fTopFrame, "bld_sortup.png");
151  fSortButton->SetStyle(gClient->GetStyle());
152  fSortButton->SetToolTipText("Sort Alphabetically\n(Current folder only)");
153  fTopFrame->AddFrame(fSortButton, new TGLayoutHints(kLHintsCenterY |
154  kLHintsLeft, 2, 2, 2, 2));
155  fSortButton->Connect("Clicked()", "TGFileBrowser", this, "ToggleSort()");
156 
157  fFilterButton = new TGPictureButton(fTopFrame, "filter.png");
158  fFilterButton->SetStyle(gClient->GetStyle());
159  fFilterButton->SetToolTipText("Filter Content");
160  fTopFrame->AddFrame(fFilterButton, new TGLayoutHints(kLHintsCenterY |
161  kLHintsLeft, 2, 2, 2, 2));
162  fFilterButton->Connect("Clicked()", "TGFileBrowser", this, "RequestFilter()");
163 
164  fRefreshButton = new TGPictureButton(fTopFrame, "refresh.png");
165  fRefreshButton->SetStyle(gClient->GetStyle());
166  fRefreshButton->SetToolTipText("Refresh Current Folder");
167  fTopFrame->AddFrame(fRefreshButton, new TGLayoutHints(kLHintsCenterY |
168  kLHintsLeft, 2, 5, 2, 2));
169  fRefreshButton->Connect("Clicked()", "TGFileBrowser", this, "Refresh()");
170 
171  AddFrame(fTopFrame, new TGLayoutHints(kLHintsLeft | kLHintsTop |
172  kLHintsExpandX, 2, 2, 2, 2));
173  fCanvas = new TGCanvas(this, 100, 100);
174  fListTree = new TGListTree(fCanvas, kHorizontalFrame);
175  AddFrame(fCanvas, new TGLayoutHints(kLHintsLeft | kLHintsTop |
176  kLHintsExpandX | kLHintsExpandY));
177  fListTree->Connect("DoubleClicked(TGListTreeItem *, Int_t)",
178  "TGFileBrowser", this, "DoubleClicked(TGListTreeItem *, Int_t)");
179  fListTree->Connect("Clicked(TGListTreeItem *, Int_t, Int_t, Int_t)",
180  "TGFileBrowser", this, "Clicked(TGListTreeItem *, Int_t, Int_t, Int_t)");
181  fListTree->Connect("Checked(TObject*, Bool_t)", "TGFileBrowser",
182  this, "Checked(TObject*, Bool_t)");
183 
184  fRootIcon = gClient->GetPicture("rootdb_t.xpm");
185  fFileIcon = gClient->GetPicture("doc_t.xpm");
186 
187  fBotFrame = new TGHorizontalFrame(this, 100, 30);
188  fBotFrame->AddFrame(new TGLabel(fBotFrame, "Filter: "),
189  new TGLayoutHints(kLHintsCenterY | kLHintsLeft,
190  2, 2, 2, 2));
191  fFileType = new TGComboBox(fBotFrame, " All Files (*.*)");
192  Int_t ftype = 1;
193  fFileType->AddEntry(" All Files (*.*)", ftype++);
194  fFileType->AddEntry(" C/C++ Files (*.c;*.cxx;*.h;...)", ftype++);
195  fFileType->AddEntry(" ROOT Files (*.root)", ftype++);
196  fFileType->AddEntry(" Text Files (*.txt)", ftype++);
197  fFileType->Resize(200, 20);
198  fBotFrame->AddFrame(fFileType, new TGLayoutHints(kLHintsLeft | kLHintsTop |
199  kLHintsExpandX, 2, 2, 2, 2));
200  fFileType->Connect("Selected(Int_t)", "TGFileBrowser", this,
201  "ApplyFilter(Int_t)");
202  fFileType->GetTextEntry()->Connect("ReturnPressed()", "TGFileBrowser",
203  this, "ApplyFilter(Int_t = -1)");
204  AddFrame(fBotFrame, new TGLayoutHints(kLHintsLeft | kLHintsTop |
205  kLHintsExpandX, 2, 2, 2, 2));
206 
207  fContextMenu = new TContextMenu("FileBrowserContextMenu");
208  fFilter = 0;
209  fGroupSize = 1000;
210  fListLevel = 0;
211  fCurrentDir = 0;
212  fRootDir = 0;
213  fDir = 0;
214  fFile = 0;
215  fNKeys = 0;
216  fCnt = 0;
217  fFilterStr = "*";
218 
219  TString gv = gEnv->GetValue("Browser.GroupView", "1000");
220  Int_t igv = atoi(gv.Data());
221  if (igv > 10)
222  fGroupSize = igv;
223 
224  if (gEnv->GetValue("Browser.ShowHidden", 0))
225  fShowHidden = kTRUE;
226  else
227  fShowHidden = kFALSE;
228 
229  fDblClick = kFALSE;
230 
231  if (TClass::GetClass("TGHtmlBrowser"))
232  TQObject::Connect("TGHtmlBrowser", "Clicked(char*)",
233  "TGFileBrowser", this, "Selected(char*)");
234 
235  TQObject::Connect("TPad", "Modified()",
236  "TGFileBrowser", this, "PadModified()");
237 
238  fListLevel = 0;
239  MapSubwindows();
240  Resize(GetDefaultSize());
241  MapWindow();
242 }
243 
244 ////////////////////////////////////////////////////////////////////////////////
245 /// Destructor.
246 
247 TGFileBrowser::~TGFileBrowser()
248 {
249  if (TClass::GetClass("TGHtmlBrowser"))
250  TQObject::Disconnect("TGHtmlBrowser", "Clicked(char*)");
251  TQObject::Disconnect("TPad", "Modified()");
252 
253  delete fContextMenu;
254  delete fListTree;
255  if (fRootIcon) fClient->FreePicture(fRootIcon);
256  if (fCachedPic && (fCachedPic != fFileIcon))
257  fClient->FreePicture(fCachedPic);
258  if (fFileIcon) fClient->FreePicture(fFileIcon);
259  Cleanup();
260 }
261 
262 ////////////////////////////////////////////////////////////////////////////////
263 /// Helper function checking if a class has a graphic properties editor.
264 
265 static Bool_t IsObjectEditable(TClass *cl)
266 {
267  TBaseClass *base;
268  TList* bcl = cl->GetListOfBases();
269  TIter next(bcl);
270  while ((base = (TBaseClass*) next())) {
271  cl = base->GetClassPointer();
272  if (cl && TClass::GetClass(Form("%sEditor", cl->GetName())))
273  return kTRUE;
274  if (IsObjectEditable(cl))
275  return kTRUE;
276  }
277  return kFALSE;
278 }
279 
280 ////////////////////////////////////////////////////////////////////////////////
281 /// Format the tooltip information, based on the object passed in argument.
282 
283 static const char *FormatToolTip(TObject *obj, Int_t maxlen=0)
284 {
285  static TString infos;
286  if (!obj) {
287  infos.Clear();
288  return 0;
289  }
290  infos = obj->GetName();
291  if (obj->GetTitle()) {
292  infos += "\n";
293  infos += obj->GetTitle();
294  }
295  if (maxlen > 0 && infos.Length() > maxlen) {
296  infos.Remove(maxlen - 3);
297  infos += "...";
298  }
299  TString objinfo = obj->GetObjectInfo(1, 1);
300  if (!objinfo.IsNull() && !objinfo.BeginsWith("x=")) {
301  Long64_t bsize, fsize, objsize;
302  objsize = objinfo.Atoll();
303  if (objsize > 0) {
304  infos += "\n";
305  bsize = fsize = objsize;
306  if (fsize > 1024) {
307  fsize /= 1024;
308  if (fsize > 1024) {
309  // 3.7MB is more informative than just 3MB
310  infos += TString::Format("Size: %lld.%lldM", fsize/1024,
311  (fsize%1024)/103);
312  } else {
313  infos += TString::Format("Size: %lld.%lldK", bsize/1024,
314  (bsize%1024)/103);
315  }
316  } else {
317  infos += TString::Format("Size: %lld bytes", bsize);
318  }
319  }
320  }
321  return infos.Data();
322 }
323 
324 /**************************************************************************/
325 // TBrowserImp virtuals
326 /**************************************************************************/
327 
328 ////////////////////////////////////////////////////////////////////////////////
329 /// Add items to the browser. This function has to be called
330 /// by the Browse() member function of objects when they are
331 /// called by a browser. If check < 0 (default) no check box is drawn,
332 /// if 0 then unchecked checkbox is added, if 1 checked checkbox is added.
333 
334 void TGFileBrowser::Add(TObject *obj, const char *name, Int_t check)
335 {
336  if (fListLevel && !strcmp(fListLevel->GetText(), "Classes") &&
337  fListLevel->GetParent() &&
338  !strcmp(fListLevel->GetParent()->GetText(), "root")) {
339  // Browsing list of root classes...
340  }
341  else {
342  if (obj && obj->InheritsFrom("TApplication"))
343  fListLevel = 0;
344  if (obj && obj->InheritsFrom("TSystemDirectory"))
345  return;
346  }
347  if (fListLevel) {
348  TString oname = "";
349  if (name) oname = name;
350  else if (obj) oname = obj->GetName();
351  // check if the current item is filtered
352  mFiltered_i it = fFilteredItems.find(fListLevel);
353  if (it != fFilteredItems.end()) {
354  // check if the item (object) name match the filter
355  const char *filter = (const char *)(*it).second;
356  TRegexp re(filter, kTRUE);
357  // if not, simply return, so no item will be added
358  if (oname.Index(re) == kNPOS) return;
359  }
360  }
361  const TGPicture *pic=0;
362  if (obj && obj->InheritsFrom("TKey") && (obj->IsA() != TClass::Class()))
363  AddKey(fListLevel, obj, name);
364  else if (obj) {
365  GetObjPicture(&pic, obj);
366  if (!name) name = obj->GetName();
367  if (check > -1) {
368  if (!fListTree->FindChildByName(fListLevel, name)) {
369  TGListTreeItem *item = fListTree->AddItem(fListLevel, name, obj,
370  pic, pic, kTRUE);
371  if ((pic != fFileIcon) && (pic != fCachedPic))
372  fClient->FreePicture(pic);
373  if (item) fListTree->CheckItem(item, (Bool_t)check);
374  fListTree->SetToolTipItem(item, FormatToolTip(obj, 32));
375  }
376  }
377  else {
378  // special case for remote object
379  Bool_t isRemote = kFALSE;
380  if (obj->InheritsFrom("TRemoteObject"))
381  isRemote = kTRUE;
382  else if (fListLevel) {
383  // check also if one of its parents is a remote object
384  TGListTreeItem *top = fListLevel;
385  while (top->GetParent()) {
386  TObject *tobj = (TObject *) top->GetUserData();
387  if (tobj && (tobj->InheritsFrom("TRemoteObject") ||
388  tobj->InheritsFrom("TApplicationRemote"))) {
389  isRemote = kTRUE;
390  break;
391  }
392  top = top->GetParent();
393  }
394  }
395  if (isRemote) {
396  TRemoteObject *robj = (TRemoteObject *)obj;
397  if (!strcmp(robj->GetClassName(), "TKey")) {
398  AddKey(fListLevel, obj, name);
399  }
400  else {
401  TString fname = name;
402  // add the remote object only if not already in the list
403  if (!fShowHidden && fname.BeginsWith("."))
404  return;
405  AddRemoteFile(obj);
406  }
407  }
408  else {
409  if (!fListTree->FindChildByName(fListLevel, name)) {
410  TGListTreeItem *item = fListTree->AddItem(fListLevel, name, obj, pic, pic);
411  if ((pic != fFileIcon) && (pic != fCachedPic))
412  fClient->FreePicture(pic);
413  if (item && obj && obj->InheritsFrom("TObject"))
414  item->SetDNDSource(kTRUE);
415  fListTree->SetToolTipItem(item, FormatToolTip(obj, 32));
416  }
417  }
418  }
419  }
420 }
421 
422 ////////////////////////////////////////////////////////////////////////////////
423 /// Add remote file in list tree.
424 
425 void TGFileBrowser::AddRemoteFile(TObject *obj)
426 {
427  Bool_t is_link;
428  Int_t type;
429  TString filename;
430  const TGPicture *spic;
431  TGPicture *pic;
432 
433  FileStat_t sbuf;
434 
435  type = 0;
436  is_link = kFALSE;
437 
438  TRemoteObject *robj = (TRemoteObject *)obj;
439 
440  robj->GetFileStat(&sbuf);
441  is_link = sbuf.fIsLink;
442  type = sbuf.fMode;
443  filename = robj->GetName();
444  if (R_ISDIR(type) || fFilter == 0 ||
445  (fFilter && filename.Index(*fFilter) != kNPOS)) {
446 
447  GetFilePictures(&spic, type, is_link, filename);
448 
449  pic = (TGPicture*)spic; pic->AddReference();
450 
451  if ((!fListTree->FindChildByName(fListLevel, filename)) &&
452  (!fListTree->FindChildByData(fListLevel, obj)))
453  fListTree->AddItem(fListLevel, filename, obj, pic, pic);
454  }
455 }
456 
457 ////////////////////////////////////////////////////////////////////////////////
458 /// Browse object. This, in turn, will trigger the calling of
459 /// TBrowser::Add() which will fill the IconBox and the tree.
460 /// Emits signal "BrowseObj(TObject*)".
461 
462 void TGFileBrowser::BrowseObj(TObject *obj)
463 {
464  if (fNewBrowser)
465  fNewBrowser->SetActBrowser(this);
466  if (obj != gROOT) {
467  if (!fListTree->FindItemByObj(fListTree->GetFirstItem(), obj)) {
468  fListLevel = 0;
469  Add(obj);
470  fListLevel = fListTree->FindItemByObj(fListTree->GetFirstItem(), obj);
471  fListTree->HighlightItem(fListLevel);
472  if (obj->IsFolder())
473  fListTree->OpenItem(fListLevel);
474  fListTree->ClearViewPort();
475  fListTree->AdjustPosition(fListLevel);
476  }
477  }
478  if (fBrowser) obj->Browse(fBrowser);
479  if (obj == gROOT) {
480  TList *volumes = gSystem->GetVolumes("all");
481  TList *curvol = gSystem->GetVolumes("cur");
482  if (volumes && curvol) {
483  const char *curdrive;
484  TNamed *named = (TNamed *)curvol->At(0);
485  if (named)
486  curdrive = named->GetName();
487  else
488  curdrive = "C:";
489  TIter next(volumes);
490  TNamed *drive;
491  while ((drive = (TNamed *)next())) {
492  AddFSDirectory(TString::Format("%s\\", drive->GetName()), drive->GetTitle(),
493  (strcmp(drive->GetName(), curdrive) == 0) ?
494  "SetRootDir" : "Add");
495  }
496  delete volumes;
497  delete curvol;
498  }
499  else {
500  AddFSDirectory("/");
501  }
502  GotoDir(gSystem->WorkingDirectory());
503  if (gROOT->GetListOfFiles() && !gROOT->GetListOfFiles()->IsEmpty())
504  Selected(0);
505  }
506 }
507 
508 ////////////////////////////////////////////////////////////////////////////////
509 /// Emits signal when double clicking on icon.
510 
511 void TGFileBrowser::Checked(TObject *obj, Bool_t checked)
512 {
513  if (fNewBrowser)
514  fNewBrowser->Checked(obj, checked);
515 }
516 
517 ////////////////////////////////////////////////////////////////////////////////
518 /// returns drawing option
519 
520 Option_t *TGFileBrowser::GetDrawOption() const
521 {
522  return fDrawOption->GetTextEntry()->GetText();
523 }
524 
525 ////////////////////////////////////////////////////////////////////////////////
526 /// Determine the file picture for the given file type.
527 
528 void TGFileBrowser::GetFilePictures(const TGPicture **pic, Int_t file_type,
529  Bool_t is_link, const char *name)
530 {
531  static TString cached_ext;
532  static const TGPicture *cached_spic = 0;
533  const char *ext = name ? strrchr(name, '.') : 0;
534  TString sname = name ? name : " ";
535  *pic = 0;
536 
537  if (ext && cached_spic && (cached_ext == ext)) {
538  *pic = cached_spic;
539  return;
540  }
541 
542  if (R_ISREG(file_type)) {
543  *pic = gClient->GetMimeTypeList()->GetIcon(name, kTRUE);
544 
545  if (*pic) {
546  if (ext) {
547  cached_ext = ext;
548  cached_spic = *pic;
549  return;
550  }
551  }
552  } else {
553  *pic = 0;
554  }
555 
556  if (*pic == 0) {
557  *pic = gClient->GetPicture("doc_t.xpm");
558 
559  if (R_ISREG(file_type) && (file_type) & kS_IXUSR) {
560  *pic = gClient->GetPicture("app_t.xpm");
561  }
562  if (R_ISDIR(file_type)) {
563  *pic = gClient->GetPicture("folder_t.xpm");
564  }
565  if(sname.EndsWith(".root")) {
566  *pic = gClient->GetPicture("rootdb_t.xpm");
567  }
568 
569  }
570  if (is_link) {
571  *pic = gClient->GetPicture("slink_t.xpm");
572  }
573 
574  cached_spic = 0;
575  cached_ext = "";
576 }
577 
578 ////////////////////////////////////////////////////////////////////////////////
579 /// Recursively remove object.
580 
581 void TGFileBrowser::RecursiveRemove(TObject *obj)
582 {
583  TGListTreeItem *itm = 0, *item = 0;
584  if (obj->InheritsFrom("TFile")) {
585  itm = fListTree->FindChildByData(0, gROOT->GetListOfFiles());
586  if (itm)
587  item = fListTree->FindChildByData(itm, obj);
588  if (item) {
589  // if the item to be deleted has a filter,
590  // delete its entry in the map
591  if (CheckFiltered(item))
592  fFilteredItems.erase(item);
593  fListTree->DeleteItem(item);
594  }
595  itm = fRootDir ? fRootDir->GetFirstChild() : 0;
596  while (itm) {
597  item = fListTree->FindItemByObj(itm, obj);
598  if (item) {
599  fListTree->DeleteChildren(item);
600  item->SetUserData(0);
601  }
602  itm = itm->GetNextSibling();
603  }
604  }
605  if (!obj->InheritsFrom("TFile") && fRootDir) {
606  item = fListTree->FindItemByObj(fRootDir, obj);
607  // if the item to be deleted has a filter, delete its entry in the map
608  if (item && CheckFiltered(item))
609  fFilteredItems.erase(item);
610  fListTree->RecursiveDeleteItem(fRootDir, obj);
611  }
612  //fListTree->ClearViewPort();
613 }
614 
615 ////////////////////////////////////////////////////////////////////////////////
616 /// Refresh content of the list tree.
617 
618 void TGFileBrowser::Refresh(Bool_t /*force*/)
619 {
620  TTimer::SingleShot(200, "TGFileBrowser", this, "Update()");
621  return; // disable refresh for the time being...
622  // coverity[unreachable]
623  TCursorSwitcher cursorSwitcher(this, fListTree);
624  static UInt_t prev = 0;
625  UInt_t curr = gROOT->GetListOfBrowsables()->GetSize();
626  if (!prev) prev = curr;
627 
628  if (prev != curr) { // refresh gROOT
629  TGListTreeItem *sav = fListLevel;
630  fListLevel = 0;
631  BrowseObj(gROOT);
632  fListLevel = sav;
633  prev = curr;
634  }
635 }
636 
637 ////////////////////////////////////////////////////////////////////////////////
638 /// Update content of the list tree.
639 
640 void TGFileBrowser::Update()
641 {
642  Long64_t size = 0;
643  Long_t id = 0, flags = 0, modtime = 0;
644  char path[1024];
645  TGListTreeItem *item = fCurrentDir;
646  if (!item) item = fRootDir;
647  if (!item) return;
648  //fListTree->DeleteChildren(item);
649  TGListTreeItem *curr = fListTree->GetSelected(); // GetCurrent() ??
650  if (curr) {
651  TObject *obj = (TObject *) curr->GetUserData();
652  if (obj && !obj->TestBit(kNotDeleted)) {
653  // if the item to be deleted has a filter,
654  // delete its entry in the map
655  if (CheckFiltered(curr))
656  fFilteredItems.erase(curr);
657  fListTree->DeleteItem(curr);
658  curr = 0;
659  obj = 0;
660  }
661  else if (obj && obj->TestBit(kNotDeleted) &&
662  obj->InheritsFrom("TObjString") && curr->GetParent()) {
663  fListTree->GetPathnameFromItem(curr->GetParent(), path);
664  if (strlen(path) > 1) {
665  TString dirpath = FullPathName(curr->GetParent());
666  Int_t res = gSystem->GetPathInfo(dirpath.Data(), &id, &size,
667  &flags, &modtime);
668  if ((res == 0) && (flags & 2)) {
669  TString fullpath = FullPathName(curr);
670  if (gSystem->AccessPathName(fullpath.Data())) {
671  // if the item to be deleted has a filter,
672  // delete its entry in the map
673  if (CheckFiltered(curr))
674  fFilteredItems.erase(curr);
675  fListTree->DeleteItem(curr);
676  curr = 0;
677  obj = 0;
678  }
679  }
680  }
681  }
682  }
683  TString actpath = FullPathName(item);
684  flags = id = size = modtime = 0;
685  if (gSystem->GetPathInfo(actpath.Data(), &id, &size, &flags, &modtime) == 0) {
686  Int_t isdir = (Int_t)flags & 2;
687 
688  TString savdir = gSystem->WorkingDirectory();
689  if (isdir) {
690  TGListTreeItem *del = 0, *itm = item->GetFirstChild();
691  while (itm) {
692  fListTree->GetPathnameFromItem(itm, path);
693  if (strlen(path) > 1) {
694  TString recpath = FullPathName(itm);
695  if (gSystem->AccessPathName(recpath.Data())) {
696  del = itm;
697  itm = itm->GetNextSibling();
698  // if the item to be deleted has a filter,
699  // delete its entry in the map
700  if (CheckFiltered(del))
701  fFilteredItems.erase(del);
702  fListTree->DeleteItem(del);
703  }
704  }
705  if (del)
706  del = 0;
707  else
708  itm = itm->GetNextSibling();
709  }
710  }
711  }
712  TGListTreeItem *sav = fListLevel;
713  DoubleClicked(item, 1);
714  fListLevel = sav;
715  CheckFiltered(fListLevel, kTRUE);
716 }
717 
718 /**************************************************************************/
719 // Other
720 /**************************************************************************/
721 
722 ////////////////////////////////////////////////////////////////////////////////
723 /// Add file system directory in the list tree.
724 
725 void TGFileBrowser::AddFSDirectory(const char *entry, const char *path,
726  Option_t *opt)
727 {
728  TGListTreeItem *item = 0;
729  if ((opt == 0) || (!opt[0])) {
730  if (fRootDir == 0 && !fListTree->FindChildByName(0, rootdir))
731  item = fRootDir = fListTree->AddItem(0, rootdir);
732  return;
733  }
734  if (strstr(opt, "SetRootDir")) {
735  if (!fListTree->FindChildByName(0, entry))
736  item = fRootDir = fListTree->AddItem(0, entry);
737  }
738  else if (strstr(opt, "Add")) {
739  // MT: i give up! wanted to place entries for selected
740  // directories like home, pwd, alice-macros.
741  // TGListTreeItem *lti = fListTree->AddItem(0, entry);
742  //
743  if (!fListTree->FindChildByName(0, entry))
744  item = fListTree->AddItem(0, entry);
745  }
746  if (item && path) {
747  TString infos = path;
748  item->SetTipText(path);
749  TGPicture *pic = 0;
750  if (infos.Contains("Removable"))
751  pic = (TGPicture *)gClient->GetPicture("fdisk_t.xpm");
752  else if (infos.Contains("Local"))
753  pic = (TGPicture *)gClient->GetPicture("hdisk_t.xpm");
754  else if (infos.Contains("CD"))
755  pic = (TGPicture *)gClient->GetPicture("cdrom_t.xpm");
756  else if (infos.Contains("Network"))
757  pic = (TGPicture *)gClient->GetPicture("netdisk_t.xpm");
758  if (pic)
759  item->SetPictures(pic, pic);
760  }
761 }
762 
763 ////////////////////////////////////////////////////////////////////////////////
764 /// display content of ROOT file
765 
766 void TGFileBrowser::AddKey(TGListTreeItem *itm, TObject *obj, const char *name)
767 {
768  // Int_t from, to;
769  TGListTreeItem *where;
770  static TGListTreeItem *olditem = itm;
771  static TGListTreeItem *item = itm;
772  const TGPicture *pic;
773 
774  if (itm == 0) return;
775 
776  if ((fCnt == 0) || (olditem != itm)) {
777  olditem = item = itm;
778  }
779  if (!name) name = obj->GetName();
780  if (fNKeys > fGroupSize) {
781  where = itm->GetFirstChild();
782  while (where) {
783  if (fListTree->FindItemByObj(where, obj))
784  return;
785  where = where->GetNextSibling();
786  }
787  }
788  if ((fNKeys > fGroupSize) && (fCnt % fGroupSize == 0)) {
789  if (item != itm) {
790  TString newname = TString::Format("%s-%s", item->GetText(), name);
791  item->Rename(newname.Data());
792  }
793  item = fListTree->AddItem(itm, name);
794  item->SetDNDSource(kTRUE);
795  }
796  if ((fCnt > fGroupSize) && (fCnt >= fNKeys-1)) {
797  TString newname = TString::Format("%s-%s", item->GetText(), name);
798  item->Rename(newname.Data());
799  }
800  GetObjPicture(&pic, obj);
801  if (!fListTree->FindChildByName(item, name)) {
802  TGListTreeItem *it = fListTree->AddItem(item, name, obj, pic, pic);
803  if (pic && (pic != fFileIcon) && (pic != fCachedPic))
804  fClient->FreePicture(pic);
805  it->SetDNDSource(kTRUE);
806  it->SetTipText(FormatToolTip(obj, 32));
807  }
808  fCnt++;
809 }
810 
811 ////////////////////////////////////////////////////////////////////////////////
812 /// Apply filter selected in combo box to the file tree view.
813 
814 void TGFileBrowser::ApplyFilter(Int_t id)
815 {
816  // Long64_t size;
817  // Long_t fid, flags, modtime;
818 
819  if (fFilter) delete fFilter;
820  fFilter = 0;
821  if ((id > 1) && (id < 5))
822  fFilter = new TRegexp(filters[id], kTRUE);
823  else if ((id < 0) || (id > 4)) {
824  TGTextLBEntry *lbe = (TGTextLBEntry *)fFileType->GetSelectedEntry();
825  if (lbe) {
826  const char *text = lbe->GetTitle();
827  fFilter = new TRegexp(text, kTRUE);
828  }
829  }
830  TGListTreeItem *item = fCurrentDir;
831  if (!item)
832  item = fRootDir;
833  if (!item) return;
834  fListTree->DeleteChildren(item);
835  DoubleClicked(item, 1);
836  //fListTree->AdjustPosition(item);
837  fListTree->ClearViewPort();
838 }
839 
840 ////////////////////////////////////////////////////////////////////////////////
841 /// Make object associated with item the current directory.
842 
843 void TGFileBrowser::Chdir(TGListTreeItem *item)
844 {
845  if (item) {
846  TGListTreeItem *i = item;
847  while (i) {
848  TObject *obj = (TObject*) i->GetUserData();
849  if ((obj) && obj->InheritsFrom("TDirectory")) {
850  ((TDirectory *)obj)->cd();
851  break;
852  }
853  i = i->GetParent();
854  }
855  }
856 }
857 
858 ////////////////////////////////////////////////////////////////////////////////
859 /// Check if the current list tree item points to a remote object.
860 
861 void TGFileBrowser::CheckRemote(TGListTreeItem *item)
862 {
863  if (!item) return;
864  TObject *obj = (TObject *) item->GetUserData();
865  if (obj) {
866  if (obj->InheritsFrom("TApplicationRemote")) {
867  if (!gApplication->GetAppRemote()) {
868  gROOT->ProcessLine(TString::Format(".R %s", item->GetText()));
869  if (gApplication->GetAppRemote()) {
870  Getlinem(kInit, TString::Format("\n%s:root [0]",
871  gApplication->GetAppRemote()->ApplicationName()));
872  }
873  }
874  }
875  if (item->GetParent() && item->GetParent()->GetUserData() &&
876  ((TObject *)item->GetParent()->GetUserData())->InheritsFrom("TApplicationRemote")) {
877  // switch to remote session
878  if (!gApplication->GetAppRemote()) {
879  gROOT->ProcessLine(TString::Format(".R %s", item->GetParent()->GetText()));
880  if (gApplication->GetAppRemote()) {
881  Getlinem(kInit, TString::Format("\n%s:root [0]",
882  gApplication->GetAppRemote()->ApplicationName()));
883  }
884  }
885  else if (!strcmp(item->GetText(), "ROOT Files")) {
886  // update list of files opened in the remote session
887  gApplication->SetBit(TApplication::kProcessRemotely);
888  gApplication->ProcessLine("((TApplicationServer *)gApplication)->BrowseFile(0);");
889  }
890  }
891  else {
892  // check if the listtree item is from a local session or
893  // from a remote session, then switch to the session it belongs to
894  TGListTreeItem *top = item;
895  while (top->GetParent()) {
896  top = top->GetParent();
897  }
898  TObject *topobj = (TObject *) top->GetUserData();
899  if (topobj && topobj->InheritsFrom("TApplicationRemote")) {
900  // it belongs to a remote session
901  if (!gApplication->GetAppRemote()) {
902  // switch to remote session if not already in
903  gROOT->ProcessLine(TString::Format(".R %s", top->GetText()));
904  if (gApplication->GetAppRemote()) {
905  Getlinem(kInit, TString::Format("\n%s:root [0]",
906  gApplication->GetAppRemote()->ApplicationName()));
907  }
908  }
909  }
910  else if (gApplication->GetAppRemote()) {
911  // switch back to local session if not already in
912  gApplication->ProcessLine(".R");
913  Getlinem(kInit, "\nroot [0]");
914  }
915  }
916  }
917  else if (gApplication->GetAppRemote()) {
918  // switch back to local session if not already in
919  gApplication->ProcessLine(".R");
920  Getlinem(kInit, "\nroot [0]");
921  }
922 }
923 
924 ////////////////////////////////////////////////////////////////////////////////
925 /// Check if there is a filter active on the children of the list tree item.
926 /// If the but argument is true, the "filter" button state is set accordingly,
927 /// and its tooltip will show the filter used.
928 
929 Bool_t TGFileBrowser::CheckFiltered(TGListTreeItem *item, Bool_t but)
930 {
931  Bool_t found = kFALSE;
932  TString filter;
933  // if there is no filter (the map is empty) then just return
934  if (fFilteredItems.empty())
935  return kFALSE;
936  mFiltered_i it = fFilteredItems.find(item);
937  if (it != fFilteredItems.end()) {
938  // if the item is in the map, take the filter regexp string
939  filter = (const char *)(*it).second;
940  fFilterStr = filter;
941  found = kTRUE;
942  }
943  if (but) {
944  // if the but argument is true, change the button state
945  // to reflect the filtering state
946  fFilterButton->SetState(found ? kButtonEngaged : kButtonUp);
947  if (found) {
948  // format the tooltip to display the regexp used as filter
949  filter.Prepend("Showing only \'");
950  filter += "\'";
951  fFilterButton->SetToolTipText(filter.Data());
952  }
953  else {
954  // reset the tooltip text
955  fFilterButton->SetToolTipText("Filter Content...");
956  }
957  }
958  return found;
959 }
960 
961 ////////////////////////////////////////////////////////////////////////////////
962 /// Check if the list tree item children are alphabetically sorted.
963 /// If the but argument is true, the "sort" button state is set accordingly.
964 
965 Bool_t TGFileBrowser::CheckSorted(TGListTreeItem *item, Bool_t but)
966 {
967  Bool_t found = kFALSE;
968  TGListTreeItem *i, *itm;
969  if (item->GetFirstChild())
970  itm = item;
971  else
972  itm = item->GetParent();
973  for (sLTI_i p=fSortedItems.begin(); p!=fSortedItems.end(); ++p) {
974  i = (TGListTreeItem *)(*p);
975  if (itm == i) {
976  found = kTRUE;
977  break;
978  }
979  }
980  if (but) fSortButton->SetState(found ? kButtonEngaged : kButtonUp);
981  return found;
982 }
983 
984 ////////////////////////////////////////////////////////////////////////////////
985 /// Process mouse clicks in TGListTree.
986 
987 void TGFileBrowser::Clicked(TGListTreeItem *item, Int_t btn, Int_t x, Int_t y)
988 {
989  char path[1024];
990  Long64_t size = 0;
991  Long_t id = 0, flags = 0, modtime = 0;
992  fListLevel = item;
993  if (!item) return;
994  CheckSorted(item, kTRUE);
995  CheckFiltered(item, kTRUE);
996  CheckRemote(item);
997  TObject *selected = 0;
998  TString fullpath = FullPathName(item);
999  TObject *obj = (TObject *) item->GetUserData();
1000  if (obj && (!obj->InheritsFrom("TObjString") ||
1001  gSystem->AccessPathName(fullpath.Data()))) {
1002  if (obj->InheritsFrom("TKey") && (obj->IsA() != TClass::Class())) {
1003  Chdir(item);
1004  const char *clname = ((TKey *)obj)->GetClassName();
1005  if (clname && strcmp(clname, "TGeoManager")) {
1006  TClass *cl = TClass::GetClass(clname);
1007  TString name = ((TKey *)obj)->GetName();
1008  name += ";";
1009  name += ((TKey *)obj)->GetCycle();
1010  void *add = gDirectory->FindObjectAny((char *) name.Data());
1011  if (add && cl->IsTObject()) {
1012  obj = (TObject*)add;
1013  // don't change the user data, to avoid deletion of the
1014  // list tree item by RecursiveRemove()
1015  // it is better to read the object each time anyway,
1016  // as it may have changed in the file
1017  if (obj->InheritsFrom("TDirectory") || obj->InheritsFrom("TList"))
1018  item->SetUserData(obj);
1019  }
1020  }
1021  }
1022  if (obj->InheritsFrom("TLeaf") ||
1023  obj->InheritsFrom("TBranch")) {
1024  Chdir(item);
1025  }
1026  if (btn == kButton3)
1027  fContextMenu->Popup(x, y, obj, fBrowser);
1028  selected = obj;
1029  }
1030  else {
1031  fListTree->GetPathnameFromItem(item, path);
1032  if (strlen(path) > 3) {
1033  if (gSystem->GetPathInfo(fullpath.Data(), &id, &size, &flags, &modtime) == 0) {
1034  if (flags & 2) {
1035  fCurrentDir = item;
1036  if (btn == kButton3) {
1037  if (fDir) delete fDir;
1038  fDir = new TSystemDirectory(item->GetText(), fullpath.Data());
1039  fContextMenu->Popup(x, y, fDir, fBrowser);
1040  }
1041  }
1042  else {
1043  fCurrentDir = item->GetParent();
1044  if (btn == kButton3) {
1045  if (fFile) delete fFile;
1046  fFile = new TSystemFile(item->GetText(), fullpath.Data());
1047  fContextMenu->Popup(x, y, fFile, fBrowser);
1048  }
1049  }
1050  }
1051  }
1052  }
1053  fListTree->ClearViewPort();
1054  if (selected && (selected->IsA() != TClass::Class())) {
1055  if (selected->InheritsFrom("TLeaf"))
1056  selected = (TObject *)gROOT->ProcessLine(TString::Format("((TLeaf *)0x%lx)->GetBranch()->GetTree();", (ULong_t)selected));
1057  if (selected->InheritsFrom("TBranch"))
1058  selected = (TObject *)gROOT->ProcessLine(TString::Format("((TBranch *)0x%lx)->GetTree();", (ULong_t)selected));
1059  if (selected->InheritsFrom("TTree")) {
1060  // if a tree not attached to any directory (e.g. in a TFolder)
1061  // then attach it to the current directory (gDirectory)
1062  TDirectory *tdir = (TDirectory *)gROOT->ProcessLine(TString::Format("((TTree *)0x%lx)->GetDirectory();", (ULong_t)selected));
1063  if (!tdir) {
1064  gROOT->ProcessLine(TString::Format("((TTree *)0x%lx)->SetDirectory(gDirectory);", (ULong_t)selected));
1065  }
1066  }
1067  }
1068  if (selected && gPad && IsObjectEditable(selected->IsA())) {
1069  TVirtualPadEditor *ved = TVirtualPadEditor::GetPadEditor(kFALSE);
1070  if (ved) {
1071  TGedEditor *ged = (TGedEditor *)ved;
1072  ged->SetModel(gPad, selected, kButton1Down);
1073  }
1074  }
1075 }
1076 
1077 ////////////////////////////////////////////////////////////////////////////////
1078 /// returns an absolute path
1079 
1080 TString TGFileBrowser::FullPathName(TGListTreeItem* item)
1081 {
1082  TGListTreeItem *parent, *itm = item;
1083  TString dirname = itm->GetText();
1084 
1085  while ((parent=itm->GetParent())) {
1086  char *s = gSystem->ConcatFileName(parent->GetText(), dirname);
1087  dirname = s;
1088  delete [] s;
1089  itm = parent;
1090  }
1091  dirname = gSystem->ExpandPathName(dirname.Data());
1092 #ifdef R__WIN32
1093  // only handle .lnk files on Windows
1094  while (dirname.Contains(".lnk")) {
1095  Ssiz_t idx = dirname.Index(".lnk") + 4;
1096  TString resolved = dirname;
1097  resolved.Remove(idx);
1098  resolved = gSystem->ExpandPathName(resolved.Data());
1099  dirname = resolved.Append(dirname.Remove(0, idx));
1100  }
1101 #endif
1102  return dirname;
1103 }
1104 
1105 ////////////////////////////////////////////////////////////////////////////////
1106 /// returns the directory path
1107 
1108 TString TGFileBrowser::DirName(TGListTreeItem* item)
1109 {
1110  TString dirname;
1111  TString fullpath = FullPathName(item);
1112 
1113 #ifdef WIN32
1114  char winDrive[256];
1115  char winDir[256];
1116  char winName[256];
1117  char winExt[256];
1118  _splitpath(fullpath.Data(), winDrive, winDir, winName, winExt);
1119  dirname = TString::Format("%s%s", winDrive, winDir);
1120 #else
1121  dirname = gSystem->DirName(fullpath);
1122 #endif
1123  return dirname;
1124 }
1125 
1126 ////////////////////////////////////////////////////////////////////////////////
1127 /// Returns true if given a text file
1128 /// Uses the specification given on p86 of the Camel book
1129 /// - Text files have no NULLs in the first block
1130 /// - and less than 30% of characters with high bit set
1131 
1132 static Bool_t IsTextFile(const char *candidate)
1133 {
1134  Int_t i;
1135  Int_t nchars;
1136  Int_t weirdcount = 0;
1137  char buffer[512];
1138  FILE *infile;
1139  FileStat_t buf;
1140 
1141  if (gSystem->GetPathInfo(candidate, buf) || !(buf.fMode & kS_IFREG))
1142  return kFALSE;
1143 
1144  infile = fopen(candidate, "r");
1145  if (infile) {
1146  // Read a block
1147  nchars = fread(buffer, 1, 512, infile);
1148  fclose (infile);
1149  // Examine the block
1150  for (i = 0; i < nchars; i++) {
1151  if (buffer[i] & 128)
1152  weirdcount++;
1153  if (buffer[i] == '\0')
1154  // No NULLs in text files
1155  return kFALSE;
1156  }
1157  if ((nchars > 0) && ((weirdcount * 100 / nchars) > 30))
1158  return kFALSE;
1159  } else {
1160  // Couldn't open it. Not a text file then
1161  return kFALSE;
1162  }
1163  return kTRUE;
1164 }
1165 
1166 ////////////////////////////////////////////////////////////////////////////////
1167 /// Create a symlink (shortcut on Windows) icon by merging the picture
1168 /// passed as argument and the slink_t.xpm icon (small arrow)
1169 
1170 static const TGPicture *MakeLinkPic(const TGPicture *pic)
1171 {
1172  const TGPicture *merged;
1173  TImage *img1, *img2;
1174  if (pic) {
1175  img1 = TImage::Create();
1176  if (img1 == 0) return pic;
1177  img1->SetImage(((const TGPicture *)pic)->GetPicture(),
1178  ((const TGPicture *)pic)->GetMask());
1179  img2 = TImage::Open("slink_t.xpm");
1180  if (img2) img1->Merge(img2);
1181  TString lnk_name = ((const TGPicture *)pic)->GetName();
1182  lnk_name.Prepend("lnk_");
1183  merged = gClient->GetPicturePool()->GetPicture(lnk_name.Data(),
1184  img1->GetPixmap(), img1->GetMask());
1185  if (img2) delete img2;
1186  delete img1;
1187  return merged;
1188  }
1189  return pic;
1190 }
1191 
1192 ////////////////////////////////////////////////////////////////////////////////
1193 /// Process double clicks in TGListTree.
1194 
1195 void TGFileBrowser::DoubleClicked(TGListTreeItem *item, Int_t /*btn*/)
1196 {
1197  const TGPicture *pic=0;
1198  TString dirname = DirName(item);
1199  TString fullpath = FullPathName(item);
1200  TGListTreeItem *itm;
1201  FileStat_t sbuf;
1202  Long64_t size;
1203  Long_t id, flags, modtime;
1204  char action[512];
1205  TString act;
1206  Bool_t is_link = kFALSE;
1207  if (!gSystem->GetPathInfo(item->GetText(), sbuf) && sbuf.fIsLink) {
1208  is_link = kTRUE;
1209  fullpath = gSystem->ExpandPathName(item->GetText());
1210  }
1211 
1212  if (fNewBrowser)
1213  fNewBrowser->SetActBrowser(this);
1214  TCursorSwitcher switcher(this, fListTree);
1215  fListLevel = item;
1216  CheckSorted(item, kTRUE);
1217  CheckFiltered(item, kTRUE);
1218  CheckRemote(item);
1219  TGListTreeItem *pitem = item->GetParent();
1220  TObject *obj = (TObject *) item->GetUserData();
1221  if (obj && !obj->InheritsFrom("TSystemFile")) {
1222  TString ext = obj->GetName();
1223  if (obj->InheritsFrom("TDirectory") && (obj->IsA() != TClass::Class())) {
1224  if (((TDirectory *)obj)->GetListOfKeys())
1225  fNKeys = ((TDirectory *)obj)->GetListOfKeys()->GetEntries();
1226  else
1227  fNKeys = 0;
1228  }
1229  else if (obj->InheritsFrom("TKey") && (obj->IsA() != TClass::Class())) {
1230  Chdir(item);
1231  const char *clname = ((TKey *)obj)->GetClassName();
1232  if (clname) {
1233  TClass *cl = TClass::GetClass(clname);
1234  TString name = ((TKey *)obj)->GetName();
1235  name += ";";
1236  name += ((TKey *)obj)->GetCycle();
1237  void *add = gDirectory->FindObjectAny((char *) name.Data());
1238  if (add && cl->IsTObject()) {
1239  obj = (TObject*)add;
1240  // don't change the user data, to avoid deletion of the
1241  // list tree item by RecursiveRemove()
1242  // it is better to read the object each time anyway,
1243  // as it may have changed in the file
1244  if (obj->InheritsFrom("TDirectory") || obj->InheritsFrom("TList"))
1245  item->SetUserData(obj);
1246  }
1247  }
1248  }
1249  else if (obj->InheritsFrom("TLeaf") || obj->InheritsFrom("TBranch")) {
1250  Chdir(item);
1251  }
1252  else if (obj->InheritsFrom("TRemoteObject")) {
1253  // the real object is a TKey
1254  TRemoteObject *robj = (TRemoteObject *)obj;
1255  if (!strcmp(robj->GetClassName(), "TKey")) {
1256  TGListTreeItem *parent = item;
1257  TRemoteObject *probj = (TRemoteObject *)parent->GetUserData();
1258  // find the TFile remote object containing the TKey
1259  while ( probj && strcmp(probj->GetClassName(), "TFile")) {
1260  parent = parent->GetParent();
1261  probj = (TRemoteObject *)parent->GetUserData();
1262  }
1263  if (probj && !strcmp(probj->GetClassName(), "TFile")) {
1264  // remotely browse file (remotely call TFile::cd())
1265  gApplication->SetBit(TApplication::kProcessRemotely);
1266  gApplication->ProcessLine(
1267  TString::Format("((TApplicationServer *)gApplication)->BrowseFile(\"%s\");",
1268  probj->GetName()));
1269  gSystem->Sleep(250);
1270  }
1271  }
1272  if (gClient->GetMimeTypeList()->GetAction(obj->GetName(), action)) {
1273  act = action;
1274  act.ReplaceAll("%s", obj->GetName());
1275  if ((act[0] != '!') && (strcmp(pitem->GetText(), "ROOT Files"))) {
1276  // special case for remote object: remote process
1277  gApplication->SetBit(TApplication::kProcessRemotely);
1278  gApplication->ProcessLine(act.Data());
1279  }
1280  }
1281  if ((ext.EndsWith(".root")) && (strcmp(pitem->GetText(), "ROOT Files"))) {
1282  gApplication->SetBit(TApplication::kProcessRemotely);
1283  gApplication->ProcessLine("((TApplicationServer *)gApplication)->BrowseFile(0);");
1284  }
1285  }
1286  if (!obj->InheritsFrom("TObjString") ||
1287  gSystem->AccessPathName(fullpath.Data())) {
1288  if (fBrowser) fBrowser->SetDrawOption(GetDrawOption());
1289  fDblClick = kTRUE;
1290  if (gClient->GetMimeTypeList()->GetAction(obj->IsA()->GetName(), action)) {
1291  act = action;
1292  if (fBrowser && act.Contains("->Browse()")) obj->Browse(fBrowser);
1293  else if (act.Contains("->Draw()")) obj->Draw(GetDrawOption());
1294  else {
1295  if (act.Contains("%s")) act.ReplaceAll("%s", obj->GetName());
1296  else act.Prepend(obj->GetName());
1297  gInterpreter->SaveGlobalsContext();
1298  if (act[0] == '!') {
1299  act.Remove(0, 1);
1300  gSystem->Exec(act.Data());
1301  } else {
1302  // special case for remote object: remote process
1303  if (obj->InheritsFrom("TRemoteObject"))
1304  gApplication->SetBit(TApplication::kProcessRemotely);
1305  gApplication->ProcessLine(act.Data());
1306  }
1307  }
1308  }
1309  else if (obj->InheritsFrom("TCanvas") && fNewBrowser &&
1310  fNewBrowser->GetTabRight() &&
1311  fNewBrowser->GetTabRight()->GetTabTab(obj->GetName())) {
1312  // avoid potential crash when drawing a canvas with the same name
1313  // than a canvas already embedded in one of the browser's tab
1314  obj->DrawClone();
1315  }
1316  else if (fBrowser && !obj->InheritsFrom("TFormula"))
1317  obj->Browse(fBrowser);
1318  fDblClick = kFALSE;
1319  fNKeys = 0;
1320  fCnt = 0;
1321  fListTree->ClearViewPort();
1322  if (gPad) gPad->Update();
1323  return;
1324  }
1325  }
1326  flags = id = size = modtime = 0;
1327  if (gSystem->GetPathInfo(fullpath.Data(), &id, &size, &flags, &modtime) != 0)
1328  return;
1329  Int_t isdir = (Int_t)flags & 2;
1330 
1331  TString savdir = gSystem->WorkingDirectory();
1332  if (isdir) {
1333  fCurrentDir = item;
1334  //fListTree->DeleteChildren(item);
1335  TSystemDirectory dir(item->GetText(),FullPathName(item));
1336  TList *files = dir.GetListOfFiles();
1337  if (files) {
1338  files->Sort();
1339  TIter next(files);
1340  TSystemFile *file;
1341  TString fname, pname;
1342  // directories first
1343  //fListTree->DeleteChildren(item);
1344  while ((file=(TSystemFile*)next())) {
1345  fname = file->GetName();
1346  if (file->IsDirectory()) {
1347  if (!fShowHidden && fname.BeginsWith("."))
1348  continue;
1349  if ((fname!="..") && (fname!=".")) { // skip it
1350  if (!fListTree->FindChildByName(item, fname)) {
1351  itm = fListTree->AddItem(item, fname);
1352  if (!gSystem->GetPathInfo(fname, sbuf) &&
1353  sbuf.fIsLink) {
1354  // change the pictures if it is a symlink
1355  // (shortcut on Windows)
1356  const TGPicture *opened = 0, *l_opened = 0;
1357  const TGPicture *closed = 0, *l_closed = 0;
1358  opened = fClient->GetPicture("ofolder_t.xpm");
1359  if (opened) l_opened = MakeLinkPic(opened);
1360  closed = fClient->GetPicture("folder_t.xpm");
1361  if (closed) l_closed = MakeLinkPic(closed);
1362  if (l_opened && l_closed)
1363  itm->SetPictures(l_opened, l_closed);
1364  if (opened) fClient->FreePicture(opened);
1365  if (closed) fClient->FreePicture(closed);
1366  if (l_opened) fClient->FreePicture(l_opened);
1367  if (l_closed) fClient->FreePicture(l_closed);
1368  }
1369  // uncomment line below to set directories as
1370  // DND targets
1371  //itm->SetDNDTarget(kTRUE);
1372  itm->SetUserData(0);
1373  }
1374  }
1375  }
1376  }
1377  // then files...
1378  TIter nextf(files);
1379  while ((file=(TSystemFile*)nextf())) {
1380  fname = pname = file->GetName();
1381  if (!file->IsDirectory() && (fFilter == 0 ||
1382  (fFilter && fname.Index(*fFilter) != kNPOS))) {
1383  if (!fShowHidden && fname.BeginsWith("."))
1384  continue;
1385  size = modtime = 0;
1386  if (gSystem->GetPathInfo(fname, sbuf) == 0) {
1387  size = sbuf.fSize;
1388  modtime = sbuf.fMtime;
1389  }
1390  if (sbuf.fIsLink && pname.EndsWith(".lnk"))
1391  pname.Remove(pname.Length()-4);
1392  pic = gClient->GetMimeTypeList()->GetIcon(pname, kTRUE);
1393  if (!pic)
1394  pic = fFileIcon;
1395  if (sbuf.fIsLink)
1396  pic = MakeLinkPic(pic);
1397  if (!fListTree->FindChildByName(item, fname)) {
1398  itm = fListTree->AddItem(item, fname, pic, pic);
1399  if (pic != fFileIcon)
1400  fClient->FreePicture(pic);
1401  if (sbuf.fIsLink)
1402  itm->SetUserData(new TObjString(TString::Format("file://%s\r\n",
1403  gSystem->ExpandPathName(file->GetName()))), kTRUE);
1404  else
1405  itm->SetUserData(new TObjString(TString::Format("file://%s/%s\r\n",
1406  gSystem->UnixPathName(file->GetTitle()),
1407  file->GetName())), kTRUE);
1408  itm->SetDNDSource(kTRUE);
1409  if (size && modtime) {
1410  char *tiptext = FormatFileInfo(fname.Data(), size, modtime);
1411  itm->SetTipText(tiptext);
1412  delete [] tiptext;
1413  }
1414  }
1415  }
1416  }
1417  files->Delete();
1418  delete files;
1419  }
1420  }
1421  else {
1422  TString lnkname = item->GetText();
1423  if (is_link && lnkname.EndsWith(".lnk"))
1424  lnkname.Remove(lnkname.Length()-4);
1425  fCurrentDir = item->GetParent();
1426  TSystemFile f(lnkname.Data(), fullpath.Data());
1427  TString fname = f.GetName();
1428  if (fname.EndsWith(".root")) {
1429  TDirectory *rfile = 0;
1430  gSystem->ChangeDirectory(dirname.Data());
1431  rfile = (TDirectory *)gROOT->GetListOfFiles()->FindObject(obj);
1432  if (!rfile) {
1433  rfile = (TDirectory *)gROOT->ProcessLine(TString::Format("new TFile(\"%s\")",fname.Data()));
1434  }
1435  if (rfile) {
1436  // replace actual user data (TObjString) by the TDirectory...
1437  if (item->GetUserData()) {
1438  // first delete the data to avoid memory leaks
1439  TObject *obj2 = static_cast<TObject *>(item->GetUserData());
1440  // only delete TObjString as they are the only objects
1441  // created who have to be deleted
1442  TObjString *ostr = dynamic_cast<TObjString *>(obj2);
1443  if (ostr) delete ostr;
1444  }
1445  item->SetUserData(rfile);
1446  fNKeys = rfile->GetListOfKeys()->GetEntries();
1447  fCnt = 0;
1448  if (fBrowser) rfile->Browse(fBrowser);
1449  fNKeys = 0;
1450  fCnt = 0;
1451  }
1452  }
1453  else if (fname.EndsWith(".png")) {
1454  gSystem->ChangeDirectory(dirname.Data());
1455  XXExecuteDefaultAction(&f);
1456  gSystem->ChangeDirectory(savdir.Data());
1457  }
1458  else if (IsTextFile(fullpath.Data())) {
1459  gSystem->ChangeDirectory(dirname.Data());
1460  if (fNewBrowser) {
1461  TGFrameElement *fe = 0;
1462  TGTab *tabRight = fNewBrowser->GetTabRight();
1463  TGCompositeFrame *frame = tabRight->GetCurrentContainer();
1464  if (frame)
1465  fe = (TGFrameElement *)frame->GetList()->First();
1466  if (fe) {
1467  TGCompositeFrame *embed = (TGCompositeFrame *)fe->fFrame;
1468  TString fullname = f.GetTitle();
1469  fullname.ReplaceAll("\\", "\\\\");
1470  if (embed->InheritsFrom("TGTextEditor")) {
1471  gROOT->ProcessLine(TString::Format("((TGTextEditor *)0x%lx)->LoadFile(\"%s\");",
1472  (ULong_t)embed, fullname.Data()));
1473  }
1474  else if (embed->InheritsFrom("TGTextEdit")) {
1475  gROOT->ProcessLine(TString::Format("((TGTextEdit *)0x%lx)->LoadFile(\"%s\");",
1476  (ULong_t)embed, fullname.Data()));
1477  }
1478  else {
1479  XXExecuteDefaultAction(&f);
1480  }
1481  }
1482  else {
1483  XXExecuteDefaultAction(&f);
1484  }
1485  }
1486  gSystem->ChangeDirectory(savdir.Data());
1487  }
1488  else {
1489  gSystem->ChangeDirectory(dirname.Data());
1490  XXExecuteDefaultAction(&f);
1491  gSystem->ChangeDirectory(savdir.Data());
1492  }
1493  }
1494  //gSystem->ChangeDirectory(savdir.Data());
1495  fListTree->ClearViewPort();
1496 }
1497 
1498 ////////////////////////////////////////////////////////////////////////////////
1499 /// Execute default action for selected object (action is specified
1500 /// in the $HOME/.root.mimes or $ROOTSYS/etc/root.mimes file.
1501 
1502 Long_t TGFileBrowser::XXExecuteDefaultAction(TObject *obj)
1503 {
1504  char action[512];
1505  TString act;
1506  TString ext = obj->GetName();
1507  if (fBrowser) fBrowser->SetDrawOption(GetDrawOption());
1508 
1509  if (gClient->GetMimeTypeList()->GetAction(obj->GetName(), action)) {
1510  act = action;
1511  act.ReplaceAll("%s", obj->GetName());
1512  gInterpreter->SaveGlobalsContext();
1513 
1514  if (act[0] == '!') {
1515  act.Remove(0, 1);
1516  gSystem->Exec(act.Data());
1517  return 0;
1518  } else {
1519  // special case for remote object: remote process
1520  if (obj->InheritsFrom("TRemoteObject"))
1521  gApplication->SetBit(TApplication::kProcessRemotely);
1522 
1523  const Long_t res = gApplication->ProcessLine(act.Data());
1524 #ifdef R__HAS_COCOA
1525  if (act.Contains(".x") || act.Contains(".X")) {
1526  if (gPad) gPad->Update();
1527  }
1528 #endif
1529  return res;
1530  }
1531  }
1532  return 0;
1533 }
1534 
1535 ////////////////////////////////////////////////////////////////////////////////
1536 /// Format file information to be displayed in the tooltip.
1537 
1538 char *TGFileBrowser::FormatFileInfo(const char *fname, Long64_t size, Long_t modtime)
1539 {
1540  Long64_t fsize, bsize;
1541  TString infos = fname;
1542  infos += "\n";
1543 
1544  fsize = bsize = size;
1545  if (fsize > 1024) {
1546  fsize /= 1024;
1547  if (fsize > 1024) {
1548  // 3.7MB is more informative than just 3MB
1549  infos += TString::Format("Size: %lld.%lldM", fsize/1024, (fsize%1024)/103);
1550  } else {
1551  infos += TString::Format("Size: %lld.%lldK", bsize/1024, (bsize%1024)/103);
1552  }
1553  } else {
1554  infos += TString::Format("Size: %lld", bsize);
1555  }
1556  struct tm *newtime;
1557  time_t loctime = (time_t) modtime;
1558  newtime = localtime(&loctime);
1559  if (newtime) {
1560  infos += "\n";
1561  infos += TString::Format("%d-%02d-%02d %02d:%02d",
1562  newtime->tm_year + 1900,
1563  newtime->tm_mon+1, newtime->tm_mday,
1564  newtime->tm_hour, newtime->tm_min);
1565  }
1566  return StrDup(infos.Data());
1567 }
1568 
1569 ////////////////////////////////////////////////////////////////////////////////
1570 /// Retrieve icons associated with class "name". Association is made
1571 /// via the user's ~/.root.mimes file or via $ROOTSYS/etc/root.mimes.
1572 
1573 void TGFileBrowser::GetObjPicture(const TGPicture **pic, TObject *obj)
1574 {
1575  const char *clname = 0;
1576  TClass *objClass = 0;
1577  static TImage *im = 0;
1578  if (!im) {
1579  im = TImage::Create();
1580  }
1581 
1582  if (obj->IsA() == TClass::Class()) {
1583  objClass = obj->IsA();
1584  if (objClass)
1585  clname = objClass->GetName();
1586  }
1587  else if (obj->InheritsFrom("TKey")) {
1588  clname = ((TKey *)obj)->GetClassName();
1589  }
1590  else if (obj->InheritsFrom("TKeyMapFile")) {
1591  clname = ((TKeyMapFile *)obj)->GetTitle();
1592  }
1593  else if (obj->InheritsFrom("TRemoteObject")) {
1594  // special case for remote object: get real object class
1595  TRemoteObject *robj = (TRemoteObject *)obj;
1596  if (!strcmp(robj->GetClassName(), "TKey"))
1597  clname = robj->GetKeyClassName();
1598  else
1599  clname = robj->GetClassName();
1600  }
1601  else {
1602  objClass = obj->IsA();
1603  if (objClass)
1604  clname = objClass->GetName();
1605  }
1606  if (!clname) {
1607  clname = "Unknown";
1608  }
1609  const char *name = obj->GetIconName() ? obj->GetIconName() : clname;
1610  TString xpm_magic(name, 3);
1611  Bool_t xpm = xpm_magic == "/* ";
1612  const char *iconname = xpm ? obj->GetName() : name;
1613 
1614  if (obj->IsA()->InheritsFrom("TGeoVolume")) {
1615  iconname = obj->GetIconName() ? obj->GetIconName() : obj->IsA()->GetName();
1616  }
1617 
1618  if (fCachedPicName == iconname) {
1619  *pic = fCachedPic;
1620  return;
1621  }
1622  *pic = gClient->GetMimeTypeList()->GetIcon(iconname, kTRUE);
1623  if (!(*pic) && xpm) {
1624  if (im && im->SetImageBuffer((char**)&name, TImage::kXpm)) {
1625  im->Scale(im->GetWidth()/4, im->GetHeight()/4);
1626  *pic = gClient->GetPicturePool()->GetPicture(iconname, im->GetPixmap(),
1627  im->GetMask());
1628  }
1629  gClient->GetMimeTypeList()->AddType("[thumbnail]", iconname, iconname, iconname, "->Browse()");
1630  return;
1631  }
1632  if (fCachedPic && (fCachedPic != fFileIcon))
1633  fClient->FreePicture(fCachedPic);
1634  if (*pic == 0) {
1635  if (!obj->IsFolder())
1636  *pic = fFileIcon;
1637  }
1638  fCachedPic = *pic;
1639  fCachedPicName = iconname;
1640 }
1641 
1642 ////////////////////////////////////////////////////////////////////////////////
1643 /// Go to the directory "path" and open all the parent list tree items.
1644 
1645 void TGFileBrowser::GotoDir(const char *path)
1646 {
1647  TGListTreeItem *item, *itm;
1648  ULong_t id;
1649  Long_t bsize, blocks, bfree;
1650  Bool_t expand = kTRUE;
1651  TString sPath(gSystem->UnixPathName(path));
1652  item = fRootDir;
1653  if (item == 0) return;
1654  fListTree->OpenItem(item);
1655  TObjArray *tokens = sPath.Tokenize("/");
1656  if (tokens->IsEmpty()) {
1657  fListTree->HighlightItem(item);
1658  DoubleClicked(item, 1);
1659  delete tokens;
1660  fListTree->ClearViewPort();
1661  fListTree->AdjustPosition(item);
1662  return;
1663  }
1664  // if the Browser.ExpandDirectories option is set to "no", then don't
1665  // expand the parent directory tree (for example on nfs)
1666  TString str = gEnv->GetValue("Browser.ExpandDirectories", "yes");
1667  str.ToLower();
1668  expand = (str == "yes") ? kTRUE : kFALSE;
1669  TString first = ((TObjString*)tokens->At(0))->GetName();
1670  // always prevent expanding the parent directory tree on afs
1671  if (first == "afs")
1672  expand = kFALSE;
1673  // check also AFS_SUPER_MAGIC, NFS_SUPER_MAGIC, FUSE_SUPER_MAGIC,
1674  // CIFS_MAGIC_NUMBER and SMB_SUPER_MAGIC
1675  if (!gSystem->GetFsInfo(path, (Long_t *)&id, &bsize, &blocks, &bfree))
1676  if (id == 0x5346414f || id == 0x6969 || id == 0x65735546 || id == 0xff534d42 || id == 0x517b)
1677  expand = kFALSE;
1678  if (first.Length() == 2 && first.EndsWith(":")) {
1679  TList *curvol = gSystem->GetVolumes("cur");
1680  if (curvol) {
1681  TNamed *drive = (TNamed *)curvol->At(0);
1682  if (first == drive->GetName()) {
1683  TString infos = drive->GetTitle();
1684  if (infos.Contains("Network"))
1685  expand = kFALSE;
1686  }
1687  delete curvol;
1688  }
1689  }
1690  for (Int_t i = 0; i < tokens->GetEntriesFast(); ++i) {
1691  TString token = ((TObjString*)tokens->At(i))->GetName();
1692  if (token.Length() == 2 && token.EndsWith(":")) {
1693  token.Append("\\");
1694  itm = fListTree->FindChildByName(0, token);
1695  if (itm) {
1696  item = itm;
1697  fListTree->OpenItem(item);
1698  if (expand)
1699  DoubleClicked(item, 1);
1700  }
1701  continue;
1702  }
1703  itm = fListTree->FindChildByName(item, token);
1704  if (itm) {
1705  item = itm;
1706  fListTree->OpenItem(item);
1707  if (expand)
1708  DoubleClicked(item, 1);
1709  }
1710  else {
1711  itm = fListTree->AddItem(item, token);
1712  item = itm;
1713  fListTree->OpenItem(item);
1714  if (expand)
1715  DoubleClicked(item, 1);
1716  }
1717  }
1718  fListTree->HighlightItem(item);
1719  DoubleClicked(item, 1);
1720  delete tokens;
1721  fListTree->ClearViewPort();
1722  fListTree->AdjustPosition(item);
1723 }
1724 
1725 ////////////////////////////////////////////////////////////////////////////////
1726 /// Slot used to switch to the tab containing the current pad/canvas (gPad)
1727 /// used e.g. when drawing a histogram by double-clicking on its list tree
1728 /// item in a root file.
1729 
1730 void TGFileBrowser::PadModified()
1731 {
1732  if (fDblClick && fNewBrowser) {
1733  Int_t i;
1734  TGTab *tabRight = fNewBrowser->GetTabRight();
1735  for (i=0;i<tabRight->GetNumberOfTabs();++i) {
1736  TGFrameElement *fe = 0;
1737  TGCompositeFrame *embed = 0;
1738  TGCompositeFrame *frame = tabRight->GetTabContainer(i);
1739  if (frame)
1740  fe = (TGFrameElement *)frame->GetList()->First();
1741  if (fe)
1742  embed = (TGCompositeFrame *)fe->fFrame;
1743  if (embed && embed->InheritsFrom("TRootCanvas")) {
1744  ULong_t canvas = gROOT->ProcessLine(TString::Format("((TRootCanvas *)0x%lx)->Canvas();",
1745  (ULong_t)embed));
1746  if ((canvas) && (canvas == (ULong_t)gPad ||
1747  canvas == (ULong_t)gPad->GetCanvas())) {
1748  tabRight->SetTab(i, kTRUE);
1749  break;
1750  }
1751  }
1752  }
1753  }
1754 }
1755 
1756 ////////////////////////////////////////////////////////////////////////////////
1757 /// Open a dialog box asking for a string to be used as filter (regexp), and
1758 /// add an entry in the map of filtered entries. Entering "*" or empty string
1759 /// ("") will disable filtering on the current list tree item.
1760 
1761 void TGFileBrowser::RequestFilter()
1762 {
1763  char filter[1024];
1764  if (!fListLevel)
1765  return;
1766  // initialize with previous (active) filter string
1767  snprintf(filter, sizeof(filter), "%s", fFilterStr.Data());
1768  new TGInputDialog(gClient->GetRoot(), this,
1769  "Enter filter expression:\n(empty string \"\" or \"*\" to remove filter)",
1770  filter, filter);
1771  // if user pressed cancel, update the status of the current list tree
1772  // item and return
1773  if ((filter[0] == 0) && (filter[1] == 0)) {
1774  CheckFiltered(fListLevel, kTRUE);
1775  return;
1776  }
1777  else if (((filter[0] == 0) && (filter[1] == 1)) || !strcmp(filter, "*")) {
1778  // if user entered "*" or "", just disable filtering for the current
1779  // list tree item
1780  fFilterButton->SetState(kButtonUp);
1781  fFilteredItems.erase(fListLevel);
1782  }
1783  else {
1784  // if user entered a string different from "*", use it to create an
1785  // entry in the filter map
1786  fFilterStr = filter;
1787  fFilterButton->SetState(kButtonEngaged);
1788  // if there is already a filter on this item, delete it
1789  if (CheckFiltered(fListLevel))
1790  fFilteredItems.erase(fListLevel);
1791  // insert a new entry for the current list tree item
1792  fFilteredItems.insert(std::make_pair(fListLevel, StrDup(filter)));
1793  }
1794  // finally update the list tree
1795  fListTree->DeleteChildren(fListLevel);
1796  DoubleClicked(fListLevel, 1);
1797  fListTree->ClearViewPort();
1798  fListTree->AdjustPosition(fListLevel);
1799 }
1800 
1801 ////////////////////////////////////////////////////////////////////////////////
1802 /// A ROOT File has been selected in TGHtmlBrowser.
1803 
1804 void TGFileBrowser::Selected(char *)
1805 {
1806  TGListTreeItem *itm = fListTree->FindChildByData(0, gROOT->GetListOfFiles());
1807  if (itm) {
1808  fListTree->ClearHighlighted();
1809  fListLevel = itm;
1810  fListTree->HighlightItem(fListLevel);
1811  fListTree->OpenItem(fListLevel);
1812  BrowseObj(gROOT->GetListOfFiles());
1813  fListTree->ClearViewPort();
1814  fListTree->AdjustPosition(fListLevel);
1815  }
1816 }
1817 
1818 ////////////////////////////////////////////////////////////////////////////////
1819 /// Toggle the sort mode and set the "sort button" state accordingly.
1820 
1821 void TGFileBrowser::ToggleSort()
1822 {
1823  if (!fListLevel) return;
1824  char *itemname = 0;
1825  TGListTreeItem *item = fListLevel;
1826  if (!fListLevel->GetFirstChild()) {
1827  item = fListLevel->GetParent();
1828  itemname = StrDup(fListLevel->GetText());
1829  }
1830  if (!item) {
1831  if (itemname)
1832  delete [] itemname;
1833  return;
1834  }
1835  Bool_t is_sorted = CheckSorted(item);
1836  if (!is_sorted) {
1837  //alphabetical sorting
1838  fListTree->SortChildren(item);
1839  fSortedItems.push_back(item);
1840  fSortButton->SetState(kButtonEngaged);
1841  }
1842  else {
1843  fListTree->DeleteChildren(item);
1844  DoubleClicked(item, 1);
1845  fSortedItems.remove(item);
1846  fSortButton->SetState(kButtonUp);
1847  gClient->NeedRedraw(fListTree, kTRUE);
1848  gClient->HandleInput();
1849  if (itemname) {
1850  TGListTreeItem *itm = fListTree->FindChildByName(item, itemname);
1851  if (itm) {
1852  fListTree->ClearHighlighted();
1853  Clicked(itm, 1, 0, 0);
1854  itm->SetActive(kTRUE);
1855  fListTree->SetSelected(itm);
1856  fListTree->HighlightItem(itm, kTRUE, kTRUE);
1857  }
1858  }
1859  }
1860  if (itemname)
1861  delete [] itemname;
1862  fListTree->ClearViewPort();
1863  fListTree->AdjustPosition(fListLevel);
1864 }
1865 
1866