<commit_before>// @(#)root/gui:$Name:  $:$Id: TRootContextMenu.cxx,v 1.17 2007/01/30 11:55:33 brun Exp $
// Author: Fons Rademakers   12/02/98

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TRootContextMenu                                                     //
//                                                                      //
// This class provides an interface to context sensitive popup menus.   //
// These menus pop up when the user hits the right mouse button, and    //
// are destroyed when the menu pops downs.                              //
// The picture below shows a canvas with a pop-up menu.                 //
//                                                                      //
//Begin_Html  End_Html                      //
//                                                                      //
// The picture below shows a canvas with a pop-up menu and a dialog box.//
//                                                                      //
//Begin_Html  End_Html                    //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#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, // first id of toggle menu items
   kToggleListStart   = 2000, // first id of toggle list menu items
   kUserFunctionStart = 3000  // first id of user added functions/methods, etc...
};

ClassImp(TRootContextMenu)

//______________________________________________________________________________
TRootContextMenu::TRootContextMenu(TContextMenu *c, const char *)
    : TGPopupMenu(gClient->GetDefaultRoot()), TContextMenuImp(c)
{
   // Create context menu.

   fDialog  = 0;
   fTrash = new TList;

   // Context menu handles its own messages
   Associate(this);
}

//______________________________________________________________________________
TRootContextMenu::~TRootContextMenu()
{
   // Delete a context menu.

   delete fDialog;
   if (fTrash) fTrash->Delete();
   delete fTrash;
}

//______________________________________________________________________________
void TRootContextMenu::DisplayPopup(Int_t x, Int_t y)
{
   // Display context popup menu for currently selected object.

   if (fClient->IsEditable()) return;

   // delete menu items releated to previous object and reset menu size
   if (fEntryList) fEntryList->Delete();
   if (fTrash)   fTrash->Delete();
   fMenuHeight = 6;
   fMenuWidth  = 8;

   // delete previous dialog
   if (fDialog) {
      delete fDialog;
      fDialog = 0;
   }

   // add menu items to popup menu
   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);
}

//______________________________________________________________________________
void TRootContextMenu::CreateMenu(TObject *object)
{
   // Create the context menu depending on the selected object.

   if (fClient->IsEditable()) return;

   int entry = 0, toggle = kToggleStart, togglelist = kToggleListStart;
   int userfunction = kUserFunctionStart;

   // Add a title
   AddLabel(fContextMenu->CreatePopupTitle(object));
   AddSeparator();

   // Get list of menu items from the selected object's class
   TList *menuItemList = object->IsA()->GetMenuList();

   TClassMenuItem *menuItem;
   TIter nextItem(menuItemList);

   while ((menuItem = (TClassMenuItem*) nextItem())) {
      switch (menuItem->GetType()) {
         case TClassMenuItem::kPopupSeparator:
            AddSeparator();
            break;
         case TClassMenuItem::kPopupStandardList:
            {
               // Standard list of class methods. Rebuild from scratch.
               // Get linked list of objects menu items (i.e. member functions
               // with the token *MENU in their comment fields.
               TList *methodList = new TList;
               object->IsA()->GetMenuItems(methodList);

               TMethod *method;
               TClass  *classPtr = 0;
               TIter next(methodList);

               while ((method = (TMethod*) next())) {
                  if (classPtr != method->GetClass()) {
                     AddSeparator();
                     classPtr = method->GetClass();
                  }

                  TDataMember *m;
                  EMenuItemKind menuKind = method->IsMenuItem();
                  switch (menuKind) {
                     case kMenuDialog:
                        AddEntry(method->GetName(), entry++, method);
                        break;
                     case kMenuSubMenu:
                        if ((m = method->FindDataMember())) {
                           if (m->GetterMethod()) {
                              TGPopupMenu *r = new TGPopupMenu(gClient->GetDefaultRoot());
                              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->AddSeparator();
                                 r->AddEntry(name, togglelist++, t);
                                 if (t->GetState()) r->CheckEntry(togglelist-1);

                              }
                           } else {
                              AddEntry(method->GetName(), entry++, method);
                           }
                        }
                        break;

                     case kMenuToggle:
                        {
                           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);
                        }
                        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)
{
   // Create dialog object with OK and Cancel buttons. This dialog
   // prompts for the arguments of "method".

   Dialog(object,(TFunction*)method);
}

//______________________________________________________________________________
void TRootContextMenu::Dialog(TObject *object, TFunction *function)
{
   // Create dialog object with OK and Cancel buttons. This dialog
   // prompts for the arguments of "function".
   // function may be a global function or a method

   Int_t selfobjpos;

   if (!function) return;

   // Position, if it exists, of the argument that correspond to the object itself
   if (fContextMenu->GetSelectedMenuItem())
      selfobjpos =  fContextMenu->GetSelectedMenuItem()->GetSelfObjectPos();
   else selfobjpos = -1;

   const TGWindow *w;
   if (fContextMenu->GetSelectedCanvas()) {
      TCanvas *c = (TCanvas *) fContextMenu->GetSelectedCanvas();
      // Embedded canvas has no canvasimp that is a TGFrame
      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));

   // iterate through all arguments and create apropriate input-data objects:
   // inputlines, option menus...
   TMethodArg *argument = 0;

   TIter next(function->GetListOfMethodArgs());
   Int_t argpos = 0;

   while ((argument = (TMethodArg *) next())) {
      // Do not input argument for self object
      if (selfobjpos != argpos) {
         Text_t       *argname    = fContextMenu->CreateArgumentTitle(argument);
         const Text_t *type       = argument->GetTypeName();
         TDataType    *datatype   = gROOT->GetType(type);
         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, "*");
         }

         TDataMember *m = argument->GetDataMember();
         if (m && m->GetterMethod(object->IsA())) {

            // Get the current value and form it as a text:

            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);
            }

            // Find out whether we have options ...

            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 {
               // we haven't got options - textfield ...
               fDialog->Add(argname, val, type);
            }
         } else {    // if m not found ...

            char val[256] = "";
            const char *tval = argument->GetDefault();
            if (tval) strncpy(val, tval, 255);
            fDialog->Add(argname, val, type);
         }
      }
      argpos++;
   }

   fDialog->Popup();
}

//______________________________________________________________________________
Bool_t TRootContextMenu::ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2)
{
   // Handle context menu messages.

   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;
}
<commit_msg>- additional fix in TRootContextMenu::Dialog to avoid side effects<commit_after>// @(#)root/gui:$Name:  $:$Id: TRootContextMenu.cxx,v 1.18 2007/02/05 11:55:38 antcheva Exp $
// Author: Fons Rademakers   12/02/98

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TRootContextMenu                                                     //
//                                                                      //
// This class provides an interface to context sensitive popup menus.   //
// These menus pop up when the user hits the right mouse button, and    //
// are destroyed when the menu pops downs.                              //
// The picture below shows a canvas with a pop-up menu.                 //
//                                                                      //
//Begin_Html  End_Html                      //
//                                                                      //
// The picture below shows a canvas with a pop-up menu and a dialog box.//
//                                                                      //
//Begin_Html  End_Html                    //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#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, // first id of toggle menu items
   kToggleListStart   = 2000, // first id of toggle list menu items
   kUserFunctionStart = 3000  // first id of user added functions/methods, etc...
};

ClassImp(TRootContextMenu)

//______________________________________________________________________________
TRootContextMenu::TRootContextMenu(TContextMenu *c, const char *)
    : TGPopupMenu(gClient->GetDefaultRoot()), TContextMenuImp(c)
{
   // Create context menu.

   fDialog  = 0;
   fTrash = new TList;

   // Context menu handles its own messages
   Associate(this);
}

//______________________________________________________________________________
TRootContextMenu::~TRootContextMenu()
{
   // Delete a context menu.

   delete fDialog;
   if (fTrash) fTrash->Delete();
   delete fTrash;
}

//______________________________________________________________________________
void TRootContextMenu::DisplayPopup(Int_t x, Int_t y)
{
   // Display context popup menu for currently selected object.

   if (fClient->IsEditable()) return;

   // delete menu items releated to previous object and reset menu size
   if (fEntryList) fEntryList->Delete();
   if (fTrash)   fTrash->Delete();
   fMenuHeight = 6;
   fMenuWidth  = 8;

   // delete previous dialog
   if (fDialog) {
      delete fDialog;
      fDialog = 0;
   }

   // add menu items to popup menu
   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);
}

