Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGListTree.cxx
Go to the documentation of this file.
1 // @(#)root/gui:$Id: 2897f2e70909348e1e18681c5c7b0aee8c027744 $
2 // Author: Fons Rademakers 25/02/98
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, 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 
13  This source is based on Xclass95, a Win95-looking GUI toolkit.
14  Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.
15 
16  Xclass95 is free software; you can redistribute it and/or
17  modify it under the terms of the GNU Library General Public
18  License as published by the Free Software Foundation; either
19  version 2 of the License, or (at your option) any later version.
20 
21 **************************************************************************/
22 
23 //////////////////////////////////////////////////////////////////////////
24 // //
25 // TGListTree and TGListTreeItem //
26 // //
27 // A list tree is a widget that can contain a number of items //
28 // arranged in a tree structure. The items are represented by small //
29 // folder icons that can be either open or closed. //
30 // //
31 // The TGListTree is user callable. The TGListTreeItem is a service //
32 // class of the list tree. //
33 // //
34 // A list tree can generate the following events: //
35 // kC_LISTTREE, kCT_ITEMCLICK, which button, location (y<<16|x). //
36 // kC_LISTTREE, kCT_ITEMDBLCLICK, which button, location (y<<16|x). //
37 // //
38 //////////////////////////////////////////////////////////////////////////
39 
40 #include <stdlib.h>
41 
42 #include "TROOT.h"
43 #include "TClass.h"
44 #include "TGListTree.h"
45 #include "TGPicture.h"
46 #include "TGCanvas.h"
47 #include "TGScrollBar.h"
48 #include "TGToolTip.h"
49 #include "KeySymbols.h"
50 #include "TGTextEditDialogs.h"
51 #include "TGResourcePool.h"
52 #include "TGMsgBox.h"
53 #include "TError.h"
54 #include "TColor.h"
55 #include "TSystem.h"
56 #include "TString.h"
57 #include "TObjString.h"
58 #include "TGDNDManager.h"
59 #include "TBufferFile.h"
60 #include "Riostream.h"
61 #include "RConfigure.h"
62 
63 Pixel_t TGListTree::fgGrayPixel = 0;
64 const TGFont *TGListTree::fgDefaultFont = 0;
65 TGGC *TGListTree::fgActiveGC = 0;
66 TGGC *TGListTree::fgDrawGC = 0;
67 TGGC *TGListTree::fgLineGC = 0;
68 TGGC *TGListTree::fgHighlightGC = 0;
69 TGGC *TGListTree::fgColorGC = 0;
70 const TGPicture *TGListTree::fgOpenPic = 0;
71 const TGPicture *TGListTree::fgClosedPic = 0;
72 const TGPicture *TGListTree::fgCheckedPic = 0;
73 const TGPicture *TGListTree::fgUncheckedPic = 0;
74 
75 
76 ClassImp(TGListTreeItem);
77 ClassImp(TGListTreeItemStd);
78 ClassImp(TGListTree);
79 
80 /******************************************************************************/
81 /******************************************************************************/
82 // TGListTreeItem
83 /******************************************************************************/
84 
85 ////////////////////////////////////////////////////////////////////////////////
86 /// Constructor.
87 
88 TGListTreeItem::TGListTreeItem(TGClient *client) :
89  fClient(client),
90  fParent (0), fFirstchild(0), fLastchild (0), fPrevsibling(0),
91  fNextsibling(0),fOpen (kFALSE), fDNDState (0),
92  fY (0), fXtext (0), fYtext(0), fHeight(0)
93 {
94 }
95 
96 ////////////////////////////////////////////////////////////////////////////////
97 /// Return width of item's icon.
98 
99 UInt_t TGListTreeItem::GetPicWidth() const
100 {
101  const TGPicture *pic = GetPicture();
102  return (pic) ? pic->GetWidth() : 0;
103 }
104 
105 /******************************************************************************/
106 /******************************************************************************/
107 // TGListTreeItemStd
108 /******************************************************************************/
109 
110 ////////////////////////////////////////////////////////////////////////////////
111 /// Create list tree item.
112 
113 TGListTreeItemStd::TGListTreeItemStd(TGClient *client, const char *name,
114  const TGPicture *opened,
115  const TGPicture *closed,
116  Bool_t checkbox) :
117  TGListTreeItem(client)
118 {
119  fText = name;
120  fCheckBox = checkbox;
121  fChecked = kTRUE;
122 
123  if (!opened)
124  opened = TGListTree::GetOpenPic();
125  else
126  ((TGPicture *)opened)->AddReference();
127 
128  if (!closed)
129  closed = TGListTree::GetClosedPic();
130  else
131  ((TGPicture *)closed)->AddReference();
132 
133  fOpenPic = opened;
134  fClosedPic = closed;
135 
136  fCheckedPic = TGListTree::GetCheckedPic();
137  fUncheckedPic = TGListTree::GetUncheckedPic();
138 
139  fActive = kFALSE;
140 
141  fOwnsData = kFALSE;
142  fUserData = 0;
143 
144  fHasColor = kFALSE;
145  fColor = 0;
146  fDNDState = 0;
147 }
148 
149 ////////////////////////////////////////////////////////////////////////////////
150 /// Delete list tree item.
151 
152 TGListTreeItemStd::~TGListTreeItemStd()
153 {
154  if (fOwnsData && fUserData) {
155  TObject *obj = static_cast<TObject *>(fUserData);
156  delete dynamic_cast<TObject *>(obj);
157  }
158  fClient->FreePicture(fOpenPic);
159  fClient->FreePicture(fClosedPic);
160  fClient->FreePicture(fCheckedPic);
161  fClient->FreePicture(fUncheckedPic);
162 }
163 
164 ////////////////////////////////////////////////////////////////////////////////
165 /// Return color for marking items that are active or selected.
166 
167 Pixel_t TGListTreeItemStd::GetActiveColor() const
168 {
169  return TGFrame::GetDefaultSelectedBackground();
170 }
171 
172 ////////////////////////////////////////////////////////////////////////////////
173 /// Add all child items of 'item' into the list 'checked'.
174 
175 Bool_t TGListTreeItemStd::HasCheckedChild(Bool_t first)
176 {
177  TGListTreeItem *item = this;
178 
179  while (item) {
180  if (item->IsChecked()) {
181  return kTRUE;
182  }
183  if (item->GetFirstChild()) {
184  if (item->GetFirstChild()->HasCheckedChild())
185  return kTRUE;
186  }
187  if (!first)
188  item = item->GetNextSibling();
189  else
190  break;
191  }
192  return kFALSE;
193 }
194 
195 ////////////////////////////////////////////////////////////////////////////////
196 /// Add all child items of 'item' into the list 'checked'.
197 
198 Bool_t TGListTreeItemStd::HasUnCheckedChild(Bool_t first)
199 {
200  TGListTreeItem *item = this;
201 
202  while (item) {
203  if (!item->IsChecked()) {
204  return kTRUE;
205  }
206  if (item->GetFirstChild()) {
207  if (item->GetFirstChild()->HasUnCheckedChild())
208  return kTRUE;
209  }
210  if (!first)
211  item = item->GetNextSibling();
212  else
213  break;
214  }
215  return kFALSE;
216 }
217 
218 ////////////////////////////////////////////////////////////////////////////////
219 /// Update the state of the node 'item' according to the children states.
220 
221 void TGListTreeItemStd::UpdateState()
222 {
223  if ((!fChecked && HasCheckedChild(kTRUE)) ||
224  (fChecked && HasUnCheckedChild(kTRUE))) {
225  SetCheckBoxPictures(gClient->GetPicture("checked_dis_t.xpm"),
226  gClient->GetPicture("unchecked_dis_t.xpm"));
227  }
228  else {
229  SetCheckBoxPictures(gClient->GetPicture("checked_t.xpm"),
230  gClient->GetPicture("unchecked_t.xpm"));
231  }
232 }
233 
234 ////////////////////////////////////////////////////////////////////////////////
235 /// Set all child items of this one checked if state=kTRUE,
236 /// unchecked if state=kFALSE.
237 
238 void TGListTreeItemStd::CheckAllChildren(Bool_t state)
239 {
240  if (state) {
241  if (!IsChecked())
242  CheckItem();
243  } else {
244  if (IsChecked())
245  Toggle();
246  }
247  CheckChildren(GetFirstChild(), state);
248  UpdateState();
249 }
250 
251 ////////////////////////////////////////////////////////////////////////////////
252 /// Set all child items of 'item' checked if state=kTRUE;
253 /// unchecked if state=kFALSE.
254 
255 void TGListTreeItemStd::CheckChildren(TGListTreeItem *item, Bool_t state)
256 {
257  if (!item) return;
258 
259  while (item) {
260  if (state){
261  if (!item->IsChecked())
262  item->CheckItem();
263  } else {
264  if (item->IsChecked())
265  item->Toggle();
266  }
267  if (item->GetFirstChild()) {
268  CheckChildren(item->GetFirstChild(), state);
269  }
270  item->UpdateState();
271  item = item->GetNextSibling();
272  }
273 }
274 
275 ////////////////////////////////////////////////////////////////////////////////
276 /// Set a check box on the tree node.
277 
278 void TGListTreeItemStd::SetCheckBox(Bool_t on)
279 {
280  fCheckBox = on;
281 }
282 
283 ////////////////////////////////////////////////////////////////////////////////
284 /// Change list tree check item icons.
285 
286 void TGListTreeItemStd::SetCheckBoxPictures(const TGPicture *checked,
287  const TGPicture *unchecked)
288 {
289  fClient->FreePicture(fCheckedPic);
290  fClient->FreePicture(fUncheckedPic);
291 
292  if (!checked) {
293  ::Warning("TGListTreeItem::SetCheckBoxPictures", "checked picture not specified, defaulting to checked_t");
294  checked = fClient->GetPicture("checked_t.xpm");
295  } else
296  ((TGPicture *)checked)->AddReference();
297 
298  if (!unchecked) {
299  ::Warning("TGListTreeItem::SetCheckBoxPictures", "unchecked picture not specified, defaulting to unchecked_t");
300  unchecked = fClient->GetPicture("unchecked_t.xpm");
301  } else
302  ((TGPicture *)unchecked)->AddReference();
303 
304  fCheckedPic = checked;
305  fUncheckedPic = unchecked;
306 }
307 
308 ////////////////////////////////////////////////////////////////////////////////
309 /// Change list tree item icons.
310 
311 void TGListTreeItemStd::SetPictures(const TGPicture *opened, const TGPicture *closed)
312 {
313  fClient->FreePicture(fOpenPic);
314  fClient->FreePicture(fClosedPic);
315 
316  if (!opened) {
317  ::Warning("TGListTreeItem::SetPictures", "opened picture not specified, defaulting to ofolder_t");
318  opened = fClient->GetPicture("ofolder_t.xpm");
319  } else
320  ((TGPicture *)opened)->AddReference();
321 
322  if (!closed) {
323  ::Warning("TGListTreeItem::SetPictures", "closed picture not specified, defaulting to folder_t");
324  closed = fClient->GetPicture("folder_t.xpm");
325  } else
326  ((TGPicture *)closed)->AddReference();
327 
328  fOpenPic = opened;
329  fClosedPic = closed;
330 }
331 
332 
333 /******************************************************************************/
334 /******************************************************************************/
335 // TGListTree
336 /******************************************************************************/
337 
338 ////////////////////////////////////////////////////////////////////////////////
339 /// Create a list tree widget.
340 
341 TGListTree::TGListTree(TGWindow *p, UInt_t w, UInt_t h, UInt_t options,
342  ULong_t back) :
343  TGContainer(p, w, h, options, back)
344 {
345  fMsgWindow = p;
346  fCanvas = 0;
347  fTip = 0;
348  fTipItem = 0;
349  fAutoTips = kFALSE;
350  fAutoCheckBoxPic = kTRUE;
351  fDisableOpen = kFALSE;
352  fBdown = kFALSE;
353  fUserControlled = kFALSE;
354  fEventHandled = kFALSE;
355  fExposeTop = fExposeBottom = 0;
356  fDropItem = 0;
357  fLastEventState = 0;
358 
359  fGrayPixel = GetGrayPixel();
360  fFont = GetDefaultFontStruct();
361 
362  fActiveGC = GetActiveGC()();
363  fDrawGC = GetDrawGC()();
364  fLineGC = GetLineGC()();
365  fHighlightGC = GetHighlightGC()();
366  fColorGC = GetColorGC()();
367 
368  fFirst = fLast = fSelected = fCurrent = fBelowMouse = 0;
369  fDefw = fDefh = 1;
370 
371  fHspacing = 2;
372  fVspacing = 2; // 0;
373  fIndent = 3; // 0;
374  fMargin = 2;
375 
376  fXDND = fYDND = 0;
377  fDNDData.fData = 0;
378  fDNDData.fDataLength = 0;
379  fDNDData.fDataType = 0;
380  fBuf = 0;
381 
382  fColorMode = kDefault;
383  fCheckMode = kSimple;
384  if (fCanvas) fCanvas->GetVScrollbar()->SetSmallIncrement(20);
385 
386  gVirtualX->GrabButton(fId, kAnyButton, kAnyModifier,
387  kButtonPressMask | kButtonReleaseMask,
388  kNone, kNone);
389 
390  AddInput(kPointerMotionMask | kEnterWindowMask |
391  kLeaveWindowMask | kKeyPressMask);
392  SetWindowName();
393 
394  fDNDTypeList = new Atom_t[3];
395  fDNDTypeList[0] = gVirtualX->InternAtom("application/root", kFALSE);
396  fDNDTypeList[1] = gVirtualX->InternAtom("text/uri-list", kFALSE);
397  fDNDTypeList[2] = 0;
398  gVirtualX->SetDNDAware(fId, fDNDTypeList);
399  SetDNDTarget(kTRUE);
400  fEditDisabled = kEditDisable | kEditDisableGrab | kEditDisableBtnEnable;
401 }
402 
403 ////////////////////////////////////////////////////////////////////////////////
404 /// Create a list tree widget.
405 
406 TGListTree::TGListTree(TGCanvas *p,UInt_t options,ULong_t back) :
407  TGContainer(p, options, back)
408 {
409  fMsgWindow = p;
410  fTip = 0;
411  fTipItem = 0;
412  fAutoTips = kFALSE;
413  fAutoCheckBoxPic = kTRUE;
414  fDisableOpen = kFALSE;
415  fBdown = kFALSE;
416  fUserControlled = kFALSE;
417  fEventHandled = kFALSE;
418  fExposeTop = fExposeBottom = 0;
419  fDropItem = 0;
420  fLastEventState = 0;
421 
422  fGrayPixel = GetGrayPixel();
423  fFont = GetDefaultFontStruct();
424 
425  fActiveGC = GetActiveGC()();
426  fDrawGC = GetDrawGC()();
427  fLineGC = GetLineGC()();
428  fHighlightGC = GetHighlightGC()();
429  fColorGC = GetColorGC()();
430 
431  fFirst = fLast = fSelected = fCurrent = fBelowMouse = 0;
432  fDefw = fDefh = 1;
433 
434  fHspacing = 2;
435  fVspacing = 2; // 0;
436  fIndent = 3; // 0;
437  fMargin = 2;
438 
439  fXDND = fYDND = 0;
440  fDNDData.fData = 0;
441  fDNDData.fDataLength = 0;
442  fDNDData.fDataType = 0;
443  fBuf = 0;
444 
445  fColorMode = kDefault;
446  fCheckMode = kSimple;
447  if (fCanvas) fCanvas->GetVScrollbar()->SetSmallIncrement(20);
448 
449  gVirtualX->GrabButton(fId, kAnyButton, kAnyModifier,
450  kButtonPressMask | kButtonReleaseMask,
451  kNone, kNone);
452 
453  AddInput(kPointerMotionMask | kEnterWindowMask |
454  kLeaveWindowMask | kKeyPressMask);
455  SetWindowName();
456 
457  fDNDTypeList = new Atom_t[3];
458  fDNDTypeList[0] = gVirtualX->InternAtom("application/root", kFALSE);
459  fDNDTypeList[1] = gVirtualX->InternAtom("text/uri-list", kFALSE);
460  fDNDTypeList[2] = 0;
461  gVirtualX->SetDNDAware(fId, fDNDTypeList);
462  SetDNDTarget(kTRUE);
463  fEditDisabled = kEditDisable | kEditDisableGrab | kEditDisableBtnEnable;
464 }
465 
466 ////////////////////////////////////////////////////////////////////////////////
467 /// Delete list tree widget.
468 
469 TGListTree::~TGListTree()
470 {
471  TGListTreeItem *item, *sibling;
472 
473  delete [] fDNDTypeList;
474  delete fTip;
475 
476  item = fFirst;
477  while (item) {
478  PDeleteChildren(item);
479  sibling = item->fNextsibling;
480  delete item;
481  item = sibling;
482  }
483 }
484 
485 //--- text utility functions
486 
487 ////////////////////////////////////////////////////////////////////////////////
488 /// Returns height of currently used font.
489 
490 Int_t TGListTree::FontHeight()
491 {
492  if (!fgDefaultFont)
493  fgDefaultFont = gClient->GetResourcePool()->GetIconFont();
494  return fgDefaultFont->TextHeight();
495 }
496 
497 ////////////////////////////////////////////////////////////////////////////////
498 /// Returns ascent of currently used font.
499 
500 Int_t TGListTree::FontAscent()
501 {
502  FontMetrics_t m;
503  if (!fgDefaultFont)
504  fgDefaultFont = gClient->GetResourcePool()->GetIconFont();
505  fgDefaultFont->GetFontMetrics(&m);
506  return m.fAscent;
507 }
508 
509 ////////////////////////////////////////////////////////////////////////////////
510 /// Returns text width relative to currently used font.
511 
512 Int_t TGListTree::TextWidth(const char *c)
513 {
514  if (!fgDefaultFont)
515  fgDefaultFont = gClient->GetResourcePool()->GetIconFont();
516  return fgDefaultFont->TextWidth(c);
517 }
518 
519 //---- highlighting utilities
520 
521 ////////////////////////////////////////////////////////////////////////////////
522 /// Highlight tree item.
523 
524 void TGListTree::HighlightItem(TGListTreeItem *item, Bool_t state, Bool_t draw)
525 {
526  if (item) {
527  if ((item == fSelected) && !state) {
528  fSelected = 0;
529  if (draw) DrawItemName(fId, item);
530  } else if (state != item->IsActive()) { // !!!! leave active alone ...
531  item->SetActive(state);
532  if (draw) DrawItemName(fId, item);
533  }
534  }
535 }
536 
537 ////////////////////////////////////////////////////////////////////////////////
538 /// Higlight item children.
539 
540 void TGListTree::HighlightChildren(TGListTreeItem *item, Bool_t state, Bool_t draw)
541 {
542  while (item) {
543  HighlightItem(item, state, draw);
544  if (item->fFirstchild)
545  HighlightChildren(item->fFirstchild, state, (item->IsOpen()) ? draw : kFALSE);
546  item = item->fNextsibling;
547  }
548 }
549 
550 ////////////////////////////////////////////////////////////////////////////////
551 /// Unselect all items.
552 
553 void TGListTree::UnselectAll(Bool_t draw)
554 {
555  ClearViewPort();
556  HighlightChildren(fFirst, kFALSE, draw);
557 }
558 
559 ////////////////////////////////////////////////////////////////////////////////
560 /// Handle button events in the list tree.
561 
562 Bool_t TGListTree::HandleButton(Event_t *event)
563 {
564  TGListTreeItem *item;
565 
566  if (fTip) fTip->Hide();
567 
568  Int_t page = 0;
569  if (event->fCode == kButton4 || event->fCode == kButton5) {
570  if (!fCanvas) return kTRUE;
571  if (fCanvas->GetContainer()->GetHeight()) {
572 // page = Int_t(Float_t(fCanvas->GetViewPort()->GetHeight() *
573 // fCanvas->GetViewPort()->GetHeight()) /
574 // fCanvas->GetContainer()->GetHeight());
575  // choose page size either 1/5 of viewport or 5 lines (90)
576  Int_t r = fCanvas->GetViewPort()->GetHeight() / 5;
577  page = TMath::Min(r, 90);
578  }
579  }
580 
581  if (event->fCode == kButton4) {
582  //scroll up
583  Int_t newpos = fCanvas->GetVsbPosition() - page;
584  if (newpos < 0) newpos = 0;
585  fCanvas->SetVsbPosition(newpos);
586  return kTRUE;
587  }
588  if (event->fCode == kButton5) {
589  // scroll down
590  Int_t newpos = fCanvas->GetVsbPosition() + page;
591  fCanvas->SetVsbPosition(newpos);
592  return kTRUE;
593  }
594 
595  if (event->fType == kButtonPress) {
596  if ((item = FindItem(event->fY)) != 0) {
597  if (event->fCode == kButton1) {
598  Int_t minx, maxx;
599  Int_t minxchk = 0, maxxchk = 0;
600  if (item->HasCheckBox() && item->GetCheckBoxPicture()) {
601  minxchk = (item->fXtext - item->GetCheckBoxPicture()->GetWidth());
602  maxxchk = (item->fXtext - 4);
603  maxx = maxxchk - Int_t(item->GetPicWidth()) - 8;
604  minx = minxchk - Int_t(item->GetPicWidth()) - 16;
605  }
606  else {
607  maxx = (item->fXtext - Int_t(item->GetPicWidth())) - 8;
608  minx = (item->fXtext - Int_t(item->GetPicWidth())) - 16;
609  }
610  if ((item->HasCheckBox()) && (event->fX < maxxchk) &&
611  (event->fX > minxchk))
612  {
613  ToggleItem(item);
614  if (fCheckMode == kRecursive) {
615  CheckAllChildren(item, item->IsChecked());
616  }
617  UpdateChecked(item, kTRUE);
618  Checked((TObject *)item->GetUserData(), item->IsChecked());
619  return kTRUE;
620  }
621  if ((event->fX < maxx) && (event->fX > minx)) {
622  item->SetOpen(!item->IsOpen());
623  ClearViewPort();
624  return kTRUE;
625  }
626  }
627  // DND specific
628  if (event->fCode == kButton1) {
629  fXDND = event->fX;
630  fYDND = event->fY;
631  fBdown = kTRUE;
632  }
633  if (!fUserControlled) {
634  if (fSelected) fSelected->SetActive(kFALSE);
635  UnselectAll(kTRUE);
636  //item->fActive = kTRUE; // this is done below w/redraw
637  fCurrent = fSelected = item;
638  HighlightItem(item, kTRUE, kTRUE);
639  SendMessage(fMsgWindow, MK_MSG(kC_LISTTREE, kCT_ITEMCLICK),
640  event->fCode, (event->fYRoot << 16) | event->fXRoot);
641  }
642  else {
643  fCurrent = fSelected = item;
644  ClearViewPort();
645  }
646  Clicked(item, event->fCode);
647  Clicked(item, event->fCode, event->fXRoot, event->fYRoot);
648  Clicked(item, event->fCode, event->fState, event->fXRoot, event->fYRoot);
649  }
650  }
651  if (event->fType == kButtonRelease) {
652  fBdown = kFALSE;
653  }
654  return kTRUE;
655 }
656 
657 ////////////////////////////////////////////////////////////////////////////////
658 /// Handle double click event in the list tree (only for kButton1).
659 
660 Bool_t TGListTree::HandleDoubleClick(Event_t *event)
661 {
662  TGListTreeItem *item = 0;
663 
664  if (event->fCode == kButton4 || event->fCode == kButton5) {
665  return kFALSE;
666  }
667  // If fDisableOpen is set, only send message and emit signals.
668  // It allows user to customize handling of double click events.
669  if (fDisableOpen && event->fCode == kButton1 && (item = FindItem(event->fY)) != 0) {
670  SendMessage(fMsgWindow, MK_MSG(kC_LISTTREE, kCT_ITEMDBLCLICK),
671  event->fCode, (event->fYRoot << 16) | event->fXRoot);
672  DoubleClicked(item, event->fCode);
673  DoubleClicked(item, event->fCode, event->fXRoot, event->fYRoot);
674  return kTRUE;
675  }
676  item = FindItem(event->fY);
677 
678  // Otherwise, just use default behaviour (open item).
679  if (event->fCode == kButton1 && item) {
680  ClearViewPort();
681  item->SetOpen(!item->IsOpen());
682  if (!fUserControlled) {
683  if (item != fSelected) { // huh?!
684  if (fSelected) fSelected->SetActive(kFALSE); // !!!!
685  UnselectAll(kTRUE);
686  HighlightItem(item, kTRUE, kTRUE);
687  }
688  }
689  SendMessage(fMsgWindow, MK_MSG(kC_LISTTREE, kCT_ITEMDBLCLICK),
690  event->fCode, (event->fYRoot << 16) | event->fXRoot);
691  DoubleClicked(item, event->fCode);
692  DoubleClicked(item, event->fCode, event->fXRoot, event->fYRoot);
693  }
694  if (!fUserControlled)
695  fSelected = item;
696  return kTRUE;
697 }
698 
699 ////////////////////////////////////////////////////////////////////////////////
700 /// Handle mouse crossing event.
701 
702 Bool_t TGListTree::HandleCrossing(Event_t *event)
703 {
704  if (event->fType == kLeaveNotify) {
705  if (fTip) {
706  fTip->Hide();
707  fTipItem = 0;
708  }
709  if (!fUserControlled) {
710  if (fCurrent)
711  DrawOutline(fId, fCurrent, 0xffffff, kTRUE);
712  if (fBelowMouse)
713  DrawOutline(fId, fBelowMouse, 0xffffff, kTRUE);
714  fCurrent = 0;
715  }
716  if (fBelowMouse) {
717  fBelowMouse = 0;
718  MouseOver(0);
719  MouseOver(0, event->fState);
720  }
721  }
722  ClearViewPort();
723  return kTRUE;
724 }
725 
726 ////////////////////////////////////////////////////////////////////////////////
727 /// Handle dragging position events.
728 
729 Atom_t TGListTree::HandleDNDPosition(Int_t /*x*/, Int_t y, Atom_t action,
730  Int_t /*xroot*/, Int_t /*yroot*/)
731 {
732  static TGListTreeItem *olditem = 0;
733  TGListTreeItem *item;
734  if ((item = FindItem(y)) != 0) {
735  if (item->IsDNDTarget()) {
736  fDropItem = item;
737  if (olditem)
738  HighlightItem(olditem, kFALSE, kTRUE);
739  HighlightItem(item, kTRUE, kTRUE);
740  olditem = item;
741  return action;
742  }
743  }
744  fDropItem = 0;
745  if (olditem) {
746  HighlightItem(olditem, kFALSE, kTRUE);
747  olditem = 0;
748  }
749  return kNone;
750 }
751 
752 ////////////////////////////////////////////////////////////////////////////////
753 /// Handle drag enter events.
754 
755 Atom_t TGListTree::HandleDNDEnter(Atom_t *typelist)
756 {
757  Atom_t ret = kNone;
758  for (int i = 0; typelist[i] != kNone; ++i) {
759  if (typelist[i] == fDNDTypeList[0])
760  ret = fDNDTypeList[0];
761  if (typelist[i] == fDNDTypeList[1])
762  ret = fDNDTypeList[1];
763  }
764  return ret;
765 }
766 
767 ////////////////////////////////////////////////////////////////////////////////
768 /// Handle drag leave events.
769 
770 Bool_t TGListTree::HandleDNDLeave()
771 {
772  return kTRUE;
773 }
774 
775 ////////////////////////////////////////////////////////////////////////////////
776 /// Handle drop events.
777 
778 Bool_t TGListTree::HandleDNDDrop(TDNDData *data)
779 {
780  DataDropped(fDropItem, data);
781  HighlightItem(fDropItem, kFALSE, kTRUE);
782  //ClearHighlighted();
783  return kTRUE;
784 }
785 
786 ////////////////////////////////////////////////////////////////////////////////
787 /// Emit DataDropped() signal.
788 
789 void TGListTree::DataDropped(TGListTreeItem *item, TDNDData *data)
790 {
791  Long_t args[2];
792 
793  args[0] = (Long_t)item;
794  args[1] = (Long_t)data;
795 
796  Emit("DataDropped(TGListTreeItem*,TDNDData*)", args);
797 }
798 
799 ////////////////////////////////////////////////////////////////////////////////
800 /// Handle mouse motion event. Used to set tool tip, to emit
801 /// MouseOver() signal and for DND handling.
802 
803 Bool_t TGListTree::HandleMotion(Event_t *event)
804 {
805  TGListTreeItem *item;
806  TGPosition pos = GetPagePosition();
807 
808  if (gDNDManager->IsDragging()) {
809  gDNDManager->Drag(event->fXRoot, event->fYRoot,
810  TGDNDManager::GetDNDActionCopy(), event->fTime);
811  } else if ((item = FindItem(event->fY)) != 0) {
812  if (!fUserControlled) {
813  if (fCurrent)
814  DrawOutline(fId, fCurrent, 0xffffff, kTRUE);
815  if (fBelowMouse)
816  DrawOutline(fId, fBelowMouse, 0xffffff, kTRUE);
817  DrawOutline(fId, item);
818  fCurrent = item;
819  }
820  if (item != fBelowMouse) {
821  fBelowMouse = item;
822  MouseOver(fBelowMouse);
823  MouseOver(fBelowMouse, event->fState);
824  }
825 
826  if (item->HasCheckBox() && item->GetCheckBoxPicture()) {
827  if ((event->fX < (item->fXtext - 4) &&
828  (event->fX > (item->fXtext - (Int_t)item->GetCheckBoxPicture()->GetWidth()))))
829  {
830  gVirtualX->SetCursor(fId, gVirtualX->CreateCursor(kPointer));
831  return kTRUE;
832  }
833  else {
834  gVirtualX->SetCursor(fId, gVirtualX->CreateCursor(kHand));
835  }
836  }
837  if (!gDNDManager->IsDragging()) {
838  if (fBdown && ((abs(event->fX - fXDND) > 2) || (abs(event->fY - fYDND) > 2))) {
839  if (gDNDManager && item->IsDNDSource()) {
840  if (!fBuf) fBuf = new TBufferFile(TBuffer::kWrite);
841  fBuf->Reset();
842  // !!!!! Here check virtual Bool_t HandlesDragAndDrop()
843  // and let the item handle this.
844  if (item->GetUserData()) {
845  TObject *obj = static_cast<TObject *>(item->GetUserData());
846  if (dynamic_cast<TObject *>(obj)) {
847  TObjString *ostr = dynamic_cast<TObjString *>(obj);
848  if (ostr) {
849  TString& str = ostr->String();
850  if (str.BeginsWith("file://")) {
851  fDNDData.fDataType = fDNDTypeList[1];
852  fDNDData.fData = (void *)strdup(str.Data());
853  fDNDData.fDataLength = str.Length()+1;
854  }
855  }
856  else {
857  fDNDData.fDataType = fDNDTypeList[0];
858  fBuf->WriteObject((TObject *)item->GetUserData());
859  fDNDData.fData = fBuf->Buffer();
860  fDNDData.fDataLength = fBuf->Length();
861  }
862  }
863  }
864  else {
865  fDNDData.fDataType = fDNDTypeList[1];
866  TString str = TString::Format("file://%s/%s\r\n",
867  gSystem->UnixPathName(gSystem->WorkingDirectory()),
868  item->GetText());
869  fDNDData.fData = (void *)strdup(str.Data());
870  fDNDData.fDataLength = str.Length()+1;
871  }
872  if (item->GetPicture()) {
873  TString xmpname = item->GetPicture()->GetName();
874  if (xmpname.EndsWith("_t.xpm"))
875  xmpname.ReplaceAll("_t.xpm", "_s.xpm");
876  if (xmpname.EndsWith("_t.xpm__16x16"))
877  xmpname.ReplaceAll("_t.xpm__16x16", "_s.xpm");
878  const TGPicture *pic = fClient->GetPicture(xmpname.Data());
879  if (!pic) pic = item->GetPicture();
880  if (pic) SetDragPixmap(pic);
881  }
882  gDNDManager->StartDrag(this, event->fXRoot, event->fYRoot);
883  }
884  }
885  }
886  if (gDNDManager->IsDragging()) {
887  gDNDManager->Drag(event->fXRoot, event->fYRoot,
888  TGDNDManager::GetDNDActionCopy(), event->fTime);
889  } else {
890  if (fTipItem == item) return kTRUE;
891  if (!fUserControlled) { // !!!! what is this? It was called above once?
892  MouseOver(item);
893  MouseOver(item, event->fState);
894  }
895  gVirtualX->SetCursor(fId, gVirtualX->CreateCursor(kHand));
896  }
897 
898  if (fTip)
899  fTip->Hide();
900 
901  if (item->GetTipTextLength() > 0) {
902 
903  SetToolTipText(item->GetTipText(), item->fXtext,
904  item->fY - pos.fY + item->fHeight, 1000);
905 
906  } else if (fAutoTips && item->GetUserData()) {
907  // must derive from TObject (in principle user can put pointer
908  // to anything in user data field). Add check.
909  TObject *obj = (TObject *)item->GetUserData();
910  if (obj && obj->IsA()->IsTObject()) {
911  SetToolTipText(obj->GetTitle(), item->fXtext,
912  item->fY - pos.fY + item->fHeight, 1000);
913  }
914  }
915  fTipItem = item;
916  } else {
917  if (fBelowMouse) {
918  fBelowMouse = 0;
919  MouseOver(fBelowMouse);
920  MouseOver(fBelowMouse, event->fState);
921  }
922  gVirtualX->SetCursor(fId, gVirtualX->CreateCursor(kPointer));
923  }
924  return kTRUE;
925 }
926 
927 ////////////////////////////////////////////////////////////////////////////////
928 /// The key press event handler converts a key press to some line editor
929 /// action.
930 
931 Bool_t TGListTree::HandleKey(Event_t *event)
932 {
933  char input[10];
934  UInt_t keysym;
935  TGListTreeItem *item = 0;
936 
937  fLastEventState = event->fState;
938  if (fTip) fTip->Hide();
939 
940  if (event->fType == kGKeyPress) {
941  gVirtualX->LookupString(event, input, sizeof(input), keysym);
942 
943  if (!event->fState && (EKeySym)keysym == kKey_Escape) {
944  if (gDNDManager->IsDragging()) gDNDManager->EndDrag();
945  }
946 
947  item = fCurrent;
948  if (!item) return kFALSE;
949 
950  fEventHandled = kFALSE;
951  KeyPressed(item, keysym, event->fState);
952 
953  if (fUserControlled && fEventHandled)
954  return kTRUE;
955 
956  switch ((EKeySym)keysym) {
957  case kKey_Enter:
958  case kKey_Return:
959  event->fType = kButtonPress;
960  event->fCode = kButton1;
961 
962  if (fSelected == item) {
963  // treat 'Enter' and 'Return' as a double click
964  ClearViewPort();
965  item->SetOpen(!item->IsOpen());
966  DoubleClicked(item, 1);
967  } else {
968  // treat 'Enter' and 'Return' as a click
969  if (fSelected) fSelected->SetActive(kFALSE);
970  UnselectAll(kTRUE);
971  ClearViewPort();
972  fSelected = item;
973  fSelected->SetActive(kTRUE);
974  HighlightItem(item, kTRUE, kTRUE);
975  Clicked(item, 1);
976  Clicked(item, 1, event->fXRoot, event->fYRoot);
977  Clicked(item, 1, event->fState, event->fXRoot, event->fYRoot);
978  }
979  break;
980  case kKey_Space:
981  if (item->HasCheckBox()) {
982  ToggleItem(item);
983  if (fCheckMode == kRecursive) {
984  CheckAllChildren(item, item->IsChecked());
985  }
986  UpdateChecked(item, kTRUE);
987  Checked((TObject *)item->GetUserData(), item->IsChecked());
988  }
989  break;
990  case kKey_F3:
991  Search(kFALSE);
992  break;
993  case kKey_F5:
994  Layout();
995  break;
996  case kKey_F7:
997  Search();
998  break;
999  case kKey_Left:
1000  ClearViewPort();
1001  item->SetOpen(kFALSE);
1002  break;
1003  case kKey_Right:
1004  ClearViewPort();
1005  item->SetOpen(kTRUE);
1006  break;
1007  case kKey_Up:
1008  LineUp(event->fState & kKeyShiftMask);
1009  break;
1010  case kKey_Down:
1011  LineDown(event->fState & kKeyShiftMask);
1012  break;
1013  case kKey_PageUp:
1014  PageUp(event->fState & kKeyShiftMask);
1015  break;
1016  case kKey_PageDown:
1017  PageDown(event->fState & kKeyShiftMask);
1018  break;
1019  case kKey_Home:
1020  Home(event->fState & kKeyShiftMask);
1021  break;
1022  case kKey_End:
1023  End(event->fState & kKeyShiftMask);
1024  break;
1025  default:
1026  break;
1027  }
1028  if (event->fState & kKeyControlMask) { // Ctrl key modifier pressed
1029  switch((EKeySym)keysym & ~0x20) { // treat upper and lower the same
1030  case kKey_F:
1031  Search();
1032  break;
1033  case kKey_G:
1034  Search(kFALSE);
1035  break;
1036  default:
1037  return kTRUE;
1038  }
1039  }
1040 
1041  }
1042  return kTRUE;
1043 }
1044 
1045 ////////////////////////////////////////////////////////////////////////////////
1046 /// Signal emitted when pointer is over entry.
1047 
1048 void TGListTree::MouseOver(TGListTreeItem *entry)
1049 {
1050  Emit("MouseOver(TGListTreeItem*)", (Long_t)entry);
1051 }
1052 
1053 ////////////////////////////////////////////////////////////////////////////////
1054 /// Signal emitted when pointer is over entry.
1055 
1056 void TGListTree::MouseOver(TGListTreeItem *entry, UInt_t mask)
1057 {
1058  Long_t args[2];
1059  args[0] = (Long_t)entry;
1060  args[1] = mask;
1061  Emit("MouseOver(TGListTreeItem*,UInt_t)", args);
1062 }
1063 
1064 ////////////////////////////////////////////////////////////////////////////////
1065 /// Signal emitted when keyboard key pressed
1066 ///
1067 /// entry - selected item
1068 /// keysym - defined in "KeySymbols.h"
1069 /// mask - modifier key mask, defined in "GuiTypes.h"
1070 ///
1071 /// const Mask_t kKeyShiftMask = BIT(0);
1072 /// const Mask_t kKeyLockMask = BIT(1);
1073 /// const Mask_t kKeyControlMask = BIT(2);
1074 /// const Mask_t kKeyMod1Mask = BIT(3); // typically the Alt key
1075 /// const Mask_t kButton1Mask = BIT(8);
1076 /// const Mask_t kButton2Mask = BIT(9);
1077 /// const Mask_t kButton3Mask = BIT(10);
1078 /// const Mask_t kButton4Mask = BIT(11);
1079 /// const Mask_t kButton5Mask = BIT(12);
1080 /// const Mask_t kAnyModifier = BIT(15);
1081 
1082 void TGListTree::KeyPressed(TGListTreeItem *entry, UInt_t keysym, UInt_t mask)
1083 {
1084  Long_t args[3];
1085  args[0] = (Long_t)entry;
1086  args[1] = (Long_t)keysym;
1087  args[2] = (Long_t)mask;
1088  Emit("KeyPressed(TGListTreeItem*,ULong_t,ULong_t)", args);
1089  SendMessage(fMsgWindow, MK_MSG(kC_LISTTREE, kCT_KEY), keysym, mask);
1090 }
1091 
1092 ////////////////////////////////////////////////////////////////////////////////
1093 /// Emit ReturnPressed() signal.
1094 
1095 void TGListTree::ReturnPressed(TGListTreeItem *entry)
1096 {
1097  Emit("ReturnPressed(TGListTreeItem*)", (Long_t)entry);
1098 }
1099 
1100 ////////////////////////////////////////////////////////////////////////////////
1101 /// Emit Checked() signal.
1102 
1103 void TGListTree::Checked(TObject *entry, Bool_t on)
1104 {
1105  Long_t args[2];
1106 
1107  args[0] = (Long_t)entry;
1108  args[1] = on;
1109 
1110  Emit("Checked(TObject*,Bool_t)", args);
1111 }
1112 
1113 ////////////////////////////////////////////////////////////////////////////////
1114 /// Emit Clicked() signal.
1115 
1116 void TGListTree::Clicked(TGListTreeItem *entry, Int_t btn)
1117 {
1118  Long_t args[2];
1119 
1120  args[0] = (Long_t)entry;
1121  args[1] = btn;
1122 
1123  Emit("Clicked(TGListTreeItem*,Int_t)", args);
1124 }
1125 
1126 ////////////////////////////////////////////////////////////////////////////////
1127 /// Emit Clicked() signal.
1128 
1129 void TGListTree::Clicked(TGListTreeItem *entry, Int_t btn, Int_t x, Int_t y)
1130 {
1131  Long_t args[4];
1132 
1133  args[0] = (Long_t)entry;
1134  args[1] = btn;
1135  args[2] = x;
1136  args[3] = y;
1137 
1138  Emit("Clicked(TGListTreeItem*,Int_t,Int_t,Int_t)", args);
1139 }
1140 
1141 ////////////////////////////////////////////////////////////////////////////////
1142 /// Emit Clicked() signal.
1143 
1144 void TGListTree::Clicked(TGListTreeItem *entry, Int_t btn, UInt_t mask, Int_t x, Int_t y)
1145 {
1146  Long_t args[5];
1147 
1148  args[0] = (Long_t)entry;
1149  args[1] = btn;
1150  args[2] = mask;
1151  args[3] = x;
1152  args[4] = y;
1153 
1154  Emit("Clicked(TGListTreeItem*,Int_t,UInt_t,Int_t,Int_t)", args);
1155 }
1156 
1157 ////////////////////////////////////////////////////////////////////////////////
1158 /// Emit DoubleClicked() signal.
1159 
1160 void TGListTree::DoubleClicked(TGListTreeItem *entry, Int_t btn)
1161 {
1162  Long_t args[2];
1163 
1164  args[0] = (Long_t)entry;
1165  args[1] = btn;
1166 
1167  Emit("DoubleClicked(TGListTreeItem*,Int_t)", args);
1168 }
1169 
1170 ////////////////////////////////////////////////////////////////////////////////
1171 /// Emit DoubleClicked() signal.
1172 
1173 void TGListTree::DoubleClicked(TGListTreeItem *entry, Int_t btn, Int_t x, Int_t y)
1174 {
1175  Long_t args[4];
1176 
1177  args[0] = (Long_t)entry;
1178  args[1] = btn;
1179  args[2] = x;
1180  args[3] = y;
1181 
1182  Emit("DoubleClicked(TGListTreeItem*,Int_t,Int_t,Int_t)", args);
1183 }
1184 
1185 ////////////////////////////////////////////////////////////////////////////////
1186 /// Move content to the top.
1187 
1188 void TGListTree::Home(Bool_t /*select*/)
1189 {
1190  if (fCanvas) fCanvas->SetVsbPosition(0);
1191 }
1192 
1193 ////////////////////////////////////////////////////////////////////////////////
1194 /// Move content to the bottom.
1195 
1196 void TGListTree::End(Bool_t /*select*/)
1197 {
1198  if (fCanvas) fCanvas->SetVsbPosition((Int_t)fHeight);
1199 }
1200 
1201 ////////////////////////////////////////////////////////////////////////////////
1202 /// Move content one page up.
1203 
1204 void TGListTree::PageUp(Bool_t /*select*/)
1205 {
1206  if (!fCanvas) return;
1207 
1208  TGDimension dim = GetPageDimension();
1209 
1210  Int_t newpos = fCanvas->GetVsbPosition() - dim.fHeight;
1211  if (newpos<0) newpos = 0;
1212 
1213  fCanvas->SetVsbPosition(newpos);
1214 }
1215 
1216 ////////////////////////////////////////////////////////////////////////////////
1217 /// Move content one page down.
1218 
1219 void TGListTree::PageDown(Bool_t /*select*/)
1220 {
1221  if (!fCanvas) return;
1222 
1223  TGDimension dim = GetPageDimension();
1224 
1225  Int_t newpos = fCanvas->GetVsbPosition() + dim.fHeight;
1226 
1227  fCanvas->SetVsbPosition(newpos);
1228 }
1229 
1230 ////////////////////////////////////////////////////////////////////////////////
1231 /// Move content one item-size up.
1232 
1233 void TGListTree::LineUp(Bool_t /*select*/)
1234 {
1235  Int_t height = 0;
1236  if (!fCurrent) return;
1237 
1238  TGPosition pos = GetPagePosition();
1239  const TGPicture *pic1 = fCurrent->GetPicture();
1240  if (pic1) height = pic1->GetHeight() + fVspacing;
1241  else height = fVspacing + 16;
1242  Int_t findy = (fCurrent->fY - height) + (fMargin - pos.fY);
1243  TGListTreeItem *next = FindItem(findy);
1244  if (next && (next != fCurrent)) {
1245  DrawOutline(fId, fCurrent, 0xffffff, kTRUE);
1246  if (findy <= 2*height) {
1247  Int_t newpos = fCanvas->GetVsbPosition() - height;
1248  if (newpos<0) newpos = 0;
1249  fCanvas->SetVsbPosition(newpos);
1250  }
1251  DrawOutline(fId, next);
1252  fCurrent = next;
1253  }
1254 }
1255 
1256 ////////////////////////////////////////////////////////////////////////////////
1257 /// Move content one item-size down.
1258 
1259 void TGListTree::LineDown(Bool_t /*select*/)
1260 {
1261  Int_t height;
1262  if (!fCurrent) return;
1263 
1264  TGDimension dim = GetPageDimension();
1265  TGPosition pos = GetPagePosition();
1266  const TGPicture *pic1 = fCurrent->GetPicture();
1267  if (pic1) height = pic1->GetHeight() + fVspacing;
1268  else height = fVspacing + 16;
1269  Int_t findy = (fCurrent->fY + height) + (fMargin - pos.fY);
1270  TGListTreeItem *next = FindItem(findy);
1271  if (next && (next != fCurrent)) {
1272  DrawOutline(fId, fCurrent, 0xffffff, kTRUE);
1273  if (findy >= ((Int_t)dim.fHeight - 2*height)) {
1274  Int_t newpos = fCanvas->GetVsbPosition() + height;
1275  if (newpos<0) newpos = 0;
1276  fCanvas->SetVsbPosition(newpos);
1277  }
1278  DrawOutline(fId, next);
1279  fCurrent = next;
1280  }
1281 }
1282 
1283 ////////////////////////////////////////////////////////////////////////////////
1284 /// Move content to position of item. If item is 0, move to position
1285 /// of currently selected item.
1286 
1287 void TGListTree::AdjustPosition(TGListTreeItem *item)
1288 {
1289  TGListTreeItem *it = item;
1290 
1291  if (!it) it = fSelected;
1292  if (!it) {
1293  HighlightItem(fFirst); // recursive call of this function
1294  return;
1295  }
1296 
1297  Int_t y = 0;
1298  Int_t yparent = 0;
1299  Int_t vh = 0;
1300  Int_t v = 0;
1301 
1302  if (it) {
1303  y = it->fY;
1304  if (it->GetParent()) yparent = it->GetParent()->fY;
1305  }
1306 
1307  if (y==0) y = yparent; // item->fY not initiated yet
1308 
1309  if (fCanvas->GetVScrollbar()->IsMapped()) {
1310  vh = fCanvas->GetVScrollbar()->GetPosition()+(Int_t)fViewPort->GetHeight();
1311 
1312  if (y<fCanvas->GetVScrollbar()->GetPosition()) {
1313  v = TMath::Max(0,y-(Int_t)fViewPort->GetHeight()/2);
1314  fCanvas->SetVsbPosition(v);
1315  } else if (y+(Int_t)it->fHeight>vh) {
1316  v = TMath::Min((Int_t)GetHeight()-(Int_t)fViewPort->GetHeight(),
1317  y+(Int_t)it->fHeight-(Int_t)fViewPort->GetHeight()/2);
1318  if (v<0) v = 0;
1319  fCanvas->SetVsbPosition(v);
1320  }
1321  }
1322 }
1323 
1324 ////////////////////////////////////////////////////////////////////////////////
1325 /// Invokes search dialog. Looks for item with the entered name.
1326 
1327 void TGListTree::Search(Bool_t close)
1328 {
1329  Int_t ret = 0;
1330  char msg[256];
1331  static TString buf;
1332 
1333  TGSearchType *srch = new TGSearchType;
1334  srch->fBuffer = (char *)StrDup(buf.Data());
1335 
1336  TGListTreeItem *item;
1337  if (close || buf.IsNull())
1338  new TGSearchDialog(fClient->GetDefaultRoot(), fCanvas, 400, 150, srch, &ret);
1339  else if (!buf.IsNull()) ret = 1;
1340 
1341  if (ret) {
1342  item = FindItemByPathname(srch->fBuffer);
1343  if (!item) {
1344  snprintf(msg, 255, "Couldn't find \"%s\"", srch->fBuffer);
1345  gVirtualX->Bell(20);
1346  new TGMsgBox(fClient->GetDefaultRoot(), fCanvas, "Container", msg,
1347  kMBIconExclamation, kMBOk, 0);
1348  } else {
1349  ClearHighlighted();
1350  HighlightItem(item);
1351  }
1352  }
1353  buf = srch->fBuffer;
1354  delete srch;
1355 }
1356 
1357 //---- drawing functions
1358 
1359 ////////////////////////////////////////////////////////////////////////////////
1360 /// Redraw list tree.
1361 
1362 void TGListTree::DrawRegion(Int_t /*x*/, Int_t y, UInt_t /*w*/, UInt_t h)
1363 {
1364  static GContext_t gcBg = 0;
1365 
1366  // sanity checks
1367  if (y > (Int_t)fViewPort->GetHeight()) {
1368  return;
1369  }
1370 
1371  y = y < 0 ? 0 : y;
1372  UInt_t w = fViewPort->GetWidth();
1373 
1374  // more sanity checks
1375  if (((Int_t)w < 1) || (w > 32768) || ((Int_t)h < 1)) {
1376  return;
1377  }
1378 
1379  Pixmap_t pixmap = gVirtualX->CreatePixmap(fId, w, fViewPort->GetHeight());
1380 
1381  if (!gcBg) {
1382  GCValues_t gcValues;
1383  gcValues.fForeground = fBackground;
1384  gcValues.fForeground = fBackground;
1385  gcValues.fGraphicsExposures = kTRUE;
1386  gcValues.fMask = kGCForeground | kGCBackground | kGCGraphicsExposures;
1387  gcBg = gVirtualX->CreateGC(fId, &gcValues);
1388  }
1389 
1390  gVirtualX->SetForeground(gcBg, fBackground);
1391  gVirtualX->FillRectangle(pixmap, gcBg, 0, 0, w, fViewPort->GetHeight());
1392 
1393  Draw(pixmap, 0, fViewPort->GetHeight());
1394 
1395  gVirtualX->CopyArea(pixmap, fId, gcBg, 0, y, w, fViewPort->GetHeight(), 0, y);
1396 
1397  gVirtualX->DeletePixmap(pixmap);
1398  gVirtualX->Update(kFALSE);
1399 }
1400 
1401 ////////////////////////////////////////////////////////////////////////////////
1402 /// Draw list tree widget.
1403 
1404 void TGListTree::Draw(Handle_t id, Int_t yevent, Int_t hevent)
1405 {
1406  TGListTreeItem *item;
1407  Int_t x, y, xbranch;
1408  UInt_t width, height, old_width, old_height;
1409 
1410  // Overestimate the expose region to be sure to draw an item that gets
1411  // cut by the region
1412  fExposeTop = yevent - FontHeight();
1413  fExposeBottom = yevent + hevent + FontHeight();
1414  old_width = fDefw;
1415  old_height = fDefh;
1416  fDefw = fDefh = 1;
1417 
1418  TGPosition pos = GetPagePosition();
1419  x = 2-pos.fX;
1420  y = fMargin;
1421  item = fFirst;
1422 
1423  while (item) {
1424  xbranch = -1;
1425 
1426  DrawItem(id, item, x, y, &xbranch, &width, &height);
1427 
1428  width += pos.fX + x + fHspacing + fMargin;
1429 
1430  if (width > fDefw) fDefw = width;
1431 
1432  y += height + fVspacing;
1433  if (item->fFirstchild && item->IsOpen()) {
1434  y = DrawChildren(id, item->fFirstchild, x, y, xbranch);
1435  }
1436 
1437  item = item->fNextsibling;
1438  }
1439 
1440  fDefh = y + fMargin;
1441 
1442  if ((old_width != fDefw) || (old_height != fDefh)) {
1443  fCanvas->Layout();
1444  }
1445 }
1446 
1447 ////////////////////////////////////////////////////////////////////////////////
1448 /// Draw children of item in list tree.
1449 
1450 Int_t TGListTree::DrawChildren(Handle_t id, TGListTreeItem *item,
1451  Int_t x, Int_t y, Int_t xroot)
1452 {
1453  UInt_t width, height;
1454  Int_t xbranch;
1455  TGPosition pos = GetPagePosition();
1456 
1457  x += fIndent + (Int_t)item->fParent->GetPicWidth();
1458  while (item) {
1459  xbranch = xroot;
1460 
1461  DrawItem(id, item, x, y, &xbranch, &width, &height);
1462 
1463  width += pos.fX + x + fHspacing + fMargin;
1464  if (width > fDefw) fDefw = width;
1465 
1466  y += height + fVspacing;
1467  if ((item->fFirstchild) && (item->IsOpen())) {
1468  y = DrawChildren(id, item->fFirstchild, x, y, xbranch);
1469  }
1470 
1471  item = item->fNextsibling;
1472  }
1473  return y;
1474 }
1475 
1476 ////////////////////////////////////////////////////////////////////////////////
1477 /// Draw list tree item.
1478 
1479 void TGListTree::DrawItem(Handle_t id, TGListTreeItem *item, Int_t x, Int_t y,
1480  Int_t *xroot, UInt_t *retwidth, UInt_t *retheight)
1481 {
1482  Int_t xpic1, ypic1, xbranch, ybranch, xtext, ytext = 0, xline, yline, xc;
1483  Int_t xpic2 = 0;
1484  UInt_t height;
1485  const TGPicture *pic1 = item->GetPicture();
1486  const TGPicture *pic2 = item->GetCheckBoxPicture();
1487 
1488  // Compute the height of this line
1489  height = FontHeight();
1490 
1491  xline = 0;
1492  xpic1 = x;
1493  xtext = x + fHspacing + (Int_t)item->GetPicWidth();
1494  if (pic2) {
1495  if (pic2->GetHeight() > height) {
1496  ytext = y + (Int_t)((pic2->GetHeight() - height) >> 1);
1497  height = pic2->GetHeight();
1498  } else {
1499  ytext = y;
1500  }
1501  if (pic1) xpic2 = xpic1 + pic1->GetWidth() + 1;
1502  else xpic2 = xpic1 + 1;
1503  xtext += pic2->GetWidth();
1504  } else {
1505  ypic1 = y;
1506  xline = 0;
1507  }
1508  if (pic1) {
1509  if (pic1->GetHeight() > height) {
1510  ytext = y + (Int_t)((pic1->GetHeight() - height) >> 1);
1511  height = pic1->GetHeight();
1512  ypic1 = y;
1513  } else {
1514 #ifdef R__HAS_COCOA
1515  if (!pic2)//DO NOT MODIFY ytext, it WAS ADJUSTED already!
1516 #endif
1517  ytext = y;
1518  ypic1 = y + (Int_t)((height - pic1->GetHeight()) >> 1);
1519  }
1520  xbranch = xpic1 + (Int_t)(pic1->GetWidth() >> 1);
1521  ybranch = ypic1 + (Int_t)pic1->GetHeight();
1522  yline = ypic1 + (Int_t)(pic1->GetHeight() >> 1);
1523  if (xline == 0) xline = xpic1;
1524  } else {
1525  if (xline == 0) xline = xpic1;
1526  ypic1 = ytext = y;
1527  xbranch = xpic1 + (Int_t)(item->GetPicWidth() >> 1);
1528  yline = ybranch = ypic1 + (Int_t)(height >> 1);
1529  yline = ypic1 + (Int_t)(height >> 1);
1530  }
1531 
1532  // height must be even, otherwise our dashed line wont appear properly
1533  //++height; height &= ~1;
1534 
1535  // Save the basic graphics info for use by other functions
1536  item->fY = y;
1537  item->fXtext = xtext;
1538  item->fYtext = ytext;
1539  item->fHeight = height;
1540 
1541  // projected coordinates
1542  TGPosition pos = GetPagePosition();
1543  TGDimension dim = GetPageDimension();
1544  Int_t yp = y - pos.fY;
1545  Int_t ylinep = yline - pos.fY;
1546  Int_t ybranchp = ybranch - pos.fY;
1547  Int_t ypicp = ypic1 - pos.fY;
1548 
1549  if ((yp >= fExposeTop) && (yp <= (Int_t)dim.fHeight))
1550  {
1551  DrawItemName(id, item);
1552  if (*xroot >= 0) {
1553  xc = *xroot;
1554 
1555  if (item->fNextsibling) {
1556  gVirtualX->DrawLine(id, fLineGC, xc, yp, xc, yp+height);
1557  } else {
1558  gVirtualX->DrawLine(id, fLineGC, xc, yp, xc, ylinep);
1559  }
1560 
1561  TGListTreeItem *p = item->fParent;
1562  while (p) {
1563  xc -= (fIndent + (Int_t)item->GetPicWidth());
1564  if (p->fNextsibling) {
1565  gVirtualX->DrawLine(id, fLineGC, xc, yp, xc, yp+height);
1566  }
1567  p = p->fParent;
1568  }
1569  gVirtualX->DrawLine(id, fLineGC, *xroot, ylinep, xpic1, ylinep);
1570  DrawNode(id, item, *xroot, yline);
1571  }
1572  if (item->IsOpen() && item->fFirstchild) {
1573  gVirtualX->DrawLine(id, fLineGC, xbranch, ybranchp, xbranch,
1574  yp+height);
1575  }
1576  if (pic1)
1577  pic1->Draw(id, fDrawGC, xpic1, ypicp);
1578  if (pic2)
1579  pic2->Draw(id, fDrawGC, xpic2, ypicp);
1580  }
1581 
1582  *xroot = xbranch;
1583  *retwidth = TextWidth(item->GetText()) + item->GetPicWidth();
1584  *retheight = height;
1585 }
1586 
1587 ////////////////////////////////////////////////////////////////////////////////
1588 /// Draw a outline of color 'col' around an item.
1589 
1590 void TGListTree::DrawOutline(Handle_t id, TGListTreeItem *item, Pixel_t col,
1591  Bool_t clear)
1592 {
1593  TGPosition pos = GetPagePosition();
1594  TGDimension dim = GetPageDimension();
1595 
1596  if (clear) {
1597  gVirtualX->SetForeground(fDrawGC, fCanvas->GetContainer()->GetBackground());
1598  //ClearViewPort(); // time consuming!!!
1599  }
1600  else
1601  gVirtualX->SetForeground(fDrawGC, col);
1602 
1603 #ifdef R__HAS_COCOA
1604  gVirtualX->DrawRectangle(id, fDrawGC, 1, item->fY - pos.fY, dim.fWidth-2, item->fHeight + 1);
1605 #else
1606  gVirtualX->DrawRectangle(id, fDrawGC, 1, item->fYtext-pos.fY-2,
1607  dim.fWidth-3, FontHeight()+4);
1608 #endif
1609  gVirtualX->SetForeground(fDrawGC, fgBlackPixel);
1610 }
1611 
1612 ////////////////////////////////////////////////////////////////////////////////
1613 /// Draw active item with its active color.
1614 
1615 void TGListTree::DrawActive(Handle_t id, TGListTreeItem *item)
1616 {
1617  UInt_t width;
1618  TGPosition pos = GetPagePosition();
1619  TGDimension dim = GetPageDimension();
1620 
1621  width = dim.fWidth-2;
1622  gVirtualX->SetForeground(fDrawGC, item->GetActiveColor());
1623 
1624 #ifdef R__HAS_COCOA
1625  gVirtualX->FillRectangle(id, fDrawGC, 1, item->fY - pos.fY, width, item->fHeight + 1);
1626 #else
1627  gVirtualX->FillRectangle(id, fDrawGC, 1, item->fYtext-pos.fY-1, width,
1628  FontHeight()+3);
1629 #endif
1630  gVirtualX->SetForeground(fDrawGC, fgBlackPixel);
1631  gVirtualX->DrawString(id, fActiveGC, item->fXtext,
1632  item->fYtext - pos.fY + FontAscent(),
1633  item->GetText(), item->GetTextLength());
1634 }
1635 
1636 ////////////////////////////////////////////////////////////////////////////////
1637 /// Draw name of list tree item.
1638 
1639 void TGListTree::DrawItemName(Handle_t id, TGListTreeItem *item)
1640 {
1641  TGPosition pos = GetPagePosition();
1642  TGDimension dim = GetPageDimension();
1643 
1644  if (item->IsActive()) {
1645  DrawActive(id, item);
1646  }
1647  else { // if (!item->IsActive() && (item != fSelected)) {
1648  gVirtualX->FillRectangle(id, fHighlightGC, item->fXtext,
1649  item->fYtext-pos.fY, dim.fWidth-item->fXtext-2,
1650  FontHeight()+1);
1651  gVirtualX->DrawString(id, fDrawGC,
1652  item->fXtext, item->fYtext-pos.fY + FontAscent(),
1653  item->GetText(), item->GetTextLength());
1654  }
1655  if (item == fCurrent) {
1656  DrawOutline(id, item);
1657  }
1658 
1659  if (fColorMode != 0 && item->HasColor()) {
1660  UInt_t width = TextWidth(item->GetText());
1661  gVirtualX->SetForeground(fColorGC, TColor::Number2Pixel(item->GetColor()));
1662  if (fColorMode & kColorUnderline) {
1663  Int_t y = item->fYtext-pos.fY + FontAscent() + 2;
1664  gVirtualX->DrawLine(id, fColorGC, item->fXtext, y,
1665  item->fXtext + width, y);
1666  }
1667  if (fColorMode & kColorBox) {
1668  Int_t x = item->fXtext + width + 4;
1669  Int_t y = item->fYtext - pos.fY + 3;
1670  Int_t h = FontAscent() - 4;
1671  gVirtualX->FillRectangle(id, fColorGC, x, y, h, h);
1672  gVirtualX->DrawRectangle(id, fDrawGC, x, y, h, h);
1673  }
1674  }
1675 }
1676 
1677 ////////////////////////////////////////////////////////////////////////////////
1678 /// Draw node (little + in box).
1679 
1680 void TGListTree::DrawNode(Handle_t id, TGListTreeItem *item, Int_t x, Int_t y)
1681 {
1682  TGPosition pos = GetPagePosition();
1683  Int_t yp = y - pos.fY;
1684 
1685  if (item->fFirstchild) {
1686  gVirtualX->DrawLine(id, fHighlightGC, x, yp-2, x, yp+2);
1687  gVirtualX->SetForeground(fHighlightGC, fgBlackPixel);
1688  gVirtualX->DrawLine(id, fHighlightGC, x-2, yp, x+2, yp);
1689  if (!item->IsOpen())
1690  gVirtualX->DrawLine(id, fHighlightGC, x, yp-2, x, yp+2);
1691  gVirtualX->SetForeground(fHighlightGC, fGrayPixel);
1692  gVirtualX->DrawLine(id, fHighlightGC, x-4, yp-4, x+4, yp-4);
1693  gVirtualX->DrawLine(id, fHighlightGC, x+4, yp-4, x+4, yp+4);
1694  gVirtualX->DrawLine(id, fHighlightGC, x-4, yp+4, x+4, yp+4);
1695  gVirtualX->DrawLine(id, fHighlightGC, x-4, yp-4, x-4, yp+4);
1696  gVirtualX->SetForeground(fHighlightGC, fgWhitePixel);
1697  }
1698 }
1699 
1700 ////////////////////////////////////////////////////////////////////////////////
1701 /// Set tool tip text associated with this item. The delay is in
1702 /// milliseconds (minimum 250). To remove tool tip call method with
1703 /// delayms = 0. To change delayms you first have to call this method
1704 /// with delayms=0.
1705 
1706 void TGListTree::SetToolTipText(const char *text, Int_t x, Int_t y, Long_t delayms)
1707 {
1708  if (delayms == 0) {
1709  delete fTip;
1710  fTip = 0;
1711  return;
1712  }
1713 
1714  if (text && strlen(text)) {
1715  if (!fTip)
1716  fTip = new TGToolTip(fClient->GetDefaultRoot(), this, text, delayms);
1717  else
1718  fTip->SetText(text);
1719  fTip->SetPosition(x, y);
1720  fTip->Reset();
1721  }
1722 }
1723 
1724 ////////////////////////////////////////////////////////////////////////////////
1725 /// This function removes the specified item from the linked list.
1726 /// It does not do anything with the data contained in the item, though.
1727 
1728 void TGListTree::RemoveReference(TGListTreeItem *item)
1729 {
1730  ClearViewPort();
1731 
1732  // Disentangle from front (previous-sibling, parent's first child)
1733  if (item->fPrevsibling) {
1734  item->fPrevsibling->fNextsibling = item->fNextsibling;
1735  } else {
1736  if (item->fParent)
1737  item->fParent->fFirstchild = item->fNextsibling;
1738  else
1739  fFirst = item->fNextsibling;
1740  }
1741  // Disentangle from end (next-sibling, parent's last child)
1742  if (item->fNextsibling) {
1743  item->fNextsibling->fPrevsibling = item->fPrevsibling;
1744  } else {
1745  if (item->fParent)
1746  item->fParent->fLastchild = item->fPrevsibling;
1747  else
1748  fLast = item->fPrevsibling;
1749  }
1750 }
1751 
1752 ////////////////////////////////////////////////////////////////////////////////
1753 /// Delete given item. Takes care of list-tree state members
1754 /// fSelected, fCurrent and fBelowMouse.
1755 
1756 void TGListTree::PDeleteItem(TGListTreeItem *item)
1757 {
1758  if (fSelected == item) {
1759  fSelected = 0;
1760  }
1761  if (fCurrent == item) {
1762  DrawOutline(fId, fCurrent, 0xffffff, kTRUE);
1763  fCurrent = item->GetPrevSibling();
1764  if (! fCurrent) {
1765  fCurrent = item->GetNextSibling();
1766  if (! fCurrent)
1767  fCurrent = item->GetParent();
1768  }
1769  }
1770  if (fBelowMouse == item) {
1771  DrawOutline(fId, fBelowMouse, 0xffffff, kTRUE);
1772  fBelowMouse = 0;
1773  MouseOver(0);
1774  MouseOver(0,fLastEventState);
1775  }
1776 
1777  delete item;
1778 }
1779 
1780 ////////////////////////////////////////////////////////////////////////////////
1781 /// Recursively delete all children of an item.
1782 
1783 void TGListTree::PDeleteChildren(TGListTreeItem *item)
1784 {
1785  TGListTreeItem *child = item->fFirstchild;
1786 
1787  while (child) {
1788  TGListTreeItem *next = child->fNextsibling;
1789  PDeleteChildren(child);
1790  PDeleteItem(child);
1791  child = next;
1792  }
1793 
1794  item->fFirstchild = item->fLastchild = 0;
1795 }
1796 
1797 ////////////////////////////////////////////////////////////////////////////////
1798 /// Insert child in list.
1799 
1800 void TGListTree::InsertChild(TGListTreeItem *parent, TGListTreeItem *item)
1801 {
1802  TGListTreeItem *i;
1803 
1804  item->fParent = parent;
1805  item->fNextsibling = item->fPrevsibling = 0;
1806 
1807  if (parent) {
1808 
1809  if (parent->fFirstchild) {
1810  if (parent->fLastchild) {
1811  i = parent->fLastchild;
1812  }
1813  else {
1814  i = parent->fFirstchild;
1815  while (i->fNextsibling) i = i->fNextsibling;
1816  }
1817  i->fNextsibling = item;
1818  item->fPrevsibling = i;
1819  } else {
1820  parent->fFirstchild = item;
1821  }
1822  parent->fLastchild = item;
1823 
1824  } else { // if parent == 0, this is a top level entry
1825 
1826  if (fFirst) {
1827  if (fLast) {
1828  i = fLast;
1829  }
1830  else {
1831  i = fFirst;
1832  while (i->fNextsibling) i = i->fNextsibling;
1833  }
1834  i->fNextsibling = item;
1835  item->fPrevsibling = i;
1836  } else {
1837  fFirst = item;
1838  }
1839  fLast = item;
1840  }
1841  if (item->HasCheckBox())
1842  UpdateChecked(item);
1843 }
1844 
1845 ////////////////////////////////////////////////////////////////////////////////
1846 /// Insert a list of ALREADY LINKED children into another list
1847 
1848 void TGListTree::InsertChildren(TGListTreeItem *parent, TGListTreeItem *item)
1849 {
1850  TGListTreeItem *next, *newnext;
1851 
1852  //while (item) {
1853  // next = item->fNextsibling;
1854  // InsertChild(parent, item);
1855  // item = next;
1856  //}
1857  //return;
1858 
1859  // Save the reference for the next item in the new list
1860  next = item->fNextsibling;
1861 
1862  // Insert the first item in the new list into the existing list
1863  InsertChild(parent, item);
1864 
1865  // The first item is inserted, with its prev and next siblings updated
1866  // to fit into the existing list. So, save the existing list reference
1867  newnext = item->fNextsibling;
1868 
1869  // Now, mark the first item's next sibling to point back to the new list
1870  item->fNextsibling = next;
1871 
1872  // Mark the parents of the new list to the new parent. The order of the
1873  // rest of the new list should be OK, and the second item should still
1874  // point to the first, even though the first was reparented.
1875  while (item->fNextsibling) {
1876  item->fParent = parent;
1877  item = item->fNextsibling;
1878  }
1879 
1880  // Fit the end of the new list back into the existing list
1881  item->fNextsibling = newnext;
1882  if (newnext)
1883  newnext->fPrevsibling = item;
1884 }
1885 
1886 ////////////////////////////////////////////////////////////////////////////////
1887 /// Search child item.
1888 
1889 Int_t TGListTree::SearchChildren(TGListTreeItem *item, Int_t y, Int_t findy,
1890  TGListTreeItem **finditem)
1891 {
1892  UInt_t height;
1893  const TGPicture *pic;
1894 
1895  while (item) {
1896  // Select the pixmap to use
1897  pic = item->GetPicture();
1898 
1899  // Compute the height of this line
1900  height = FontHeight();
1901  if (pic && pic->GetHeight() > height)
1902  height = pic->GetHeight();
1903 
1904  if ((findy >= y) && (findy <= y + (Int_t)height)) {
1905  *finditem = item;
1906  return -1;
1907  }
1908 
1909  y += (Int_t)height + fVspacing;
1910  if (item->fFirstchild && item->IsOpen()) {
1911  y = SearchChildren(item->fFirstchild, y, findy, finditem);
1912  if (*finditem) return -1;
1913  }
1914 
1915  item = item->fNextsibling;
1916  }
1917 
1918  return y;
1919 }
1920 
1921 ////////////////////////////////////////////////////////////////////////////////
1922 /// Find item at postion findy.
1923 
1924 TGListTreeItem *TGListTree::FindItem(Int_t findy)
1925 {
1926  Int_t y;
1927  UInt_t height;
1928  TGListTreeItem *item, *finditem;
1929  const TGPicture *pic;
1930  TGPosition pos = GetPagePosition();
1931 
1932  y = fMargin - pos.fY;
1933  item = fFirst;
1934  finditem = 0;
1935  while (item && !finditem) {
1936  // Select the pixmap to use
1937  pic = item->GetPicture();
1938 
1939  // Compute the height of this line
1940  height = FontHeight();
1941  if (pic && (pic->GetHeight() > height))
1942  height = pic->GetHeight();
1943 
1944  if ((findy >= y) && (findy <= y + (Int_t)height))
1945  return item;
1946 
1947  y += (Int_t)height + fVspacing;
1948  if ((item->fFirstchild) && (item->IsOpen())) {
1949  y = SearchChildren(item->fFirstchild, y, findy, &finditem);
1950  //if (finditem) return finditem;
1951  }
1952  item = item->fNextsibling;
1953  }
1954 
1955  return finditem;
1956 }
1957 
1958 //----- Public Functions
1959 
1960 ////////////////////////////////////////////////////////////////////////////////
1961 /// Add given item to list tree.
1962 
1963 void TGListTree::AddItem(TGListTreeItem *parent, TGListTreeItem *item)
1964 {
1965  InsertChild(parent, item);
1966 
1967  if ((parent == 0) || (parent && parent->IsOpen()))
1968  ClearViewPort();
1969 }
1970 
1971 ////////////////////////////////////////////////////////////////////////////////
1972 /// Add item to list tree. Returns new item.
1973 
1974 TGListTreeItem *TGListTree::AddItem(TGListTreeItem *parent, const char *string,
1975  const TGPicture *open, const TGPicture *closed,
1976  Bool_t checkbox)
1977 {
1978  TGListTreeItem *item;
1979 
1980  item = new TGListTreeItemStd(fClient, string, open, closed, checkbox);
1981  InsertChild(parent, item);
1982 
1983  if ((parent == 0) || (parent && parent->IsOpen()))
1984  ClearViewPort();
1985  return item;
1986 }
1987 
1988 ////////////////////////////////////////////////////////////////////////////////
1989 /// Add item to list tree. If item with same userData already exists
1990 /// don't add it. Returns new item.
1991 
1992 TGListTreeItem *TGListTree::AddItem(TGListTreeItem *parent, const char *string,
1993  void *userData, const TGPicture *open,
1994  const TGPicture *closed,
1995  Bool_t checkbox)
1996 {
1997  TGListTreeItem *item = FindChildByData(parent, userData);
1998  if (!item) {
1999  item = AddItem(parent, string, open, closed, checkbox);
2000  if (item) item->SetUserData(userData);
2001  }
2002 
2003  return item;
2004 }
2005 
2006 ////////////////////////////////////////////////////////////////////////////////
2007 /// Rename item in list tree.
2008 
2009 void TGListTree::RenameItem(TGListTreeItem *item, const char *string)
2010 {
2011  if (item) {
2012  item->Rename(string);
2013  }
2014 
2015  DoRedraw();
2016 }
2017 
2018 ////////////////////////////////////////////////////////////////////////////////
2019 /// Delete item from list tree.
2020 
2021 Int_t TGListTree::DeleteItem(TGListTreeItem *item)
2022 {
2023  if (!fUserControlled)
2024  fCurrent = fBelowMouse = 0;
2025 
2026  PDeleteChildren(item);
2027  RemoveReference(item);
2028  PDeleteItem(item);
2029 
2030  fClient->NeedRedraw(this);
2031 
2032  return 1;
2033 }
2034 
2035 ////////////////////////////////////////////////////////////////////////////////
2036 /// Open item in list tree (i.e. show child items).
2037 
2038 void TGListTree::OpenItem(TGListTreeItem *item)
2039 {
2040  if (item) {
2041  item->SetOpen(kTRUE);
2042  DoRedraw(); // force layout
2043  AdjustPosition(item);
2044  }
2045 }
2046 
2047 ////////////////////////////////////////////////////////////////////////////////
2048 /// Close item in list tree (i.e. hide child items).
2049 
2050 void TGListTree::CloseItem(TGListTreeItem *item)
2051 {
2052  if (item) {
2053  item->SetOpen(kFALSE);
2054  DoRedraw(); // force layout
2055  AdjustPosition(item);
2056  }
2057 }
2058 
2059 ////////////////////////////////////////////////////////////////////////////////
2060 /// Delete item with fUserData == ptr. Search tree downwards starting
2061 /// at item.
2062 
2063 Int_t TGListTree::RecursiveDeleteItem(TGListTreeItem *item, void *ptr)
2064 {
2065  if (item && ptr) {
2066  if (item->GetUserData() == ptr) {
2067  DeleteItem(item);
2068  } else {
2069  if (item->IsOpen() && item->fFirstchild) {
2070  RecursiveDeleteItem(item->fFirstchild, ptr);
2071  }
2072  RecursiveDeleteItem(item->fNextsibling, ptr);
2073  }
2074  }
2075  return 1;
2076 }
2077 
2078 ////////////////////////////////////////////////////////////////////////////////
2079 /// Set tooltip text for this item. By default an item for which the
2080 /// userData is a pointer to an TObject the TObject::GetTitle() will
2081 /// be used to get the tip text.
2082 
2083 void TGListTree::SetToolTipItem(TGListTreeItem *item, const char *string)
2084 {
2085  if (item) {
2086  item->SetTipText(string);
2087  }
2088 }
2089 
2090 ////////////////////////////////////////////////////////////////////////////////
2091 /// Delete children of item from list.
2092 
2093 Int_t TGListTree::DeleteChildren(TGListTreeItem *item)
2094 {
2095  if (!fUserControlled)
2096  fCurrent = fBelowMouse = 0;
2097 
2098  PDeleteChildren(item);
2099 
2100  DoRedraw();
2101 
2102  return 1;
2103 }
2104 
2105 ////////////////////////////////////////////////////////////////////////////////
2106 /// Make newparent the new parent of item.
2107 
2108 Int_t TGListTree::Reparent(TGListTreeItem *item, TGListTreeItem *newparent)
2109 {
2110  // Remove the item from its old location.
2111  RemoveReference(item);
2112 
2113  // The item is now unattached. Reparent it.
2114  InsertChild(newparent, item);
2115 
2116  DoRedraw();
2117 
2118  return 1;
2119 }
2120 
2121 ////////////////////////////////////////////////////////////////////////////////
2122 /// Make newparent the new parent of the children of item.
2123 
2124 Int_t TGListTree::ReparentChildren(TGListTreeItem *item,
2125  TGListTreeItem *newparent)
2126 {
2127  TGListTreeItem *first;
2128 
2129  if (item->fFirstchild) {
2130  first = item->fFirstchild;
2131  item->fFirstchild = 0;
2132 
2133  InsertChildren(newparent, first);
2134 
2135  DoRedraw();
2136  return 1;
2137  }
2138  return 0;
2139 }
2140 
2141 ////////////////////////////////////////////////////////////////////////////////
2142 
2143 extern "C"
2144 Int_t Compare(const void *item1, const void *item2)
2145 {
2146  return strcmp((*((TGListTreeItem **) item1))->GetText(),
2147  (*((TGListTreeItem **) item2))->GetText());
2148 }
2149 
2150 ////////////////////////////////////////////////////////////////////////////////
2151 /// Sort items starting with item.
2152 
2153 Int_t TGListTree::Sort(TGListTreeItem *item)
2154 {
2155  TGListTreeItem *first, *parent, **list;
2156  size_t i, count;
2157 
2158  // Get first child in list;
2159  while (item->fPrevsibling) item = item->fPrevsibling;
2160 
2161  first = item;
2162  parent = first->fParent;
2163 
2164  // Count the children
2165  count = 1;
2166  while (item->fNextsibling) item = item->fNextsibling, count++;
2167  if (count <= 1) return 1;
2168 
2169  list = new TGListTreeItem* [count];
2170  list[0] = first;
2171  count = 1;
2172  while (first->fNextsibling) {
2173  list[count] = first->fNextsibling;
2174  count++;
2175  first = first->fNextsibling;
2176  }
2177 
2178  ::qsort(list, count, sizeof(TGListTreeItem*), ::Compare);
2179 
2180  list[0]->fPrevsibling = 0;
2181  for (i = 0; i < count; i++) {
2182  if (i < count - 1)
2183  list[i]->fNextsibling = list[i + 1];
2184  if (i > 0)
2185  list[i]->fPrevsibling = list[i - 1];
2186  }
2187  list[count - 1]->fNextsibling = 0;
2188  if (parent) {
2189  parent->fFirstchild = list[0];
2190  parent->fLastchild = list[count-1];
2191  }
2192  else {
2193  fFirst = list[0];
2194  fLast = list[count-1];
2195  }
2196 
2197  delete [] list;
2198 
2199  DoRedraw();
2200 
2201  return 1;
2202 }
2203 
2204 ////////////////////////////////////////////////////////////////////////////////
2205 /// Sort siblings of item.
2206 
2207 Int_t TGListTree::SortSiblings(TGListTreeItem *item)
2208 {
2209  return Sort(item);
2210 }
2211 
2212 ////////////////////////////////////////////////////////////////////////////////
2213 /// Sort children of item.
2214 
2215 Int_t TGListTree::SortChildren(TGListTreeItem *item)
2216 {
2217  TGListTreeItem *first;
2218 
2219  if (item) {
2220  first = item->fFirstchild;
2221  if (first) {
2222  SortSiblings(first);
2223  }
2224  } else {
2225  if (fFirst) {
2226  first = fFirst->fFirstchild;
2227  if (first) {
2228  SortSiblings(first);
2229  }
2230  }
2231  }
2232  DoRedraw();
2233  return 1;
2234 }
2235 
2236 ////////////////////////////////////////////////////////////////////////////////
2237 /// Find sibling of item by name.
2238 
2239 TGListTreeItem *TGListTree::FindSiblingByName(TGListTreeItem *item, const char *name)
2240 {
2241  // Get first child in list
2242  if (item) {
2243  while (item->fPrevsibling) {
2244  item = item->fPrevsibling;
2245  }
2246 
2247  while (item) {
2248  if (strcmp(item->GetText(), name) == 0) {
2249  return item;
2250  }
2251  item = item->fNextsibling;
2252  }
2253  return item;
2254  }
2255  return 0;
2256 }
2257 
2258 ////////////////////////////////////////////////////////////////////////////////
2259 /// Find sibling of item by userData.
2260 
2261 TGListTreeItem *TGListTree::FindSiblingByData(TGListTreeItem *item, void *userData)
2262 {
2263  // Get first child in list
2264  if (item) {
2265  while (item->fPrevsibling) {
2266  item = item->fPrevsibling;
2267  }
2268 
2269  while (item) {
2270  if (item->GetUserData() == userData) {
2271  return item;
2272  }
2273  item = item->fNextsibling;
2274  }
2275  return item;
2276  }
2277  return 0;
2278 }
2279 
2280 ////////////////////////////////////////////////////////////////////////////////
2281 /// Find child of item by name.
2282 
2283 TGListTreeItem *TGListTree::FindChildByName(TGListTreeItem *item, const char *name)
2284 {
2285  // Get first child in list
2286  if (item && item->fFirstchild) {
2287  item = item->fFirstchild;
2288  } else if (!item && fFirst) {
2289  item = fFirst;
2290  } else {
2291  item = 0;
2292  }
2293 
2294  while (item) {
2295  if (strcmp(item->GetText(), name) == 0) {
2296  return item;
2297  }
2298  item = item->fNextsibling;
2299  }
2300  return 0;
2301 }
2302 
2303 ////////////////////////////////////////////////////////////////////////////////
2304 /// Find child of item by userData.
2305 
2306 TGListTreeItem *TGListTree::FindChildByData(TGListTreeItem *item, void *userData)
2307 {
2308  // Get first child in list
2309  if (item && item->fFirstchild) {
2310  item = item->fFirstchild;
2311  } else if (!item && fFirst) {
2312  item = fFirst;
2313  } else {
2314  item = 0;
2315  }
2316 
2317  while (item) {
2318  if (item->GetUserData() == userData) {
2319  return item;
2320  }
2321  item = item->fNextsibling;
2322  }
2323  return 0;
2324 }
2325 
2326 ////////////////////////////////////////////////////////////////////////////////
2327 /// Find item by pathname. Pathname is in the form of /xx/yy/zz. If zz
2328 /// in path /xx/yy is found it returns item, 0 otherwise.
2329 
2330 TGListTreeItem *TGListTree::FindItemByPathname(const char *path)
2331 {
2332  if (!path || !*path) return 0;
2333 
2334  const char *p = path, *s;
2335  char dirname[1024];
2336  TGListTreeItem *item = 0;
2337  item = FindChildByName(item, "/");
2338  if (!gVirtualX->InheritsFrom("TGX11")) {
2339  // on Windows, use the current drive instead of root (/)
2340  TList *curvol = gSystem->GetVolumes("cur");
2341  if (curvol) {
2342  TNamed *drive = (TNamed *)curvol->At(0);
2343  item = FindChildByName(0, TString::Format("%s\\", drive->GetName()));
2344  }
2345  }
2346  TGListTreeItem *diritem = 0;
2347  TString fulldir;
2348 
2349  while (1) {
2350  while (*p && *p == '/') p++;
2351  if (!*p) break;
2352 
2353  s = strchr(p, '/');
2354 
2355  if (!s) {
2356  strlcpy(dirname, p, 1024);
2357  } else {
2358  strlcpy(dirname, p, (s-p)+1);
2359  }
2360 
2361  item = FindChildByName(item, dirname);
2362 
2363  if (!diritem && dirname[0]) {
2364  fulldir += "/";
2365  fulldir += dirname;
2366 
2367  if ((diritem=FindChildByName(0, fulldir.Data()))) {
2368  if (!s || !s[0]) return diritem;
2369  p = ++s;
2370  item = diritem;
2371  continue;
2372  }
2373  }
2374 
2375  if (!s || !s[0]) return item;
2376  p = ++s;
2377  }
2378  return 0;
2379 }
2380 
2381 ////////////////////////////////////////////////////////////////////////////////
2382 /// Highlight item.
2383 
2384 void TGListTree::HighlightItem(TGListTreeItem *item)
2385 {
2386  UnselectAll(kFALSE);
2387  HighlightItem(item, kTRUE, kFALSE);
2388  AdjustPosition(item);
2389 }
2390 
2391 ////////////////////////////////////////////////////////////////////////////////
2392 /// Un highlight items.
2393 
2394 void TGListTree::ClearHighlighted()
2395 {
2396  UnselectAll(kFALSE);
2397 }
2398 
2399 ////////////////////////////////////////////////////////////////////////////////
2400 /// Get pathname from item. Use depth to limit path name to last
2401 /// depth levels. By default depth is not limited.
2402 
2403 void TGListTree::GetPathnameFromItem(TGListTreeItem *item, char *path, Int_t depth)
2404 {
2405  char tmppath[1024];
2406 
2407  *path = '\0';
2408  while (item) {
2409  snprintf(tmppath, 1023, "/%s%s", item->GetText(), path);
2410  strlcpy(path, tmppath, 1024);
2411  item = item->fParent;
2412  if (--depth == 0 && item) {
2413  snprintf(tmppath, 1023, "...%s", path);
2414  strlcpy(path, tmppath, 1024);
2415  return;
2416  }
2417  }
2418 }
2419 
2420 ////////////////////////////////////////////////////////////////////////////////
2421 /// Return gray draw color in use.
2422 
2423 Pixel_t TGListTree::GetGrayPixel()
2424 {
2425  static Bool_t init = kFALSE;
2426  if (!init) {
2427  if (!gClient->GetColorByName("#808080", fgGrayPixel))
2428  fgGrayPixel = fgBlackPixel;
2429  init = kTRUE;
2430  }
2431  return fgGrayPixel;
2432 }
2433 
2434 ////////////////////////////////////////////////////////////////////////////////
2435 /// Return default font structure in use.
2436 
2437 FontStruct_t TGListTree::GetDefaultFontStruct()
2438 {
2439  if (!fgDefaultFont)
2440  fgDefaultFont = gClient->GetResourcePool()->GetIconFont();
2441  return fgDefaultFont->GetFontStruct();
2442 }
2443 
2444 ////////////////////////////////////////////////////////////////////////////////
2445 /// Return default graphics context in use.
2446 
2447 const TGGC &TGListTree::GetActiveGC()
2448 {
2449  if (!fgActiveGC) {
2450  GCValues_t gcv;
2451 
2452  gcv.fMask = kGCLineStyle | kGCLineWidth | kGCFillStyle |
2453  kGCForeground | kGCBackground | kGCFont;
2454  gcv.fLineStyle = kLineSolid;
2455  gcv.fLineWidth = 0;
2456  gcv.fFillStyle = kFillSolid;
2457  gcv.fFont = fgDefaultFont->GetFontHandle();
2458  gcv.fBackground = fgDefaultSelectedBackground;
2459  const TGGC *selgc = gClient->GetResourcePool()->GetSelectedGC();
2460  if (selgc)
2461  gcv.fForeground = selgc->GetForeground();
2462  else
2463  gcv.fForeground = fgWhitePixel;
2464  fgActiveGC = gClient->GetGC(&gcv, kTRUE);
2465  }
2466  return *fgActiveGC;
2467 }
2468 
2469 ////////////////////////////////////////////////////////////////////////////////
2470 /// Return default graphics context in use.
2471 
2472 const TGGC &TGListTree::GetDrawGC()
2473 {
2474  if (!fgDrawGC) {
2475  GCValues_t gcv;
2476 
2477  gcv.fMask = kGCLineStyle | kGCLineWidth | kGCFillStyle |
2478  kGCForeground | kGCBackground | kGCFont;
2479  gcv.fLineStyle = kLineSolid;
2480  gcv.fLineWidth = 0;
2481  gcv.fFillStyle = kFillSolid;
2482  gcv.fFont = fgDefaultFont->GetFontHandle();
2483  gcv.fBackground = fgWhitePixel;
2484  gcv.fForeground = fgBlackPixel;
2485 
2486  fgDrawGC = gClient->GetGC(&gcv, kTRUE);
2487  }
2488  return *fgDrawGC;
2489 }
2490 
2491 ////////////////////////////////////////////////////////////////////////////////
2492 /// Return graphics context in use for line drawing.
2493 
2494 const TGGC &TGListTree::GetLineGC()
2495 {
2496  if (!fgLineGC) {
2497  GCValues_t gcv;
2498 
2499  gcv.fMask = kGCLineStyle | kGCLineWidth | kGCFillStyle |
2500  kGCForeground | kGCBackground | kGCFont;
2501  gcv.fLineStyle = kLineOnOffDash;
2502  gcv.fLineWidth = 0;
2503  gcv.fFillStyle = kFillSolid;
2504  gcv.fFont = fgDefaultFont->GetFontHandle();
2505  gcv.fBackground = fgWhitePixel;
2506  gcv.fForeground = GetGrayPixel();
2507 
2508  fgLineGC = gClient->GetGC(&gcv, kTRUE);
2509  fgLineGC->SetDashOffset(0);
2510  fgLineGC->SetDashList("\x1\x1", 2);
2511  }
2512  return *fgLineGC;
2513 }
2514 
2515 ////////////////////////////////////////////////////////////////////////////////
2516 /// Return graphics context for highlighted frame background.
2517 
2518 const TGGC &TGListTree::GetHighlightGC()
2519 {
2520  if (!fgHighlightGC) {
2521  GCValues_t gcv;
2522 
2523  gcv.fMask = kGCLineStyle | kGCLineWidth | kGCFillStyle |
2524  kGCForeground | kGCBackground | kGCFont;
2525  gcv.fLineStyle = kLineSolid;
2526  gcv.fLineWidth = 0;
2527  gcv.fFillStyle = kFillSolid;
2528  gcv.fFont = fgDefaultFont->GetFontHandle();
2529  gcv.fBackground = fgDefaultSelectedBackground;
2530  gcv.fForeground = fgWhitePixel;
2531 
2532  fgHighlightGC = gClient->GetGC(&gcv, kTRUE);
2533  }
2534  return *fgHighlightGC;
2535 }
2536 
2537 ////////////////////////////////////////////////////////////////////////////////
2538 /// Return graphics context for highlighted frame background.
2539 
2540 const TGGC &TGListTree::GetColorGC()
2541 {
2542  if (!fgColorGC) {
2543  GCValues_t gcv;
2544 
2545  gcv.fMask = kGCLineStyle | kGCLineWidth | kGCFillStyle |
2546  kGCForeground | kGCBackground;
2547  gcv.fLineStyle = kLineSolid;
2548  gcv.fLineWidth = 1;
2549  gcv.fFillStyle = kFillSolid;
2550  gcv.fBackground = fgDefaultSelectedBackground;
2551  gcv.fForeground = fgWhitePixel;
2552 
2553  fgColorGC = gClient->GetGC(&gcv, kTRUE);
2554  }
2555  return *fgColorGC;
2556 }
2557 
2558 ////////////////////////////////////////////////////////////////////////////////
2559 /// Returns the icon used by items in open state.
2560 
2561 const TGPicture *TGListTree::GetOpenPic()
2562 {
2563  if (!fgOpenPic)
2564  fgOpenPic = gClient->GetPicture("ofolder_t.xpm");
2565  ((TGPicture *)fgOpenPic)->AddReference();
2566  return fgOpenPic;
2567 }
2568 
2569 ////////////////////////////////////////////////////////////////////////////////
2570 /// Returns the icon used by items in closed state.
2571 
2572 const TGPicture *TGListTree::GetClosedPic()
2573 {
2574  if (!fgClosedPic)
2575  fgClosedPic = gClient->GetPicture("folder_t.xpm");
2576  ((TGPicture *)fgClosedPic)->AddReference();
2577  return fgClosedPic;
2578 }
2579 
2580 ////////////////////////////////////////////////////////////////////////////////
2581 /// Returns the icon used for checked checkbox.
2582 
2583 const TGPicture *TGListTree::GetCheckedPic()
2584 {
2585  if (!fgCheckedPic)
2586  fgCheckedPic = gClient->GetPicture("checked_t.xpm");
2587  ((TGPicture *)fgCheckedPic)->AddReference();
2588  return fgCheckedPic;
2589 }
2590 
2591 ////////////////////////////////////////////////////////////////////////////////
2592 /// Returns the icon used for unchecked checkbox.
2593 
2594 const TGPicture *TGListTree::GetUncheckedPic()
2595 {
2596  if (!fgUncheckedPic)
2597  fgUncheckedPic = gClient->GetPicture("unchecked_t.xpm");
2598  ((TGPicture *)fgUncheckedPic)->AddReference();
2599  return fgUncheckedPic;
2600 }
2601 
2602 ////////////////////////////////////////////////////////////////////////////////
2603 /// Save a list tree widget as a C++ statements on output stream out.
2604 
2605 void TGListTree::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
2606 {
2607  if (fBackground != GetWhitePixel()) SaveUserColor(out, option);
2608 
2609  out << std::endl << " // list tree" << std::endl;
2610  out << " TGListTree *";
2611 
2612  if ((fParent->GetParent())->InheritsFrom(TGCanvas::Class())) {
2613  out << GetName() << " = new TGListTree(" << GetCanvas()->GetName();
2614  } else {
2615  out << GetName() << " = new TGListTree(" << fParent->GetName();
2616  out << "," << GetWidth() << "," << GetHeight();
2617  }
2618 
2619  if (fBackground == GetWhitePixel()) {
2620  if (GetOptions() == kSunkenFrame) {
2621  out <<");" << std::endl;
2622  } else {
2623  out << "," << GetOptionString() <<");" << std::endl;
2624  }
2625  } else {
2626  out << "," << GetOptionString() << ",ucolor);" << std::endl;
2627  }
2628  if (option && strstr(option, "keep_names"))
2629  out << " " << GetName() << "->SetName(\"" << GetName() << "\");" << std::endl;
2630 
2631  out << std::endl;
2632 
2633  static Int_t n = 0;
2634 
2635  TGListTreeItem *current;
2636  current = GetFirstItem();
2637 
2638  out << " const TGPicture *popen; //used for list tree items" << std::endl;
2639  out << " const TGPicture *pclose; //used for list tree items" << std::endl;
2640  out << std::endl;
2641 
2642  while (current) {
2643  out << " TGListTreeItem *item" << n << " = " << GetName() << "->AddItem(";
2644  current->SavePrimitive(out, TString::Format("%d",n), n);
2645  if (current->IsOpen())
2646  out << " " << GetName() << "->OpenItem(item" << n << ");" << std::endl;
2647  else
2648  out << " " << GetName() << "->CloseItem(item" << n << ");" << std::endl;
2649 
2650  if (current == fSelected)
2651  out << " " << GetName() << "->SetSelected(item" << n << ");" << std::endl;
2652 
2653  n++;
2654  if (current->fFirstchild) {
2655  SaveChildren(out, current->fFirstchild, n);
2656  }
2657  current = current->fNextsibling;
2658  }
2659 
2660  out << std::endl;
2661 }
2662 
2663 ////////////////////////////////////////////////////////////////////////////////
2664 /// Save child items as a C++ statements on output stream out.
2665 
2666 void TGListTree::SaveChildren(std::ostream &out, TGListTreeItem *item, Int_t &n)
2667 {
2668  Int_t p = n-1;
2669  while (item) {
2670  out << " TGListTreeItem *item" << n << " = " << GetName() << "->AddItem(";
2671  item->SavePrimitive(out, TString::Format("%d",p),n);
2672  n++;
2673  if (item->fFirstchild) {
2674  SaveChildren(out, item->fFirstchild, n);
2675  }
2676  item = item->fNextsibling;
2677  }
2678 }
2679 
2680 ////////////////////////////////////////////////////////////////////////////////
2681 /// Save a list tree item attributes as a C++ statements on output stream.
2682 
2683 void TGListTreeItemStd::SavePrimitive(std::ostream &out, Option_t *option, Int_t n)
2684 {
2685  static const TGPicture *oldopen=0;
2686  static const TGPicture *oldclose=0;
2687  static const TGPicture *oldcheck=0;
2688  static const TGPicture *olduncheck=0;
2689  static Bool_t makecheck = kTRUE;
2690  static Bool_t makeuncheck = kTRUE;
2691  static Color_t oldcolor = -1;
2692 
2693  char quote = '"';
2694  TString s = TString::Format("%d", n);
2695 
2696  if (!fParent)
2697  out << "NULL,";
2698  else
2699  out << "item" << option << ",";
2700  TString text = GetText();
2701  text.ReplaceAll('\\', "\\\\");
2702  text.ReplaceAll("\"", "\\\"");
2703  out << quote << text << quote;
2704  out << ");" << std::endl;
2705 
2706  if (oldopen != fOpenPic) {
2707  oldopen = fOpenPic;
2708  out << " popen = gClient->GetPicture(" << quote
2709  << gSystem->ExpandPathName(gSystem->UnixPathName(fOpenPic->GetName()))
2710  << quote << ");" << std::endl;
2711  }
2712  if (oldclose != fClosedPic) {
2713  oldclose = fClosedPic;
2714  out << " pclose = gClient->GetPicture(" << quote
2715  << gSystem->ExpandPathName(gSystem->UnixPathName(fClosedPic->GetName()))
2716  << quote << ");" << std::endl;
2717  }
2718  out << " item" << s.Data() << "->SetPictures(popen, pclose);" << std::endl;
2719  if (HasCheckBox()) {
2720  if (fCheckedPic && makecheck) {
2721  out << " const TGPicture *pcheck; //used for checked items" << std::endl;
2722  makecheck = kFALSE;
2723  }
2724  if (fUncheckedPic && makeuncheck) {
2725  out << " const TGPicture *puncheck; //used for unchecked items" << std::endl;
2726  makeuncheck = kFALSE;
2727  }
2728  out << " item" << s.Data() << "->CheckItem();" << std::endl;
2729  if (fCheckedPic && oldcheck != fCheckedPic) {
2730  oldcheck = fCheckedPic;
2731  out << " pcheck = gClient->GetPicture(" << quote
2732  << gSystem->ExpandPathName(gSystem->UnixPathName(fCheckedPic->GetName()))
2733  << quote << ");" << std::endl;
2734  }
2735  if (fUncheckedPic && olduncheck != fUncheckedPic) {
2736  olduncheck = fUncheckedPic;
2737  out << " puncheck = gClient->GetPicture(" << quote
2738  << gSystem->ExpandPathName(gSystem->UnixPathName(fUncheckedPic->GetName()))
2739  << quote << ");" << std::endl;
2740  }
2741  out << " item" << s.Data() << "->SetCheckBoxPictures(pcheck, puncheck);" << std::endl;
2742  out << " item" << s.Data() << "->SetCheckBox(kTRUE);" << std::endl;
2743  }
2744  if (fHasColor) {
2745  if (oldcolor != fColor) {
2746  oldcolor = fColor;
2747  out << " item" << s.Data() << "->SetColor(" << fColor << ");" << std::endl;
2748  }
2749  }
2750  if (fTipText.Length() > 0) {
2751  TString tiptext = GetTipText();
2752  tiptext.ReplaceAll('\\', "\\\\");
2753  tiptext.ReplaceAll("\n", "\\n");
2754  tiptext.ReplaceAll("\"", "\\\"");
2755  out << " item" << s.Data() << "->SetTipText(" << quote
2756  << tiptext << quote << ");" << std::endl;
2757  }
2758 
2759 }
2760 
2761 ////////////////////////////////////////////////////////////////////////////////
2762 /// Set check button state for the node 'item'.
2763 
2764 void TGListTree::CheckItem(TGListTreeItem *item, Bool_t check)
2765 {
2766  item->CheckItem(check);
2767 }
2768 
2769 ////////////////////////////////////////////////////////////////////////////////
2770 /// Set check button state for the node 'item'.
2771 
2772 void TGListTree::SetCheckBox(TGListTreeItem *item, Bool_t on)
2773 {
2774  item->SetCheckBox(on);
2775 }
2776 
2777 ////////////////////////////////////////////////////////////////////////////////
2778 /// Toggle check button state of the node 'item'.
2779 
2780 void TGListTree::ToggleItem(TGListTreeItem *item)
2781 {
2782  item->Toggle();
2783 }
2784 
2785 ////////////////////////////////////////////////////////////////////////////////
2786 /// Update the state of the node 'item' according to the children states.
2787 
2788 void TGListTree::UpdateChecked(TGListTreeItem *item, Bool_t redraw)
2789 {
2790  if (fAutoCheckBoxPic == kFALSE) return;
2791 
2792  TGListTreeItem *parent;
2793  TGListTreeItem *current;
2794  current = item->GetFirstChild();
2795  parent = current ? current : item;
2796  // recursively check parent/children status
2797  while (parent && parent->HasCheckBox()) {
2798  if ((!parent->IsChecked() && parent->HasCheckedChild(kTRUE)) ||
2799  (parent->IsChecked() && parent->HasUnCheckedChild(kTRUE))) {
2800  parent->SetCheckBoxPictures(fClient->GetPicture("checked_dis_t.xpm"),
2801  fClient->GetPicture("unchecked_dis_t.xpm"));
2802  }
2803  else {
2804  parent->SetCheckBoxPictures(fClient->GetPicture("checked_t.xpm"),
2805  fClient->GetPicture("unchecked_t.xpm"));
2806  }
2807  parent = parent->GetParent();
2808  if (parent && fCheckMode == kRecursive) {
2809  if (!parent->IsChecked() && parent->GetFirstChild() &&
2810  !parent->GetFirstChild()->HasUnCheckedChild()) {
2811  parent->SetCheckBoxPictures(fClient->GetPicture("checked_t.xpm"),
2812  fClient->GetPicture("unchecked_t.xpm"));
2813  parent->CheckItem(kTRUE);
2814  }
2815  else if (parent->IsChecked() && parent->GetFirstChild() &&
2816  !parent->GetFirstChild()->HasCheckedChild()) {
2817  parent->SetCheckBoxPictures(fClient->GetPicture("checked_t.xpm"),
2818  fClient->GetPicture("unchecked_t.xpm"));
2819  parent->CheckItem(kFALSE);
2820  }
2821  }
2822  }
2823  if (redraw) {
2824  ClearViewPort();
2825  }
2826 }
2827 
2828 ////////////////////////////////////////////////////////////////////////////////
2829 /// Find item with fUserData == ptr. Search tree downwards starting
2830 /// at item.
2831 
2832 TGListTreeItem *TGListTree::FindItemByObj(TGListTreeItem *item, void *ptr)
2833 {
2834  TGListTreeItem *fitem;
2835  if (item && ptr) {
2836  if (item->GetUserData() == ptr)
2837  return item;
2838  else {
2839  if (item->fFirstchild) {
2840  fitem = FindItemByObj(item->fFirstchild, ptr);
2841  if (fitem) return fitem;
2842  }
2843  return FindItemByObj(item->fNextsibling, ptr);
2844  }
2845  }
2846  return 0;
2847 }
2848 
2849 ////////////////////////////////////////////////////////////////////////////////
2850 /// Add all checked list tree items of this list tree into
2851 /// the list 'checked'. This list is not adopted and must
2852 /// be deleted by the user later.
2853 
2854 void TGListTree::GetChecked(TList *checked)
2855 {
2856  if (!checked || !fFirst) return;
2857  TGListTreeItem *current = fFirst;
2858  if (current->IsChecked()) {
2859  checked->Add(new TObjString(current->GetText()));
2860  }
2861  while(current) {
2862  if (current->GetFirstChild())
2863  GetCheckedChildren(checked, current->GetFirstChild());
2864  current = current->GetNextSibling();
2865  }
2866 }
2867 
2868 ////////////////////////////////////////////////////////////////////////////////
2869 /// Add all child items of 'item' into the list 'checked'.
2870 
2871 void TGListTree::GetCheckedChildren(TList *checked, TGListTreeItem *item)
2872 {
2873  if (!checked || !item) return;
2874 
2875  while (item) {
2876  if (item->IsChecked()) {
2877  checked->Add(new TObjString(item->GetText()));
2878  }
2879  if (item->GetFirstChild()) {
2880  GetCheckedChildren(checked, item->GetFirstChild());
2881  }
2882  item = item->GetNextSibling();
2883  }
2884 }
2885 
2886 ////////////////////////////////////////////////////////////////////////////////
2887 /// Check all child items of 'item' and 'item' itself according
2888 /// to the state value: kTRUE means check all, kFALSE - uncheck all.
2889 
2890 void TGListTree::CheckAllChildren(TGListTreeItem *item, Bool_t state)
2891 {
2892  if (item)
2893  item->CheckAllChildren(state);
2894 }
2895