screenlets.menu

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

# Source Code for Module screenlets.menu

      1  # This program is free software: you can redistribute it and/or modify
      2  # it under the terms of the GNU General Public License as published by
      3  # the Free Software Foundation, either version 3 of the License, or
      4  # (at your option) any later version.
      5  #
      6  # This program is distributed in the hope that it will be useful,
      7  # but WITHOUT ANY WARRANTY; without even the implied warranty of
      8  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      9  # GNU General Public License for more details.
     10  #
     11  # You should have received a copy of the GNU General Public License
     12  # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     13
     14  # a very hackish, XML-based menu-system (c) RYX (Rico Pfaus) 2007
     15  #
     16  # NOTE: This thing is to be considered a quick hack and it lacks on all ends.
     17  #       It should be either improved (and become a OOP-system ) or removed
     18  #       once there is a suitable alternative ...
     19  #
     20
     21  import glob, gtk
     22  import xml.dom.minidom
     23  from xml.dom.minidom import Node
     24  import os
     25  import gettext
     26  import screenlets
     27
     28  gettext.textdomain('screenlets')
     29  gettext.bindtextdomain('screenlets', screenlets.INSTALL_PREFIX +  '/share/locale')
     30
     31 -def _(s):
     32          return gettext.gettext(s)
     33
     34 -def add_menuitem (menu, label, callback=None, cb_data=None):
     35          """Convenience function to create a menuitem, connect
     36          a callback, and add the menuitem to menu."""
     37          if label == "-":
     38                  item = gtk.SeparatorMenuItem()
     39          else:
     40                  item = gtk.MenuItem(label)
     41          return add_menuitem_with_item(menu, item, callback, cb_data)
     42
     43 -def add_image_menuitem (menu, stock, label=None, callback=None, cb_data=None):
     44          """Convenience function to create an ImageMenuItem, connect
     45          a callback, and add the menuitem to menu."""
     46          item = ImageMenuItem(stock, label)
     47          return add_menuitem_with_item(menu, item, callback, cb_data)
     48
     49 -def add_submenuitem (root_menu, label, lst, images=None, image_size=(22,22), callback=None, prefix=None):
     50                  """Convenience function to add submenuitems to a right-click menu through a list.
     51
     52                  images is an optional list of filenames to be used as an image in each menuitem.
     53                  Each item in the list should either be a string or None. (If an item is None, gtk's
     54                  no-image icon will be used.)
     55
     56                  If callback is not None, each menuitem will be connected to callback with it's
     57                  label as callback data. If prefix exists, prefix will be prefixed to the label's
     58                  name in the callback data.
     59
     60                  Returns the new submenu."""
     61                  root_item = gtk.MenuItem(label)
     62                  root_menu.append(root_item)
     63                  root_item.show()
     64
     65                  menu = gtk.Menu()
     66                  root_item.set_submenu(menu)
     67
     68                  i = 0
     69                  for name in lst:
     70                          # if this menu contains _some_ images
     71                          if images is not None:
     72                                  item = ImageMenuItem(label=name)
     73                                  # if there's an image for this specific item then use it
     74                                  if images[i] is not None:
     75                                          pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(images[i], *image_size)
     76                                          item.set_image_from_pixbuf(pixbuf)
     77                                  # if there isn't an image then cause gtk to use the generic broken-img icon
     78                                  else:
     79                                          item.set_image_from_file('')
     80                          # if this menu doesn't contain _any_ images
     81                          else:
     82                                  item = gtk.MenuItem(name)
     83                          if callback is not None:
     84                                  if prefix is not None:
     85                                          item.connect("activate", callback, prefix+name)
     86                                  else:
     87                                          item.connect("activate", callback, name)
     88                          item.show()
     89                          menu.append(item)
     90                          i += 1
     91
     92                  return menu
     93
     94 -def add_menuitem_with_item (menu, item, callback=None, cb_data=None):
     95          """Convenience function to add a menuitem to a menu
     96          and connect a callback."""
     97          if callback:
     98                  if cb_data:
     99                          item.connect("activate", callback, cb_data)
    100                  else:
    101                          item.connect("activate", callback)
    102          menu.append(item)
    103          item.show()
    104          return item
    105
    115
    190
    220
    221 -def imageitem_from_name (filename, label, icon_size=32):
    222          """Creates a new gtk.ImageMenuItem from a given icon/filename.
    223          If an absolute path is not given, the function checks for the name
    224          of the icon within the current gtk-theme."""
    225          item = gtk.ImageMenuItem(label)
    226          image = gtk.Image()
    227          if filename and filename[0]=='/':
    228                  # load from file
    229                  try:
    230                          image.set_from_file(filename)
    231                          pb = image.get_pixbuf()
    232                          # rescale, if too big
    233                          if pb.get_width() > icon_size :
    234                                  pb2 = pb.scale_simple(
    235                                          icon_size, icon_size,
    236                                          gtk.gdk.INTERP_HYPER)
    237                                  image.set_from_pixbuf(pb2)
    238                          else:
    239                                  image.set_from_pixbuf(pb)
    240                  except:
    241                          print "Error while creating image from file: %s" % filename
    242                          return None
    243          else:
    244                  image.set_from_icon_name(filename, 3)   # TODO: use better size
    245          if image:
    246                  item.set_image(image)
    247          return item
    248
    249 -def read_desktop_file (filename):
    250          """Read ".desktop"-file into a dict
    251          NOTE: Should use utils.IniReader ..."""
    252          list = {}
    253          f=None
    254          try:
    255                  f = open (filename, "r")
    256          except:
    257                  print "Error: file %s not found." % filename
    258          if f:
    259                  lines = f.readlines()
    260                  for line in lines:
    261                          if line[0] != "#" and line !="\n" and line[0] != "[":
    262                                  ll = line.split('=', 1)
    263                                  if len(ll) > 1:
    264                                          list[ll[0]] = ll[1].replace("\n", "")
    265          return list
    266
    267  #-----------------------------------------------
    268  # Classes
    269  #-----------------------------------------------
    270
    271 -class ApplicationMenu(object):
    272          """A utility-class to simplify the creation of gtk.Menus from directories with
    273          desktop-files. Reads all files in one or multiple directories into its internal list
    274          and offers an easy way to create entire categories as complete gtk.Menu
    275          with gtk.ImageMenuItems. """
    276
    277          # the path to read files from
    278          __path = ""
    279          # list with apps (could be called "cache")
    280          __applications = []
    281
    282 -        def __init__ (self, path):
    283                  """constructor"""
    284                  self.__path = path
    285                  self.__categories = {}
    286                  self.read_directory(path)
    287
    288 -        def read_directory (self, path):
    289                  """read all desktop-files in a directory into the internal list
    290                  and sort them into the available categories"""
    291                  dirlst = glob.glob(path + '/*')
    292                  #print "Path: "+path
    293                  namelen = len(path)
    294                  for file in dirlst:
    295                          if file[-8:]=='.desktop':
    296                                  fname = file[namelen:]
    297                                  #print "file: "+fname
    298                                  df = read_desktop_file(file)
    299                                  name = ""
    300                                  icon = ""
    301                                  cmd = ""
    302                                  try:
    303                                          name = df['Name']
    304                                          icon = df['Icon']
    305                                          cmd = df['Exec']
    306                                          cats = df['Categories'].split(';')
    307                                          #typ = df['Type']
    308                                          #if typ == "Application":
    309                                          self.__applications.append(df)
    310                                  except Exception, ex:
    311                                          print "Exception: %s" % str(ex)
    312                                          print "An error occured with desktop-file: %s" % file
    313
    314 -        def get_menu_for_category (self, cat_name, callback):
    315                  """returns a gtk.Menu with all apps in the given category"""
    316                  # get apps in the category
    317                  applist = []
    318                  for app in self.__applications:
    319                          try:
    320                                  if (';'+app['Categories']).count(';'+cat_name+';') > 0:
    321                                          applist.append(app)
    322                          except:
    323                                  pass
    324
    325                  # remove duplicates
    326                  for app in applist:
    327                          if applist.count(app) > 1:
    328                                  applist.remove(app)
    329                  # sort list
    330                  applist.sort()
    331                  # create menu from list
    332                  menu = gtk.Menu()
    333                  for app in applist:
    334                          item = imageitem_from_name(app['Icon'], app['Name'], 24)
    335                          if item:
    336                                  item.connect("activate", callback, "exec:" + app['Exec'])
    337                                  item.show()
    338                                  menu.append(item)
    339                  # return menu
    340                  return menu
    341
    342 -class DefaultMenuItem(object):
    343          """A container with constants for the default menuitems"""
    344
    345          # default menuitem constants (is it right to increase like this?)
    346          NONE            = 0
    347          DELETE          = 1
    348          THEMES          = 2
    349          INFO            = 4
    350          SIZE            = 8
    351          WINDOW_MENU     = 16
    352          PROPERTIES      = 32
    353          DELETE          = 64
    354          QUIT            = 128
    355          QUIT_ALL        = 256
    356          # EXPERIMENTAL!! If you use this, the file menu.xml in the
    357          # Screenlet's data-dir is used for generating the menu ...
    358          XML                     = 512
    359          ADD                     = 1024
    360          # the default items
    361          STANDARD        = 1|2|8|16|32|64|128|256|1024
    362
    363
    364 -class ImageMenuItem(gtk.ImageMenuItem):
    365          """A menuitem with a custom image and label.
    366          To set the image to a non-stock image, just
    367          create the menuitem without an image and then
    368          set the image with the appropriate method."""
    369
    370 -        def __init__ (self, stock=gtk.STOCK_MISSING_IMAGE, label=None):
    371                  """stock: a stock image or 'none'.
    372                  label: text to set as the label or None."""
    373                  # call the superclass
    374                  super(ImageMenuItem, self).__init__(stock)
    375
    376                  # get the label and image for later
    377                  self.label = self.get_child()
    378                  self.image = self.get_image()
    379
    380                  # set the label to custom text
    381                  if label is not None:
    382                          self.set_label(label)
    383
    384 -        def set_image_from_file (self, filename):
    385                  """Set the image from file."""
    386                  self.image.set_from_file(filename)
    387
    388 -        def set_image_from_pixbuf (self, pixbuf):
    389                  """Set the image from a pixbuf."""
    390                  self.image.set_from_pixbuf(pixbuf)
    391
    392 -        def set_image_from_stock(self, name):
    393                  """Set the image from a stock image."""
    394                  self.image.set_from_stock(name, gtk.ICON_SIZE_MENU)
    395
    396 -        def set_label(self, text):
    397                  """Set the label's text."""
    398                  self.label.set_text(text)
    399
    400 -        def set_image_size (self, width, height):
    401                  """Resize the menuitem's image."""
    402                  self.image.set_size_request(width, height)
    403