//______________________________________________________________________________
void TRootContextMenu::CreateMenu(TObject *object)
{
   // Create the context menu depending on the selected object.

   if (fClient->IsEditable()) return;

   int entry = 0, toggle = kToggleStart, togglelist = kToggleListStart;
   int userfunction = kUserFunctionStart;

   // Add a title
   AddLabel(fContextMenu->CreatePopupTitle(object));
   AddSeparator();

   // Get list of menu items from the selected object's class
   TList *menuItemList = object->IsA()->GetMenuList();

   TClassMenuItem *menuItem;
   TIter nextItem(menuItemList);

   while ((menuItem = (TClassMenuItem*) nextItem())) {
      switch (menuItem->GetType()) {
         case TClassMenuItem::kPopupSeparator:
            AddSeparator();
            break;
         case TClassMenuItem::kPopupStandardList:
            {
               // Standard list of class methods. Rebuild from scratch.
               // Get linked list of objects menu items (i.e. member functions
               // with the token *MENU in their comment fields.
               TList *methodList = new TList;
               object->IsA()->GetMenuItems(methodList);

               TMethod *method;
               TClass  *classPtr = 0;
               TIter next(methodList);

               while ((method = (TMethod*) next())) {
                  if (classPtr != method->GetClass()) {
                     AddSeparator();
                     classPtr = method->GetClass();
                  }

                  TDataMember *m;
                  EMenuItemKind menuKind = method->IsMenuItem();
                  switch (menuKind) {
                     case kMenuDialog:
                        AddEntry(method->GetName(), entry++, method);
                        break;
                     case kMenuSubMenu:
                        if ((m = method->FindDataMember())) {
                           if (m->GetterMethod()) {
                              TGPopupMenu *r = new TGPopupMenu(gClient->GetDefaultRoot());
                              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->AddSeparator();
                                 r->AddEntry(name, togglelist++, t);
                                 if (t->GetState()) r->CheckEntry(togglelist-1);

                              }
                           } else {
                              AddEntry(method->GetName(), entry++, method);
                           }
                        }
                        break;

                     case kMenuToggle:
                        {
                           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);
                        }
                        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)
{
   // Create dialog object with OK and Cancel buttons. This dialog
   // prompts for the arguments of "method".

   Dialog(object,(TFunction*)method);
}

//______________________________________________________________________________
void TRootContextMenu::Dialog(TObject *object, TFunction *function)
{
   // Create dialog object with OK and Cancel buttons. This dialog
   // prompts for the arguments of "function".
   // function may be a global function or a method

   Int_t selfobjpos;

   if (!function) return;

   // Position, if it exists, of the argument that correspond to the object itself
   if (fContextMenu->GetSelectedMenuItem())
      selfobjpos =  fContextMenu->GetSelectedMenuItem()->GetSelfObjectPos();
   else selfobjpos = -1;

   const TGWindow *w;
   if (fContextMenu->GetSelectedCanvas()) {
      TCanvas *c = (TCanvas *) fContextMenu->GetSelectedCanvas();
      // Embedded canvas has no canvasimp that is a TGFrame
      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));

   // iterate through all arguments and create apropriate input-data objects:
   // inputlines, option menus...
   TMethodArg *argument = 0;

   TIter next(function->GetListOfMethodArgs());
   Int_t argpos = 0;

   while ((argument = (TMethodArg *) next())) {
      // Do not input argument for self object
      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())) {

            // Get the current value and form it as a text:

            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);
            }

            // Find out whether we have options ...

            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 {
               // we haven't got options - textfield ...
               fDialog->Add(argname, val, type);
            }
         } else {    // if m not found ...

            char val[256] = "";
            const char *tval = argument->GetDefault();
            if (tval) strncpy(val, tval, 255);
            fDialog->Add(argname, val, type);
         }
      }
      argpos++;
   }

   fDialog->Popup();
}

