Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGFSContainer.cxx
Go to the documentation of this file.
1 // @(#)root/gui:$Id$
2 // Author: Fons Rademakers 19/01/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 // TGFileIcon, TGFileEntry, TGFSContainer //
26 // //
27 // Utility classes used by the file selection dialog (TGFSDialog). //
28 // //
29 //////////////////////////////////////////////////////////////////////////
30 
31 #include "TGFSContainer.h"
32 #include "TGIcon.h"
33 #include "TGMsgBox.h"
34 #include "TGMimeTypes.h"
35 #include "TRegexp.h"
36 #include "TList.h"
37 #include "TSystem.h"
38 #include "TGDNDManager.h"
39 #include "Riostream.h"
40 #include "TRemoteObject.h"
41 #include "TImage.h"
42 
43 #include <time.h>
44 #include <stdlib.h>
45 
46 ClassImp(TGFileItem);
47 ClassImp(TGFileContainer);
48 
49 class TViewUpdateTimer : public TTimer {
50 
51 private:
52  TGFileContainer *fContainer;
53 
54 public:
55  TViewUpdateTimer(TGFileContainer *t, Long_t ms) : TTimer(ms, kTRUE) { fContainer = t; }
56  Bool_t Notify();
57 };
58 
59 
60 
61 class TGFileIcon : public TGIcon {
62 
63 protected:
64  const TGPicture *fLpic; // icon picture
65 
66  virtual void DoRedraw();
67 
68 public:
69  TGFileIcon(const TGWindow *p, const TGPicture *pic, const TGPicture *lpic,
70  UInt_t options = kChildFrame, Pixel_t back = GetWhitePixel()) :
71  TGIcon(p, pic, 0, 0, options, back) { fLpic = lpic; }
72 };
73 
74 
75 
76 ////////////////////////////////////////////////////////////////////////////////
77 
78 class TGFSFrameElement : public TGFrameElement {
79 public:
80  TGFileContainer *fContainer; // file container
81 
82  Bool_t IsSortable() const { return kTRUE; }
83  Int_t Compare(const TObject *obj) const;
84 };
85 
86 ////////////////////////////////////////////////////////////////////////////////
87 /// Sort frame elements in file selection list view container.
88 
89 Int_t TGFSFrameElement::Compare(const TObject *obj) const
90 {
91  Int_t type1, type2;
92 
93  TGFileItem *f1 = (TGFileItem *) fFrame;
94  TGFileItem *f2 = (TGFileItem *) ((TGFrameElement *) obj)->fFrame;
95 
96  switch (fContainer->fSortType) {
97  default:
98  case kSortByName:
99  //--- this is not exactly what I want...
100  type1 = f1->GetType();
101  type2 = f2->GetType();
102 
103  //--- use posix macros
104  if (R_ISDIR(type1)) type1 = 1;
105  else type1 = 6;
106 
107  if (R_ISDIR(type2)) type2 = 1;
108  else type2 = 6;
109 
110  if (type1 < type2) return -1;
111  if (type1 > type2) return 1;
112  return strcmp(f1->GetItemName()->GetString(),
113  f2->GetItemName()->GetString());
114 
115  case kSortByOwner:
116  if (f1->GetUid() != f2->GetUid()) {
117  if (f1->GetUid() < f2->GetUid())
118  return -1;
119  else
120  return +1;
121  }
122 
123  // else sort by name
124  type1 = f1->GetType();
125  type2 = f2->GetType();
126 
127  //--- use posix macros
128  if (R_ISDIR(type1)) type1 = 1;
129  else type1 = 6;
130 
131  if (R_ISDIR(type2)) type2 = 1;
132  else type2 = 6;
133 
134  if (type1 < type2) return -1;
135  if (type1 > type2) return 1;
136  return strcmp(f1->GetItemName()->GetString(),
137  f2->GetItemName()->GetString());
138 
139  case kSortByGroup:
140  if (f1->GetGid() != f2->GetGid()) {
141  if (f1->GetGid() < f2->GetGid())
142  return -1;
143  else
144  return +1;
145  }
146 
147  // else sort by name
148  type1 = f1->GetType();
149  type2 = f2->GetType();
150 
151  //--- use posix macros
152  if (R_ISDIR(type1)) type1 = 1;
153  else type1 = 6;
154 
155  if (R_ISDIR(type2)) type2 = 1;
156  else type2 = 6;
157 
158  if (type1 < type2) return -1;
159  if (type1 > type2) return 1;
160  return strcmp(f1->GetItemName()->GetString(),
161  f2->GetItemName()->GetString());
162 
163  case kSortByType:
164  //--- this is not exactly what I want...
165 
166  type1 = f1->GetType();
167  type2 = f2->GetType();
168 
169  //--- use posix macros
170 
171  if (R_ISDIR(type1)) type1 = 1;
172  else if (R_ISLNK(type1)) type1 = 2;
173  else if (R_ISSOCK(type1)) type1 = 3;
174  else if (R_ISFIFO(type1)) type1 = 4;
175  else if (R_ISREG(type1) && (type1 & kS_IXUSR)) type1 = 5;
176  else type1 = 6;
177 
178  if (R_ISDIR(type2)) type2 = 1;
179  else if (R_ISLNK(type2)) type2 = 2;
180  else if (R_ISSOCK(type2)) type2 = 3;
181  else if (R_ISFIFO(type2)) type2 = 4;
182  else if (R_ISREG(type2) && (type2 & kS_IXUSR)) type2 = 5;
183  else type2 = 6;
184 
185  if (type1 < type2) return -1;
186  if (type1 > type2) return 1;
187  return strcmp(f1->GetItemName()->GetString(),
188  f2->GetItemName()->GetString());
189 
190  case kSortBySize:
191  if (f1->GetSize() < f2->GetSize()) return -1;
192  if (f1->GetSize() > f2->GetSize()) return 1;
193  return strcmp(f1->GetItemName()->GetString(),
194  f2->GetItemName()->GetString());
195 
196  case kSortByDate:
197  time_t loctimeF1 = (time_t) f1->GetModTime();
198  // coverity[returned_null]
199  struct tm tmF1 = *localtime(&loctimeF1);
200 
201  time_t loctimeF2 = (time_t) f2->GetModTime();
202  // coverity[returned_null]
203  struct tm tmF2 = *localtime(&loctimeF2);
204 
205  if ( tmF1.tm_year != tmF2.tm_year )
206  return (tmF1.tm_year < tmF2.tm_year) ? +1 : -1;
207  else if ( tmF1.tm_mon != tmF2.tm_mon )
208  return (tmF1.tm_mon < tmF2.tm_mon) ? +1 : -1;
209  else if ( tmF1.tm_mday != tmF2.tm_mday )
210  return (tmF1.tm_mday < tmF2.tm_mday) ? +1 : -1;
211  else if ( tmF1.tm_hour != tmF2.tm_hour )
212  return (tmF1.tm_hour < tmF2.tm_hour) ? +1 : -1;
213  else if ( tmF1.tm_min != tmF2.tm_min )
214  return (tmF1.tm_min < tmF2.tm_min) ? +1 : -1;
215  else if ( tmF1.tm_sec != tmF2.tm_sec )
216  return (tmF1.tm_sec < tmF2.tm_sec) ? +1 : -1;
217  else
218  return 0;
219  }
220 }
221 
222 
223 ////////////////////////////////////////////////////////////////////////////////
224 /// Reset the timer.
225 
226 Bool_t TViewUpdateTimer::Notify()
227 {
228  fContainer->HandleTimer(0);
229  Reset();
230  return kFALSE;
231 }
232 
233 
234 ////////////////////////////////////////////////////////////////////////////////
235 /// Draw icon.
236 
237 void TGFileIcon::DoRedraw()
238 {
239  TGIcon::DoRedraw();
240  if (fLpic) fLpic->Draw(fId, GetBckgndGC()(), 0, 0);
241 }
242 
243 
244 ////////////////////////////////////////////////////////////////////////////////
245 /// Create a list view item.
246 
247 TGFileItem::TGFileItem(const TGWindow *p,
248  const TGPicture *bpic, const TGPicture *blpic,
249  const TGPicture *spic, const TGPicture *slpic,
250  TGString *name, Int_t type, Long64_t size, Int_t uid,
251  Int_t gid, Long_t modtime, EListViewMode viewMode,
252  UInt_t options, ULong_t back) :
253  TGLVEntry(p, bpic, spic, name, 0, viewMode, options, back)
254 {
255  FileStat_t buf;
256 
257  buf.fMode = type;
258  buf.fSize = size;
259  buf.fUid = uid;
260  buf.fGid = gid;
261  buf.fMtime = modtime;
262  buf.fIsLink = (blpic != 0); // FIXME: hack...
263 
264  Init(blpic, slpic, buf, viewMode);
265 }
266 
267 ////////////////////////////////////////////////////////////////////////////////
268 /// Create a list view item.
269 
270 TGFileItem::TGFileItem(const TGWindow *p,
271  const TGPicture *bpic, const TGPicture *blpic,
272  const TGPicture *spic, const TGPicture *slpic,
273  TGString *name, FileStat_t &stat, EListViewMode viewMode,
274  UInt_t options, ULong_t back) :
275  TGLVEntry(p, bpic, spic, name, 0, viewMode, options, back)
276 {
277  Init(blpic, slpic, stat, viewMode);
278 }
279 
280 ////////////////////////////////////////////////////////////////////////////////
281 /// Common initializer for file list view item.
282 
283 void TGFileItem::Init(const TGPicture *blpic, const TGPicture *slpic,
284  FileStat_t &stat, EListViewMode viewMode)
285 {
286  char tmp[256];
287  Long64_t fsize, bsize;
288 
289  fBuf = 0;
290  fDNDData.fData = 0;
291  fDNDData.fDataLength = 0;
292  fDNDData.fDataType = 0;
293  fLcurrent =
294  fBlpic = blpic;
295  fSlpic = slpic;
296 
297  fViewMode = (EListViewMode) -1;
298  SetViewMode(viewMode);
299 
300  fType = stat.fMode;
301  fSize = stat.fSize;
302  fUid = stat.fUid;
303  fGid = stat.fGid;
304  fModTime = stat.fMtime;
305  fIsLink = stat.fIsLink;
306 
307  fSubnames = new TGString* [6];
308 
309  // file type
310  snprintf(tmp, sizeof(tmp), "%c%c%c%c%c%c%c%c%c%c",
311  (fIsLink ?
312  'l' :
313  R_ISREG(fType) ?
314  '-' :
315  (R_ISDIR(fType) ?
316  'd' :
317  (R_ISCHR(fType) ?
318  'c' :
319  (R_ISBLK(fType) ?
320  'b' :
321  (R_ISFIFO(fType) ?
322  'p' :
323  (R_ISSOCK(fType) ?
324  's' : '?' )))))),
325  ((fType & kS_IRUSR) ? 'r' : '-'),
326  ((fType & kS_IWUSR) ? 'w' : '-'),
327  ((fType & kS_ISUID) ? 's' : ((fType & kS_IXUSR) ? 'x' : '-')),
328  ((fType & kS_IRGRP) ? 'r' : '-'),
329  ((fType & kS_IWGRP) ? 'w' : '-'),
330  ((fType & kS_ISGID) ? 's' : ((fType & kS_IXGRP) ? 'x' : '-')),
331  ((fType & kS_IROTH) ? 'r' : '-'),
332  ((fType & kS_IWOTH) ? 'w' : '-'),
333  ((fType & kS_ISVTX) ? 't' : ((fType & kS_IXOTH) ? 'x' : '-')));
334  fSubnames[0] = new TGString(tmp);
335 
336  // file size
337  fsize = bsize = fSize;
338  if (fsize > 1024) {
339  fsize /= 1024;
340  if (fsize > 1024) {
341  // 3.7MB is more informative than just 3MB
342  snprintf(tmp, sizeof(tmp), "%lld.%lldM", fsize/1024, (fsize%1024)/103);
343  } else {
344  snprintf(tmp, sizeof(tmp), "%lld.%lldK", bsize/1024, (bsize%1024)/103);
345  }
346  } else {
347  snprintf(tmp, sizeof(tmp), "%lld", bsize);
348  }
349  fSubnames[1] = new TGString(tmp);
350 
351  {
352  struct UserGroup_t *user_group;
353 
354  user_group = gSystem->GetUserInfo(fUid);
355  if (user_group) {
356  fSubnames[2] = new TGString(user_group->fUser);
357  fSubnames[3] = new TGString(user_group->fGroup);
358  delete user_group;
359  } else {
360  fSubnames[2] = new TGString(TString::Format("%d", fUid));
361  fSubnames[3] = new TGString(TString::Format("%d", fGid));
362  }
363  }
364 
365  struct tm *newtime;
366  time_t loctime = (time_t) fModTime;
367  newtime = localtime(&loctime);
368  if (newtime) {
369  snprintf(tmp, sizeof(tmp), "%d-%02d-%02d %02d:%02d", newtime->tm_year + 1900,
370  newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour,
371  newtime->tm_min);
372  fSubnames[4] = new TGString(tmp);
373  }
374  else
375  fSubnames[4] = new TGString("1901-01-01 00:00");
376 
377  fSubnames[5] = 0;
378 
379  int i;
380  for (i = 0; fSubnames[i] != 0; ++i)
381  ;
382  fCtw = new int[i+1];
383  fCtw[i] = 0;
384  for (i = 0; fSubnames[i] != 0; ++i)
385  fCtw[i] = gVirtualX->TextWidth(fFontStruct, fSubnames[i]->GetString(),
386  fSubnames[i]->GetLength());
387 
388  SetWindowName();
389 }
390 
391 ////////////////////////////////////////////////////////////////////////////////
392 /// Destructor.
393 
394 TGFileItem::~TGFileItem()
395 {
396  delete fBuf;
397 }
398 
399 ////////////////////////////////////////////////////////////////////////////////
400 /// Set container item view mode.
401 
402 void TGFileItem::SetViewMode(EListViewMode viewMode)
403 {
404  TGLVEntry::SetViewMode(viewMode);
405 
406  if (viewMode == kLVLargeIcons)
407  fLcurrent = fBlpic;
408  else
409  fLcurrent = fSlpic;
410 
411  if (fClient) fClient->NeedRedraw(this);
412 }
413 
414 ////////////////////////////////////////////////////////////////////////////////
415 /// Draw list view container item.
416 
417 void TGFileItem::DoRedraw()
418 {
419  int ix, iy;
420 
421  TGLVEntry::DoRedraw();
422  if (!fLcurrent) return;
423 
424  if (fViewMode == kLVLargeIcons) {
425  ix = (fWidth - fLcurrent->GetWidth()) >> 1;
426  iy = 0;
427  } else {
428  ix = 0;
429  iy = (fHeight - fLcurrent->GetHeight()) >> 1;
430  }
431 
432  fLcurrent->Draw(fId, fNormGC, ix, iy);
433 }
434 
435 
436 ////////////////////////////////////////////////////////////////////////////////
437 /// Create a list view container which will hold the contents of
438 /// the current directory.
439 
440 TGFileContainer::TGFileContainer(const TGWindow *p, UInt_t w, UInt_t h,
441  UInt_t options, ULong_t back) :
442  TGLVContainer(p, w, h, options, back)
443 {
444  fSortType = kSortByName;
445  fFilter = 0;
446  fMtime = 0;
447  fDirectory = gSystem->WorkingDirectory();
448  fRefresh = new TViewUpdateTimer(this, 1000);
449  gSystem->AddTimer(fRefresh);
450  fCachePictures = kTRUE;
451  fDisplayStat = kTRUE;
452  fCleanups = new TList;
453 
454  fFolder_s = fClient->GetPicture("folder_s.xpm");
455  fFolder_t = fClient->GetPicture("folder_t.xpm");
456  fApp_s = fClient->GetPicture("app_s.xpm");
457  fApp_t = fClient->GetPicture("app_t.xpm");
458  fDoc_s = fClient->GetPicture("doc_s.xpm");
459  fDoc_t = fClient->GetPicture("doc_t.xpm");
460  fSlink_s = fClient->GetPicture("slink_s.xpm");
461  fSlink_t = fClient->GetPicture("slink_t.xpm");
462 
463  if (!fFolder_s || !fFolder_t ||
464  !fApp_s || !fApp_t ||
465  !fDoc_s || !fDoc_t ||
466  !fSlink_s || !fSlink_t)
467  Error("TGFileContainer", "required pixmap(s) missing\n");
468 
469  SetWindowName();
470 }
471 
472 ////////////////////////////////////////////////////////////////////////////////
473 /// Create a list view container which will hold the contents of
474 /// the current directory.
475 
476 TGFileContainer::TGFileContainer(TGCanvas *p, UInt_t options, ULong_t back) :
477  TGLVContainer(p,options, back)
478 {
479  fSortType = kSortByName;
480  fFilter = 0;
481  fMtime = 0;
482  fDirectory = gSystem->WorkingDirectory();
483  fRefresh = new TViewUpdateTimer(this, 1000);
484  gSystem->AddTimer(fRefresh);
485  fCachePictures = kTRUE;
486  fDisplayStat = kTRUE;
487  fCleanups = new TList;
488 
489  fFolder_s = fClient->GetPicture("folder_s.xpm");
490  fFolder_t = fClient->GetPicture("folder_t.xpm");
491  fApp_s = fClient->GetPicture("app_s.xpm");
492  fApp_t = fClient->GetPicture("app_t.xpm");
493  fDoc_s = fClient->GetPicture("doc_s.xpm");
494  fDoc_t = fClient->GetPicture("doc_t.xpm");
495  fSlink_s = fClient->GetPicture("slink_s.xpm");
496  fSlink_t = fClient->GetPicture("slink_t.xpm");
497 
498  if (!fFolder_s || !fFolder_t ||
499  !fApp_s || !fApp_t ||
500  !fDoc_s || !fDoc_t ||
501  !fSlink_s || !fSlink_t)
502  Error("TGFileContainer", "required pixmap(s) missing\n");
503 
504  SetWindowName();
505 }
506 
507 ////////////////////////////////////////////////////////////////////////////////
508 /// Delete list view file container.
509 
510 TGFileContainer::~TGFileContainer()
511 {
512  if (fRefresh) delete fRefresh;
513  if (fFilter) delete fFilter;
514  fClient->FreePicture(fFolder_s);
515  fClient->FreePicture(fFolder_t);
516  fClient->FreePicture(fApp_s);
517  fClient->FreePicture(fApp_t);
518  fClient->FreePicture(fDoc_s);
519  fClient->FreePicture(fDoc_t);
520  fClient->FreePicture(fSlink_s);
521  fClient->FreePicture(fSlink_t);
522  if (fCleanups) {
523  TGPicture *pic;
524  TIter nextp(fCleanups);
525  while ((pic = (TGPicture *)nextp())) {
526  fClient->GetPicturePool()->FreePicture(pic);
527  }
528  fCleanups->Clear();
529  delete fCleanups;
530  }
531 }
532 
533 ////////////////////////////////////////////////////////////////////////////////
534 /// Add frame to the composite frame.
535 
536 void TGFileContainer::AddFrame(TGFrame *f, TGLayoutHints *l)
537 {
538  TGFSFrameElement *nw;
539 
540  nw = new TGFSFrameElement;
541  nw->fFrame = f;
542  nw->fLayout = l ? l : fgDefaultHints;
543  nw->fState = 1;
544  nw->fContainer = this;
545  fList->Add(nw);
546 }
547 
548 ////////////////////////////////////////////////////////////////////////////////
549 /// Refresh container contents. Check every 5 seconds to see if the
550 /// directory modification date has changed.
551 
552 Bool_t TGFileContainer::HandleTimer(TTimer *)
553 {
554  FileStat_t sbuf;
555 
556  if (gSystem->GetPathInfo(fDirectory, sbuf) == 0)
557  if (fMtime != (ULong_t)sbuf.fMtime) DisplayDirectory();
558 
559  return kTRUE;
560 }
561 
562 ////////////////////////////////////////////////////////////////////////////////
563 /// Set file selection filter.
564 
565 void TGFileContainer::SetFilter(const char *filter)
566 {
567  if (fFilter) delete fFilter;
568  fFilter = new TRegexp(filter, kTRUE);
569 }
570 
571 ////////////////////////////////////////////////////////////////////////////////
572 /// Sort file system list view container according to sortType.
573 
574 void TGFileContainer::Sort(EFSSortMode sortType)
575 {
576  fSortType = sortType;
577 
578  fList->Sort();
579 
580  TGCanvas *canvas = (TGCanvas *) this->GetParent()->GetParent();
581  canvas->Layout();
582 }
583 
584 ////////////////////////////////////////////////////////////////////////////////
585 /// Determine the file picture for the given file type.
586 
587 void TGFileContainer::GetFilePictures(const TGPicture **pic,
588  const TGPicture **lpic, Int_t file_type, Bool_t is_link,
589  const char *name, Bool_t /*small*/)
590 {
591  static TString cached_ext;
592  static const TGPicture *cached_spic = 0;
593  static const TGPicture *cached_lpic = 0;
594  const char *ext = name ? strrchr(name, '.') : 0;
595  *pic = 0;
596  *lpic = 0;
597 
598  if (fCachePictures && ext && cached_spic && cached_lpic && (cached_ext == ext)) {
599  *pic = cached_spic;
600  *lpic = cached_lpic;
601  if (!is_link) return;
602  }
603 
604  if (R_ISREG(file_type)) {
605  TString fname(name);
606  if (is_link && fname.EndsWith(".lnk")) {
607  fname.Remove(fname.Length()-4);
608  }
609  *pic = fClient->GetMimeTypeList()->GetIcon(fname.Data(), kTRUE);
610  *lpic = fClient->GetMimeTypeList()->GetIcon(fname.Data(), kFALSE);
611 
612  if (*pic) {
613  if (!*lpic) *lpic = *pic;
614  if (ext) {
615  cached_ext = ext;
616  cached_spic = *pic;
617  cached_lpic = *lpic;
618  if (!is_link) return;
619  }
620  }
621  } else {
622  *pic = 0;
623  }
624 
625  if (*pic == 0) {
626  *pic = fDoc_t;
627  *lpic = fDoc_s;
628 
629  if (R_ISREG(file_type) && (file_type) & kS_IXUSR) {
630  *pic = fApp_t;
631  *lpic = fApp_s;
632  }
633  if (R_ISDIR(file_type)) {
634  *pic = fFolder_t;
635  *lpic = fFolder_s;
636  }
637  }
638  if (is_link) {
639  TImage *img1, *img2;
640  if (*pic && *lpic) {
641  TString lnk_name;
642  img1 = TImage::Create();
643  if (img1) {
644  img1->SetImage(((const TGPicture *)*pic)->GetPicture(),
645  ((const TGPicture *)*pic)->GetMask());
646  img2 = TImage::Open("slink_t.xpm");
647  if (img2) img1->Merge(img2);
648  lnk_name = ((const TGPicture *)*pic)->GetName();
649  lnk_name.Prepend("lnk_");
650  *pic = fClient->GetPicturePool()->GetPicture(lnk_name.Data(),
651  img1->GetPixmap(), img1->GetMask());
652  fCleanups->Add(((TObject *)*pic));
653  if (img2) delete img2;
654  delete img1;
655  }
656  img1 = TImage::Create();
657  if (img1) {
658  img1->SetImage(((const TGPicture *)*lpic)->GetPicture(),
659  ((const TGPicture *)*lpic)->GetMask());
660  img2 = TImage::Open("slink_s.xpm");
661  if (img2) img1->Merge(img2);
662  lnk_name = ((const TGPicture *)*lpic)->GetName();
663  lnk_name.Prepend("lnk_");
664  *lpic = fClient->GetPicturePool()->GetPicture(lnk_name.Data(),
665  img1->GetPixmap(), img1->GetMask());
666  fCleanups->Add(((TObject *)*lpic));
667  if (img2) delete img2;
668  delete img1;
669  }
670  }
671  else {
672  *pic = fSlink_t;
673  *lpic = fSlink_s;
674  }
675  }
676 
677  cached_lpic = 0;
678  cached_spic = 0;
679  cached_ext = "";
680 }
681 
682 ////////////////////////////////////////////////////////////////////////////////
683 /// Change current directory.
684 
685 void TGFileContainer::ChangeDirectory(const char *path)
686 {
687  TString savdir = gSystem->WorkingDirectory();
688  gSystem->ChangeDirectory(fDirectory.Data()); // so path of ".." will work
689  char *exppath = gSystem->ExpandPathName(path);
690  if (gSystem->ChangeDirectory(exppath)) {
691  fDirectory = gSystem->WorkingDirectory();
692  gSystem->ChangeDirectory(savdir.Data());
693  DisplayDirectory();
694  }
695  delete[] exppath;
696 }
697 
698 ////////////////////////////////////////////////////////////////////////////////
699 /// Display the contents of the current directory in the container.
700 /// This can be used to refresh the contents of the window.
701 
702 void TGFileContainer::DisplayDirectory()
703 {
704  RemoveAll();
705  CreateFileList();
706 
707  // This automatically calls layout
708  Sort(fSortType);
709 
710  // Make TGExplorerMainFrame display total objects in status bar
711  SendMessage(fMsgWindow, MK_MSG(kC_CONTAINER, kCT_SELCHANGED),
712  fTotal, fSelected);
713 
714  MapSubwindows();
715 }
716 
717 ////////////////////////////////////////////////////////////////////////////////
718 /// This function creates the file list from current dir.
719 
720 void TGFileContainer::CreateFileList()
721 {
722  TString savdir = gSystem->WorkingDirectory();
723  if (!gSystem->ChangeDirectory(fDirectory.Data())) return;
724 
725  FileStat_t sbuf;
726  if (gSystem->GetPathInfo(".", sbuf) == 0)
727  fMtime = sbuf.fMtime;
728 
729  void *dirp;
730  if ((dirp = gSystem->OpenDirectory(".")) == 0) {
731  gSystem->ChangeDirectory(savdir.Data());
732  return;
733  }
734 
735  const char *name;
736  while ((name = gSystem->GetDirEntry(dirp)) != 0 && fDisplayStat) {
737  if (strcmp(name, ".") && strcmp(name, ".."))
738  AddFile(name);
739  gSystem->ProcessEvents();
740  }
741  gSystem->FreeDirectory(dirp);
742 
743  gSystem->ChangeDirectory(savdir.Data());
744 }
745 
746 ////////////////////////////////////////////////////////////////////////////////
747 /// Add file in container.
748 
749 TGFileItem *TGFileContainer::AddFile(const char *name, const TGPicture *ipic,
750  const TGPicture *ilpic)
751 {
752  TString filename;
753  TGFileItem *item = 0;
754  const TGPicture *spic, *slpic;
755  TGPicture *pic, *lpic;
756 
757  FileStat_t sbuf;
758 
759  if (gSystem->GetPathInfo(name, sbuf)) {
760  if (sbuf.fIsLink) {
761  Info("AddFile", "Broken symlink of %s.", name);
762  } else {
763  TString msg;
764  msg.Form("Can't read file attributes of \"%s\": %s.",
765  name, gSystem->GetError());
766  new TGMsgBox(fClient->GetDefaultRoot(), GetMainFrame(),
767  "Error", msg.Data(), kMBIconStop, kMBOk);
768  }
769  return item;
770  }
771 
772  filename = name;
773  if (R_ISDIR(sbuf.fMode) || fFilter == 0 ||
774  (fFilter && filename.Index(*fFilter) != kNPOS)) {
775 
776  if (ipic && ilpic) { // dynamic icons
777  spic = ipic;
778  slpic = ilpic;
779  } else {
780  GetFilePictures(&spic, &slpic, sbuf.fMode, sbuf.fIsLink, name, kTRUE);
781  }
782 
783  pic = (TGPicture*)spic; pic->AddReference();
784  lpic = (TGPicture*)slpic; lpic->AddReference();
785 
786  item = new TGFileItem(this, lpic, slpic, spic, pic,
787  new TGString(gSystem->BaseName(name)),
788  sbuf, fViewMode);
789  AddItem(item);
790  }
791 
792  return item;
793 }
794 
795 ////////////////////////////////////////////////////////////////////////////////
796 /// Add remote file in container.
797 
798 TGFileItem *TGFileContainer::AddRemoteFile(TObject *obj, const TGPicture *ipic,
799  const TGPicture *ilpic)
800 {
801  TString filename;
802  TGFileItem *item = 0;
803  const TGPicture *spic, *slpic;
804  TGPicture *pic, *lpic;
805 
806  FileStat_t sbuf;
807 
808  TRemoteObject *robj = (TRemoteObject *)obj;
809 
810  robj->GetFileStat(&sbuf);
811  filename = robj->GetName();
812 
813  if (R_ISDIR(sbuf.fMode) || fFilter == 0 ||
814  (fFilter && filename.Index(*fFilter) != kNPOS)) {
815 
816  if (ipic && ilpic) { // dynamic icons
817  spic = ipic;
818  slpic = ilpic;
819  } else {
820  GetFilePictures(&spic, &slpic, sbuf.fMode, sbuf.fIsLink, filename, kTRUE);
821  }
822 
823  pic = (TGPicture*)spic; pic->AddReference();
824  lpic = (TGPicture*)slpic; lpic->AddReference();
825 
826  item = new TGFileItem(this, lpic, slpic, spic, pic, new TGString(filename),
827  sbuf, fViewMode);
828  AddItem(item);
829  }
830  return item;
831 }
832 
833 ////////////////////////////////////////////////////////////////////////////////
834 /// stop refresh timer
835 
836 void TGFileContainer::StopRefreshTimer()
837 {
838  if (fRefresh) delete fRefresh;
839  fRefresh = 0;
840 }
841 
842 ////////////////////////////////////////////////////////////////////////////////
843 /// start refreshing
844 
845 void TGFileContainer::StartRefreshTimer(ULong_t msec)
846 {
847  fRefresh = new TViewUpdateTimer(this, msec);
848  gSystem->AddTimer(fRefresh);
849 }
850 
851 ////////////////////////////////////////////////////////////////////////////////
852 /// Save a file container widget as a C++ statement(s) on output stream out.
853 
854 void TGFileContainer::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
855 {
856  if (fBackground != GetDefaultFrameBackground()) SaveUserColor(out, option);
857 
858  char quote = '"';
859  out << std::endl << " // container frame" << std::endl;
860  out << " TGFileContainer *";
861 
862  if ((fParent->GetParent())->InheritsFrom(TGCanvas::Class())) {
863  out << GetName() << " = new TGFileContainer(" << GetCanvas()->GetName();
864  } else {
865  out << GetName() << " = new TGFileContainer(" << fParent->GetName();
866  out << "," << GetWidth() << "," << GetHeight();
867  }
868 
869  if (fBackground == GetDefaultFrameBackground()) {
870  if (GetOptions() == kSunkenFrame) {
871  out <<");" << std::endl;
872  } else {
873  out << "," << GetOptionString() <<");" << std::endl;
874  }
875  } else {
876  out << "," << GetOptionString() << ",ucolor);" << std::endl;
877  }
878  if (option && strstr(option, "keep_names"))
879  out << " " << GetName() << "->SetName(\"" << GetName() << "\");" << std::endl;
880  out << " " << GetCanvas()->GetName() << "->SetContainer("
881  << GetName() << ");" << std::endl;
882  out << " " << GetName() << "->DisplayDirectory();" << std::endl;
883  out << " " << GetName() << "->AddFile("<< quote << ".." << quote << ");" << std::endl;
884  out << " " << GetName() << "->StopRefreshTimer();" << std::endl;
885 }