Gnome backgrounds, scanner app for VIP Express (circa Jun 2004)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

442 lines
13 KiB

  1. #!/usr/bin/env python
  2. # simple-glade-codegen.py
  3. # A code generator that uses pygtk, glade and SimpleGladeApp.py
  4. # Copyright (C) 2004 Sandino Flores Moreno
  5. # This library is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU Lesser General Public
  7. # License as published by the Free Software Foundation; either
  8. # version 2.1 of the License, or (at your option) any later version.
  9. #
  10. # This library is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. # Lesser General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Lesser General Public
  16. # License along with this library; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  18. # USA
  19. import sys, os, re, codecs
  20. import tokenize, shutil, time
  21. import xml.sax
  22. from xml.sax._exceptions import SAXParseException
  23. header_format = """\
  24. #!/usr/bin/env python
  25. # -*- coding: UTF8 -*-
  26. # Python module %(module)s.py
  27. # Autogenerated from %(glade)s
  28. # Generated on %(date)s
  29. # Warning: Do not delete or modify comments related to context
  30. # They are required to keep user's code
  31. import os, gtk
  32. from SimpleGladeApp import SimpleGladeApp
  33. glade_dir = ""
  34. # Put your modules and data here
  35. # From here through main() codegen inserts/updates a class for
  36. # every top-level widget in the .glade file.
  37. """
  38. class_format = """\
  39. class %(class)s(SimpleGladeApp):
  40. %(t)sdef __init__(self, glade_path="%(glade)s", root="%(root)s", domain=None):
  41. %(t)s%(t)sglade_path = os.path.join(glade_dir, glade_path)
  42. %(t)s%(t)sSimpleGladeApp.__init__(self, glade_path, root, domain)
  43. %(t)sdef new(self):
  44. %(t)s%(t)s#context %(class)s.new {
  45. %(t)s%(t)sprint "A new %(class)s has been created"
  46. %(t)s%(t)s#context %(class)s.new }
  47. %(t)s#context %(class)s custom methods {
  48. %(t)s#--- Write your own methods here ---#
  49. %(t)s#context %(class)s custom methods }
  50. """
  51. callback_format = """\
  52. %(t)sdef %(handler)s(self, widget, *args):
  53. %(t)s%(t)s#context %(class)s.%(handler)s {
  54. %(t)s%(t)sprint "%(handler)s called with self.%%s" %% widget.get_name()
  55. %(t)s%(t)s#context %(class)s.%(handler)s }
  56. """
  57. creation_format = """\
  58. %(t)sdef %(handler)s(self, str1, str2, int1, int2):
  59. %(t)s%(t)s#context %(class)s.%(handler)s {
  60. %(t)s%(t)swidget = gtk.Label("%(handler)s")
  61. %(t)s%(t)swidget.show_all()
  62. %(t)s%(t)sreturn widget
  63. %(t)s%(t)s#context %(class)s.%(handler)s }
  64. """
  65. main_format = """\
  66. def main():
  67. """
  68. instance_format = """\
  69. %(t)s%(root)s = %(class)s()
  70. """
  71. run_format = """\
  72. %(t)s%(root)s.run()
  73. if __name__ == "__main__":
  74. %(t)smain()
  75. """
  76. class NotGladeDocumentException(SAXParseException):
  77. def __init__(self, glade_writer):
  78. strerror = "Not a glade-2 document"
  79. SAXParseException.__init__(self, strerror, None, glade_writer.sax_parser)
  80. class SimpleGladeCodeWriter(xml.sax.handler.ContentHandler):
  81. def __init__(self, glade_file):
  82. self.indent = "\t"
  83. self.code = ""
  84. self.roots_list = []
  85. self.widgets_stack = []
  86. self.creation_functions = []
  87. self.callbacks = []
  88. self.parent_is_creation_function = False
  89. self.glade_file = glade_file
  90. self.data = {}
  91. self.input_dir, self.input_file = os.path.split(glade_file)
  92. base = os.path.splitext(self.input_file)[0]
  93. module = self.normalize_symbol(base)
  94. self.output_file = os.path.join(self.input_dir, module) + ".py"
  95. self.sax_parser = xml.sax.make_parser()
  96. self.sax_parser.setFeature(xml.sax.handler.feature_external_ges, False)
  97. self.sax_parser.setContentHandler(self)
  98. self.data["glade"] = self.input_file
  99. self.data["module"] = module
  100. self.data["date"] = time.asctime()
  101. def normalize_symbol(self, base):
  102. return "_".join( re.findall(tokenize.Name, base) )
  103. def capitalize_symbol(self, base):
  104. ClassName = "[a-zA-Z0-9]+"
  105. base = self.normalize_symbol(base)
  106. capitalize_map = lambda s : s[0].upper() + s[1:]
  107. return "".join( map(capitalize_map, re.findall(ClassName, base)) )
  108. def uncapitalize_symbol(self, base):
  109. InstanceName = "([a-z])([A-Z])"
  110. action = lambda m: "%s_%s" % ( m.groups()[0], m.groups()[1].lower() )
  111. base = self.normalize_symbol(base)
  112. base = base[0].lower() + base[1:]
  113. return re.sub(InstanceName, action, base)
  114. def startElement(self, name, attrs):
  115. if name == "widget":
  116. widget_id = attrs.get("id")
  117. widget_class = attrs.get("class")
  118. if not widget_id or not widget_class:
  119. raise NotGladeDocumentException(self)
  120. if not self.widgets_stack:
  121. self.creation_functions = []
  122. self.callbacks = []
  123. class_name = self.capitalize_symbol(widget_id)
  124. self.data["class"] = class_name
  125. self.data["root"] = widget_id
  126. self.roots_list.append(widget_id)
  127. self.code += class_format % self.data
  128. self.widgets_stack.append(widget_id)
  129. elif name == "signal":
  130. if not self.widgets_stack:
  131. raise NotGladeDocumentException(self)
  132. widget = self.widgets_stack[-1]
  133. signal_object = attrs.get("object")
  134. if signal_object:
  135. return
  136. handler = attrs.get("handler")
  137. if not handler:
  138. raise NotGladeDocumentException(self)
  139. if handler.startswith("gtk_"):
  140. return
  141. signal = attrs.get("name")
  142. if not signal:
  143. raise NotGladeDocumentException(self)
  144. self.data["widget"] = widget
  145. self.data["signal"] = signal
  146. self.data["handler"]= handler
  147. if handler not in self.callbacks:
  148. self.code += callback_format % self.data
  149. self.callbacks.append(handler)
  150. elif name == "property":
  151. if not self.widgets_stack:
  152. raise NotGladeDocumentException(self)
  153. widget = self.widgets_stack[-1]
  154. prop_name = attrs.get("name")
  155. if not prop_name:
  156. raise NotGladeDocumentException(self)
  157. if prop_name == "creation_function":
  158. self.parent_is_creation_function = True
  159. def characters(self, content):
  160. if self.parent_is_creation_function:
  161. if not self.widgets_stack:
  162. raise NotGladeDocumentException(self)
  163. handler = content.strip()
  164. if handler not in self.creation_functions:
  165. self.data["handler"] = handler
  166. self.code += creation_format % self.data
  167. self.creation_functions.append(handler)
  168. def endElement(self, name):
  169. if name == "property":
  170. self.parent_is_creation_function = False
  171. elif name == "widget":
  172. if not self.widgets_stack:
  173. raise NotGladeDocumentException(self)
  174. self.widgets_stack.pop()
  175. def write(self):
  176. self.data["t"] = self.indent
  177. self.code += header_format % self.data
  178. try:
  179. glade = open(self.glade_file, "r")
  180. self.sax_parser.parse(glade)
  181. except xml.sax._exceptions.SAXParseException, e:
  182. sys.stderr.write("Error parsing document\n")
  183. return None
  184. except IOError, e:
  185. sys.stderr.write("%s\n" % e.strerror)
  186. return None
  187. self.code += main_format % self.data
  188. for root in self.roots_list:
  189. self.data["class"] = self.capitalize_symbol(root)
  190. self.data["root"] = self.uncapitalize_symbol(root)
  191. self.code += instance_format % self.data
  192. self.data["root"] = self.uncapitalize_symbol(self.roots_list[0])
  193. self.code += run_format % self.data
  194. try:
  195. self.output = codecs.open(self.output_file, "w", "utf-8")
  196. self.output.write(self.code)
  197. self.output.close()
  198. except IOError, e:
  199. sys.stderr.write("%s\n" % e.strerror)
  200. return None
  201. return self.output_file
  202. def usage():
  203. program = sys.argv[0]
  204. print """\
  205. Write a simple python file from a glade file.
  206. Usage: %s <file.glade>
  207. """ % program
  208. def which(program):
  209. if sys.platform.startswith("win"):
  210. exe_ext = ".exe"
  211. else:
  212. exe_ext = ""
  213. path_list = os.environ["PATH"].split(os.pathsep)
  214. for path in path_list:
  215. program_path = os.path.join(path, program) + exe_ext
  216. if os.path.isfile(program_path):
  217. return program_path
  218. return None
  219. def check_for_programs():
  220. packages = {"diff" : "diffutils", "patch" : "patch"}
  221. for package in packages.keys():
  222. if not which(package):
  223. sys.stderr.write("Required program %s could not be found\n" % package)
  224. sys.stderr.write("Is the package %s installed?\n" % packages[package])
  225. if sys.platform.startswith("win"):
  226. sys.stderr.write("Download it from http://gnuwin32.sourceforge.net/packages.html\n")
  227. sys.stderr.write("Also, be sure it is in the PATH\n")
  228. return False
  229. return True
  230. def main():
  231. if not check_for_programs():
  232. return -1
  233. if len(sys.argv) == 2:
  234. code_writer = SimpleGladeCodeWriter( sys.argv[1] )
  235. glade_file = code_writer.glade_file
  236. output_file = code_writer.output_file
  237. output_file_orig = output_file + ".orig"
  238. output_file_bak = output_file + ".bak"
  239. short_f = os.path.split(output_file)[1]
  240. short_f_orig = short_f + ".orig"
  241. short_f_bak = short_f + ".bak"
  242. helper_module = os.path.join(code_writer.input_dir,SimpleGladeApp_py)
  243. custom_diff = "custom.diff"
  244. exists_output_file = os.path.exists(output_file)
  245. exists_output_file_orig = os.path.exists(output_file_orig)
  246. if not exists_output_file_orig and exists_output_file:
  247. sys.stderr.write('File "%s" exists\n' % short_f)
  248. sys.stderr.write('but "%s" does not.\n' % short_f_orig)
  249. sys.stderr.write("That means your custom code would be overwritten.\n")
  250. sys.stderr.write('Please manually remove "%s"\n' % short_f)
  251. sys.stderr.write("from this directory.\n")
  252. sys.stderr.write("Anyway, I\'ll create a backup for you in\n")
  253. sys.stderr.write('"%s"\n' % short_f_bak)
  254. shutil.copy(output_file, output_file_bak)
  255. return -1
  256. if exists_output_file_orig and exists_output_file:
  257. os.system("diff -U1 %s %s > %s" % (output_file_orig, output_file, custom_diff) )
  258. if not code_writer.write():
  259. os.remove(custom_diff)
  260. return -1
  261. shutil.copy(output_file, output_file_orig)
  262. if os.system("patch -fp0 < %s" % custom_diff):
  263. os.remove(custom_diff)
  264. return -1
  265. os.remove(custom_diff)
  266. else:
  267. if not code_writer.write():
  268. return -1
  269. shutil.copy(output_file, output_file_orig)
  270. os.chmod(output_file, 0755)
  271. if not os.path.isfile(helper_module):
  272. open(helper_module, "w").write(SimpleGladeApp_content)
  273. print "Wrote", output_file
  274. return 0
  275. else:
  276. usage()
  277. return -1
  278. SimpleGladeApp_py = "SimpleGladeApp.py"
  279. SimpleGladeApp_content = """\
  280. # SimpleGladeApp.py
  281. # Module that provides an object oriented abstraction to pygtk and libglade.
  282. # Copyright (C) 2004 Sandino Flores Moreno
  283. # This library is free software; you can redistribute it and/or
  284. # modify it under the terms of the GNU Lesser General Public
  285. # License as published by the Free Software Foundation; either
  286. # version 2.1 of the License, or (at your option) any later version.
  287. #
  288. # This library is distributed in the hope that it will be useful,
  289. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  290. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  291. # Lesser General Public License for more details.
  292. #
  293. # You should have received a copy of the GNU Lesser General Public
  294. # License along with this library; if not, write to the Free Software
  295. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  296. # USA
  297. try:
  298. import os
  299. import sys
  300. import gtk
  301. import gtk.glade
  302. except ImportError:
  303. print "Error importing pygtk2 and pygtk2-libglade"
  304. sys.exit(1)
  305. class SimpleGladeApp(dict):
  306. def __init__(self, glade_filename, main_widget_name=None, domain=None):
  307. gtk.glade.set_custom_handler(self.custom_handler)
  308. if os.path.isfile(glade_filename):
  309. self.glade_path = glade_filename
  310. else:
  311. glade_dir = os.path.split( sys.argv[0] )[0]
  312. self.glade_path = os.path.join(glade_dir, glade_filename)
  313. self.glade = gtk.glade.XML(self.glade_path, main_widget_name, domain)
  314. if main_widget_name:
  315. self.main_widget = self.glade.get_widget(main_widget_name)
  316. else:
  317. self.main_widget = None
  318. self.signal_autoconnect()
  319. self.new()
  320. def signal_autoconnect(self):
  321. signals = {}
  322. for attr_name in dir(self):
  323. attr = getattr(self, attr_name)
  324. if callable(attr):
  325. signals[attr_name] = attr
  326. self.glade.signal_autoconnect(signals)
  327. def custom_handler(self,
  328. glade, function_name, widget_name,
  329. str1, str2, int1, int2):
  330. if hasattr(self, function_name):
  331. handler = getattr(self, function_name)
  332. return handler(str1, str2, int1, int2)
  333. def __getattr__(self, data_name):
  334. if data_name in self:
  335. data = self[data_name]
  336. return data
  337. else:
  338. widget = self.glade.get_widget(data_name)
  339. if widget != None:
  340. self[data_name] = widget
  341. return widget
  342. else:
  343. raise AttributeError, data_name
  344. def __setattr__(self, name, value):
  345. self[name] = value
  346. def new(self):
  347. pass
  348. def on_keyboard_interrupt(self):
  349. pass
  350. def gtk_widget_show(self, widget, *args):
  351. widget.show()
  352. def gtk_widget_hide(self, widget, *args):
  353. widget.hide()
  354. def gtk_widget_grab_focus(self, widget, *args):
  355. widget.grab_focus()
  356. def gtk_widget_destroy(self, widget, *args):
  357. widget.destroy()
  358. def gtk_window_activate_default(self, widget, *args):
  359. widget.activate_default()
  360. def gtk_true(self, *args):
  361. return gtk.TRUE
  362. def gtk_false(self, *args):
  363. return gtk.FALSE
  364. def gtk_main_quit(self, *args):
  365. gtk.main_quit()
  366. def main(self):
  367. gtk.main()
  368. def quit(self):
  369. gtk.main_quit()
  370. def run(self):
  371. try:
  372. self.main()
  373. except KeyboardInterrupt:
  374. self.on_keyboard_interrupt()
  375. """
  376. if __name__ == "__main__":
  377. exit_code = main()
  378. sys.exit(exit_code)