//______________________________________________________________________________
Bool_t TRootContextMenu::ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2)
{
   // Handle context menu messages.

   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;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015-2019 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "MediaLibraryTester.h"

#include "Album.h"
#include "AlbumTrack.h"
#include "Artist.h"
#include "Device.h"
#include "Playlist.h"
#include "Genre.h"
#include "Media.h"
#include "Folder.h"
#include "Show.h"
#include "mocks/FileSystem.h"
#include "parser/Task.h"

MediaLibraryTester::MediaLibraryTester( const std::string& dbPath,
                                        const std::string& mlFolderPath )
    : MediaLibrary( dbPath, mlFolderPath )
    , dummyDevice( new mock::NoopDevice )
    , dummyDirectory( new mock::NoopDirectory )
{
}

void MediaLibraryTester::onDbConnectionReady( sqlite::Connection* dbConn )
{
    deleteAllTables( dbConn );
}

std::shared_ptr<Media> MediaLibraryTester::media( int64_t id )
{
    return std::static_pointer_cast<Media>( MediaLibrary::media( id ) );
}

FolderPtr MediaLibraryTester::folder( const std::string& mrl ) const
{
    return Folder::fromMrl( this, mrl, Folder::BannedType::No );
}

FolderPtr MediaLibraryTester::folder( int64_t id ) const
{
    return MediaLibrary::folder( id );
}

std::shared_ptr<Media> MediaLibraryTester::addFile( const std::string& path, IMedia::Type type )
{
    return addFile( std::make_shared<mock::NoopFile>( path ),
                    dummyFolder, dummyDirectory, IFile::Type::Main, type );
}

std::shared_ptr<Media> MediaLibraryTester::addFile( std::shared_ptr<fs::IFile> file, IMedia::Type type )
{
    return addFile( std::move( file ), dummyFolder, dummyDirectory,
                    IFile::Type::Main, type );
}

std::shared_ptr<Media> MediaLibraryTester::addFile( std::shared_ptr<fs::IFile> fileFs,
                                              std::shared_ptr<Folder> parentFolder,
                                              std::shared_ptr<fs::IDirectory> parentFolderFs,
                                              IFile::Type fileType,
                                              IMedia::Type type )
{
    LOG_INFO( "Adding ", fileFs->mrl() );
    auto mptr = Media::create( this, type, parentFolder->deviceId(), parentFolder->id(),
                               fileFs->name(), -1 );
    if ( mptr == nullptr )
    {
        LOG_ERROR( "Failed to add media ", fileFs->mrl(), " to the media library" );
        return nullptr;
    }
    // For now, assume all media are made of a single file
    auto file = mptr->addFile( *fileFs, parentFolder->id(),
                               parentFolderFs->device()->isRemovable(), fileType );
    if ( file == nullptr )
    {
        LOG_ERROR( "Failed to add file ", fileFs->mrl(), " to media #", mptr->id() );
        Media::destroy( this, mptr->id() );
        return nullptr;
    }
    return mptr;
}

void MediaLibraryTester::addLocalFsFactory()
{
    if ( fsFactory != nullptr )
    {
        m_fsHolder.addFsFactory( fsFactory );
    }
    else
    {
        MediaLibrary::addLocalFsFactory();
    }
}

void MediaLibraryTester::deleteAlbum( int64_t albumId )
{
    Album::destroy( this, albumId );
}

std::shared_ptr<Genre> MediaLibraryTester::createGenre( const std::string& name )
{
    return Genre::create( this, name );
}

void MediaLibraryTester::deleteGenre( int64_t genreId )
{
    Genre::destroy( this, genreId );
}

void MediaLibraryTester::deleteArtist( int64_t artistId )
{
    Artist::destroy( this, artistId );
}

void MediaLibraryTester::deleteShow( int64_t showId )
{
    Show::destroy( this, showId );
}

std::shared_ptr<Device> MediaLibraryTester::addDevice( const std::string& uuid,
                                                       const std::string& scheme,
                                                       bool isRemovable )
{
    return Device::create( this, uuid, scheme, isRemovable, false );
}

void MediaLibraryTester::setFsFactory( std::shared_ptr<fs::IFileSystemFactory> fsf )
{
    fsFactory = fsf;
}

std::shared_ptr<AlbumTrack> MediaLibraryTester::albumTrack( int64_t id )
{
    return AlbumTrack::fetch( this, id );
}

std::vector<MediaPtr> MediaLibraryTester::files()
{
    static const std::string req = "SELECT * FROM " + Media::Table::Name + " WHERE is_present != 0";
    return Media::fetchAll<IMedia>( this, req );
}

std::shared_ptr<Device> MediaLibraryTester::device( const std::string& uuid,
                                                    const std::string& scheme )
{
    return Device::fromUuid( this, uuid, scheme );
}

void MediaLibraryTester::onDiscoveredFile(std::shared_ptr<fs::IFile> fileFs,
                                          std::shared_ptr<Folder> parentFolder,
                                          std::shared_ptr<fs::IDirectory> parentFolderFs,
                                          IFile::Type fileType)
{
    addFile( fileFs, parentFolder, parentFolderFs, fileType, IMedia::Type::Unknown );
}

void MediaLibraryTester::populateNetworkFsFactories()
{
}

MediaPtr MediaLibraryTester::addMedia( const std::string& mrl, IMedia::Type type )
{
    return addFile( mrl, type );
}

void MediaLibraryTester::deleteMedia( int64_t mediaId )
{
    Media::destroy( this, mediaId );
}

bool MediaLibraryTester::outdateAllDevices()
{
    std::string req = "UPDATE " + Device::Table::Name + " SET last_seen = 1";
    return sqlite::Tools::executeUpdate( getConn(), req );
}

bool MediaLibraryTester::setMediaInsertionDate( int64_t mediaId, time_t t )
{
    std::string req = "UPDATE " + Media::Table::Name + " SET insertion_date = ? "
            "WHERE id_media = ?";
    return sqlite::Tools::executeUpdate( getConn(), req, mediaId, t );
}

bool MediaLibraryTester::outdateAllExternalMedia()
{
    std::string req = "UPDATE " + Media::Table::Name + " SET last_played_date = 1 "
            "WHERE import_type != ?";
    return sqlite::Tools::executeUpdate( getConn(), req, Media::ImportType::Internal );
}

bool MediaLibraryTester::setMediaType(int64_t mediaId, IMedia::Type type)
{
    std::string req = "UPDATE " + Media::Table::Name + " SET type = ? WHERE id_media = ?";
    return sqlite::Tools::executeUpdate( getConn(), req, type, mediaId );
}

uint32_t MediaLibraryTester::countNbThumbnails()
{
    sqlite::Statement stmt{
        getConn()->handle(),
        "SELECT COUNT(*) FROM " + Thumbnail::Table::Name
    };
    uint32_t res;
    stmt.execute();
    auto row = stmt.row();
    row >> res;
    return res;
}

uint32_t MediaLibraryTester::countNbTasks()
{
    sqlite::Statement stmt{
        getConn()->handle(),
        "SELECT COUNT(*) FROM " + parser::Task::Table::Name
    };
    uint32_t res;
    stmt.execute();
    auto row = stmt.row();
    row >> res;
    return res;
}

bool MediaLibraryTester::setupDummyFolder()
{
    // We create a dummy device in database, and a dummy folder.
    // This allows us to have a DB setup which is equivalent to an real one
    // File need to have a parent folder to be considered non-external, and a
    // folder needs to have a parent device.
    // However, if we just add a dummy device to DB and be done with it, when
    // the media library refreshes the devices, it will not find the device we
    // inserted and will mark it as missing, which will cause all its media to
    // be marked missing as well, which tends to make the tests fail
    std::shared_ptr<Device> device;
    try
    {
        device = Device::create( this, mock::FileSystemFactory::NoopDeviceUuid,
                                 "file://", false, false );
        if ( device == nullptr )
            return false;
    }
    catch ( const sqlite::errors::ConstraintUnique& )
    {
        // Most test cases call Reload() which will end up calling setupDummyFolder
        // again. We don't want the UNIQUE constraint to terminate the test.
        // Let's assume that this folder will be the first create folder
        dummyFolder = Folder::fetch( this, 1 );
        return true;
    }
    dummyFolder = Folder::create( this, "./", 0, *device, *dummyDevice );
    if ( dummyFolder == nullptr || dummyFolder->id() != 1 )
        return false;
    return true;
}

void MediaLibraryTester::deleteAllTables( sqlite::Connection* dbConn )
{
    MediaLibrary::deleteAllTables( dbConn );
}
<commit_msg>unitests: MediaLibraryTester: Fix setMediaInsertionDate helper<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015-2019 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "MediaLibraryTester.h"

#include "Album.h"
#include "AlbumTrack.h"
#include "Artist.h"
#include "Device.h"
#include "Playlist.h"
#include "Genre.h"
#include "Media.h"
#include "Folder.h"
#include "Show.h"
#include "mocks/FileSystem.h"
#include "parser/Task.h"

MediaLibraryTester::MediaLibraryTester( const std::string& dbPath,
                                        const std::string& mlFolderPath )
    : MediaLibrary( dbPath, mlFolderPath )
    , dummyDevice( new mock::NoopDevice )
    , dummyDirectory( new mock::NoopDirectory )
{
}

void MediaLibraryTester::onDbConnectionReady( sqlite::Connection* dbConn )
{
    deleteAllTables( dbConn );
}

std::shared_ptr<Media> MediaLibraryTester::media( int64_t id )
{
    return std::static_pointer_cast<Media>( MediaLibrary::media( id ) );
}

FolderPtr MediaLibraryTester::folder( const std::string& mrl ) const
{
    return Folder::fromMrl( this, mrl, Folder::BannedType::No );
}

FolderPtr MediaLibraryTester::folder( int64_t id ) const
{
    return MediaLibrary::folder( id );
}

std::shared_ptr<Media> MediaLibraryTester::addFile( const std::string& path, IMedia::Type type )
{
    return addFile( std::make_shared<mock::NoopFile>( path ),
                    dummyFolder, dummyDirectory, IFile::Type::Main, type );
}

std::shared_ptr<Media> MediaLibraryTester::addFile( std::shared_ptr<fs::IFile> file, IMedia::Type type )
{
    return addFile( std::move( file ), dummyFolder, dummyDirectory,
                    IFile::Type::Main, type );
}

std::shared_ptr<Media> MediaLibraryTester::addFile( std::shared_ptr<fs::IFile> fileFs,
                                              std::shared_ptr<Folder> parentFolder,
                                              std::shared_ptr<fs::IDirectory> parentFolderFs,
                                              IFile::Type fileType,
                                              IMedia::Type type )
{
    LOG_INFO( "Adding ", fileFs->mrl() );
    auto mptr = Media::create( this, type, parentFolder->deviceId(), parentFolder->id(),
                               fileFs->name(), -1 );
    if ( mptr == nullptr )
    {
        LOG_ERROR( "Failed to add media ", fileFs->mrl(), " to the media library" );
        return nullptr;
    }
    // For now, assume all media are made of a single file
    auto file = mptr->addFile( *fileFs, parentFolder->id(),
                               parentFolderFs->device()->isRemovable(), fileType );
    if ( file == nullptr )
    {
        LOG_ERROR( "Failed to add file ", fileFs->mrl(), " to media #", mptr->id() );
        Media::destroy( this, mptr->id() );
        return nullptr;
    }
    return mptr;
}

void MediaLibraryTester::addLocalFsFactory()
{
    if ( fsFactory != nullptr )
    {
        m_fsHolder.addFsFactory( fsFactory );
    }
    else
    {
        MediaLibrary::addLocalFsFactory();
    }
}

void MediaLibraryTester::deleteAlbum( int64_t albumId )
{
    Album::destroy( this, albumId );
}

std::shared_ptr<Genre> MediaLibraryTester::createGenre( const std::string& name )
{
    return Genre::create( this, name );
}

void MediaLibraryTester::deleteGenre( int64_t genreId )
{
    Genre::destroy( this, genreId );
}

void MediaLibraryTester::deleteArtist( int64_t artistId )
{
    Artist::destroy( this, artistId );
}

void MediaLibraryTester::deleteShow( int64_t showId )
{
    Show::destroy( this, showId );
}

std::shared_ptr<Device> MediaLibraryTester::addDevice( const std::string& uuid,
                                                       const std::string& scheme,
                                                       bool isRemovable )
{
    return Device::create( this, uuid, scheme, isRemovable, false );
}

void MediaLibraryTester::setFsFactory( std::shared_ptr<fs::IFileSystemFactory> fsf )
{
    fsFactory = fsf;
}

std::shared_ptr<AlbumTrack> MediaLibraryTester::albumTrack( int64_t id )
{
    return AlbumTrack::fetch( this, id );
}

std::vector<MediaPtr> MediaLibraryTester::files()
{
    static const std::string req = "SELECT * FROM " + Media::Table::Name + " WHERE is_present != 0";
    return Media::fetchAll<IMedia>( this, req );
}

std::shared_ptr<Device> MediaLibraryTester::device( const std::string& uuid,
                                                    const std::string& scheme )
{
    return Device::fromUuid( this, uuid, scheme );
}

void MediaLibraryTester::onDiscoveredFile(std::shared_ptr<fs::IFile> fileFs,
                                          std::shared_ptr<Folder> parentFolder,
                                          std::shared_ptr<fs::IDirectory> parentFolderFs,
                                          IFile::Type fileType)
{
    addFile( fileFs, parentFolder, parentFolderFs, fileType, IMedia::Type::Unknown );
}

void MediaLibraryTester::populateNetworkFsFactories()
{
}

MediaPtr MediaLibraryTester::addMedia( const std::string& mrl, IMedia::Type type )
{
    return addFile( mrl, type );
}

void MediaLibraryTester::deleteMedia( int64_t mediaId )
{
    Media::destroy( this, mediaId );
}

bool MediaLibraryTester::outdateAllDevices()
{
    std::string req = "UPDATE " + Device::Table::Name + " SET last_seen = 1";
    return sqlite::Tools::executeUpdate( getConn(), req );
}

bool MediaLibraryTester::setMediaInsertionDate( int64_t mediaId, time_t t )
{
    std::string req = "UPDATE " + Media::Table::Name + " SET insertion_date = ? "
            "WHERE id_media = ?";
    return sqlite::Tools::executeUpdate( getConn(), req, t, mediaId );
}

bool MediaLibraryTester::outdateAllExternalMedia()
{
    std::string req = "UPDATE " + Media::Table::Name + " SET last_played_date = 1 "
            "WHERE import_type != ?";
    return sqlite::Tools::executeUpdate( getConn(), req, Media::ImportType::Internal );
}

bool MediaLibraryTester::setMediaType(int64_t mediaId, IMedia::Type type)
{
    std::string req = "UPDATE " + Media::Table::Name + " SET type = ? WHERE id_media = ?";
    return sqlite::Tools::executeUpdate( getConn(), req, type, mediaId );
}

uint32_t MediaLibraryTester::countNbThumbnails()
{
    sqlite::Statement stmt{
        getConn()->handle(),
        "SELECT COUNT(*) FROM " + Thumbnail::Table::Name
    };
    uint32_t res;
    stmt.execute();
    auto row = stmt.row();
    row >> res;
    return res;
}

uint32_t MediaLibraryTester::countNbTasks()
{
    sqlite::Statement stmt{
        getConn()->handle(),
        "SELECT COUNT(*) FROM " + parser::Task::Table::Name
    };
    uint32_t res;
    stmt.execute();
    auto row = stmt.row();
    row >> res;
    return res;
}

bool MediaLibraryTester::setupDummyFolder()
{
    // We create a dummy device in database, and a dummy folder.
    // This allows us to have a DB setup which is equivalent to an real one
    // File need to have a parent folder to be considered non-external, and a
    // folder needs to have a parent device.
    // However, if we just add a dummy device to DB and be done with it, when
    // the media library refreshes the devices, it will not find the device we
    // inserted and will mark it as missing, which will cause all its media to
    // be marked missing as well, which tends to make the tests fail
    std::shared_ptr<Device> device;
    try
    {
        device = Device::create( this, mock::FileSystemFactory::NoopDeviceUuid,
                                 "file://", false, false );
        if ( device == nullptr )
            return false;
    }
    catch ( const sqlite::errors::ConstraintUnique& )
    {
        // Most test cases call Reload() which will end up calling setupDummyFolder
        // again. We don't want the UNIQUE constraint to terminate the test.
        // Let's assume that this folder will be the first create folder
        dummyFolder = Folder::fetch( this, 1 );
        return true;
    }
    dummyFolder = Folder::create( this, "./", 0, *device, *dummyDevice );
    if ( dummyFolder == nullptr || dummyFolder->id() != 1 )
        return false;
    return true;
}

void MediaLibraryTester::deleteAllTables( sqlite::Connection* dbConn )
{
    MediaLibrary::deleteAllTables( dbConn );
}
<|endoftext|>


<commit_before>#ifndef INSANITY_ENUMERATION_KEY_MAP
#define INSANITY_ENUMERATION_KEY_MAP

#include "Constants.hpp"

namespace Insanity
{
	typedef u16 EKey;

	//this only maps a common English keyboard. Other keyboards might not be laid out the same way.
	//I'd suggest allowing remapping keys in game.
	class INSANITY_API EKeyMap final
	{
	private:
		virtual void __enumclass() = 0;
	public:
		static const EKey Backspace;
		static const EKey Tab;
		static const EKey Clear;
		static const EKey Enter;
		static const EKey Shift; //Seems to be received instead of more specific Right/Left
		static const EKey Control; //as Shift
		static const EKey Alt; //as Shift
		static const EKey Pause;
		static const EKey CapsLock;
		static const EKey Escape;
		static const EKey Spacebar;
		static const EKey PageUp;
		static const EKey PageDown;
		static const EKey End;
		static const EKey Home;
		static const EKey LeftArrow;
		static const EKey UpArrow;
		static const EKey RightArrow;
		static const EKey DownArrow;
		static const EKey PrintScreen;
		static const EKey Insert;
		static const EKey Delete;
		// zero through nine are all mapped to numbers equivalent to their ASCII values.
		// catch A through Z using uppercase character literals.
		//could put in enumerations for those, and make this an enum class.
		static const EKey A;
		static const EKey B;
		static const EKey C;
		static const EKey D;
		static const EKey E;
		static const EKey F;
		static const EKey G;
		static const EKey H;
		static const EKey I;
		static const EKey J;
		static const EKey K;
		static const EKey L;
		static const EKey M;
		static const EKey N;
		static const EKey O;
		static const EKey P;
		static const EKey Q;
		static const EKey R;
		static const EKey S;
		static const EKey T;
		static const EKey U;
		static const EKey V;
		static const EKey W;
		static const EKey X;
		static const EKey Y;
		static const EKey Z;
		static const EKey Zero;
		static const EKey One;
		static const EKey Two;
		static const EKey Three;
		static const EKey Four;
		static const EKey Five;
		static const EKey Six;
		static const EKey Seven;
		static const EKey Eight;
		static const EKey Nine;
		static const EKey LeftSuper;
		static const EKey RightSuper;
		//what key is this? The one that looks like an arrow and menu.
		static const EKey Applications;
		static const EKey Numpad0;
		static const EKey Numpad1;
		static const EKey Numpad2;
		static const EKey Numpad3;
		static const EKey Numpad4;
		static const EKey Numpad5;
		static const EKey Numpad6;
		static const EKey Numpad7;
		static const EKey Numpad8;
		static const EKey Numpad9;
		static const EKey Multiply;
		static const EKey Add;
		static const EKey Subtract;
		static const EKey Decimal;
		static const EKey Divide;
		static const EKey F1;
		static const EKey F2;
		static const EKey F3;
		static const EKey F4;
		static const EKey F5;
		static const EKey F6;
		static const EKey F7;
		static const EKey F8;
		static const EKey F9;
		static const EKey F10;
		static const EKey F11;
		static const EKey F12;
		//the only keyboard I've seen with function keys past 12 is a Mac keyboard
		static const EKey F13;
		static const EKey F14;
		static const EKey F15;
		static const EKey F16;
		//even the Mac keyboard I have only goes this far (16)
		static const EKey F17;
		static const EKey F18;
		static const EKey F19;
		static const EKey F20;
		static const EKey F21;
		static const EKey F22;
		static const EKey F23;
		static const EKey F24;
		static const EKey NumLock;
		static const EKey ScrollLock;
		//the following are not used, at least on my keyboard. Pressing either shift key sends only Shift, for instance.
		static const EKey LeftShift;
		static const EKey RightShift;
		static const EKey LeftControl;
		static const EKey RightControl;
		static const EKey LeftAlt;
		static const EKey RightAlt;
		//end unused region
		static const EKey Semicolon;
		static const EKey Equals;
		static const EKey Comma;
		static const EKey Minus;
		static const EKey Period;
		static const EKey Slash;
		static const EKey Backquote;
		static const EKey LeftSquareBracket;
		static const EKey Backslash;
		static const EKey RightSquareBracket;
		static const EKey Quote;
	};
}

#endif<commit_msg>Change the way EKeyMap is made noninstantiable<commit_after>#ifndef INSANITY_ENUMERATION_KEY_MAP
#define INSANITY_ENUMERATION_KEY_MAP

#include "Constants.hpp"

namespace Insanity
{
	typedef u16 EKey;

	//this only maps a common English keyboard. Other keyboards might not be laid out the same way.
	//I'd suggest allowing remapping keys in game.
	class INSANITY_API EKeyMap final
	{
	private:
	public:
		EKeyMap() = delete;
		EKeyMap(EKeyMap const&) = delete;
		EKeyMap(EKeyMap &&) = delete;
		~EKeyMap() = delete;
		EKeyMap & operator=(EKeyMap const&) = delete;
		EKeyMap & operator=(EKeyMap &&) = delete;

		static const EKey Backspace;
		static const EKey Tab;
		static const EKey Clear;
		static const EKey Enter;
		static const EKey Shift; //Seems to be received instead of more specific Right/Left
		static const EKey Control; //as Shift
		static const EKey Alt; //as Shift
		static const EKey Pause;
		static const EKey CapsLock;
		static const EKey Escape;
		static const EKey Spacebar;
		static const EKey PageUp;
		static const EKey PageDown;
		static const EKey End;
		static const EKey Home;
		static const EKey LeftArrow;
		static const EKey UpArrow;
		static const EKey RightArrow;
		static const EKey DownArrow;
		static const EKey PrintScreen;
		static const EKey Insert;
		static const EKey Delete;
		// zero through nine are all mapped to numbers equivalent to their ASCII values.
		// catch A through Z using uppercase character literals.
		//could put in enumerations for those, and make this an enum class.
		static const EKey A;
		static const EKey B;
		static const EKey C;
		static const EKey D;
		static const EKey E;
		static const EKey F;
		static const EKey G;
		static const EKey H;
		static const EKey I;
		static const EKey J;
		static const EKey K;
		static const EKey L;
		static const EKey M;
		static const EKey N;
		static const EKey O;
		static const EKey P;
		static const EKey Q;
		static const EKey R;
		static const EKey S;
		static const EKey T;
		static const EKey U;
		static const EKey V;
		static const EKey W;
		static const EKey X;
		static const EKey Y;
		static const EKey Z;
		static const EKey Zero;
		static const EKey One;
		static const EKey Two;
		static const EKey Three;
		static const EKey Four;
		static const EKey Five;
		static const EKey Six;
		static const EKey Seven;
		static const EKey Eight;
		static const EKey Nine;
		static const EKey LeftSuper;
		static const EKey RightSuper;
		//what key is this? The one that looks like an arrow and menu.
		static const EKey Applications;
		static const EKey Numpad0;
		static const EKey Numpad1;
		static const EKey Numpad2;
		static const EKey Numpad3;
		static const EKey Numpad4;
		static const EKey Numpad5;
		static const EKey Numpad6;
		static const EKey Numpad7;
		static const EKey Numpad8;
		static const EKey Numpad9;
		static const EKey Multiply;
		static const EKey Add;
		static const EKey Subtract;
		static const EKey Decimal;
		static const EKey Divide;
		static const EKey F1;
		static const EKey F2;
		static const EKey F3;
		static const EKey F4;
		static const EKey F5;
		static const EKey F6;
		static const EKey F7;
		static const EKey F8;
		static const EKey F9;
		static const EKey F10;
		static const EKey F11;
		static const EKey F12;
		//the only keyboard I've seen with function keys past 12 is a Mac keyboard
		static const EKey F13;
		static const EKey F14;
		static const EKey F15;
		static const EKey F16;
		//even the Mac keyboard I have only goes this far (16)
		static const EKey F17;
		static const EKey F18;
		static const EKey F19;
		static const EKey F20;
		static const EKey F21;
		static const EKey F22;
		static const EKey F23;
		static const EKey F24;
		static const EKey NumLock;
		static const EKey ScrollLock;
		//the following are not used, at least on my keyboard. Pressing either shift key sends only Shift, for instance.
		static const EKey LeftShift;
		static const EKey RightShift;
		static const EKey LeftControl;
		static const EKey RightControl;
		static const EKey LeftAlt;
		static const EKey RightAlt;
		//end unused region
		static const EKey Semicolon;
		static const EKey Equals;
		static const EKey Comma;
		static const EKey Minus;
		static const EKey Period;
		static const EKey Slash;
		static const EKey Backquote;
		static const EKey LeftSquareBracket;
		static const EKey Backslash;
		static const EKey RightSquareBracket;
		static const EKey Quote;
	};
}

#endif<|endoftext|>


<commit_before>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2015 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "ExpansionManager.h"

#include "MacroImportHelper.h"
#include "StaticStuff.h"

namespace CppImport {

ExpansionManager::ExpansionManager(ClangHelper* clang, AstMapping* astMapping, DefinitionManager* definitionManager,
											  LexicalHelper* lexicalHelper)
	: clang_(clang), astMapping_(astMapping), definitionManager_(definitionManager), lexicalHelper_(lexicalHelper) {}

void ExpansionManager::addMacroExpansion(clang::SourceRange sourceRange, const clang::MacroDirective* macroDirective,
													  const clang::MacroArgs* macroArguments)
{
	if (definitionManager_->isPartialEnd(macroDirective))
	{
		/*
		 * if the to be registered expansion's definition is a partial end macro then we are not going to generate a
		 * meta definition for this expansion.
		 * instead we remember that we are currently not in an xMacro body.
		 */
		currentXMacroParent = nullptr;
		return;
	}

	// build new macro expansion entry from the provided information
	auto entry = new MacroExpansion();
	entry->range = sourceRange;
	entry->definition = macroDirective;
	entry->parent = expansion(sourceRange.getBegin());
	if (entry->parent) entry->parent->children.append(entry);

	// handle xMacro data members
	if (definitionManager_->isPartialBegin(macroDirective) && !currentXMacroParent)
		/*
		 * if the definition of this expansion is a partial begin macro we remember that we are now in a xMacro body.
		 * we check whether we are not already in a xMacro body because we want to remember the .h part (the first one) of
		 * the xMacro begins (the potential .cpp part could overwrite the stored information otherwise).
		 */
		currentXMacroParent = entry;
	else if (currentXMacroParent && !entry->parent)
	{
		/*
		 * if we are in a xMacro body and the current expansion is not a top level expansion then this expansion is a
		 * xMacro child of the stored xMacro expansion.
		 */
		entry->xMacroParent = currentXMacroParent;
		currentXMacroParent->xMacroChildren.append(entry);
	}

	entry->metaCall =
			new OOModel::MetaCallExpression(definitionManager_->definitionName(entry->definition));

	if (!macroDirective->getMacroInfo()->isObjectLike()) // only function like macros have braces in their signature to parse
	{
		// extract everything in parentheses of the expansion signature using a regular expression
		QRegularExpression regex ("\\((.*)\\)", QRegularExpression::DotMatchesEverythingOption);
		auto argumentsString = lexicalHelper_->unexpandedSpelling(sourceRange);
		auto match = regex.match(argumentsString);
		auto arguments = match.captured(1).split(",");

		// by default initialize meta call arguments to be reference expressions with the raw spelling at this expansion
		for (auto i = 0; i < clang_->argumentNames(entry->definition).size(); i++)
		{
			auto actualArg = macroArguments->getUnexpArgument((unsigned int)i);
			entry->metaCall->arguments()->append(new OOModel::ReferenceExpression(arguments[i]));
			entry->argumentLocs.append(actualArg->getLocation());
		}
	}

	expansions_.append(entry);
}

void ExpansionManager::clear()
{
	expansionCache_.clear();
	expansions_.clear();
}

QVector<MacroExpansion*> ExpansionManager::topLevelExpansions()
{
	QVector<MacroExpansion*> result;
	for (auto expansion : expansions_)
		if (!expansion->parent)
			result.append(expansion);

	return result;
}

MacroExpansion*ExpansionManager::expansion(clang::SourceLocation loc)
{
	MacroExpansion* expansion = immediateExpansion(loc);
	MacroExpansion* last = expansion;

	if (expansion)
	{
		do
		{
			last = expansion;
			loc = clang_->sourceManager()->getImmediateExpansionRange(loc).first;
			expansion = immediateExpansion(loc);
		} while (expansion && expansion->isChildOf(last));
	}

	return last;
}

MacroExpansion*ExpansionManager::immediateExpansion(clang::SourceLocation loc)
{
	auto expansion = clang_->immediateMacroLocation(loc);
	for (auto i = 0; i < expansions_.size(); i++)
		if (expansions_[i]->range.getBegin() == expansion) return expansions_[i];

	/*
	 * if we have not found an immediate expansion for loc then we try again using the found immediateExpansionLoc.
	 * this can happen in case of token concatenation or stringifycation where the first expansion location would point
	 * to the location of the concatenated token or stringifycation result.
	 */
	expansion = clang_->immediateMacroLocation(expansion);
	for (auto i = 0; i < expansions_.size(); i++)
		if (expansions_[i]->range.getBegin() == expansion) return expansions_[i];

	return nullptr;
}

QSet<MacroExpansion*> ExpansionManager::expansion(Model::Node* node)
{
	Q_ASSERT(node);

	if (!expansionCache_.contains(node))
	{
		expansionCache_[node] = {};

		if (auto n = astMapping_->closestParentWithAstMapping(node))
			if (astMapping_->contains(n))
				for (auto range : astMapping_->get(n))
				{
					auto exp = expansion(range.getBegin());
					if (exp)	expansionCache_[node].insert(exp);
				}
	}

	return expansionCache_[node];
}

QVector<Model::Node*> ExpansionManager::tLExpansionTLNodes(MacroExpansion* expansion)
{
	Q_ASSERT(expansion);
	Q_ASSERT(!expansion->parent); // ensure expansion is a top level expansion

	QVector<Model::Node*> allTLExpansionNodes;
	for (auto node : astMapping_->nodes())
		for (auto range : astMapping_->get(node))
			// for all mapped nodes check whether any of their ranges expand to the top level macro range
			if (clang_->sourceManager()->getExpansionLoc(range.getBegin()) == expansion->range.getBegin())
			{
				allTLExpansionNodes.append(node);
				break;
			}

	QVector<Model::Node*> result = StaticStuff::topLevelNodes(allTLExpansionNodes);
	StaticStuff::orderNodes(result);
	return result;
}

QVector<Model::Node*> ExpansionManager::nTLExpansionTLNodes(MacroExpansion* exp)
{
	Q_ASSERT(exp);

	QVector<Model::Node*> allNTLExpansionNodes;
	for (auto node : astMapping_->nodes())
		if (expansion(node).contains(exp))
			allNTLExpansionNodes.append(node);

	QVector<Model::Node*> result = StaticStuff::topLevelNodes(allNTLExpansionNodes);
	StaticStuff::orderNodes(result);
	return result;
}

}
<commit_msg>fix too long line<commit_after>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2015 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "ExpansionManager.h"

#include "MacroImportHelper.h"
#include "StaticStuff.h"

namespace CppImport {

ExpansionManager::ExpansionManager(ClangHelper* clang, AstMapping* astMapping, DefinitionManager* definitionManager,
											  LexicalHelper* lexicalHelper)
	: clang_(clang), astMapping_(astMapping), definitionManager_(definitionManager), lexicalHelper_(lexicalHelper) {}

void ExpansionManager::addMacroExpansion(clang::SourceRange sourceRange, const clang::MacroDirective* macroDirective,
													  const clang::MacroArgs* macroArguments)
{
	if (definitionManager_->isPartialEnd(macroDirective))
	{
		/*
		 * if the to be registered expansion's definition is a partial end macro then we are not going to generate a
		 * meta definition for this expansion.
		 * instead we remember that we are currently not in an xMacro body.
		 */
		currentXMacroParent = nullptr;
		return;
	}

	// build new macro expansion entry from the provided information
	auto entry = new MacroExpansion();
	entry->range = sourceRange;
	entry->definition = macroDirective;
	entry->parent = expansion(sourceRange.getBegin());
	if (entry->parent) entry->parent->children.append(entry);

	// handle xMacro data members
	if (definitionManager_->isPartialBegin(macroDirective) && !currentXMacroParent)
		/*
		 * if the definition of this expansion is a partial begin macro we remember that we are now in a xMacro body.
		 * we check whether we are not already in a xMacro body because we want to remember the .h part (the first one) of
		 * the xMacro begins (the potential .cpp part could overwrite the stored information otherwise).
		 */
		currentXMacroParent = entry;
	else if (currentXMacroParent && !entry->parent)
	{
		/*
		 * if we are in a xMacro body and the current expansion is not a top level expansion then this expansion is a
		 * xMacro child of the stored xMacro expansion.
		 */
		entry->xMacroParent = currentXMacroParent;
		currentXMacroParent->xMacroChildren.append(entry);
	}

	entry->metaCall =
			new OOModel::MetaCallExpression(definitionManager_->definitionName(entry->definition));

	// only function like macros have braces in their signature to parse
	if (!macroDirective->getMacroInfo()->isObjectLike())
	{
		// extract everything in parentheses of the expansion signature using a regular expression
		QRegularExpression regex ("\\((.*)\\)", QRegularExpression::DotMatchesEverythingOption);
		auto argumentsString = lexicalHelper_->unexpandedSpelling(sourceRange);
		auto match = regex.match(argumentsString);
		auto arguments = match.captured(1).split(",");

		// by default initialize meta call arguments to be reference expressions with the raw spelling at this expansion
		for (auto i = 0; i < clang_->argumentNames(entry->definition).size(); i++)
		{
			auto actualArg = macroArguments->getUnexpArgument((unsigned int)i);
			entry->metaCall->arguments()->append(new OOModel::ReferenceExpression(arguments[i]));
			entry->argumentLocs.append(actualArg->getLocation());
		}
	}

	expansions_.append(entry);
}

void ExpansionManager::clear()
{
	expansionCache_.clear();
	expansions_.clear();
}

QVector<MacroExpansion*> ExpansionManager::topLevelExpansions()
{
	QVector<MacroExpansion*> result;
	for (auto expansion : expansions_)
		if (!expansion->parent)
			result.append(expansion);

	return result;
}

MacroExpansion*ExpansionManager::expansion(clang::SourceLocation loc)
{
	MacroExpansion* expansion = immediateExpansion(loc);
	MacroExpansion* last = expansion;

	if (expansion)
	{
		do
		{
			last = expansion;
			loc = clang_->sourceManager()->getImmediateExpansionRange(loc).first;
			expansion = immediateExpansion(loc);
		} while (expansion && expansion->isChildOf(last));
	}

	return last;
}

MacroExpansion*ExpansionManager::immediateExpansion(clang::SourceLocation loc)
{
	auto expansion = clang_->immediateMacroLocation(loc);
	for (auto i = 0; i < expansions_.size(); i++)
		if (expansions_[i]->range.getBegin() == expansion) return expansions_[i];

	/*
	 * if we have not found an immediate expansion for loc then we try again using the found immediateExpansionLoc.
	 * this can happen in case of token concatenation or stringifycation where the first expansion location would point
	 * to the location of the concatenated token or stringifycation result.
	 */
	expansion = clang_->immediateMacroLocation(expansion);
	for (auto i = 0; i < expansions_.size(); i++)
		if (expansions_[i]->range.getBegin() == expansion) return expansions_[i];

	return nullptr;
}

QSet<MacroExpansion*> ExpansionManager::expansion(Model::Node* node)
{
	Q_ASSERT(node);

	if (!expansionCache_.contains(node))
	{
		expansionCache_[node] = {};

		if (auto n = astMapping_->closestParentWithAstMapping(node))
			if (astMapping_->contains(n))
				for (auto range : astMapping_->get(n))
				{
					auto exp = expansion(range.getBegin());
					if (exp)	expansionCache_[node].insert(exp);
				}
	}

	return expansionCache_[node];
}

QVector<Model::Node*> ExpansionManager::tLExpansionTLNodes(MacroExpansion* expansion)
{
	Q_ASSERT(expansion);
	Q_ASSERT(!expansion->parent); // ensure expansion is a top level expansion

	QVector<Model::Node*> allTLExpansionNodes;
	for (auto node : astMapping_->nodes())
		for (auto range : astMapping_->get(node))
			// for all mapped nodes check whether any of their ranges expand to the top level macro range
			if (clang_->sourceManager()->getExpansionLoc(range.getBegin()) == expansion->range.getBegin())
			{
				allTLExpansionNodes.append(node);
				break;
			}

	QVector<Model::Node*> result = StaticStuff::topLevelNodes(allTLExpansionNodes);
	StaticStuff::orderNodes(result);
	return result;
}

QVector<Model::Node*> ExpansionManager::nTLExpansionTLNodes(MacroExpansion* exp)
{
	Q_ASSERT(exp);

	QVector<Model::Node*> allNTLExpansionNodes;
	for (auto node : astMapping_->nodes())
		if (expansion(node).contains(exp))
			allNTLExpansionNodes.append(node);

	QVector<Model::Node*> result = StaticStuff::topLevelNodes(allNTLExpansionNodes);
	StaticStuff::orderNodes(result);
	return result;
}

}
<|endoftext|>


<commit_before>
#include "stdafx.h"

#include "bind2thread.h"
#include "taskify.h"

class test_taskify : public ::testing::Test {
protected:

	test_taskify()  {
	}
	virtual void SetUp() {
		thread.reset(new ThreadWithTasks());
	}
	virtual void TearDown() {
		tearDown();
	}
	void awaitTasksDone() {
		thread->sync().get();
	}
	void tearDown()	{
		thread->stop();
		if (thread->joinable()) {
			thread->join();
		}
	}
	TaskDispatcherPtr secondThread() const  {
		return thread->dispatcher();
	}

	// DATA

	std::shared_ptr<ThreadWithTasks> thread;

};

class TestTaskifyException : public std::exception {
public:
	TestTaskifyException(const char * what) : mWhat(what) {
	}
	virtual const char * what() const override {
		return mWhat;
	}
private:
	const char * mWhat;
};

//exception immediatelly
//translate error immediatelly->best practices to link own errors with exception system

static void async_file_sizes_cr( const std::function< void(int) >& foo, int size) {
	foo(size);
}

static void async_file_sizes( std::function< void(int) > foo, int size) {
	foo(size);
}

static void async_exception(std::function< void(int) > foo, const char* what ) {
	throw TestTaskifyException (what);
}

static void async_exception_ptr(std::function< void(int) > foo, std::function< void(const std::exception_ptr&) > onException, const char* what) {
	try {
		throw TestTaskifyException(what);
	}
	catch (...) {
		onException( std::current_exception());
	}
}

static void async_delayed_file_sizes(std::function< void(int) > foo, int size) {
	post2current( std::bind(foo, size));
}

static void async_delayed_file_sizes_2nd_thread( const TaskDispatcherPtr& workerThread, const std::function< void(int) >& foo, int size) {
	workerThread->postex( bind2current(foo, size));
}

TEST_F(test_taskify, callbackImmediately) {

	std::shared_ptr<TaskDispatcher4StdThread> dispatcher(TaskDispatcher4StdThread::create());

	post2current([dispatcher] {
		make_task([dispatcher]
		{
			Task< boost::future< std::tuple<int> > > t( taskify( async_file_sizes, placeholders::CALLBACK, 3 ));
			size_t sizes = std::get<0>( t.get());
			EXPECT_EQ(sizes, 3);
			dispatcher->stop();
		}
		);
	});

	dispatcher->run();

}

TEST_F(test_taskify, callbackDelayed ) {

	std::shared_ptr<TaskDispatcher4StdThread> dispatcher(TaskDispatcher4StdThread::create());

	post2current([dispatcher] {
		make_task([dispatcher]
		{
			Task< boost::future< std::tuple<int> > > t(taskify(async_delayed_file_sizes, placeholders::CALLBACK, 4));
			size_t sizes = std::get<0>(t.get());
			EXPECT_EQ(sizes, 4);
			dispatcher->stop();
		}
		);
	});

	dispatcher->run();

}

TEST_F(test_taskify, callbackFrom2ndThread ) {

	std::shared_ptr<TaskDispatcher4StdThread> dispatcher(TaskDispatcher4StdThread::create());
	TaskDispatcherPtr secondThread = this->secondThread();

	post2current([dispatcher, secondThread] {
		make_task([dispatcher, secondThread]
		{
			Task< boost::future< std::tuple<int> > > t( taskify( async_delayed_file_sizes_2nd_thread, secondThread, placeholders::CALLBACK, 4));
			size_t sizes = std::get<0>(t.get());
			EXPECT_EQ(sizes, 4);
			dispatcher->stop();
		}
		);
	});

	dispatcher->run();

}

TEST_F(test_taskify, exceptionImmediately) {

	std::shared_ptr<TaskDispatcher4StdThread> dispatcher(TaskDispatcher4StdThread::create());

	post2current([dispatcher] {
		make_task([dispatcher]
		{
			const char *resultingWhat = 0;
			std::exception r;
			try
			{
				Task< boost::future< std::tuple<int> > > t(taskify(async_exception, placeholders::CALLBACK, "exceptionImmediately"));
				size_t sizes = std::get<0>(t.get());
			}
			catch (std::exception& e)
			{
				resultingWhat = e.what();
			}
			EXPECT_EQ( std::string(resultingWhat), std::string("exceptionImmediately"));
			dispatcher->stop();
		}
		);
	});

	dispatcher->run();

}

TEST_F(test_taskify, exceptionWithinCallback ) {

	std::shared_ptr<TaskDispatcher4StdThread> dispatcher(TaskDispatcher4StdThread::create());

	post2current([dispatcher] {
		make_task([dispatcher]
		{
			const char *resultingWhat = 0;
			auto&& t( taskify( async_exception_ptr, placeholders::CALLBACK, placeholders::EXCEPTION_PTR, "exceptionWithinCallback" ));
			try
			{
				t.get();
			}
			catch (std::exception& e)
			{
				resultingWhat = e.what();
			}
			EXPECT_EQ(std::string(resultingWhat), std::string("exceptionWithinCallback"));
			dispatcher->stop();
		}
		);
	});

	dispatcher->run();

}

<commit_msg>compile fix for gcc<commit_after>
#include "stdafx.h"

#include "bind2thread.h"
#include "taskify.h"

class test_taskify : public ::testing::Test {
protected:

	test_taskify()  {
	}
	virtual void SetUp() {
		thread.reset(new ThreadWithTasks());
	}
	virtual void TearDown() {
		tearDown();
	}
	void awaitTasksDone() {
		thread->sync().get();
	}
	void tearDown()	{
		thread->stop();
		if (thread->joinable()) {
			thread->join();
		}
	}
	TaskDispatcherPtr secondThread() const  {
		return thread->dispatcher();
	}

	// DATA

	std::shared_ptr<ThreadWithTasks> thread;

};

class TestTaskifyException : public std::exception {
public:
	TestTaskifyException(const char * what) : mWhat(what) {
	}
#ifdef _GLIBCXX_USE_NOEXCEPT
	virtual const char * what() const _GLIBCXX_USE_NOEXCEPT override{
#else
	virtual const char * what() const override {
#endif
		return mWhat;
	}
private:
	const char * mWhat;
};

//exception immediatelly
//translate error immediatelly->best practices to link own errors with exception system

static void async_file_sizes_cr( const std::function< void(int) >& foo, int size) {
	foo(size);
}

static void async_file_sizes( std::function< void(int) > foo, int size) {
	foo(size);
}

static void async_exception(std::function< void(int) > foo, const char* what ) {
	throw TestTaskifyException (what);
}

static void async_exception_ptr(std::function< void(int) > foo, std::function< void(const std::exception_ptr&) > onException, const char* what) {
	try {
		throw TestTaskifyException(what);
	}
	catch (...) {
		onException( std::current_exception());
	}
}

static void async_delayed_file_sizes(std::function< void(int) > foo, int size) {
	post2current( std::bind(foo, size));
}

static void async_delayed_file_sizes_2nd_thread( const TaskDispatcherPtr& workerThread, const std::function< void(int) >& foo, int size) {
	workerThread->postex( bind2current(foo, size));
}

TEST_F(test_taskify, callbackImmediately) {

	std::shared_ptr<TaskDispatcher4StdThread> dispatcher(TaskDispatcher4StdThread::create());

	post2current([dispatcher] {
		make_task([dispatcher]
		{
			Task< boost::future< std::tuple<int> > > t( taskify( async_file_sizes, placeholders::CALLBACK, 3 ));
			size_t sizes = std::get<0>( t.get());
			EXPECT_EQ(sizes, 3);
			dispatcher->stop();
		}
		);
	});

	dispatcher->run();

}

TEST_F(test_taskify, callbackDelayed ) {

	std::shared_ptr<TaskDispatcher4StdThread> dispatcher(TaskDispatcher4StdThread::create());

	post2current([dispatcher] {
		make_task([dispatcher]
		{
			Task< boost::future< std::tuple<int> > > t(taskify(async_delayed_file_sizes, placeholders::CALLBACK, 4));
			size_t sizes = std::get<0>(t.get());
			EXPECT_EQ(sizes, 4);
			dispatcher->stop();
		}
		);
	});

	dispatcher->run();

}

TEST_F(test_taskify, callbackFrom2ndThread ) {

	std::shared_ptr<TaskDispatcher4StdThread> dispatcher(TaskDispatcher4StdThread::create());
	TaskDispatcherPtr secondThread = this->secondThread();

	post2current([dispatcher, secondThread] {
		make_task([dispatcher, secondThread]
		{
			Task< boost::future< std::tuple<int> > > t( taskify( async_delayed_file_sizes_2nd_thread, secondThread, placeholders::CALLBACK, 4));
			size_t sizes = std::get<0>(t.get());
			EXPECT_EQ(sizes, 4);
			dispatcher->stop();
		}
		);
	});

	dispatcher->run();

}

TEST_F(test_taskify, exceptionImmediately) {

	std::shared_ptr<TaskDispatcher4StdThread> dispatcher(TaskDispatcher4StdThread::create());

	post2current([dispatcher] {
		make_task([dispatcher]
		{
			const char *resultingWhat = 0;
			std::exception r;
			try
			{
				Task< boost::future< std::tuple<int> > > t(taskify(async_exception, placeholders::CALLBACK, "exceptionImmediately"));
				size_t sizes = std::get<0>(t.get());
			}
			catch (std::exception& e)
			{
				resultingWhat = e.what();
			}
			EXPECT_EQ( std::string(resultingWhat), std::string("exceptionImmediately"));
			dispatcher->stop();
		}
		);
	});

	dispatcher->run();

}

TEST_F(test_taskify, exceptionWithinCallback ) {

	std::shared_ptr<TaskDispatcher4StdThread> dispatcher(TaskDispatcher4StdThread::create());

	post2current([dispatcher] {
		make_task([dispatcher]
		{
			const char *resultingWhat = 0;
			auto&& t( taskify( async_exception_ptr, placeholders::CALLBACK, placeholders::EXCEPTION_PTR, "exceptionWithinCallback" ));
			try
			{
				t.get();
			}
			catch (std::exception& e)
			{
				resultingWhat = e.what();
			}
			EXPECT_EQ(std::string(resultingWhat), std::string("exceptionWithinCallback"));
			dispatcher->stop();
		}
		);
	});

	dispatcher->run();

}

<|endoftext|>


<commit_before>#pragma once

#include <unordered_map>
#include <memory>
#include <type_traits>
#include <tuple>

namespace kgr {

template<typename... Types>
struct Dependency {
	using DependenciesTypes = std::tuple<Types...>;
};

using NoDependencies = Dependency<>;

struct Single {
	using ParentTypes = std::tuple<>;
};

template<typename T>
struct Service;

template<typename... Types>
struct Overrides : Single {
	using ParentTypes = std::tuple<Types...>;
};

namespace detail {

template<int ...>
struct seq { };

template<int N, int ...S>
struct seq_gen : seq_gen<N-1, N-1, S...> { };

template<int ...S>
struct seq_gen<0, S...> {
	using type = seq<S...>;
};

template <typename Tuple>
using tuple_seq = typename seq_gen<std::tuple_size<Tuple>::value>::type;

template <bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::type;

struct Holder {
	virtual ~Holder() {

	}
};

template<typename T>
struct InstanceHolder : Holder {
	InstanceHolder(std::shared_ptr<T> instance) : _instance{instance} {}

	std::shared_ptr<T> getInstance() const {
		return _instance;
	}

private:
	std::shared_ptr<T> _instance;
};

template<typename T, typename... Args>
struct CallbackHolder : Holder {
	using callback_t = std::function<std::shared_ptr<T>(Args...)>;

	CallbackHolder(callback_t callback) : _callback{callback} {}

	callback_t getCallback() const {
		return _callback;
	}
private:
	callback_t _callback;
};

}  // namespace detail

struct Container : std::enable_shared_from_this<Container> {
	template<typename T>
	void instance(std::shared_ptr<T> service) {
		static_assert(std::is_base_of<Single, Service<T>>::value, "instance only accept Single Service instance.");
		call_save_instance(service, detail::tuple_seq<typename Service<T>::ParentTypes>{});
	}

	template<typename T>
	void instance() {
		static_assert(std::is_base_of<Single, Service<T>>::value, "instance only accept Single Service instance.");
		using DependenciesTypes = typename Service<T>::DependenciesTypes;
		auto dependencies = dependency<DependenciesTypes>(detail::tuple_seq<DependenciesTypes>{});
		instance(make_service<T>(detail::tuple_seq<DependenciesTypes>{}, dependencies));
	}

	template<typename T>
	detail::enable_if_t<(!std::is_abstract<T>::value && !std::is_base_of<Container, T>::value), std::shared_ptr<T>> service() {
		return get_service<T>();
	}

	template<typename T>
	detail::enable_if_t<(std::is_same<T, Container>::value), std::shared_ptr<T>> service() {
		return shared_from_this();
	}

	template<typename T>
	detail::enable_if_t<(std::is_base_of<Container, T>::value && !std::is_same<T, Container>::value), std::shared_ptr<T>> service() {
		auto service = std::dynamic_pointer_cast<T>(shared_from_this());
		if (service) {
			return service;
		} else {
			return nullptr;
		}
	}

	template<typename T>
	detail::enable_if_t<std::is_abstract<T>::value, std::shared_ptr<T>> service() {
		auto it = _services.find(typeid(T).name());
		if (it != _services.end()) {
			auto holder = dynamic_cast<detail::InstanceHolder<T>*>(it->second.get());
			if (holder) {
				return holder->getInstance();
			}
		}
		return nullptr;
	}

	template<typename T, typename U>
	void callback(U callback) {
		static_assert(!std::is_base_of<Single, Service<T>>::value, "instance does not accept Single Service.");
		using DependenciesTypes = typename Service<T>::DependenciesTypes;
		save_callback<T, DependenciesTypes>(detail::tuple_seq<DependenciesTypes>{}, callback);
	}

	virtual void init(){}

private:
	template<typename T>
	detail::enable_if_t<std::is_base_of<Single, Service<T>>::value, std::shared_ptr<T>> get_service() {
		using DependenciesTypes = typename Service<T>::DependenciesTypes;
		auto it = _services.find(typeid(T).name());
		if (it == _services.end()) {
			auto dependencies = dependency<DependenciesTypes>(detail::tuple_seq<DependenciesTypes>{});
			auto service = make_service<T>(detail::tuple_seq<DependenciesTypes>{}, dependencies);
			instance(service);
			return service;
		} else {
			auto holder = dynamic_cast<detail::InstanceHolder<T>*>(it->second.get());
			if (holder) {
				return holder->getInstance();
			} else {
				return nullptr;
			}
		}
	}

	template<typename T>
	detail::enable_if_t<!std::is_base_of<Single, Service<T>>::value, std::shared_ptr<T>> get_service() {
		using DependenciesTypes = typename Service<T>::DependenciesTypes;
		auto dependencies = dependency<DependenciesTypes>(detail::tuple_seq<DependenciesTypes>{});
		auto service = make_service<T>(detail::tuple_seq<DependenciesTypes>{}, dependencies);

		return service;
	}

	template<typename T, int ...S>
	void call_save_instance(std::shared_ptr<T> service, detail::seq<S...>) {
		save_instance<T, typename std::tuple_element<S, typename Service<T>::ParentTypes>::type...>(service);
	}

	template<typename Tuple, int ...S>
	std::tuple<std::shared_ptr<typename std::tuple_element<S, Tuple>::type>...> dependency(detail::seq<S...>) {
		return std::make_tuple(service<typename std::tuple_element<S, Tuple>::type>()...);
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> callback_make_service(detail::seq<S...> seq, Tuple dependencies) const {
		auto it = _callbacks.find(typeid(T).name());
		if (it != _callbacks.end()) {
			auto holder = dynamic_cast<detail::CallbackHolder<T, typename std::tuple_element<S, Tuple>::type...>*>(it->second.get());
			if (holder) {
				return holder->getCallback()(std::get<S>(dependencies)...);
			}
		}
		return nullptr;
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> make_service(detail::seq<S...> seq, Tuple dependencies) const {
		auto service = callback_make_service<T, Tuple>(seq, dependencies);
		if (service) {
			return service;
		}
		return std::make_shared<T>(std::get<S>(dependencies)...);
	}

	template<typename T, typename ...Others>
	detail::enable_if_t<(sizeof...(Others) > 0), void> save_instance(std::shared_ptr<T> service) {
		save_instance<T>(service);
		save_instance<Others...>(service);
	}

	template<typename T>
	void save_instance (std::shared_ptr<T> service) {
		_services[typeid(T).name()] = std::unique_ptr<detail::InstanceHolder<T>>(new detail::InstanceHolder<T>(service));
	}

	template<typename T, typename Tuple, int ...S, typename U>
	void save_callback (detail::seq<S...>, U callback) {
		_callbacks[typeid(T).name()] = std::unique_ptr<detail::CallbackHolder<T, std::shared_ptr<typename std::tuple_element<S, Tuple>::type>...>>(new detail::CallbackHolder<T, std::shared_ptr<typename std::tuple_element<S, Tuple>::type>...>(callback));
	}

	std::unordered_map<std::string, std::unique_ptr<detail::Holder>> _callbacks;
	std::unordered_map<std::string, std::unique_ptr<detail::Holder>> _services;
};

template<typename T = Container, typename ...Args>
std::shared_ptr<T> make_container(Args&& ...args) {
	static_assert(std::is_base_of<Container, T>::value, "make_container only accept container types.");
	auto container = std::make_shared<T>(std::forward<Args>(args)...);
	container->init();
	return container;
}

}  // namespace kgr

<commit_msg>Remove check for service<commit_after>#pragma once

#include <unordered_map>
#include <memory>
#include <type_traits>
#include <tuple>

namespace kgr {

template<typename... Types>
struct Dependency {
	using DependenciesTypes = std::tuple<Types...>;
};

using NoDependencies = Dependency<>;

struct Single {
	using ParentTypes = std::tuple<>;
};

template<typename T>
struct Service;

template<typename... Types>
struct Overrides : Single {
	using ParentTypes = std::tuple<Types...>;
};

namespace detail {

template<int ...>
struct seq { };

template<int N, int ...S>
struct seq_gen : seq_gen<N-1, N-1, S...> { };

template<int ...S>
struct seq_gen<0, S...> {
	using type = seq<S...>;
};

template <typename Tuple>
using tuple_seq = typename seq_gen<std::tuple_size<Tuple>::value>::type;

template <bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::type;

struct Holder {
	virtual ~Holder() {

	}
};

template<typename T>
struct InstanceHolder : Holder {
	InstanceHolder(std::shared_ptr<T> instance) : _instance{instance} {}

	std::shared_ptr<T> getInstance() const {
		return _instance;
	}

private:
	std::shared_ptr<T> _instance;
};

template<typename T, typename... Args>
struct CallbackHolder : Holder {
	using callback_t = std::function<std::shared_ptr<T>(Args...)>;

	CallbackHolder(callback_t callback) : _callback{callback} {}

	callback_t getCallback() const {
		return _callback;
	}
private:
	callback_t _callback;
};

}  // namespace detail

struct Container : std::enable_shared_from_this<Container> {
	template<typename T>
	void instance(std::shared_ptr<T> service) {
		static_assert(std::is_base_of<Single, Service<T>>::value, "instance only accept Single Service instance.");
		call_save_instance(service, detail::tuple_seq<typename Service<T>::ParentTypes>{});
	}

	template<typename T>
	void instance() {
		static_assert(std::is_base_of<Single, Service<T>>::value, "instance only accept Single Service instance.");
		using DependenciesTypes = typename Service<T>::DependenciesTypes;
		auto dependencies = dependency<DependenciesTypes>(detail::tuple_seq<DependenciesTypes>{});
		instance(make_service<T>(detail::tuple_seq<DependenciesTypes>{}, dependencies));
	}

	template<typename T>
	detail::enable_if_t<(!std::is_abstract<T>::value && !std::is_base_of<Container, T>::value), std::shared_ptr<T>> service() {
		return get_service<T>();
	}

	template<typename T>
	detail::enable_if_t<(std::is_same<T, Container>::value), std::shared_ptr<T>> service() {
		return shared_from_this();
	}

	template<typename T>
	detail::enable_if_t<(std::is_base_of<Container, T>::value && !std::is_same<T, Container>::value), std::shared_ptr<T>> service() {
		return std::dynamic_pointer_cast<T>(shared_from_this());
	}

	template<typename T>
	detail::enable_if_t<std::is_abstract<T>::value, std::shared_ptr<T>> service() {
		auto it = _services.find(typeid(T).name());
		if (it != _services.end()) {
			auto holder = dynamic_cast<detail::InstanceHolder<T>*>(it->second.get());
			if (holder) {
				return holder->getInstance();
			}
		}
		return nullptr;
	}

	template<typename T, typename U>
	void callback(U callback) {
		static_assert(!std::is_base_of<Single, Service<T>>::value, "instance does not accept Single Service.");
		using DependenciesTypes = typename Service<T>::DependenciesTypes;
		save_callback<T, DependenciesTypes>(detail::tuple_seq<DependenciesTypes>{}, callback);
	}

	virtual void init(){}

private:
	template<typename T>
	detail::enable_if_t<std::is_base_of<Single, Service<T>>::value, std::shared_ptr<T>> get_service() {
		using DependenciesTypes = typename Service<T>::DependenciesTypes;
		auto it = _services.find(typeid(T).name());
		if (it == _services.end()) {
			auto dependencies = dependency<DependenciesTypes>(detail::tuple_seq<DependenciesTypes>{});
			auto service = make_service<T>(detail::tuple_seq<DependenciesTypes>{}, dependencies);
			instance(service);
			return service;
		} else {
			auto holder = dynamic_cast<detail::InstanceHolder<T>*>(it->second.get());
			if (holder) {
				return holder->getInstance();
			} else {
				return nullptr;
			}
		}
	}

	template<typename T>
	detail::enable_if_t<!std::is_base_of<Single, Service<T>>::value, std::shared_ptr<T>> get_service() {
		using DependenciesTypes = typename Service<T>::DependenciesTypes;
		auto dependencies = dependency<DependenciesTypes>(detail::tuple_seq<DependenciesTypes>{});
		auto service = make_service<T>(detail::tuple_seq<DependenciesTypes>{}, dependencies);

		return service;
	}

	template<typename T, int ...S>
	void call_save_instance(std::shared_ptr<T> service, detail::seq<S...>) {
		save_instance<T, typename std::tuple_element<S, typename Service<T>::ParentTypes>::type...>(service);
	}

	template<typename Tuple, int ...S>
	std::tuple<std::shared_ptr<typename std::tuple_element<S, Tuple>::type>...> dependency(detail::seq<S...>) {
		return std::make_tuple(service<typename std::tuple_element<S, Tuple>::type>()...);
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> callback_make_service(detail::seq<S...> seq, Tuple dependencies) const {
		auto it = _callbacks.find(typeid(T).name());
		if (it != _callbacks.end()) {
			auto holder = dynamic_cast<detail::CallbackHolder<T, typename std::tuple_element<S, Tuple>::type...>*>(it->second.get());
			if (holder) {
				return holder->getCallback()(std::get<S>(dependencies)...);
			}
		}
		return nullptr;
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> make_service(detail::seq<S...> seq, Tuple dependencies) const {
		auto service = callback_make_service<T, Tuple>(seq, dependencies);
		if (service) {
			return service;
		}
		return std::make_shared<T>(std::get<S>(dependencies)...);
	}

	template<typename T, typename ...Others>
	detail::enable_if_t<(sizeof...(Others) > 0), void> save_instance(std::shared_ptr<T> service) {
		save_instance<T>(service);
		save_instance<Others...>(service);
	}

	template<typename T>
	void save_instance (std::shared_ptr<T> service) {
		_services[typeid(T).name()] = std::unique_ptr<detail::InstanceHolder<T>>(new detail::InstanceHolder<T>(service));
	}

	template<typename T, typename Tuple, int ...S, typename U>
	void save_callback (detail::seq<S...>, U callback) {
		_callbacks[typeid(T).name()] = std::unique_ptr<detail::CallbackHolder<T, std::shared_ptr<typename std::tuple_element<S, Tuple>::type>...>>(new detail::CallbackHolder<T, std::shared_ptr<typename std::tuple_element<S, Tuple>::type>...>(callback));
	}

	std::unordered_map<std::string, std::unique_ptr<detail::Holder>> _callbacks;
	std::unordered_map<std::string, std::unique_ptr<detail::Holder>> _services;
};

template<typename T = Container, typename ...Args>
std::shared_ptr<T> make_container(Args&& ...args) {
	static_assert(std::is_base_of<Container, T>::value, "make_container only accept container types.");
	auto container = std::make_shared<T>(std::forward<Args>(args)...);
	container->init();
	return container;
}

}  // namespace kgr

<|endoftext|>