Package screenlets :: Module XmlMenu
[hide private]
[frames] | no frames]

Source Code for Module screenlets.XmlMenu

  1  # This application is released under the GNU General Public License  
  2  # v3 (or, at your option, any later version). You can find the full  
  3  # text of the license under http://www.gnu.org/licenses/gpl.txt.  
  4  # By using, editing and/or distributing this software you agree to  
  5  # the terms and conditions of this license.  
  6  # Thank you for using free software! 
  7   
  8  # a very hackish, XML-based menu-system (c) RYX (Rico Pfaus) 2007 
  9  # 
 10  # NOTE: This thing is to be considered a quick hack and it lacks on all ends. 
 11  #       It should be either improved (and become a OOP-system ) or removed 
 12  #       once there is a suitable alternative ... 
 13  # 
 14   
 15  import glob, gtk 
 16  import xml.dom.minidom 
 17  from xml.dom.minidom import Node 
 18  import os 
 19  import gettext 
 20   
 21  gettext.textdomain('screenlets') 
 22  gettext.bindtextdomain('screenlets', '/usr/share/locale') 
 23   
24 -def _(s):
25 return gettext.gettext(s)
26 27 # creates a nw gtk.ImageMenuItem from a given icon-/filename. 28 # If no absolute path is given, the function checks for the name 29 # of the icon within the current gtk-theme.
30 -def imageitem_from_name (filename, label, icon_size=32):
31 """Creates a nw gtk.ImageMenuItem from a given icon-/filename.""" 32 item = gtk.ImageMenuItem(label) 33 image = gtk.Image() 34 if filename and filename[0]=='/': 35 # load from file 36 try: 37 image.set_from_file(filename) 38 pb = image.get_pixbuf() 39 # rescale, if too big 40 if pb.get_width() > icon_size : 41 pb2 = pb.scale_simple( 42 icon_size, icon_size, 43 gtk.gdk.INTERP_HYPER) 44 image.set_from_pixbuf(pb2) 45 else: 46 image.set_from_pixbuf(pb) 47 except: 48 print _("Error while creating image from file: %s") % filename 49 return None 50 else: 51 image.set_from_icon_name(filename, 3) # TODO: use better size 52 if image: 53 item.set_image(image) 54 return item
55
56 -def read_desktop_file (filename):
57 """Read ".desktop"-file into a dict 58 NOTE: Should use utils.IniReader ...""" 59 list = {} 60 f=None 61 try: 62 f = open (filename, "r") 63 except: 64 print "Error: file %s not found." % filename 65 if f: 66 lines = f.readlines() 67 for line in lines: 68 if line[0] != "#" and line !="\n" and line[0] != "[": 69 ll = line.split('=', 1) 70 if len(ll) > 1: 71 list[ll[0]] = ll[1].replace("\n", "") 72 return list
73
74 -def fill_menu_from_directory (dirname, menu, callback, filter='*', 75 id_prefix='', id_suffix='', search=[], replace=[], skip=[]):
76 """Create MenuItems from a directory. 77 TODO: use regular expressions""" 78 # create theme-list from theme-directory 79 lst = glob.glob(dirname + "/" + filter) 80 #print "Scanning: "+dirname + "/" + filter 81 lst.sort() 82 dlen = len(dirname) + 1 83 # check each entry in dir 84 for filename in lst: 85 #print "FILE: " + filename 86 fname = filename[dlen:] 87 # file allowed? 88 if skip.count(fname)<1: 89 #print "OK" 90 # create label (replace unwanted strings) 91 l = len(search) 92 if l>0 and l == len(replace): 93 for i in xrange(l): 94 fname = fname.replace(search[i], replace[i]) 95 # create label (add prefix/suffix/replace) 96 id = id_prefix + fname + id_suffix 97 #print "NAME: "+fname 98 # create menuitem 99 item = gtk.MenuItem(fname) 100 item.connect("activate", callback, id) 101 item.show() 102 menu.append(item)
103
104 -def create_menu_from_xml (node, callback, icon_size=22):
105 """Create a gtk.Menu by an XML-Node""" 106 menu = gtk.Menu() 107 for node in node.childNodes: 108 #print node 109 type = node.nodeType 110 if type == Node.ELEMENT_NODE: 111 label = node.getAttribute("label") 112 id = node.getAttribute("id") 113 item = None 114 is_check = False 115 # <item> gtk.MenuItem 116 if node.nodeName == "item": 117 item = gtk.MenuItem(label) 118 # <checkitem> gtk.CheckMenuItem 119 elif node.nodeName == "checkitem": 120 item = gtk.CheckMenuItem(label) 121 is_check = True 122 if node.hasAttribute("checked"): 123 item.set_active(True) 124 # <imageitem> gtk.ImageMenuItem 125 elif node.nodeName == "imageitem": 126 icon = node.getAttribute("icon") 127 item = imageitem_from_name(icon, label, icon_size) 128 # <separator> gtk.SeparatorMenuItem 129 elif node.nodeName == "separator": 130 item = gtk.SeparatorMenuItem() 131 # <appdir> 132 elif node.nodeName == "appdir": 133 # create menu from dir with desktop-files 134 path = node.getAttribute("path") 135 appmenu = ApplicationMenu(path) 136 cats = node.getAttribute("cats").split(",") 137 for cat in cats: 138 item = gtk.MenuItem(cat) 139 #item = imageitem_from_name('games', cat) 140 submenu = appmenu.get_menu_for_category(cat, callback) 141 item.set_submenu(submenu) 142 item.show() 143 menu.append(item) 144 item = None # to overjump further append-item calls 145 # <scandir> create directory list 146 elif node.nodeName == "scandir": 147 # get dirname, prefix, suffix, replace-list, skip-list 148 dir = node.getAttribute("directory") 149 # replace $HOME with environment var 150 dir = dir.replace('$HOME', os.environ['HOME']) 151 #expr = node.getAttribute("expr") 152 idprfx = node.getAttribute("id_prefix") 153 idsufx = node.getAttribute("id_suffix") 154 srch = node.getAttribute("search").split(',') 155 repl = node.getAttribute("replace").split(',') 156 skp = node.getAttribute("skip").split(',') 157 # get filter attribute 158 flt = node.getAttribute("filter") 159 if flt=='': 160 flt='*' 161 # scan directory and append items to current menu 162 #fill_menu_from_directory(dir, menu, callback, regexp=expr, filter=flt) 163 fill_menu_from_directory(dir, menu, callback, filter=flt, 164 id_prefix=idprfx, id_suffix=idsufx, search=srch, 165 replace=repl, skip=skp) 166 # item created? 167 if item: 168 if node.hasChildNodes(): 169 # ... call function recursive and set returned menu as submenu 170 submenu = create_menu_from_xml(node, 171 callback, icon_size) 172 item.set_submenu(submenu) 173 item.show() 174 if id: 175 item.connect("activate", callback, id) 176 menu.append(item) 177 return menu
178
179 -def create_menu_from_file (filename, callback):
180 """Creates a menu from an XML-file and returns None if something went wrong""" 181 doc = None 182 try: 183 doc = xml.dom.minidom.parse(filename) 184 except Exception, e: 185 print _("XML-Error: %s") % str(e) 186 return None 187 return create_menu_from_xml(doc.firstChild, callback)
188 189 190
191 -class ApplicationMenu:
192 """A utility-class to simplify the creation of gtk.Menus from directories with 193 desktop-files. Reads all files in one or multiple directories into its internal list 194 and offers an easy way to create entire categories as complete gtk.Menu 195 with gtk.ImageMenuItems. """ 196 197 # the path to read files from 198 __path = "" 199 # list with apps (could be called "cache") 200 __applications = [] 201 202 # constructor
203 - def __init__ (self, path):
204 self.__path = path 205 self.__categories = {} 206 self.read_directory(path)
207 208 # read all desktop-files in a directory into the internal list 209 # and sort them into the available categories
210 - def read_directory (self, path):
211 dirlst = glob.glob(path + '/*') 212 #print "Path: "+path 213 namelen = len(path) 214 for file in dirlst: 215 if file[-8:]=='.desktop': 216 fname = file[namelen:] 217 #print "file: "+fname 218 df = read_desktop_file(file) 219 name = "" 220 icon = "" 221 cmd = "" 222 try: 223 name = df['Name'] 224 icon = df['Icon'] 225 cmd = df['Exec'] 226 cats = df['Categories'].split(';') 227 #typ = df['Type'] 228 #if typ == "Application": 229 self.__applications.append(df) 230 except Exception, ex: 231 print _("Exception: %s") % str(ex) 232 print _("An error occured with desktop-file: %s") % file
233 234 # return a gtk.Menu with all app in the given category
235 - def get_menu_for_category (self, cat_name, callback):
236 # get apps in the given category 237 applist = [] 238 for app in self.__applications: 239 try: 240 if (';'+app['Categories']).count(';'+cat_name+';') > 0: 241 applist.append(app) 242 except: 243 pass 244 # sort list 245 applist.sort() 246 # create menu from list 247 menu = gtk.Menu() 248 for app in applist: 249 item = imageitem_from_name(app['Icon'], app['Name'], 24) 250 if item: 251 item.connect("activate", callback, "exec:" + app['Exec']) 252 item.show() 253 menu.append(item) 254 # return menu 255 return menu
256 257 258 """ 259 # TEST: 260 261 # menu-callback 262 def menu_handler(item, id): 263 # now check id 264 if id[:5]=="exec:": 265 print "EXECUTE: " + id[5:] 266 267 def button_press(widget, event): 268 widget.menu.popup(None, None, None, event.button, 269 event.time) 270 return False 271 272 def destroy(widget, event): 273 gtk.main_quit() 274 275 276 277 # ApplicationMenu test 278 279 appmenu = ApplicationMenu('/usr/share/applications') 280 281 win = gtk.Window() 282 win.resize(200, 200) 283 win.connect("delete_event", destroy) 284 but = gtk.Button("Press!") 285 but.menu = gtk.Menu() 286 lst = ["Development", "Office", "Game", "Utility"] 287 for i in xrange(len(lst)): 288 item = gtk.MenuItem(lst[i]) 289 submenu = appmenu.get_menu_for_category(lst[i], menu_handler) 290 if submenu: 291 item.set_submenu(submenu) 292 item.show() 293 but.menu.append(item) 294 but.menu.show() 295 but.connect("button_press_event", button_press) 296 win.add(but) 297 but.show() 298 win.show() 299 gtk.main() 300 """ 301 302 # XML/Appmenu TEST 303 if __name__ == "__main__": 304 305 import screenlets.utils 306 307 # menu callback
308 - def xml_menu_handler (item, id):
309 print "ID: "+str(id) 310 # now check id 311 if id[:5]=="exec:": 312 print "EXECUTE: " + id[5:]
313
314 - def button_press (widget, event):
315 widget.menu.popup(None, None, None, event.button, 316 event.time) 317 return False
318
319 - def destroy (widget, event):
320 gtk.main_quit()
321 322 # create menu from XML-file 323 p = screenlets.utils.find_first_screenlet_path('Control') 324 print p 325 menu = create_menu_from_file(p + "/menu.xml", xml_menu_handler) 326 if menu: 327 win = gtk.Window() 328 win.resize(200, 200) 329 win.connect("delete_event", destroy) 330 but = gtk.Button("Press!") 331 but.menu = menu 332 but.connect("button_press_event", button_press) 333 win.add(but) 334 but.show() 335 win.show() 336 gtk.main() 337 else: 338 print _("Error while creating menu.") 339