-
Notifications
You must be signed in to change notification settings - Fork 0
/
python_only_plugin.py
314 lines (237 loc) · 10.5 KB
/
python_only_plugin.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# this is the original attempt at adding python extensions
# to the menus
# only left for testing purposes
import sys
import os
import pdb
import traceback
import gc
from gi.repository import GObject
import ctypes
# junky internationalization function
def N_(msg):
return msg
# junk test
import sw_app_utils
#pdb.set_trace()
try:
#import _sw_app_utils
#from gnucash import *
#from _sw_core_utils import gnc_prefs_is_extra_enabled
# we need to fake an argv
# apparently sys.argv does not exist in side sub-interpreters
# this fakes it for all subsequent usages I believe
sys.argv = []
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
pass
except Exception as errexc:
traceback.print_exc()
print("Failed to import!!", file=sys.stderr)
pdb.set_trace()
gncmainwindowtype = GObject.type_from_name('GncMainWindow')
# this lists the properties
#print(GObject.list_properties(gncmainwindowtype), file=sys.stderr)
# this lists the signal names
#print(GObject.signal_list_names(gncmainwindowtype), file=sys.stderr)
#print(dir(gncmainwindowtype), file=sys.stderr)
# can we access a function in a python module via ctypes?
# - no because it needs to be a dylib not an so
#libcallback = ctypes.CDLL("/Users/djosg/.gnucash/python/pythoncallback.so")
#libcallback.gnc_python_callback.argtypes = [ ctypes.c_void_p, ctypes.c_void_p ]
#libcallback.gnc_python_callback.restype = None
#python_callbacktype = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p)
import gnc_main_window
import gnc_plugin_page_python_report
import gnc_menu_extension
import report_objects
class GncMenuItem(object):
def __init__ (self,path=None,ae=None,action=None,type=None):
self.path = path
self.ae = ae
self.action = action
self.type = type
class GncActionEntry(object):
def __init__ (self,name=None,stock_id=None,label=None,accelerator=None,tooltip=None,callback=None):
self.name = name
self.stock_id = stock_id
self.label = label
self.accelerator = accelerator
self.tooltip = tooltip
self.callback = callback
def as_tuple (self):
return (self.name,self.stock_id,self.label,self.accelerator,self.tooltip,self.callback)
#import pythoncallback
# this works with the pythoncallback module
# NOTA BENE - pythoncallback module NOT used at the moment
# pass a callback saver object for the moment
class MyCallbacks(object):
def __init__ (self):
self.user_data = None
self.callbacks = {}
class MyPlugin(GObject.GObject):
def __init__(self):
self.plugin_class_init()
self.plugin_init()
def plugin_class_init (self):
print("plugin_class_init called", file=sys.stderr)
# try creating the ui xml file here
ui_xml = """<ui>
<menubar>
<menu name="Reports" action="ReportsAction">
<placeholder name="OtherReports">
<menu name="PythonReports" action="PythonReportsAction">
<placeholder name="PythonReportsholder">
</placeholder>
</menu>
</placeholder>
</menu>
<menu name="Tools" action="ToolsAction" >
<placeholder name="ToolsPlaceholder">
<menu name="PythonTools" action="PythonToolsAction">
<placeholder name="PythonToolsholder">
<menuitem name="Python Tools" action="pythongenericAction"/>
</placeholder>
</menu>
</placeholder>
</menu>
</menubar>
</ui>
"""
#fdes = open("/Users/djosg/.gnucash/ui/python-example-plugin.xml",'w')
#fdes.write(ui_xml)
#fdes.close()
# yes - we now can add menu items in python
# we simply need the main window object wrapped either using
# a gncmainwindow module or ctypes and pygobject_new (mapped to to_object) from gobject module
# (ctypes works now got right argument and return types)
# currently using ctypes version
# we apparently have to use the main window ui_merge object
self.main_window = gnc_main_window.gnc_gui_init()
self.main_ui_merge = self.main_window.get_uimanager()
pdb.set_trace()
self.merge_id = 0
#accelgroup = self.main_ui_merge.get_accel_group()
#self.main_window.add_accel_group(accelgroup)
# Create an ActionGroup
actiongroup = Gtk.ActionGroup('GncPythonMyPluginActions')
self.actiongroup = actiongroup
# create callback object
#self.save_callbacks = MyCallbacks()
# ok this whole issue may have been because of my stupidity with GIL Ensure
#newcb = python_callbacktype(self.reports_cb)
#pythoncallback.add_actions(self.save_callbacks, actiongroup, [ \
actiongroup.add_actions([
("PythonReportsAction", None, "Python Reports...", None, "python reports tooltip", None),
("PythonToolsAction", None, "Python Tools...", None, "python tools tooltip", None),
("pythongenericAction", None, "Python tools description...", None, "python tools tooltip", self.tools_cb),
], user_data=self.main_window)
#("pythonreportsAction", None, "Python reports description...", None, "python reports tooltip", self.reports_cb),
#("pythongenericAction", None, "Python tools description...", None, "python tools tooltip", self.tools_cb),
# ], user_data=self.main_window)
self.main_ui_merge.insert_action_group(actiongroup,0)
self.merge_id = self.main_ui_merge.add_ui_from_string(ui_xml)
self.main_ui_merge.ensure_update()
print("merge_id",self.merge_id)
# load the report classes and create instances
# first import the report definitions
report_objects.load_python_reports()
# now setup the menus
self.load_python_reports_menu()
def plugin_init (self):
print("python only plugin_init called", file=sys.stderr)
def load_python_reports_menu (self):
# this is effectively the replacement for gnc:add-report-template-menu-items
# in report-gnome.scm
menu_list = []
for rpt in report_objects.python_reports_by_name:
menu_list.append(self.add_menuitems(rpt,report_objects.python_reports_by_name[rpt]))
# now need to update menu
# we cannot use the gnc-menu-extensions and gnc-plugin-menu-additions
# as they are tied to scheme - because gnc-plugin-menu-additions gets its
# list from gnc-menu-extensions which is totally tied to scheme
self.menu_extensions = gnc_menu_extension.MyMenuAdditions(self.main_window)
self.menu_extensions.add_to_window(menu_list)
def add_menuitems (self, name, rpt):
# create the data needed for Gtk.ActionGroup.add_actions
title = N_("Report")+": "+N_(name)
menuitm = GncMenuItem()
ae = GncActionEntry()
ae.name = rpt.report_guid
if rpt.menu_name:
ae.label = rpt.menu_name
else:
ae.label = name
if rpt.menu_tip:
ae.tooltip = rpt.menu_tip
else:
ae.tooltip = N_("Display the %s report"%name)
ae.stock_id = None
ae.accelerator = None
ae.callback = self.reports_cb
menuitm.ae = ae
if rpt.menu_path:
#menuitm.path = "ui/menubar/Reports/StandardReports/"+rpt.menu_path
menuitm.path = "ui/menubar/Reports/OtherReports/PythonReports/PythonReportsholder/"
else:
menuitm.path = "ui/menubar/Reports/OtherReports/PythonReports/PythonReportsholder/"
menuitm.name = ae.label
menuitm.action = ae.name
menuitm.type = Gtk.UIManagerItemType.MENUITEM
return menuitm
def reports_cb (self, actionobj, user_data=None):
print("report_cb",actionobj,user_data, file=sys.stderr)
print("report_cb",actionobj.get_name(), file=sys.stderr)
#(lambda (window)
# (let ((report (gnc:make-report
# (gnc:report-template-report-guid template))))
# (gnc-main-window-open-report report window)))))
print("report_cb",user_data, file=sys.stderr)
window = user_data
# junk test
trybook = sw_app_utils.get_current_book()
try:
# so we need either the report instance, guid or key name here
# in scheme/C implementation what is passed here is an integer representing the scheme
# report object - which is an "instance" of a report template
# so finally understood the scheme process - the report is instantiated here
# by the gnc:make-report - which returns the report id rather than an instance pointer
# so question is do we maintain passing the id integer or go with passing the instance
# pointer
report_guid = actionobj.get_name()
report_type = report_objects.python_reports_by_guid[report_guid]
report = report_objects.Report(report_type=report_type)
#gnc_plugin_page_python_report.GncPluginPagePythonReport.OpenReport(report,window)
gnc_plugin_page_python_report.OpenReport(report,window)
#gc.collect()
print("call back done")
except Exception as errexc:
traceback.print_exc()
print("error in reports_cb callback",str(errexc), file=sys.stderr)
# unfortunately looks as though this wont work because of GIL issues
# - in the python C plugin we lock the callback and plugin_finalize
# this is crashing when we try a second call
def plugin_finalize (self):
print("python only plugin_finalize called", file=sys.stderr)
def old_reports_cb (self, actionobj, user_data=None):
print("reports_cb",actionobj,user_data, file=sys.stderr)
#pdb.set_trace()
window = user_data
try:
#gnc_plugin_page_python_report.GncPluginPagePythonReport.OpenReport(42,window)
gnc_plugin_page_python_report.OpenReport(42,window)
print("call back done")
except Exception as errexc:
traceback.print_exc()
print("error in reports_cb callback",str(errexc), file=sys.stderr)
def tools_cb (self,*args):
print("tools_cb",args, file=sys.stderr)
# gdb call back for report
#0 0x0000000100040898 in gnc_html_report_stream_cb ()
#1 0x00000001001c853e in load_to_stream ()
#2 0x00000001001c8d97 in impl_webkit_show_url ()
#3 0x00000001001c5fb1 in gnc_html_show_url ()
#4 0x000000010003e8d6 in gnc_plugin_page_report_create_widget ()
#5 0x000000010021e981 in gnc_plugin_page_create_widget ()
#6 0x0000000100214220 in gnc_main_window_open_page ()