#include "TRootContextMenu.h"
#include "TROOT.h"
#include "TGClient.h"
#include "TList.h"
#include "TContextMenu.h"
#include "TMethod.h"
#include "TMethodArg.h"
#include "TClass.h"
#include "TVirtualX.h"
#include "TCanvas.h"
#include "TDataMember.h"
#include "TToggle.h"
#include "TRootDialog.h"
#include "TDataType.h"
#include "TCanvas.h"
#include "TBrowser.h"
#include "TRootCanvas.h"
#include "TRootBrowser.h"
#include "TClassMenuItem.h"
#include "TObjectSpy.h"
enum EContextMenu {
   kToggleStart       = 1000, 
   kToggleListStart   = 2000, 
   kUserFunctionStart = 3000  
};
ClassImp(TRootContextMenu)
TRootContextMenu::TRootContextMenu(TContextMenu *c, const char *)
    : TGPopupMenu(gClient->GetDefaultRoot()), TContextMenuImp(c)
{
   
   fDialog  = 0;
   fTrash = new TList;
   
   Associate(this);
}
TRootContextMenu::~TRootContextMenu()
{
   
   delete fDialog;
   if (fTrash) fTrash->Delete();
   delete fTrash;
}
void TRootContextMenu::DisplayPopup(Int_t x, Int_t y)
{
   
   if (fClient->IsEditable()) return;
   
   if (fEntryList) fEntryList->Delete();
   fCurrent = 0;
   if (fTrash)   fTrash->Delete();
   fMenuHeight = 6;
   fMenuWidth  = 8;
   
   if (fDialog) {
      delete fDialog;
      fDialog = 0;
   }
   
   CreateMenu(fContextMenu->GetSelectedObject());
   int    xx, yy, topx = 0, topy = 0;
   UInt_t w, h;
   if (fContextMenu->GetSelectedCanvas())
      gVirtualX->GetGeometry(fContextMenu->GetSelectedCanvas()->GetCanvasID(),
                        topx, topy, w, h);
   xx = topx + x + 1;
   yy = topy + y + 1;
   PlaceMenu(xx, yy, kFALSE, kTRUE);
}
TGPopupMenu * TRootContextMenu::FindHierarchy(const char *commentstring, TString & last_component)
{
  
  
  
   TString cmd(commentstring);
   TString option;
   TString hierarchy;
   TGPopupMenu *currentMenu = 0;
   
   
   Ssiz_t opt_ptr;
   if ((opt_ptr=cmd.Index("*MENU={"))   != kNPOS ||
       (opt_ptr=cmd.Index("*SUBMENU={"))!= kNPOS ||
       (opt_ptr=cmd.Index("*TOGGLE={")) != kNPOS ) {
      Ssiz_t start = cmd.Index("{",opt_ptr) + 1;
      Ssiz_t end = cmd.Index("}",start);
      option = cmd(start,end - start);
      
      TObjArray * array = option.Tokenize(";");
      TIter iter(array);
      TObject *obj;
      while((obj = iter())) {
         TString token(obj->GetName());
         if (token.Index("Hierarchy=\"") != kNPOS) {
            Ssiz_t tstart = token.Index("\"") + 1;
            Ssiz_t tend = token.Index("\"",tstart+1);
            if (tend == kNPOS) continue;
            hierarchy = token(tstart,tend - tstart);
         }				  
      }
      delete array;
   }
   
   currentMenu = this;
   TObjArray * array = hierarchy.Tokenize("/");
   TIter iter(array);
   TObject *obj = iter();
   while(obj) {
      last_component = obj->GetName();
      obj = iter();
      if (obj) {
         TGMenuEntry *ptr;
         TIter next(currentMenu->GetListOfEntries());
         
         while ((ptr = (TGMenuEntry *) next()) &&				    
                (ptr->GetType() != kMenuPopup || 
                last_component.CompareTo(ptr->GetName()))) { }
         if (ptr) 
            currentMenu = ptr->GetPopup();
         else {
            TGPopupMenu *r = new TGPopupMenu(gClient->GetDefaultRoot());
            
            TGMenuEntry *ptr2;
            TIter next2(currentMenu->GetListOfEntries());
            
            while ((ptr2 = (TGMenuEntry *) next2()) &&				    
                   (ptr2->GetType() != kMenuPopup  ||
                   last_component.CompareTo(ptr2->GetName()) > 0 )) { }
	
            currentMenu->AddPopup(last_component, r,ptr2);
            currentMenu = r;
            fTrash->Add(r);
            last_component = obj->GetName();
         }
      }
   }
  
   delete array;
   return currentMenu;
}
void TRootContextMenu::AddEntrySorted(TGPopupMenu *currentMenu, const char *s, Int_t id, void *ud,
                                         const TGPicture *p , Bool_t sorted)
{
   
   
   TGMenuEntry *ptr2 = 0;
   if (sorted) {
      TIter next(currentMenu->GetListOfEntries());
      
      while ((ptr2 = (TGMenuEntry *) next()) &&				    
             (ptr2->GetType() != kMenuEntry || 
             strcmp(ptr2->GetName(), s)<0 )) { }
   }
   currentMenu->AddEntry(s,id,ud,p,ptr2);
}
void TRootContextMenu::CreateMenu(TObject *object)
{
   
   if (fClient->IsEditable()) return;
   int entry = 0, toggle = kToggleStart, togglelist = kToggleListStart;
   int userfunction = kUserFunctionStart;
   
   AddLabel(fContextMenu->CreatePopupTitle(object));
   AddSeparator();
   
   TList *menuItemList = object->IsA()->GetMenuList();
   TClassMenuItem *menuItem;
   TIter nextItem(menuItemList);
   while ((menuItem = (TClassMenuItem*) nextItem())) {
      switch (menuItem->GetType()) {
         case TClassMenuItem::kPopupSeparator:
            {
            TGMenuEntry *last = (TGMenuEntry *)GetListOfEntries()->Last();
            if (last && last->GetType() != kMenuSeparator)
               AddSeparator();
            break;
            }
         case TClassMenuItem::kPopupStandardList:
            {
               
               
               
               TList *methodList = new TList;
               object->IsA()->GetMenuItems(methodList);
               TMethod *method;
               TClass  *classPtr = 0;
               TIter next(methodList);
               Bool_t needSep = kFALSE;
               while ((method = (TMethod*) next())) {
                  if (classPtr != method->GetClass()) {
                     needSep = kTRUE;
                     classPtr = method->GetClass();
                  }
                  TDataMember *m;
                  EMenuItemKind menuKind = method->IsMenuItem();
                  TGPopupMenu *currentMenu = 0;
                  TString last_component;
		  
                  switch (menuKind) {
                     case kMenuDialog:
                        
                        currentMenu = FindHierarchy(method->GetCommentString(),last_component);
                        if (needSep && currentMenu == this) {
                           AddSeparator();
                           needSep = kFALSE;
                        }
                        AddEntrySorted(currentMenu,last_component.Length() ? last_component.Data() : method->GetName(), entry++, method,0,currentMenu != this);
                        break;
                     case kMenuSubMenu:
                        if ((m = method->FindDataMember())) {
			  
                           
                           currentMenu = FindHierarchy(method->GetCommentString(),last_component);
                           if (m->GetterMethod()) {
                              TGPopupMenu *r = new TGPopupMenu(gClient->GetDefaultRoot());
                              if (needSep && currentMenu == this) {
                                 AddSeparator();
                                 needSep = kFALSE;
                              }
                              if (last_component.Length()) {
                                 currentMenu->AddPopup(last_component, r);
                              } else {
                                 currentMenu->AddPopup(method->GetName(), r);
                              }
                              fTrash->Add(r);
                              TIter nxt(m->GetOptions());
                              TOptionListItem *it;
                              while ((it = (TOptionListItem*) nxt())) {
                                 char *name = it->fOptName;
                                 Long_t val = it->fValue;
                                 TToggle *t = new TToggle;
                                 t->SetToggledObject(object, method);
                                 t->SetOnValue(val);
                                 fTrash->Add(t);
			      
                                 r->AddEntry(name, togglelist++, t);
                                 if (t->GetState()) 
                                    r->CheckEntry(togglelist-1);
                              }
                           } else {
                              if (needSep && currentMenu == this) {
                                 AddSeparator();
                                 needSep = kFALSE;
                              }
                              AddEntrySorted(currentMenu,last_component.Length() ? last_component.Data() : method->GetName(), entry++, method,0,currentMenu != this);
                           }
                        }
                        break;
                     case kMenuToggle:
                        {
                           TToggle *t = new TToggle;
                           t->SetToggledObject(object, method);
                           t->SetOnValue(1);
                           fTrash->Add(t);
                           
                           currentMenu = FindHierarchy(method->GetCommentString(),last_component);
                           if (needSep && currentMenu == this) {
                              AddSeparator();
                              needSep = kFALSE;
                           }
                           AddEntrySorted(currentMenu,last_component.Length() ? last_component.Data() : method->GetName(), toggle++, t,0,currentMenu != this);
                           if (t->GetState()) currentMenu->CheckEntry(toggle-1);
                        }
                        break;
                     default:
                        break;
                  }
               }
               delete methodList;
            }
            break;
         case TClassMenuItem::kPopupUserFunction:
            {
               if (menuItem->IsToggle()) {
                  if (object) {
                     TMethod* method =
                           object->IsA()->GetMethodWithPrototype(menuItem->GetFunctionName(),menuItem->GetArgs());
                     TToggle *t = new TToggle;
                     t->SetToggledObject(object, method);
                     t->SetOnValue(1);
                     fTrash->Add(t);
                     AddEntry(method->GetName(), toggle++, t);
                     if (t->GetState()) CheckEntry(toggle-1);
                  } else {
                     Warning("Dialog","Cannot use toggle for a global function");
                  }
               } else {
                  const char* menuItemTitle = menuItem->GetTitle();
                  if (strlen(menuItemTitle)==0) menuItemTitle = menuItem->GetFunctionName();
                  AddEntry(menuItemTitle,userfunction++,menuItem);
               }
            }
            break;
         default:
            break;
      }
   }
}
void TRootContextMenu::Dialog(TObject *object, TMethod *method)
{
   
   
   Dialog(object,(TFunction*)method);
}
void TRootContextMenu::Dialog(TObject *object, TFunction *function)
{
   
   
   
   Int_t selfobjpos;
   if (!function) return;
   
   if (fContextMenu->GetSelectedMenuItem())
      selfobjpos =  fContextMenu->GetSelectedMenuItem()->GetSelfObjectPos();
   else selfobjpos = -1;
   const TGWindow *w;
   if (fContextMenu->GetSelectedCanvas()) {
      TCanvas *c = (TCanvas *) fContextMenu->GetSelectedCanvas();
      
      if (c->GetCanvasImp()->IsA()->InheritsFrom(TGFrame::Class())) {
         w = fClient->GetWindowById(gVirtualX->GetWindowID(c->GetCanvasID()));
         if (!w) w = (TRootCanvas *) c->GetCanvasImp();
      } else {
         w = gClient->GetDefaultRoot();
      }
   } else if (fContextMenu->GetBrowser()) {
      TBrowser *b = (TBrowser *) fContextMenu->GetBrowser();
      w = (TRootBrowser *) b->GetBrowserImp();
   } else {
      w = gClient->GetDefaultRoot();
   }
   fDialog = new TRootDialog(this, w, fContextMenu->CreateDialogTitle(object, function));
   
   
   TMethodArg *argument = 0;
   TIter next(function->GetListOfMethodArgs());
   Int_t argpos = 0;
   while ((argument = (TMethodArg *) next())) {
      
      if (selfobjpos != argpos) {
         Text_t       *argname    = fContextMenu->CreateArgumentTitle(argument);
         const Text_t *type       = argument->GetTypeName();
         TDataType    *datatype   = gROOT->GetType(type);
         const Text_t *charstar   = "char*";
         Text_t        basictype[32];
         if (datatype) {
            strcpy(basictype, datatype->GetTypeName());
         } else {
            TClass *cl = TClass::GetClass(type);
            if (strncmp(type, "enum", 4) && (cl && !(cl->Property() & kIsEnum)))
               Warning("Dialog", "data type is not basic type, assuming (int)");
            strcpy(basictype, "int");
         }
         if (strchr(argname, '*')) {
            strcat(basictype, "*");
            if (!strncmp(type, "char", 4)) 
               type = charstar;
         }
         
         TDataMember *m = argument->GetDataMember();
         if (m && m->GetterMethod(object->IsA())) {
            
            Text_t val[256];
            if (!strncmp(basictype, "char*", 5)) {
               Text_t *tdefval;
               m->GetterMethod()->Execute(object, "", &tdefval);
               strncpy(val, tdefval, 255);
            } else if (!strncmp(basictype, "float", 5) ||
                       !strncmp(basictype, "double", 6)) {
               Double_t ddefval;
               m->GetterMethod()->Execute(object, "", ddefval);
               sprintf(val, "%g", ddefval);
            } else if (!strncmp(basictype, "char", 4) ||
                       !strncmp(basictype, "bool", 4) ||
                       !strncmp(basictype, "int", 3)  ||
                       !strncmp(basictype, "long", 4) ||
                       !strncmp(basictype, "short", 5)) {
               Long_t ldefval;
               m->GetterMethod()->Execute(object, "", ldefval);
               sprintf(val, "%li", ldefval);
            }
            
            TList *opt;
            if ((opt = m->GetOptions())) {
               Warning("Dialog", "option menu not yet implemented", opt);
#if 0
               TMotifOptionMenu *o= new TMotifOptionMenu(argname);
               TIter nextopt(opt);
               TOptionListItem *it = 0;
               while ((it = (TOptionListItem*) nextopt())) {
                  Text_t *name  = it->fOptName;
                  Text_t *label = it->fOptLabel;
                  Long_t value  = it->fValue;
                  if (value != -9999) {
                     Text_t val[256];
                     sprintf(val, "%li", value);
                     o->AddItem(name, val);
                  }else
                     o->AddItem(name, label);
               }
               o->SetData(val);
               fDialog->Add(o);
#endif
            } else {
               
               fDialog->Add(argname, val, type);
            }
         } else {    
            char val[256] = "";
            const char *tval = argument->GetDefault();
            if (tval && strlen(tval)) {
               
               strncpy(val, tval + (tval[0] == '"' ? 1 : 0), 255);
               if (val[strlen(val)-1] == '"')		
                  val[strlen(val)-1]= 0;
            }
            fDialog->Add(argname, val, type);
         }
      }
      argpos++;
   }
   fDialog->Popup();
}
Bool_t TRootContextMenu::ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2)
{
   
   
   TObjectSpy savedPad;
   if (GetContextMenu()->GetSelectedPad()) {
      savedPad.SetObject(gPad);
      gPad = GetContextMenu()->GetSelectedPad();
   }
   switch (GET_MSG(msg)) {
      case kC_COMMAND:
         switch (GET_SUBMSG(msg)) {
            case kCM_MENU:
   
               if (parm1 < kToggleStart) {
                  TMethod *m = (TMethod *) parm2;
                  GetContextMenu()->Action(m);
               } else if (parm1 >= kToggleStart && parm1 < kToggleListStart) {
                  TToggle *t = (TToggle *) parm2;
                  GetContextMenu()->Action(t);
               } else if (parm1 >= kToggleListStart && parm1<kUserFunctionStart) {
                  TToggle *t = (TToggle *) parm2;
                  if (t->GetState() == 0)
                     t->SetState(1);
               } else {
                  TClassMenuItem *mi = (TClassMenuItem*)parm2;
                  GetContextMenu()->Action(mi);
               }
               break;
            case kCM_BUTTON:
               if (parm1 == 1) {
                  const char *args = fDialog->GetParameters();
                  GetContextMenu()->Execute((char *)args);
                  delete fDialog;
                  fDialog = 0;
               }
               if (parm1 == 2) {
                  const char *args = fDialog->GetParameters();
                  GetContextMenu()->Execute((char *)args);
               }
               if (parm1 == 3) {
                  delete fDialog;
                  fDialog = 0;
               }
               break;
            default:
               break;
         }
         break;
      case kC_TEXTENTRY:
         switch (GET_SUBMSG(msg)) {
            case kTE_ENTER:
               {
                  const char *args = fDialog->GetParameters();
                  GetContextMenu()->Execute((char *)args);
                  delete fDialog;
                  fDialog = 0;
               }
               break;
            default:
               break;
         }
         break;
      default:
         break;
   }
   if (savedPad.GetObject()) gPad = (TVirtualPad*) savedPad.GetObject();
   return kTRUE;
}
Last change: Wed Jun 25 08:52:20 2008
Last generated: 2008-06-25 08:52
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.