drag_and_drop.C

Go to the documentation of this file.
00001 // This tutorial illustrates how to use drag and drop within ROOT.
00002 // Select a list tree item with a mouse press, drag it (move the mouse
00003 // while keeping the mouse button pressed) and release the mouse button
00004 // in any pad inside the canvas or in the top list tree item ("Base").
00005 // When the button is released the selected data is \"dropped\" at that
00006 // location, displaying the object in the canvas or adding (copying) it
00007 // in the list tree
00008 // Author: Bertrand Bellenot
00009 
00010 #include "TROOT.h"
00011 #include "TApplication.h"
00012 #include "TSystem.h"
00013 #include "TGFrame.h"
00014 #include "TGButton.h"
00015 #include "TGLabel.h"
00016 #include "TGMenu.h"
00017 #include "TGFileDialog.h"
00018 #include "TBrowser.h"
00019 #include "TRootEmbeddedCanvas.h"
00020 #include "TRootHelpDialog.h"
00021 #include "TCanvas.h"
00022 #include "TH1F.h"
00023 #include "TH2F.h"
00024 #include "TF2.h"
00025 #include "TGraph.h"
00026 #include "TImage.h"
00027 #include "TRandom.h"
00028 #include "TGMsgBox.h"
00029 #include "TGPicture.h"
00030 #include "TGListTree.h"
00031 #include "TObjString.h"
00032 #include "TMessage.h"
00033 #include "TTimer.h"
00034 #include "TGDNDManager.h"
00035 #include <cmath>
00036 
00037 const char gHelpDND[] = "\
00038                      Drag & Drop (DnD)\n\
00039 Drag and Drop support is implemented on Linux via Xdnd, the\n\
00040 drag and drop protocol for X window system, and on Windows\n\
00041 via the Clipboard.\n\
00042 Users can selects something in ROOT with a mouse press, drags\n\
00043 it (moves the mouse while keeping the mouse button pressed) and\n\
00044 releases the mouse button somewhere else. When the button is\n\
00045 released the selected data is \"dropped\" at that location. This\n\
00046 way, a histogram from an opened ROOT file in the browser can be\n\
00047 dragged to any TCanvas. A script file from the browser can be\n\
00048 dropped to a TGTextView or TGTextEdit widget in TGTextEditor.\n\
00049 On Linux, it is possible to drag objects between ROOT and an\n\
00050 external application. For example to drag a macro file from the\n\
00051 ROOT browser to the Kate editor. On Windows, drag and drop works\n\
00052 only within a single ROOT application, but it is possible to drag\n\
00053 from the Windows Explorer to ROOT (e.g. a picture file to a canvas\n\
00054 or a text file to a text editor).\n\
00055 ";
00056 
00057 const char gReadyMsg[] = "Ready. You can drag list tree items to any \
00058 pad in the canvas, or to the \"Base\" folder of the list tree itself...";
00059 
00060 //----------------------------------------------------------------------
00061 
00062 class DNDMainFrame : public TGMainFrame {
00063 
00064 protected:
00065    TRootEmbeddedCanvas  *fEc;          // embedded canvas
00066    TGTextButton         *fButtonExit;  // "Exit" text button
00067    TGMenuBar            *fMenuBar;     // main menu bar
00068    TGPopupMenu          *fMenuFile;    // "File" popup menu entry
00069    TGPopupMenu          *fMenuHelp;    // "Help" popup menu entry
00070    TCanvas              *fCanvas;      // canvas
00071    TGListTree           *fListTree;    // left list tree
00072    TGListTreeItem       *fBaseLTI;     // base (root) list tree item
00073    TGLabel              *fStatus;      // label used to display status
00074    TGraph               *fGraph;       // TGraph object
00075    TH1F                 *fHist1D;      // 1D histogram
00076    TH2F                 *fHist2D;      // 2D histogram
00077 
00078 public:
00079    DNDMainFrame(const TGWindow *p, int w, int h);
00080    virtual ~DNDMainFrame();
00081 
00082    void              DoCloseWindow();
00083    void              HandleMenu(Int_t);
00084    TObject          *GetObject(const char *obj);
00085    void              DataDropped(TGListTreeItem* item, TDNDData* data);
00086    void              ResetStatus();
00087 
00088    //ClassDef(DNDMainFrame, 0); // Mainframe for Drag and Drop demo
00089 };
00090 
00091 enum EMyMessageTypes {
00092    M_FILE_OPEN,
00093    M_FILE_BROWSE,
00094    M_FILE_NEWCANVAS,
00095    M_FILE_CLOSEWIN,
00096    M_FILE_EXIT,
00097    M_HELP_ABOUT
00098 };
00099 
00100 const char *dnd_types[] = {
00101    "ROOT files",    "*.root",
00102    "ROOT macros",   "*.C",
00103    "All files",     "*",
00104     0,               0
00105 };
00106 
00107 static Atom_t gRootObj  = kNone;
00108 
00109 //______________________________________________________________________________
00110 DNDMainFrame::DNDMainFrame(const TGWindow *p, int w, int h) :
00111    TGMainFrame(p, w, h), fGraph(0), fHist1D(0), fHist2D(0)
00112 
00113 {
00114    // Constructor.
00115 
00116    SetCleanup(kDeepCleanup);
00117    const TGPicture *pic = 0;
00118    TGListTreeItem *item;
00119    fMenuBar = new TGMenuBar(this, 35, 50, kHorizontalFrame);
00120 
00121    fMenuFile = new TGPopupMenu(gClient->GetRoot());
00122    fMenuFile->AddEntry(" &Open...\tCtrl+O", M_FILE_OPEN, 0,
00123                        gClient->GetPicture("bld_open.png"));
00124    fMenuFile->AddEntry(" &Browse...\tCtrl+B", M_FILE_BROWSE);
00125    fMenuFile->AddEntry(" &New Canvas\tCtrl+N", M_FILE_NEWCANVAS);
00126    fMenuFile->AddEntry(" &Close Window\tCtrl+W", M_FILE_CLOSEWIN);
00127    fMenuFile->AddSeparator();
00128    fMenuFile->AddEntry(" E&xit\tCtrl+Q", M_FILE_EXIT, 0,
00129                        gClient->GetPicture("bld_exit.png"));
00130    fMenuFile->Connect("Activated(Int_t)", "DNDMainFrame", this,
00131                       "HandleMenu(Int_t)");
00132 
00133    fMenuHelp = new TGPopupMenu(gClient->GetRoot());
00134    fMenuHelp->AddEntry(" &About...", M_HELP_ABOUT, 0,
00135                        gClient->GetPicture("about.xpm"));
00136    fMenuHelp->Connect("Activated(Int_t)", "DNDMainFrame", this,
00137                       "HandleMenu(Int_t)");
00138 
00139    fMenuBar->AddPopup("&File", fMenuFile, new TGLayoutHints(kLHintsTop|kLHintsLeft,
00140                                                             0, 4, 0, 0));
00141 
00142    fMenuBar->AddPopup("&Help", fMenuHelp, new TGLayoutHints(kLHintsTop|kLHintsRight));
00143 
00144    AddFrame(fMenuBar, new TGLayoutHints(kLHintsTop | kLHintsExpandX, 2, 2, 2, 5));
00145 
00146    TGHorizontalFrame *hfrm = new TGHorizontalFrame(this, 10, 10);
00147    TGCanvas *canvas = new TGCanvas(hfrm, 150, 100);
00148    fListTree = new TGListTree(canvas, kHorizontalFrame);
00149    fListTree->Associate(this);
00150    fEc = new TRootEmbeddedCanvas("glec", hfrm, 550, 350);
00151    hfrm->AddFrame(canvas, new TGLayoutHints(kLHintsLeft | kLHintsExpandY, 5, 5));
00152    hfrm->AddFrame(fEc, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
00153    AddFrame(hfrm, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
00154    fEc->SetDNDTarget(kTRUE);
00155    fCanvas = fEc->GetCanvas();
00156    fCanvas->Divide(3, 2);
00157    fCanvas->SetBorderMode(0);
00158    fBaseLTI = fListTree->AddItem(0, "Base");
00159 
00160    TGHorizontalFrame *hf = new TGHorizontalFrame(this, 10, 10);
00161 
00162    fStatus = new TGLabel(hf, new TGHotString(gReadyMsg));
00163    fStatus->SetTextJustify(kTextLeft);
00164    fStatus->SetTextColor(0x0000ff);
00165    hf->AddFrame(fStatus, new TGLayoutHints(kLHintsExpandX | kLHintsCenterY,
00166                 10, 10, 10, 10));
00167 
00168    fButtonExit = new TGTextButton(hf, "        &Exit...        ", 3);
00169    fButtonExit->Resize(fButtonExit->GetDefaultSize());
00170    fButtonExit->SetToolTipText("Exit Application (ROOT)");
00171    fButtonExit->Connect("Clicked()" , "TApplication", gApplication,
00172                         "Terminate()");
00173    hf->AddFrame(fButtonExit, new TGLayoutHints(kLHintsCenterY | kLHintsRight,
00174                                                10, 10, 10, 10));
00175 
00176    AddFrame(hf, new TGLayoutHints(kLHintsTop | kLHintsExpandX, 5, 5, 5, 5));
00177 
00178    gRootObj  = gVirtualX->InternAtom("application/root", kFALSE);
00179 
00180    TGraph *gr = (TGraph *)GetObject("Graph");
00181    pic = gClient->GetPicture("f1_t.xpm");
00182    item = fListTree->AddItem(fBaseLTI, gr->GetName(), gr, pic, pic);
00183    fListTree->SetToolTipItem(item, "Simple Graph");
00184    item->SetDNDSource(kTRUE);
00185 
00186    TH1F *hpx = (TH1F *)GetObject("1D Hist");
00187    pic = gClient->GetPicture("h1_t.xpm");
00188    item = fListTree->AddItem(fBaseLTI, hpx->GetName(), hpx, pic, pic);
00189    fListTree->SetToolTipItem(item, "1D Histogram");
00190    item->SetDNDSource(kTRUE);
00191 
00192    TH2F *h2 = (TH2F *)GetObject("2D Hist");
00193    pic = gClient->GetPicture("h2_t.xpm");
00194    item = fListTree->AddItem(fBaseLTI, h2->GetName(), h2, pic, pic);
00195    fListTree->SetToolTipItem(item, "2D Histogram");
00196    item->SetDNDSource(kTRUE);
00197 
00198    TString rootsys(gSystem->UnixPathName(gSystem->Getenv("ROOTSYS")));
00199 #ifdef G__WIN32
00200    // remove the drive letter (e.g. "C:/") from $ROOTSYS, if any
00201    if (rootsys[1] == ':' && rootsys[2] == '/')
00202       rootsys.Remove(0, 3);
00203 #endif
00204    TString link = TString::Format("/%s/tutorials/image/rose512.jpg", 
00205                                   rootsys.Data());
00206    if (!gSystem->AccessPathName(link.Data(), kReadPermission)) {
00207       TImage *img = TImage::Open(link.Data());
00208       if (img) {
00209          // create a 16x16 icon from the original picture
00210          img->Scale(16, 16);
00211          pic = gClient->GetPicturePool()->GetPicture("rose512", img->GetPixmap(),
00212                                                      img->GetMask());
00213          delete img;
00214       }
00215       else pic = gClient->GetPicture("psp_t.xpm");
00216       link.Prepend("file://");
00217       TObjString *ostr = new TObjString(link.Data());
00218       item = fListTree->AddItem(fBaseLTI, "Rose", ostr, pic, pic);
00219       fListTree->SetToolTipItem(item, link.Data());
00220       item->SetDNDSource(kTRUE);
00221    }
00222 
00223    // open the base list tree item and allow to drop into it
00224    fListTree->OpenItem(fBaseLTI);
00225    fListTree->GetFirstItem()->SetDNDTarget(kTRUE);
00226 
00227    // connect the DataDropped signal to be able to handle it
00228    fListTree->Connect("DataDropped(TGListTreeItem*, TDNDData*)", "DNDMainFrame",
00229                       this, "DataDropped(TGListTreeItem*,TDNDData*)");
00230 
00231    SetWindowName("ROOT DND Demo Application");
00232    MapSubwindows();
00233    Resize(GetDefaultSize());
00234    Connect("CloseWindow()", "DNDMainFrame", this, "DoCloseWindow()");
00235    DontCallClose(); // to avoid double deletions.
00236 }
00237 
00238 //______________________________________________________________________________
00239 DNDMainFrame::~DNDMainFrame()
00240 {
00241    // Destructor. Doesnt't do much here.
00242 }
00243 
00244 //______________________________________________________________________________
00245 void DNDMainFrame::DoCloseWindow()
00246 {
00247    // Do some cleanup, disconnect signals and then really close the main window.
00248 
00249    if (fGraph) { delete fGraph; fGraph = 0; }
00250    if (fHist1D) { delete fHist1D; fHist1D = 0; }
00251    if (fHist2D) { delete fHist2D; fHist2D = 0; }
00252    fMenuFile->Disconnect("Activated(Int_t)", this, "HandleMenu(Int_t)");
00253    fMenuHelp->Disconnect("Activated(Int_t)", this, "HandleMenu(Int_t)");
00254    fButtonExit->Disconnect("Clicked()" , this, "CloseWindow()");
00255    fListTree->Disconnect("DataDropped(TGListTreeItem*, TDNDData*)", this,
00256                          "DataDropped(TGListTreeItem*,TDNDData*)");
00257    delete fListTree;
00258    CloseWindow();
00259 }
00260 
00261 //______________________________________________________________________________
00262 void DNDMainFrame::DataDropped(TGListTreeItem *, TDNDData *data)
00263 {
00264    // Handle the drop event in the TGListTree. This will just create a new
00265    // list tree item and copy the received data into it.
00266 
00267    fStatus->SetTextColor(0xff0000);
00268    fStatus->ChangeText("I received data!!!");
00269    if (data) {
00270       const TGPicture *pic = 0;
00271       TGListTreeItem *itm = 0;
00272       char tmp[1000];
00273       if (data->fDataType == gRootObj) {
00274          TBufferFile buf(TBuffer::kRead, data->fDataLength, (void *)data->fData);
00275          buf.SetReadMode();
00276          TObject *obj = (TObject *)buf.ReadObjectAny(TObject::Class());
00277          sprintf(tmp, "Received DND data : Type = \"%s\"; Length = %d bytes;",
00278                  obj->ClassName(), data->fDataLength);
00279          if (obj->InheritsFrom("TGraph"))
00280             pic = gClient->GetPicture("f1_t.xpm");
00281          else if (obj->InheritsFrom("TH2F"))
00282             pic = gClient->GetPicture("h2_t.xpm");
00283          else if (obj->InheritsFrom("TH1F"))
00284             pic = gClient->GetPicture("h1_t.xpm");
00285          itm = fListTree->AddItem(fBaseLTI, obj->GetName(), obj, pic, pic);
00286          fListTree->SetToolTipItem(itm, obj->GetName());
00287       }
00288       else {
00289          sprintf(tmp, "Received DND data: \"%s\"", (char *)data->fData);
00290          TObjString *ostr = new TObjString((char *)data->fData);
00291          TImage *img1 = TImage::Open("doc_t.xpm");
00292          TImage *img2 = TImage::Open("slink_t.xpm");
00293          if (img1 && img2) {
00294             img1->Merge(img2);
00295             pic = gClient->GetPicturePool()->GetPicture("doc_lnk", img1->GetPixmap(),
00296                                                         img1->GetMask());
00297             delete img2;
00298             delete img1;
00299          }
00300          else pic = gClient->GetPicture("doc_t.xpm");
00301          itm = fListTree->AddItem(fBaseLTI, "Link...", ostr, pic, pic);
00302          fListTree->SetToolTipItem(itm, (const char *)data->fData);
00303       }
00304       if (itm) itm->SetDNDSource(kTRUE);
00305       fStatus->ChangeText(tmp);
00306    }
00307    TTimer::SingleShot(3000, "DNDMainFrame", this, "ResetStatus()");
00308 }
00309 
00310 //______________________________________________________________________________
00311 TObject *DNDMainFrame::GetObject(const char *obj)
00312 {
00313    // Return the object specified in argument. If the object doesn't exist yet,
00314    // it is firt created.
00315 
00316    if (!strcmp(obj, "Graph")) {
00317       if (fGraph == 0) {
00318          const Int_t n = 20;
00319          Double_t x[n], y[n];
00320          for (Int_t i=0;i<n;i++) {
00321            x[i] = i*0.1;
00322            y[i] = 10*sin(x[i]+0.2);
00323          }
00324          fGraph = new TGraph(n, x, y);
00325       }
00326       return fGraph;
00327    }
00328    else if (!strcmp(obj, "1D Hist")) {
00329       if (fHist1D == 0) {
00330          fHist1D = new TH1F("1D Hist","This is the px distribution",100,-4,4);
00331          Float_t px, py;
00332          for ( Int_t i=0; i<10000; i++) {
00333             gRandom->Rannor(px, py);
00334             fHist1D->Fill(px);
00335          }
00336       }
00337       return fHist1D;
00338    }
00339    else if (!strcmp(obj, "2D Hist")) {
00340       if (fHist2D == 0) {
00341          Double_t params[] = {
00342             130,-1.4,1.8,1.5,1, 150,2,0.5,-2,0.5, 3600,-2,0.7,-3,0.3
00343          };
00344          TF2 *f2 = new TF2("f2","xygaus + xygaus(5) + xylandau(10)",
00345                            -4, 4, -4, 4);
00346          f2->SetParameters(params);
00347          fHist2D = new TH2F("2D Hist","xygaus+xygaus(5)+xylandau(10)",
00348                             20, -4, 4, 20, -4, 4);
00349          fHist2D->FillRandom("f2",40000);
00350       }
00351       return fHist2D;
00352    }
00353    return 0;
00354 }
00355 
00356 //______________________________________________________________________________
00357 void DNDMainFrame::HandleMenu(Int_t menu_id)
00358 {
00359    // Handle menu events.
00360 
00361    TRootHelpDialog *hd;
00362    static TString dir(".");
00363    TGFileInfo fi;
00364    fi.fFileTypes = dnd_types;
00365    fi.fIniDir    = StrDup(dir);
00366 
00367    switch (menu_id) {
00368       case M_FILE_EXIT:
00369          // close the window and quit application
00370          DoCloseWindow();
00371          gApplication->Terminate(0);
00372          break;
00373       case M_FILE_OPEN:
00374          new TGFileDialog(gClient->GetRoot(), this, kFDOpen, &fi);
00375          dir = fi.fIniDir;
00376          // doesn't do much, but can be used to open a root file...
00377          break;
00378       case M_FILE_BROWSE:
00379          // start a root object browser
00380          new TBrowser();
00381          break;
00382       case M_FILE_NEWCANVAS:
00383          // open a root canvas
00384          gROOT->MakeDefCanvas();
00385          break;
00386       case M_FILE_CLOSEWIN:
00387          DoCloseWindow();
00388          break;
00389       case M_HELP_ABOUT:
00390          hd = new TRootHelpDialog(this, "About Drag and Drop...", 550, 250);
00391          hd->SetText(gHelpDND);
00392          hd->Popup();
00393          break;
00394    }
00395 }
00396 
00397 //______________________________________________________________________________
00398 void DNDMainFrame::ResetStatus()
00399 {
00400    // Restore the original text of the status label and its original color.
00401 
00402    fStatus->SetTextColor(0x0000ff);
00403    fStatus->ChangeText(gReadyMsg);
00404 }
00405 
00406 //------------------------------------------------------------------------------
00407 void drag_and_drop()
00408 {
00409    // Main function (entry point)
00410 
00411    DNDMainFrame *mainWindow = new DNDMainFrame(gClient->GetRoot(), 700, 400);
00412    mainWindow->MapWindow();
00413 }
00414 

Generated on Tue Jul 5 15:44:23 2011 for ROOT_528-00b_version by  doxygen 1.5.1