Code::Blocks  SVN r11506
sc_plugin.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
3  * http://www.gnu.org/licenses/lgpl-3.0.html
4  *
5  * $Revision: 9419 $
6  * $Id: sc_plugin.cpp 9419 2013-10-24 15:54:57Z alpha0010 $
7  * $HeadURL: https://svn.code.sf.net/p/codeblocks/code/trunk/src/sdk/scripting/bindings/sc_plugin.cpp $
8  */
9 
10 #include <sdk_precomp.h>
11 #include "sc_plugin.h"
12 #include <manager.h>
13 #include <scriptingmanager.h>
14 #include <wx/menu.h>
15 
16 #include <map>
17 
18 namespace ScriptBindings {
19 namespace ScriptPluginWrapper {
20 
21 // struct and map for mapping script plugins to menu callbacks
23 {
24  SquirrelObject object;
25  int menuIndex;
26 };
27 typedef std::map<int, MenuCallback> ModuleMenuCallbacks;
28 ModuleMenuCallbacks s_MenuCallbacks;
29 
30 // master list of registered script plugins
31 typedef std::map<wxString, SquirrelObject> ScriptPlugins;
32 ScriptPlugins s_ScriptPlugins;
33 
34 // list of registered script plugins menubar items
35 typedef std::map<wxString, MenuItemsManager> ScriptPluginsMenus;
36 ScriptPluginsMenus s_ScriptPluginsMenus;
37 
39 // ask the script plugin what menus to add in the menubar
40 // and return an integer array of the menu IDs
43 {
44  wxArrayInt ret;
45 
46  ScriptPlugins::iterator it = s_ScriptPlugins.find(name);
47  if (it == s_ScriptPlugins.end())
48  return ret;
49  SquirrelObject& o = it->second;
50 
51  ScriptPluginsMenus::iterator itm = s_ScriptPluginsMenus.find(name);
52  if (itm == s_ScriptPluginsMenus.end())
53  {
54  itm = s_ScriptPluginsMenus.insert(s_ScriptPluginsMenus.end(), std::make_pair(name, MenuItemsManager(false)));
55  }
56  MenuItemsManager& mi = itm->second;
57 
58  SqPlus::SquirrelFunction<wxArrayString&> f(o, "GetMenu");
59  if (f.func.IsNull())
60  return ret;
61 
62  wxArrayString arr;
63  try
64  {
65  arr = f();
66  }
67  catch (SquirrelError e)
68  {
69  cbMessageBox(cbC2U(e.desc), _("Script error"), wxICON_ERROR);
70  return ret;
71  }
72 
73  if (arr.GetCount())
74  {
75  for (size_t i = 0; i < arr.GetCount(); ++i)
76  {
77  int id = wxNewId();
78  id = mi.CreateFromString(arr[i], id);
79 
80  ret.Add(id);
81 
82  MenuCallback callback;
83  callback.object = it->second;
84  callback.menuIndex = i;
85 
86  ModuleMenuCallbacks::iterator mmcIt = s_MenuCallbacks.find(id);
87  if (mmcIt == s_MenuCallbacks.end())
88  s_MenuCallbacks.insert(s_MenuCallbacks.end(), std::make_pair(id, callback));
89  else
90  {
91  s_MenuCallbacks.erase(mmcIt);
92  s_MenuCallbacks.insert(s_MenuCallbacks.end(), std::make_pair(id, callback));
93  }
94  }
95  }
96 
97  return ret;
98 }
99 
101 // ask the script plugin what items to add in the context menu
102 // and return an integer array of the menu IDs
105 {
106  wxArrayInt ret;
107 
108  ScriptPlugins::iterator it;
109  for (it = s_ScriptPlugins.begin(); it != s_ScriptPlugins.end(); ++it)
110  {
111  SquirrelObject& o = it->second;
112  SqPlus::SquirrelFunction<wxArrayString&> f(o, "GetModuleMenu");
113  if (f.func.IsNull())
114  continue;
115 
116  wxArrayString arr;
117  try
118  {
119  arr = f(typ, data);
120  }
121  catch (SquirrelError e)
122  {
123  cbMessageBox(cbC2U(e.desc), _("Script error"), wxICON_ERROR);
124  continue;
125  }
126 
127  if (arr.GetCount()==1) // exactly one menu entry
128  {
129  int id = wxNewId();
130  menu->Append(id, arr[0]);
131  ret.Add(id);
132 
133  MenuCallback callback;
134  callback.object = it->second;
135  callback.menuIndex = 0;
136  s_MenuCallbacks.insert(s_MenuCallbacks.end(), std::make_pair(id, callback));
137  }
138  else if (arr.GetCount()>1) // more menu entries -> create sub-menu
139  {
140  wxMenu* sub = new wxMenu;
141  for (size_t i = 0; i < arr.GetCount(); ++i)
142  {
143  int id = wxNewId();
144  sub->Append(id, arr[i]);
145 
146  ret.Add(id);
147 
148  MenuCallback callback;
149  callback.object = it->second;
150  callback.menuIndex = i;
151  s_MenuCallbacks.insert(s_MenuCallbacks.end(), std::make_pair(id, callback));
152  }
153  menu->Append(-1, it->first, sub);
154  }
155  }
156  return ret;
157 }
158 
160 // callback for script plugins menubar entries
162 void OnScriptMenu(int id)
163 {
164  ModuleMenuCallbacks::iterator it;
165  it = s_MenuCallbacks.find(id);
166  if (it != s_MenuCallbacks.end())
167  {
168  MenuCallback& callback = it->second;
169  SqPlus::SquirrelFunction<void> f(callback.object, "OnMenuClicked");
170  if (!f.func.IsNull())
171  {
172  try
173  {
174  f(callback.menuIndex);
175  }
176  catch (SquirrelError e)
177  {
178  cbMessageBox(cbC2U(e.desc), _("Script error"), wxICON_ERROR);
179  }
180  }
181  }
182 }
183 
185 // callback for script plugins context menu entries
187 void OnScriptModuleMenu(int id)
188 {
189  ModuleMenuCallbacks::iterator it;
190  it = s_MenuCallbacks.find(id);
191  if (it != s_MenuCallbacks.end())
192  {
193  MenuCallback& callback = it->second;
194  SqPlus::SquirrelFunction<void> f(callback.object, "OnModuleMenuClicked");
195  if (!f.func.IsNull())
196  {
197  try
198  {
199  f(callback.menuIndex);
200  }
201  catch (SquirrelError e)
202  {
203  cbMessageBox(cbC2U(e.desc), _("Script error"), wxICON_ERROR);
204  }
205  }
206  }
207 }
208 
210 // register a script plugin (script-bound function)
212 SQInteger RegisterPlugin(HSQUIRRELVM v)
213 {
214  // get squirrel object to register from stack
215  SquirrelObject o;
216  o.AttachToStackObject(2);
217 
218  // first verify that there is a member function to retrieve the plugin info
219  if (!o.Exists("GetPluginInfo"))
220  return sq_throwerror(v, "Not a script plugin!");
221 
222  // ask for its registration name
223  SqPlus::SquirrelFunction<PluginInfo&> f(o, "GetPluginInfo");
224  PluginInfo& info = f();
225  wxString s = info.name;
226 
227  // look if a script plugin with the same name already exists
228  ScriptPlugins::iterator it = s_ScriptPlugins.find(s);
229  if (it != s_ScriptPlugins.end())
230  {
231  // already exists; release the old one
232  s_ScriptPlugins.erase(it);
233  Manager::Get()->GetLogManager()->Log(_("Script plugin unregistered: ") + s);
234  }
235 
236  // finally, register this script plugin
237  it = s_ScriptPlugins.insert(s_ScriptPlugins.end(), std::make_pair(s, o));
238  Manager::Get()->GetLogManager()->Log(_("Script plugin registered: ") + s);
239 
241 
242  // this function returns nothing on the squirrel stack
243  return 0;
244 }
245 
247 // get a script plugin squirrel object (script-bound function)
249 SQInteger GetPlugin(HSQUIRRELVM v)
250 {
251  StackHandler sa(v);
252 
253  // get the script plugin's name
254  const wxString& name = *SqPlus::GetInstance<wxString,false>(v, 2);
255 
256  // search for it in the registered script plugins list
257  ScriptPlugins::iterator it = s_ScriptPlugins.find(name);
258  if (it != s_ScriptPlugins.end())
259  {
260  // found; return the squirrel object
261  return sa.Return(it->second);
262  }
263 
264  // not found; return nothing
265  return sa.Return();
266 }
267 
269 // execute a script plugin (script-bound function)
271 int ExecutePlugin(const wxString& name)
272 {
273  // look for script plugin
274  ScriptPlugins::iterator it = s_ScriptPlugins.find(name);
275  if (it != s_ScriptPlugins.end())
276  {
277  // found; execute it
278  SquirrelObject& o = it->second;
279  SqPlus::SquirrelFunction<int> f(o, "Execute");
280  if (!f.func.IsNull())
281  {
282  try
283  {
284  f();
285  }
286  catch (SquirrelError e)
287  {
288  cbMessageBox(cbC2U(e.desc), _("Script error"), wxICON_ERROR);
289  }
290  }
291  }
292  return -1;
293 }
294 
295 }; // namespace ScriptPluginWrapper
296 
297 // base script plugin class
298 const char* s_cbScriptPlugin =
299  "class cbScriptPlugin\n"
300  "{\n"
301  " info = PluginInfo();\n"
302  " constructor()\n"
303  " {\n"
304  " info.name = _T(\"cbScriptPlugin\");\n"
305  " info.title = _T(\"Base script plugin\");\n"
306  " info.version = _T(\"0.1a\");\n"
307  " info.license = _T(\"GPL\");\n"
308  " }\n"
309  " function GetPluginInfo()\n"
310  " {\n"
311  " return info;\n"
312  " }\n"
313  " function GetMenu()\n"
314  " {\n"
315  " return wxArrayString();\n"
316  " }\n"
317  " function GetModuleMenu(who,data)\n"
318  " {\n"
319  " return wxArrayString();\n"
320  " }\n"
321  " function Execute()\n"
322  " {\n"
323  " LogDebug(info.name + _T(\"::Run() : not implemented\"));\n"
324  " return -1;\n"
325  " }\n"
326  " function OnMenuClicked(index)\n"
327  " {\n"
328  " LogDebug(info.name + _T(\": menu clicked: \") + index);\n"
329  " }\n"
330  " function OnModuleMenuClicked(index)\n"
331  " {\n"
332  " LogDebug(info.name + _T(\": module menu clicked: \") + index);\n"
333  " }\n"
334  "}\n";
335 
337 // register the script plugin framework
340 {
341  SqPlus::RegisterGlobal(&ScriptPluginWrapper::ExecutePlugin, "ExecutePlugin");
342  SquirrelVM::CreateFunctionGlobal(&ScriptPluginWrapper::GetPlugin, "GetPlugin", "*");
343  SquirrelVM::CreateFunctionGlobal(&ScriptPluginWrapper::RegisterPlugin, "RegisterPlugin", "*");
344 
345  // load base script plugin
346 
347  // WARNING: we CANNOT use ScriptingManager::LoadBuffer() because we have reached here
348  // by a call from inside ScriptingManager's constructor. This would cause an infinite
349  // loop and the app would die with a stack overflow. We got to load the script manually...
350  // we also have to disable the printfunc for a while
351 
352  SQPRINTFUNCTION oldPrintFunc = sq_getprintfunc(SquirrelVM::GetVMPtr());
353  sq_setprintfunc(SquirrelVM::GetVMPtr(), 0);
354 
355  // compile and run script
356  SquirrelObject script;
357  try
358  {
359  script = SquirrelVM::CompileBuffer(s_cbScriptPlugin, "cbScriptPlugin");
360  SquirrelVM::RunScript(script);
361  }
362  catch (SquirrelError e)
363  {
364  cbMessageBox(wxString::Format(_("Failed to register script plugins framework.\n\n%s"),
365  cbC2U(e.desc).c_str()),
366  _("Script compile error"), wxICON_ERROR);
367  }
368 
369  // restore the printfunc
370  sq_setprintfunc(SquirrelVM::GetVMPtr(), oldPrintFunc);
371 }
372 
373 }; // namespace ScriptBindings
374 
wxString name
Definition: pluginmanager.h:40
ScriptPluginsMenus s_ScriptPluginsMenus
Definition: sc_plugin.cpp:36
int wxNewId()
static Manager * Get()
Use Manager::Get() to get a pointer to its instance Manager::Get() is guaranteed to never return an i...
Definition: manager.cpp:182
SQInteger GetPlugin(HSQUIRRELVM v)
Definition: sc_plugin.cpp:249
Information about the plugin.
Definition: pluginmanager.h:38
std::map< wxString, SquirrelObject > ScriptPlugins
Definition: sc_plugin.cpp:31
#define wxICON_ERROR
SQRESULT sq_throwerror(HSQUIRRELVM v, const SQChar *err)
Definition: sqapi.cpp:918
int ExecutePlugin(const wxString &name)
Definition: sc_plugin.cpp:271
const char * s_cbScriptPlugin
Definition: sc_plugin.cpp:298
wxArrayInt CreateMenu(wxMenuBar *mbar)
wxCStrData c_str() const
wxMenuItem * Append(int id, const wxString &item=wxEmptyString, const wxString &helpString=wxEmptyString, wxItemKind kind=wxITEM_NORMAL)
std::map< wxString, MenuItemsManager > ScriptPluginsMenus
Definition: sc_plugin.cpp:35
virtual int CreateFromString(const wxString &menuPath, int id)
Create menu path from string.
size_t find(const wxString &str, size_t nStart=0) const
std::map< int, MenuCallback > ModuleMenuCallbacks
Definition: sc_plugin.cpp:27
ModuleType
The type of module offering a context menu.
Definition: globals.h:38
DLLIMPORT wxString cbC2U(const char *str)
Return str as a proper unicode-compatible string.
Definition: globals.cpp:733
SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v)
Definition: sqapi.cpp:1254
Manager for wxMenuItem pointers.
LogManager * GetLogManager() const
Definition: manager.cpp:439
const wxString & _(const wxString &string)
ModuleMenuCallbacks s_MenuCallbacks
Definition: sc_plugin.cpp:28
wxArray< int > wxArrayInt
void Log(const wxString &msg, int i=app_log, Logger::level lv=Logger::info)
Definition: logmanager.h:140
void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc)
Definition: sqapi.cpp:1249
bool RegisterScriptPlugin(const wxString &name, const wxArrayInt &ids)
Registers a script plugin menu IDs with the callback function.
void Register_ScriptPlugin()
Definition: sc_plugin.cpp:339
size_t GetCount() const
wxArrayInt CreateModuleMenu(const ModuleType type, wxMenu *menu, const FileTreeData *data)
Definition: sc_plugin.cpp:104
ScriptingManager * GetScriptingManager() const
Definition: manager.cpp:469
SQInteger RegisterPlugin(HSQUIRRELVM v)
Definition: sc_plugin.cpp:212
static wxString Format(const wxString &format,...)
DLLIMPORT int cbMessageBox(const wxString &message, const wxString &caption=wxEmptyString, int style=wxOK, wxWindow *parent=NULL, int x=-1, int y=-1)
wxMessageBox wrapper.
Definition: globals.cpp:1395