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

Source Code for Module screenlets.options

   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  # Options-system (c) RYX (aka Rico Pfaus) 2007 <ryx@ryxperience.com> 
   9  # 
  10  # INFO: 
  11  # - a dynamic Options-system that allows very easy creation of 
  12  #   objects with embedded configuration-system. 
  13  #   NOTE: The Dialog is not very nice yet - it is not good OOP-practice 
  14  #   because too big functions and bad class-layout ... but it works 
  15  #   for now ... :) 
  16  # 
  17  # TODO: 
  18  # - option-widgets for all option-types (e.g. ListOptionWidget, ColorOptionWidget) 
  19  # - OptionGroup-class instead of (or behind) add_options_group 
  20  # - TimeOption, DateOption 
  21  # - FileOption needs filter/limit-attribute 
  22  # - allow options to disable/enable other options 
  23  # - support for EditableOptions-subclasses as options 
  24  # - separate OptionEditorWidget from Editor-Dialog 
  25  # - place ui-code into screenlets.options.ui-module 
  26  # - create own widgets for each Option-subclass 
  27  # 
  28   
  29  import screenlets 
  30  import utils 
  31   
  32  import os                
  33  import gtk, gobject 
  34  import xml.dom.minidom 
  35  from xml.dom.minidom import Node 
  36   
  37  # translation stuff 
  38  import gettext 
  39  gettext.textdomain('screenlets') 
  40  gettext.bindtextdomain('screenlets', screenlets.INSTALL_PREFIX +  '/share/locale') 
  41   
42 -def _(s):
43 return gettext.gettext(s)
44 45 # ----------------------------------------------------------------------- 46 # Option-classes and subclasses 47 # ----------------------------------------------------------------------- 48
49 -class Option(gobject.GObject):
50 """An Option stores information about a certain object-attribute. It doesn't 51 carry information about the value or the object it belongs to - it is only a 52 one-way data-storage for describing how to handle attributes.""" 53 54 __gsignals__ = dict(option_changed=(gobject.SIGNAL_RUN_FIRST, 55 gobject.TYPE_NONE, (gobject.TYPE_OBJECT,))) 56
57 - def __init__ (self, group, name, default, label, desc, 58 disabled=False, hidden=False, callback=None, protected=False):
59 """Creates a new Option with the given information.""" 60 super(Option, self).__init__() 61 self.name = name 62 self.label = label 63 self.desc = desc 64 self.default = default 65 self.disabled = disabled 66 self.hidden = hidden 67 # for groups (TODO: OptionGroup) 68 self.group= group 69 # callback to be notified when this option changes 70 self.callback = callback 71 # real-time update? 72 self.realtime = True 73 # protected from get/set through service 74 self.protected = protected
75
76 - def on_import (self, strvalue):
77 """Callback - called when an option gets imported from a string. 78 This function MUST return the string-value converted to the required 79 type!""" 80 return strvalue.replace("\\n", "\n")
81
82 - def on_export (self, value):
83 """Callback - called when an option gets exported to a string. The 84 value-argument needs to be converted to a string that can be imported 85 by the on_import-handler. This handler MUST return the value 86 converted to a string!""" 87 return str(value).replace("\n", "\\n")
88 89
90 -class FileOption (Option):
91 """An Option-subclass for string-values that contain filenames. Adds 92 a patterns-attribute that can contain a list of patterns to be shown 93 in the assigned file selection dialog. The show_pixmaps-attribute 94 can be set to True to make the filedialog show all image-types 95 supported by gtk.Pixmap. If the directory-attributue is true, the 96 dialog will ony allow directories.""" 97
98 - def __init__ (self, group, name, default, label, desc, 99 patterns=['*'], image=False, directory=False, **keyword_args):
100 Option.__init__(self, group, name, default,label, desc, **keyword_args) 101 self.patterns = patterns 102 self.image = image 103 self.directory = False
104 105
106 -class ImageOption (Option):
107 """An Option-subclass for string-values that contain filenames of 108 image-files."""
109 110
111 -class DirectoryOption (Option):
112 """An Option-subclass for filename-strings that contain directories."""
113 114
115 -class BoolOption (Option):
116 """An Option for boolean values.""" 117
118 - def on_import (self, strvalue):
119 if strvalue == "True": 120 return True 121 return False
122 123
124 -class StringOption (Option):
125 """An Option for values of type string.""" 126
127 - def __init__ (self, group, name, default, label, desc, 128 choices=None, password=False, **keyword_args):
129 Option.__init__(self, group, name, default,label, desc, **keyword_args) 130 self.choices = choices 131 self.password = password
132 133
134 -class IntOption (Option):
135 """An Option for values of type number (can be int or float).""" 136
137 - def __init__ (self, group, name, default, label, desc, min=0, max=0, 138 increment=1, **keyword_args):
139 Option.__init__(self, group, name, default, label, desc, **keyword_args) 140 self.min = min 141 self.max = max 142 self.increment = increment
143
144 - def on_import (self, strvalue):
145 """Called when IntOption gets imported. Converts str to int.""" 146 try: 147 if strvalue[0]=='-': 148 return int(strvalue[1:]) * -1 149 return int(strvalue) 150 except: 151 print _("Error during on_import - option: %s.") % self.name 152 return 0
153 154
155 -class FloatOption (IntOption):
156 """An Option for values of type float.""" 157
158 - def __init__ (self, group, name, default, label, desc, digits=1, 159 **keyword_args):
160 IntOption.__init__(self, group, name, default, label, desc, 161 **keyword_args) 162 self.digits = digits
163
164 - def on_import (self, strvalue):
165 """Called when FloatOption gets imported. Converts str to float.""" 166 if strvalue[0]=='-': 167 return float(strvalue[1:]) * -1.0 168 return float(strvalue)
169 170
171 -class FontOption (Option):
172 """An Option for fonts (a simple StringOption)."""
173 174
175 -class ColorOption (Option):
176 """An Option for colors. Stored as a list with 4 values (r, g, b, a).""" 177
178 - def on_import (self, strvalue):
179 """Import (r, g, b, a) from comma-separated string.""" 180 # strip braces and spaces 181 strvalue = strvalue.lstrip('(') 182 strvalue = strvalue.rstrip(')') 183 strvalue = strvalue.strip() 184 # split value on commas 185 tmpval = strvalue.split(',') 186 outval = [] 187 for f in tmpval: 188 # create list and again remove spaces 189 outval.append(float(f.strip())) 190 return outval
191
192 - def on_export (self, value):
193 """Export r, g, b, a to comma-separated string.""" 194 l = len(value) 195 outval = '' 196 for i in xrange(l): 197 outval += str(value[i]) 198 if i < l-1: 199 outval += ',' 200 return outval
201 202
203 -class ListOption (Option):
204 """An Option-type for list of strings.""" 205
206 - def on_import (self, strvalue):
207 """Import python-style list from a string (like [1, 2, 'test'])""" 208 lst = eval(strvalue) 209 return lst
210
211 - def on_export (self, value):
212 """Export list as string.""" 213 return str(value)
214 215 216 import gnomekeyring
217 -class AccountOption (Option):
218 """An Option-type for username/password combos. Stores the password in 219 the gnome-keyring (if available) and only saves username and auth_token 220 through the screenlets-backend. 221 TODO: 222 - not create new token for any change (use "set" instead of "create" if 223 the given item already exists) 224 - use usual storage if no keyring is available but output warning 225 - on_delete-function for removing the data from keyring when the 226 Screenlet holding the option gets deleted""" 227
228 - def __init__ (self, group, name, default, label, desc, **keyword_args):
229 Option.__init__ (self, group, name, default, label, desc, 230 protected=True, **keyword_args) 231 # check for availability of keyring 232 if not gnomekeyring.is_available(): 233 raise Exception(_('GnomeKeyring is not available!!')) # TEMP!!! 234 # THIS IS A WORKAROUND FOR A BUG IN KEYRING (usually we would use 235 # gnomekeyring.get_default_keyring_sync() here): 236 # find first available keyring 237 self.keyring_list = gnomekeyring.list_keyring_names_sync() 238 if len(self.keyring_list) == 0: 239 raise Exception(_('No keyrings found. Please create one first!')) 240 else: 241 # we prefer the default keyring 242 try: 243 self.keyring = gnomekeyring.get_default_keyring_sync() 244 except: 245 print _("Warning: No default keyring found, storage is not permanent!") 246 self.keyring = self.keyring_list[0]
247
248 - def on_import (self, strvalue):
249 """Import account info from a string (like 'username:auth_token'), 250 retrieve the password from the storage and return a tuple containing 251 username and password.""" 252 # split string into username/auth_token 253 #data = strvalue.split(':', 1) 254 (name, auth_token) = strvalue.split(':', 1) 255 if name and auth_token: 256 # read pass from storage 257 try: 258 if self.keyring == self.keyring_list[0]: 259 pw = gnomekeyring.item_get_info_sync('session', 260 int(auth_token)).get_secret() 261 else: 262 pw = gnomekeyring.item_get_info_sync(self.keyring, 263 int(auth_token)).get_secret() 264 except Exception, ex: 265 print _("ERROR: Unable to read password from keyring: %s") % ex 266 pw = '' 267 # return 268 return (name, pw) 269 else: 270 raise Exception(_('Illegal value in AccountOption.on_import.'))
271
272 - def on_export (self, value):
273 """Export the given tuple/list containing a username and a password. The 274 function stores the password in the gnomekeyring and returns a 275 string in form 'username:auth_token'.""" 276 # store password in storage 277 attribs = dict(name=value[0]) 278 if self.keyring == self.keyring_list[0]: 279 auth_token = gnomekeyring.item_create_sync('session', 280 gnomekeyring.ITEM_GENERIC_SECRET, value[0], attribs, value[1], True) 281 else: 282 auth_token = gnomekeyring.item_create_sync(self.keyring, 283 gnomekeyring.ITEM_GENERIC_SECRET, value[0], attribs, value[1], True) 284 # build value from username and auth_token 285 return value[0] + ':' + str(auth_token)
286 287 """#TEST: 288 o = AccountOption('None', 'pop3_account', ('',''), 'Username/Password', 'Enter username/password here ...') 289 # save option to keyring 290 exported_account = o.on_export(('RYX', 'mysecretpassword')) 291 print exported_account 292 # and read option back from keyring 293 print o.on_import(exported_account) 294 295 296 import sys 297 sys.exit(0)""" 298
299 -class TimeOption (ColorOption):
300 """An Option-subclass for string-values that contain dates."""
301 302 303 # ----------------------------------------------------------------------- 304 # EditableOptions-class and needed functions 305 # ----------------------------------------------------------------------- 306
307 -def create_option_from_node (node, groupname):
308 """Create an Option from an XML-node with option-metadata.""" 309 #print "TODO OPTION: " + str(cn) 310 otype = node.getAttribute("type") 311 oname = node.getAttribute("name") 312 ohidden = node.getAttribute("hidden") 313 odefault = None 314 oinfo = '' 315 olabel = '' 316 omin = None 317 omax = None 318 oincrement = 1 319 ochoices = '' 320 odigits = None 321 if otype and oname: 322 # parse children of option-node and save all useful attributes 323 for attr in node.childNodes: 324 if attr.nodeType == Node.ELEMENT_NODE: 325 if attr.nodeName == 'label': 326 olabel = attr.firstChild.nodeValue 327 elif attr.nodeName == 'info': 328 oinfo = attr.firstChild.nodeValue 329 elif attr.nodeName == 'default': 330 odefault = attr.firstChild.nodeValue 331 elif attr.nodeName == 'min': 332 omin = attr.firstChild.nodeValue 333 elif attr.nodeName == 'max': 334 omax = attr.firstChild.nodeValue 335 elif attr.nodeName == 'increment': 336 oincrement = attr.firstChild.nodeValue 337 elif attr.nodeName == 'choices': 338 ochoices = attr.firstChild.nodeValue 339 elif attr.nodeName == 'digits': 340 odigits = attr.firstChild.nodeValue 341 # if we have all needed values, create the Option 342 if odefault: 343 # create correct classname here 344 cls = otype[0].upper() + otype.lower()[1:] + 'Option' 345 #print 'Create: ' +cls +' / ' + oname + ' ('+otype+')' 346 # and build new instance (we use on_import for setting default val) 347 clsobj = getattr(__import__(__name__), cls) 348 opt = clsobj(groupname, oname, None, olabel, oinfo) 349 opt.default = opt.on_import(odefault) 350 # set values to the correct types 351 if cls == 'IntOption': 352 if omin: 353 opt.min = int(omin) 354 if omax: 355 opt.max = int(omax) 356 if oincrement: 357 opt.increment = int(oincrement) 358 elif cls == 'FloatOption': 359 if odigits: 360 opt.digits = int(odigits) 361 if omin: 362 opt.min = float(omin) 363 if omax: 364 opt.max = float(omax) 365 if oincrement: 366 opt.increment = float(oincrement) 367 elif cls == 'StringOption': 368 if ochoices: 369 opt.choices = ochoices 370 return opt 371 return None
372 373
374 -class EditableOptions:
375 """The EditableOptions can be inherited from to allow objects to export 376 editable options for editing them with the OptionsEditor-class. 377 NOTE: This could use some improvement and is very poorly coded :) ...""" 378
379 - def __init__ (self):
380 self.__options__ = [] 381 self.__options_groups__ = {} 382 # This is a workaround to remember the order of groups 383 self.__options_groups_ordered__ = []
384
385 - def add_option (self, option, callback=None, realtime=True):
386 """Add an editable option to this object. Editable Options can be edited 387 and configured using the OptionsDialog. The optional callback-arg can be 388 used to set a callback that gets notified when the option changes its 389 value.""" 390 #print "Add option: "+option.name 391 # if option already editable (i.e. initialized), return 392 for o in self.__options__: 393 if o.name == option.name: 394 return False 395 self.__dict__[option.name] = option.default 396 # set auto-update (TEMPORARY?) 397 option.realtime = realtime 398 # add option to group (output error if group is undefined) 399 try: 400 self.__options_groups__[option.group]['options'].append(option) 401 except: 402 print _("Options: Error - group %s not defined.") % option.group 403 return False 404 # now add the option 405 self.__options__.append(option) 406 # if callback is set, add callback 407 if callback: 408 option.connect("option_changed", callback) 409 return True
410 411
412 - def add_options_group (self, name, group_info):
413 """Add a new options-group to this Options-object""" 414 self.__options_groups__[name] = {'label':name, 415 'info':group_info, 'options':[]} 416 self.__options_groups_ordered__.append(name)
417 #print self.options_groups 418
419 - def disable_option (self, name):
420 """Disable the inputs for a certain Option.""" 421 for o in self.__options__: 422 if o.name == name: 423 o.disabled = True 424 return True 425 return False
426
427 - def export_options_as_list (self):
428 """Returns all editable options within a list (without groups) 429 as key/value tuples.""" 430 lst = [] 431 for o in self.__options__: 432 lst.append((o.name, getattr(self, o.name))) 433 return lst
434
435 - def get_option_by_name (self, name):
436 """Returns an option in this Options by it's name (or None). 437 TODO: this gives wrong results in childclasses ... maybe access 438 as class-attribute??""" 439 for o in self.__options__: 440 if o.name == name: 441 return o 442 return None
443
444 - def remove_option (self, name):
445 """Remove an option from this Options.""" 446 for o in self.__options__: 447 if o.name == name: 448 del o 449 return True 450 return True
451
452 - def add_options_from_file (self, filename):
453 """This function creates options from an XML-file with option-metadata. 454 TODO: make this more reusable and place it into module (once the groups 455 are own objects)""" 456 # create xml document 457 try: 458 doc = xml.dom.minidom.parse(filename) 459 except: 460 raise Exception(_('Invalid XML in metadata-file (or file missing): "%s".') % filename) 461 # get rootnode 462 root = doc.firstChild 463 if not root or root.nodeName != 'screenlet': 464 raise Exception(_('Missing or invalid rootnode in metadata-file: "%s".') % filename) 465 # ok, let's check the nodes: this one should contain option-groups 466 groups = [] 467 for node in root.childNodes: 468 # we only want element-nodes 469 if node.nodeType == Node.ELEMENT_NODE: 470 #print node 471 if node.nodeName != 'group' or not node.hasChildNodes(): 472 # we only allow groups in the first level (groups need children) 473 raise Exception(_('Error in metadata-file "%s" - only <group>-tags allowed in first level. Groups must contain at least one <info>-element.') % filename) 474 else: 475 # ok, create a new group and parse its elements 476 group = {} 477 group['name'] = node.getAttribute("name") 478 if not group['name']: 479 raise Exception(_('No name for group defined in "%s".') % filename) 480 group['info'] = '' 481 group['options'] = [] 482 # check all children in group 483 for on in node.childNodes: 484 if on.nodeType == Node.ELEMENT_NODE: 485 if on.nodeName == 'info': 486 # info-node? set group-info 487 group['info'] = on.firstChild.nodeValue 488 elif on.nodeName == 'option': 489 # option node? parse option node 490 opt = create_option_from_node (on, group['name']) 491 # ok? add it to list 492 if opt: 493 group['options'].append(opt) 494 else: 495 raise Exception(_('Invalid option-node found in "%s".') % filename) 496 497 # create new group 498 if len(group['options']): 499 self.add_options_group(group['name'], group['info']) 500 for o in group['options']: 501 self.add_option(o)
502 # add group to list 503 #groups.append(group) 504 505 # ----------------------------------------------------------------------- 506 # OptionsDialog and UI-classes 507 # ----------------------------------------------------------------------- 508
509 -class ListOptionDialog (gtk.Dialog):
510 """An editing dialog used for editing options of the ListOption-type.""" 511 512 model = None 513 tree = None 514 buttonbox = None 515 516 # call gtk.Dialog.__init__
517 - def __init__ (self):
518 super(ListOptionDialog, self).__init__("Edit List", 519 flags=gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, 520 buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, 521 gtk.STOCK_OK, gtk.RESPONSE_OK)) 522 # set size 523 self.resize(300, 370) 524 self.set_keep_above(True) # to avoid confusion 525 # init vars 526 self.model = gtk.ListStore(str) 527 # create UI 528 self.create_ui()
529
530 - def create_ui (self):
531 """Create the user-interface for this dialog.""" 532 # create outer hbox (tree|buttons) 533 hbox = gtk.HBox() 534 hbox.set_border_width(10) 535 hbox.set_spacing(10) 536 # create tree 537 self.tree = gtk.TreeView(model=self.model) 538 self.tree.set_headers_visible(False) 539 self.tree.set_reorderable(True) 540 #self.tree.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_HORIZONTAL) 541 col = gtk.TreeViewColumn('') 542 cell = gtk.CellRendererText() 543 #cell.set_property('cell-background', 'cyan') 544 cell.set_property('foreground', 'black') 545 col.pack_start(cell, False) 546 col.set_attributes(cell, text=0) 547 self.tree.append_column(col) 548 self.tree.show() 549 hbox.pack_start(self.tree, True, True) 550 #sep = gtk.VSeparator() 551 #sep.show() 552 #hbox.add(sep) 553 # create buttons 554 self.buttonbox = bb = gtk.VButtonBox() 555 self.buttonbox.set_layout(gtk.BUTTONBOX_START) 556 b1 = gtk.Button(stock=gtk.STOCK_ADD) 557 b2 = gtk.Button(stock=gtk.STOCK_EDIT) 558 b3 = gtk.Button(stock=gtk.STOCK_REMOVE) 559 b1.connect('clicked', self.button_callback, 'add') 560 b2.connect('clicked', self.button_callback, 'edit') 561 b3.connect('clicked', self.button_callback, 'remove') 562 bb.add(b1) 563 bb.add(b2) 564 bb.add(b3) 565 self.buttonbox.show_all() 566 #hbox.add(self.buttonbox) 567 hbox.pack_end(self.buttonbox, False) 568 # add everything to outer hbox and show it 569 hbox.show() 570 self.vbox.add(hbox)
571
572 - def set_list (self, lst):
573 """Set the list to be edited in this editor.""" 574 for el in lst: 575 self.model.append([el])
576
577 - def get_list (self):
578 """Return the list that is currently being edited in this editor.""" 579 lst = [] 580 for i in self.model: 581 lst.append(i[0]) 582 return lst
583
584 - def remove_selected_item (self):
585 """Remove the currently selected item.""" 586 sel = self.tree.get_selection() 587 if sel: 588 it = sel.get_selected()[1] 589 if it: 590 print self.model.get_value(it, 0) 591 self.model.remove(it)
592
593 - def entry_dialog (self, default = ''):
594 """Show entry-dialog and return string.""" 595 entry = gtk.Entry() 596 entry.set_text(default) 597 entry.show() 598 dlg = gtk.Dialog("Add/Edit Item", flags=gtk.DIALOG_DESTROY_WITH_PARENT, 599 buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, 600 gtk.RESPONSE_OK)) 601 dlg.set_keep_above(True) 602 dlg.vbox.add(entry) 603 resp = dlg.run() 604 ret = None 605 if resp == gtk.RESPONSE_OK: 606 ret = entry.get_text() 607 dlg.destroy() 608 return ret
609
610 - def button_callback (self, widget, id):
611 print _("PRESS: %s") % id 612 if id == 'remove': 613 self.remove_selected_item() 614 if id == 'add': 615 new = self.entry_dialog() 616 if new != None: 617 self.model.append([new]) 618 if id == 'edit': 619 sel = self.tree.get_selection() 620 if sel: 621 it = sel.get_selected()[1] 622 if it: 623 new = self.entry_dialog(self.model.get_value(it, 0)) 624 if new != None: 625 #self.model.append([new]) 626 self.model.set_value(it, 0, new)
627 628 629 # TEST 630 """dlg = ListOptionDialog() 631 dlg.set_list(['test1', 'afarew34s', 'fhjh23faj', 'yxcdfs58df', 'hsdf7jsdfh']) 632 dlg.run() 633 print "RESULT: " + str(dlg.get_list()) 634 dlg.destroy() 635 import sys 636 sys.exit(1)""" 637 # /TEST 638
639 -class OptionsDialog (gtk.Dialog):
640 """A dynamic options-editor for editing Screenlets which are implementing 641 the EditableOptions-class.""" 642 643 __shown_object = None 644
645 - def __init__ (self, width, height):
646 # call gtk.Dialog.__init__ 647 super(OptionsDialog, self).__init__( 648 _("Edit Options"), flags=gtk.DIALOG_DESTROY_WITH_PARENT | 649 gtk.DIALOG_NO_SEPARATOR, 650 buttons = (#gtk.STOCK_REVERT_TO_SAVED, gtk.RESPONSE_APPLY, 651 gtk.STOCK_CLOSE, gtk.RESPONSE_OK)) 652 # set size 653 self.resize(width, height) 654 self.set_keep_above(True) # to avoid confusion 655 self.set_border_width(10) 656 # create attribs 657 self.page_about = None 658 self.page_options = None 659 self.page_themes = None 660 self.vbox_editor = None 661 self.hbox_about = None 662 self.infotext = None 663 self.infoicon = None 664 # create theme-list 665 self.liststore = gtk.ListStore(object) 666 self.tree = gtk.TreeView(model=self.liststore) 667 # create/add outer notebook 668 self.main_notebook = gtk.Notebook() 669 self.main_notebook.show() 670 self.vbox.add(self.main_notebook) 671 # create/init notebook pages 672 self.create_about_page() 673 self.create_themes_page() 674 self.create_options_page() 675 # crete tooltips-object 676 self.tooltips = gtk.Tooltips()
677 678 # "public" functions 679
680 - def reset_to_defaults (self):
681 """Reset all entries for the currently shown object to their default 682 values (the values the object has when it is first created). 683 NOTE: This function resets ALL options, so BE CARFEUL!""" 684 if self.__shown_object: 685 for o in self.__shown_object.__options__: 686 # set default value 687 setattr(self.__shown_object, o.name, o.default)
688
689 - def set_info (self, name, info, copyright='', version='', icon=None):
690 """Update the "About"-page with the given information.""" 691 # convert infotext (remove EOLs and TABs) 692 info = info.replace("\n", "") 693 info = info.replace("\t", " ") 694 # create markup 695 markup = '\n<b><span size="xx-large">' + name + '</span></b>' 696 if version: 697 markup += ' <span size="large"><b>' + version + '</b></span>' 698 markup += '\n\n'+info+'\n<span size="small">\n'+copyright+'</span>' 699 self.infotext.set_markup(markup) 700 # icon? 701 if icon: 702 # remove old icon 703 if self.infoicon: 704 self.infoicon.destroy() 705 # set new icon 706 self.infoicon = icon 707 self.infoicon.set_alignment(0.0, 0.10) 708 self.infoicon.show() 709 self.hbox_about.pack_start(self.infoicon, 0, 1, 10) 710 else: 711 self.infoicon.hide()
712
713 - def show_options_for_object (self, obj):
714 """Update the OptionsEditor to show the options for the given Object. 715 The Object needs to be an EditableOptions-subclass. 716 NOTE: This needs heavy improvement and should use OptionGroups once 717 they exist""" 718 self.__shown_object = obj 719 # create notebook for groups 720 notebook = gtk.Notebook() 721 self.vbox_editor.add(notebook) 722 for group in obj.__options_groups_ordered__: 723 group_data = obj.__options_groups__[group] 724 # create box for tab-page 725 page = gtk.VBox() 726 page.set_border_width(10) 727 if group_data['info'] != '': 728 info = gtk.Label(group_data['info']) 729 info.show() 730 info.set_alignment(0, 0) 731 page.pack_start(info, 0, 0, 7) 732 sep = gtk.HSeparator() 733 sep.show() 734 #page.pack_start(sep, 0, 0, 5) 735 # create VBox for inputs 736 box = gtk.VBox() 737 box.show() 738 box.set_border_width(5) 739 # add box to page 740 page.add(box) 741 page.show() 742 # add new notebook-page 743 label = gtk.Label(group_data['label']) 744 label.show() 745 notebook.append_page(page, label) 746 # and create inputs 747 for option in group_data['options']: 748 if option.hidden == False: 749 val = getattr(obj, option.name)#obj.__dict__[option.name] 750 w = self.get_widget_for_option(option, val) 751 if w: 752 box.pack_start(w, 0, 0) 753 w.show() 754 notebook.show() 755 # show/hide themes tab, depending on whether the screenlet uses themes 756 if obj.uses_theme and obj.theme_name != '': 757 self.show_themes_for_screenlet(obj) 758 else: 759 self.page_themes.hide()
760
761 - def show_themes_for_screenlet (self, obj):
762 """Update the Themes-page to display the available themes for the 763 given Screenlet-object.""" 764 # list with found themes 765 found_themes = [] 766 # now check all paths for themes 767 for path in screenlets.SCREENLETS_PATH: 768 p = path + '/' + obj.get_short_name() + '/themes' 769 print p 770 #p = '/usr/local/share/screenlets/Clock/themes' # TEMP!!! 771 try: 772 dircontent = os.listdir(p) 773 except: 774 print _("Path %s not found.") % p 775 continue 776 # check all themes in path 777 for name in dircontent: 778 # load themes with the same name only once 779 if found_themes.count(name): 780 continue 781 found_themes.append(name) 782 # build full path of theme.conf 783 theme_conf = p + '/' + name + '/theme.conf' 784 # if dir contains a theme.conf 785 if os.access(theme_conf, os.F_OK): 786 # load it and create new list entry 787 ini = screenlets.utils.IniReader() 788 if ini.load(theme_conf): 789 # check for section 790 if ini.has_section('Theme'): 791 # get metainfo from theme 792 th_fullname = ini.get_option('name', 793 section='Theme') 794 th_info = ini.get_option('info', 795 section='Theme') 796 th_version = ini.get_option('version', 797 section='Theme') 798 th_author = ini.get_option('author', 799 section='Theme') 800 # create array from metainfo and add it to liststore 801 info = [name, th_fullname, th_info, th_author, 802 th_version] 803 self.liststore.append([info]) 804 else: 805 # no theme.conf in dir? just add theme-name 806 self.liststore.append([[name, '-', '-', '-', '-']]) 807 # is it the active theme? 808 if name == obj.theme_name: 809 # select it in tree 810 print _("active theme is: %s") % name 811 sel = self.tree.get_selection() 812 if sel: 813 it = self.liststore.get_iter_from_string(\ 814 str(len(self.liststore)-1)) 815 if it: 816 sel.select_iter(it)
817 818 # UI-creation 819
820 - def create_about_page (self):
821 """Create the "About"-tab.""" 822 self.page_about = gtk.HBox() 823 # create about box 824 self.hbox_about = gtk.HBox() 825 self.hbox_about.show() 826 self.page_about.add(self.hbox_about) 827 # create icon 828 self.infoicon = gtk.Image() 829 self.infoicon.show() 830 self.page_about.pack_start(self.infoicon, 0, 1, 10) 831 # create infotext 832 self.infotext = gtk.Label() 833 self.infotext.use_markup = True 834 self.infotext.set_line_wrap(True) 835 self.infotext.set_alignment(0.0, 0.0) 836 self.infotext.show() 837 self.page_about.pack_start(self.infotext, 1, 1, 5) 838 # add page 839 self.page_about.show() 840 self.main_notebook.append_page(self.page_about, gtk.Label(_('About ')))
841
842 - def create_options_page (self):
843 """Create the "Options"-tab.""" 844 self.page_options = gtk.HBox() 845 # create vbox for options-editor 846 self.vbox_editor = gtk.VBox(spacing=3) 847 self.vbox_editor.set_border_width(5) 848 self.vbox_editor.show() 849 self.page_options.add(self.vbox_editor) 850 # show/add page 851 self.page_options.show() 852 self.main_notebook.append_page(self.page_options, gtk.Label(_('Options ')))
853
854 - def create_themes_page (self):
855 """Create the "Themes"-tab.""" 856 self.page_themes = gtk.VBox(spacing=5) 857 self.page_themes.set_border_width(10) 858 # create info-text list 859 txt = gtk.Label(_('Themes allow you to easily switch the appearance of your Screenlets. On this page you find a list of all available themes for this Screenlet.')) 860 txt.set_size_request(450, -1) 861 txt.set_line_wrap(True) 862 txt.set_alignment(0.0, 0.0) 863 txt.show() 864 self.page_themes.pack_start(txt, False, True) 865 # create theme-selector list 866 self.tree.set_headers_visible(False) 867 self.tree.connect('cursor-changed', self.__tree_cursor_changed) 868 self.tree.show() 869 col = gtk.TreeViewColumn('') 870 cell = gtk.CellRendererText() 871 col.pack_start(cell, True) 872 #cell.set_property('foreground', 'black') 873 col.set_cell_data_func(cell, self.__render_cell) 874 self.tree.append_column(col) 875 # wrap tree in scrollwin 876 sw = gtk.ScrolledWindow() 877 sw.set_shadow_type(gtk.SHADOW_IN) 878 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) 879 sw.add(self.tree) 880 sw.show() 881 # add vbox and add tree/buttons 882 vbox = gtk.VBox() 883 vbox.pack_start(sw, True, True) 884 vbox.show() 885 # show/add page 886 self.page_themes.add(vbox) 887 self.page_themes.show() 888 self.main_notebook.append_page(self.page_themes, gtk.Label(_('Themes ')))
889
890 - def __render_cell(self, tvcolumn, cell, model, iter):
891 """Callback for rendering the cells in the theme-treeview.""" 892 # get attributes-list from Treemodel 893 attrib = model.get_value(iter, 0) 894 895 # set colors depending on state 896 col = '555555' 897 name_uc = attrib[0][0].upper() + attrib[0][1:] 898 # create markup depending on info 899 if attrib[1] == '-' and attrib[2] == '-': 900 mu = '<b><span weight="ultrabold" size="large">' + name_uc + \ 901 '</span></b> (' + _('no info available') + ')' 902 else: 903 if attrib[1] == None : attrib[1] = '-' 904 if attrib[2] == None : attrib[2] = '-' 905 if attrib[3] == None : attrib[3] = '-' 906 if attrib[4] == None : attrib[4] = '-' 907 mu = '<b><span weight="ultrabold" size="large">' + name_uc + \ 908 '</span></b> v' + attrib[4] + '\n<small><span color="#555555' +\ 909 '">' + attrib[2].replace('\\n', '\n') + \ 910 '</span></small>\n<i><small>by '+str(attrib[3])+'</small></i>' 911 # set markup 912 cell.set_property('markup', mu)
913 914 # UI-callbacks 915
916 - def __tree_cursor_changed (self, treeview):
917 """Callback for handling selection changes in the Themes-treeview.""" 918 sel = self.tree.get_selection() 919 if sel: 920 s = sel.get_selected() 921 if s: 922 it = s[1] 923 if it: 924 attribs = self.liststore.get_value(it, 0) 925 if attribs and self.__shown_object: 926 #print attribs 927 # set theme in Screenlet (if not already active) 928 if self.__shown_object.theme_name != attribs[0]: 929 self.__shown_object.theme_name = attribs[0]
930 931 # option-widget creation (should be split in several classes) 932
933 - def get_widget_for_option (self, option, value=None):
934 """Return a gtk.*Widget with Label within a HBox for a given option. 935 NOTE: This is incredibly ugly, ideally all Option-subclasses should 936 have their own widgets - like StringOptionWidget, ColorOptionWidget, 937 ... and then be simply created dynamically""" 938 t = option.__class__ 939 widget = None 940 if t == BoolOption: 941 widget = gtk.CheckButton() 942 widget.set_active(value) 943 widget.connect("toggled", self.options_callback, option) 944 elif t == StringOption: 945 if option.choices: 946 # if a list of values is defined, show combobox 947 widget = gtk.combo_box_new_text() 948 p = -1 949 i = 0 950 for s in option.choices: 951 widget.append_text(s) 952 if s==value: 953 p = i 954 i+=1 955 widget.set_active(p) 956 #widget.connect("changed", self.options_callback, option) 957 else: 958 widget = gtk.Entry() 959 widget.set_text(value) 960 # if it is a password, set text to be invisible 961 if option.password: 962 widget.set_visibility(False) 963 #widget.connect("key-press-event", self.options_callback, option) 964 widget.connect("changed", self.options_callback, option) 965 #widget.set_size_request(180, 28) 966 elif t == IntOption or t == FloatOption: 967 widget = gtk.SpinButton() 968 #widget.set_size_request(50, 22) 969 #widget.set_text(str(value)) 970 if t == FloatOption: 971 widget.set_digits(option.digits) 972 widget.set_increments(option.increment, int(option.max/option.increment)) 973 else: 974 widget.set_increments(option.increment, int(option.max/option.increment)) 975 if option.min!=None and option.max!=None: 976 #print "Setting range for input to: %f, %f" % (option.min, option.max) 977 widget.set_range(option.min, option.max) 978 widget.set_value(value) 979 widget.connect("value-changed", self.options_callback, option) 980 elif t == ColorOption: 981 widget = gtk.ColorButton(gtk.gdk.Color(int(value[0]*65535), int(value[1]*65535), int(value[2]*65535))) 982 widget.set_use_alpha(True) 983 print value 984 print value[3] 985 widget.set_alpha(int(value[3]*65535)) 986 widget.connect("color-set", self.options_callback, option) 987 elif t == FontOption: 988 widget = gtk.FontButton() 989 widget.set_font_name(value) 990 widget.connect("font-set", self.options_callback, option) 991 elif t == FileOption: 992 widget = gtk.FileChooserButton(_("Choose File")) 993 widget.set_filename(value) 994 widget.set_size_request(180, 28) 995 widget.connect("selection-changed", self.options_callback, option) 996 elif t == DirectoryOption: 997 dlg = gtk.FileChooserDialog(buttons=(gtk.STOCK_CANCEL, 998 gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK), 999 action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER) 1000 widget = gtk.FileChooserButton(dlg) 1001 widget.set_title(_("Choose Directory")) 1002 widget.set_filename(value) 1003 widget.set_size_request(180, 28) 1004 widget.connect("selection-changed", self.options_callback, option) 1005 elif t == ImageOption: 1006 # create entry and button (entry is hidden) 1007 entry = gtk.Entry() 1008 entry.set_text(value) 1009 entry.set_editable(False) 1010 but = gtk.Button('') 1011 # util to reload preview image 1012 def create_preview (filename): 1013 if filename and os.path.isfile(filename): 1014 pb = gtk.gdk.pixbuf_new_from_file_at_size(filename, 64, -1) 1015 if pb: 1016 img = gtk.Image() 1017 img.set_from_pixbuf(pb) 1018 return img 1019 img = gtk.image_new_from_stock(gtk.STOCK_MISSING_IMAGE, 1020 gtk.ICON_SIZE_LARGE_TOOLBAR) 1021 img.set_size_request(64, 64) 1022 return img
1023 # create button 1024 def but_callback (widget): 1025 dlg = gtk.FileChooserDialog(buttons=(gtk.STOCK_CANCEL, 1026 gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) 1027 dlg.set_title(_("Choose Image")) 1028 dlg.set_keep_above(True) 1029 dlg.set_filename(entry.get_text()) 1030 flt = gtk.FileFilter() 1031 flt.add_pixbuf_formats() 1032 dlg.set_filter(flt) 1033 prev = gtk.Image() 1034 box = gtk.VBox() 1035 box.set_size_request(150, -1) 1036 box.add(prev) 1037 prev.show() 1038 # add preview widget to filechooser 1039 def preview_callback(widget): 1040 fname = dlg.get_preview_filename() 1041 if fname and os.path.isfile(fname): 1042 pb = gtk.gdk.pixbuf_new_from_file_at_size(fname, 150, -1) 1043 if pb: 1044 prev.set_from_pixbuf(pb) 1045 dlg.set_preview_widget_active(True) 1046 else: 1047 dlg.set_preview_widget_active(False)
1048 dlg.set_preview_widget_active(True) 1049 dlg.connect('selection-changed', preview_callback) 1050 dlg.set_preview_widget(box) 1051 # run 1052 response = dlg.run() 1053 if response == gtk.RESPONSE_OK: 1054 entry.set_text(dlg.get_filename()) 1055 but.set_image(create_preview(dlg.get_filename())) 1056 self.options_callback(dlg, option) 1057 dlg.destroy() 1058 # load preview image 1059 but.set_image(create_preview(value)) 1060 but.connect('clicked', but_callback) 1061 # create widget 1062 widget = gtk.HBox() 1063 widget.add(entry) 1064 widget.add(but) 1065 but.show() 1066 widget.show() 1067 # add tooltips 1068 #self.tooltips.set_tip(but, 'Select Image ...') 1069 self.tooltips.set_tip(but, option.desc) 1070 elif t == ListOption: 1071 entry= gtk.Entry() 1072 entry.set_editable(False) 1073 entry.set_text(str(value)) 1074 entry.show() 1075 img = gtk.Image() 1076 img.set_from_stock(gtk.STOCK_EDIT, 1) 1077 but = gtk.Button('') 1078 but.set_image(img) 1079 def open_listeditor(event): 1080 # open dialog 1081 dlg = ListOptionDialog() 1082 # read string from entry and import it through option-class 1083 # (this is needed to always have an up-to-date value) 1084 dlg.set_list(option.on_import(entry.get_text())) 1085 resp = dlg.run() 1086 if resp == gtk.RESPONSE_OK: 1087 # set text in entry 1088 entry.set_text(str(dlg.get_list())) 1089 # manually call the options-callback 1090 self.options_callback(dlg, option) 1091 dlg.destroy() 1092 but.show() 1093 but.connect("clicked", open_listeditor) 1094 self.tooltips.set_tip(but, _('Open List-Editor ...')) 1095 self.tooltips.set_tip(entry, option.desc) 1096 widget = gtk.HBox() 1097 widget.add(entry) 1098 widget.add(but) 1099 elif t == AccountOption: 1100 widget = gtk.HBox() 1101 vb = gtk.VBox() 1102 input_name = gtk.Entry() 1103 input_name.set_text(value[0]) 1104 input_name.show() 1105 input_pass = gtk.Entry() 1106 input_pass.set_visibility(False) # password 1107 input_pass.set_text(value[1]) 1108 input_pass.show() 1109 but = gtk.Button('Apply', gtk.STOCK_APPLY) 1110 but.show() 1111 but.connect("clicked", self.apply_options_callback, option, widget) 1112 vb.add(input_name) 1113 vb.add(input_pass) 1114 vb.show() 1115 self.tooltips.set_tip(but, _('Apply username/password ...')) 1116 self.tooltips.set_tip(input_name, _('Enter username here ...')) 1117 self.tooltips.set_tip(input_pass, _('Enter password here ...')) 1118 widget.add(vb) 1119 widget.add(but) 1120 elif t == TimeOption: 1121 widget = gtk.HBox() 1122 input_hour = gtk.SpinButton()#climb_rate=1.0) 1123 input_minute = gtk.SpinButton() 1124 input_second = gtk.SpinButton() 1125 input_hour.set_range(0, 23) 1126 input_hour.set_max_length(2) 1127 input_hour.set_increments(1, 1) 1128 input_hour.set_numeric(True) 1129 input_hour.set_value(value[0]) 1130 input_minute.set_range(0, 59) 1131 input_minute.set_max_length(2) 1132 input_minute.set_increments(1, 1) 1133 input_minute.set_numeric(True) 1134 input_minute.set_value(value[1]) 1135 input_second.set_range(0, 59) 1136 input_second.set_max_length(2) 1137 input_second.set_increments(1, 1) 1138 input_second.set_numeric(True) 1139 input_second.set_value(value[2]) 1140 input_hour.connect('value-changed', self.options_callback, option) 1141 input_minute.connect('value-changed', self.options_callback, option) 1142 input_second.connect('value-changed', self.options_callback, option) 1143 self.tooltips.set_tip(input_hour, option.desc) 1144 self.tooltips.set_tip(input_minute, option.desc) 1145 self.tooltips.set_tip(input_second, option.desc) 1146 widget.add(input_hour) 1147 widget.add(gtk.Label(':')) 1148 widget.add(input_minute) 1149 widget.add(gtk.Label(':')) 1150 widget.add(input_second) 1151 widget.add(gtk.Label('h')) 1152 widget.show_all() 1153 else: 1154 widget = gtk.Entry() 1155 print _("unsupported type ''") % str(t) 1156 hbox = gtk.HBox() 1157 label = gtk.Label() 1158 label.set_alignment(0.0, 0.0) 1159 label.set_label(option.label) 1160 label.set_size_request(180, 28) 1161 label.show() 1162 hbox.pack_start(label, 0, 1) 1163 if widget: 1164 if option.disabled: # option disabled? 1165 widget.set_sensitive(False) 1166 label.set_sensitive(False) 1167 #label.set_mnemonic_widget(widget) 1168 self.tooltips.set_tip(widget, option.desc) 1169 widget.show() 1170 # check if needs Apply-button 1171 if option.realtime == False: 1172 but = gtk.Button(_('Apply'), gtk.STOCK_APPLY) 1173 but.show() 1174 but.connect("clicked", self.apply_options_callback, 1175 option, widget) 1176 b = gtk.HBox() 1177 b.show() 1178 b.pack_start(widget, 0, 0) 1179 b.pack_start(but, 0, 0) 1180 hbox.pack_start(b, 0, 0) 1181 else: 1182 #hbox.pack_start(widget, -1, 1) 1183 hbox.pack_start(widget, 0, 0) 1184 return hbox 1185
1186 - def read_option_from_widget (self, widget, option):
1187 """Read an option's value from the widget and return it.""" 1188 if not widget.window: 1189 return False 1190 # get type of option and read the widget's value 1191 val = None 1192 t = option.__class__ 1193 if t == IntOption: 1194 val = int(widget.get_value()) 1195 elif t == FloatOption: 1196 val = widget.get_value() 1197 elif t == StringOption: 1198 if option.choices: 1199 # if default is a list, handle combobox 1200 val = widget.get_active_text() 1201 else: 1202 val = widget.get_text() 1203 elif t == BoolOption: 1204 val = widget.get_active() 1205 elif t == ColorOption: 1206 col = widget.get_color() 1207 al = widget.get_alpha() 1208 val = (col.red/65535.0, col.green/65535.0, 1209 col.blue/65535.0, al/65535.0) 1210 elif t == FontOption: 1211 val = widget.get_font_name() 1212 elif t == FileOption or t == DirectoryOption or t == ImageOption: 1213 val = widget.get_filename() 1214 #print widget 1215 #elif t == ImageOption: 1216 # val = widget.get_text() 1217 elif t == ListOption: 1218 # the widget is a ListOptionDialog here 1219 val = widget.get_list() 1220 elif t == AccountOption: 1221 # the widget is a HBox containing a VBox containing two Entries 1222 # (ideally we should have a custom widget for the AccountOption) 1223 for c in widget.get_children(): 1224 if c.__class__ == gtk.VBox: 1225 c2 = c.get_children() 1226 val = (c2[0].get_text(), c2[1].get_text()) 1227 elif t == TimeOption: 1228 box = widget.get_parent() 1229 inputs = box.get_children() 1230 val = (int(inputs[0].get_value()), int(inputs[2].get_value()), 1231 int(inputs[4].get_value())) 1232 else: 1233 print _("OptionsDialog: Unknown option type: %s") % str(t) 1234 return None 1235 # return the value 1236 return val
1237 1238 # option-widget event-handling 1239 1240 # TODO: custom callback/signal for each option?
1241 - def options_callback (self, widget, optionobj):
1242 """Callback for handling changed-events on entries.""" 1243 print _("Changed: %s") % optionobj.name 1244 if self.__shown_object: 1245 # if the option is not real-time updated, 1246 if optionobj.realtime == False: 1247 return False 1248 # read option 1249 val = self.read_option_from_widget(widget, optionobj) 1250 if val != None: 1251 #print "SetOption: "+optionobj.name+"="+str(val) 1252 # set option 1253 setattr(self.__shown_object, optionobj.name, val) 1254 # notify option-object's on_changed-handler 1255 optionobj.emit("option_changed", optionobj) 1256 return False
1257
1258 - def apply_options_callback (self, widget, optionobj, entry):
1259 """Callback for handling Apply-button presses.""" 1260 if self.__shown_object: 1261 # read option 1262 val = self.read_option_from_widget(entry, optionobj) 1263 if val != None: 1264 #print "SetOption: "+optionobj.name+"="+str(val) 1265 # set option 1266 setattr(self.__shown_object, optionobj.name, val) 1267 # notify option-object's on_changed-handler 1268 optionobj.emit("option_changed", optionobj) 1269 return False
1270 1271 1272 1273 # ------ ONLY FOR TESTING ------------------: 1274 if __name__ == "__main__": 1275 1276 import os 1277 1278 # this is only for testing - should be a Screenlet
1279 - class TestObject (EditableOptions):
1280 1281 testlist = ['test1', 'test2', 3, 5, 'Noch ein Test'] 1282 pop3_account = ('Username', '') 1283 1284 # TEST 1285 pin_x = 100 1286 pin_y = 6 1287 text_x = 19 1288 text_y = 35 1289 font_name = 'Sans 12' 1290 rgba_color = (0.0, 0.0, 1.0, 1.0) 1291 text_prefix = '<b>' 1292 text_suffix = '</b>' 1293 note_text = "" # hidden option because val has its own editing-dialog 1294 random_pin_pos = True 1295 opt1 = 'testval 1' 1296 opt2 = 'testval 2' 1297 filename2 = '' 1298 filename = '' 1299 dirname = '' 1300 font = 'Sans 12' 1301 color = (0.1, 0.5, 0.9, 0.9) 1302 name = 'a name' 1303 name2 = 'another name' 1304 combo_test = 'el2' 1305 flt = 0.5 1306 x = 10 1307 y = 25 1308 width = 30 1309 height = 50 1310 is_sticky = False 1311 is_widget = False 1312 time = (12, 32, 49) # a time-value (tuple with ints) 1313
1314 - def __init__ (self):
1315 EditableOptions.__init__(self) 1316 # Add group 1317 self.add_options_group('General', 1318 'The general options for this Object ...') 1319 self.add_options_group('Window', 1320 'The Window-related options for this Object ...') 1321 self.add_options_group('Test', 'A Test-group ...') 1322 # Add editable options 1323 self.add_option(ListOption('Test', 'testlist', self.testlist, 1324 'ListOption-Test', 'Testing a ListOption-type ...')) 1325 self.add_option(StringOption('Window', 'name', 'TESTNAME', 1326 'Testname', 'The name/id of this Screenlet-instance ...'), 1327 realtime=False) 1328 self.add_option(AccountOption('Test', 'pop3_account', 1329 self.pop3_account, 'Username/Password', 1330 'Enter username/password here ...')) 1331 self.add_option(StringOption('Window', 'name2', 'TESTNAME2', 1332 'String2', 'Another string-test ...')) 1333 self.add_option(StringOption('Test', 'combo_test', "el1", 'Combo', 1334 'A StringOption displaying a drop-down-list with choices...', 1335 choices=['el1', 'el2', 'element 3'])) 1336 self.add_option(FloatOption('General', 'flt', 30, 1337 'A Float', 'Testing a FLOAT-type ...', 1338 min=0, max=gtk.gdk.screen_width(), increment=0.01, digits=4)) 1339 self.add_option(IntOption('General', 'x', 30, 1340 'X-Position', 'The X-position of this Screenlet ...', 1341 min=0, max=gtk.gdk.screen_width())) 1342 self.add_option(IntOption('General', 'y', 30, 1343 'Y-Position', 'The Y-position of this Screenlet ...', 1344 min=0, max=gtk.gdk.screen_height())) 1345 self.add_option(IntOption('Test', 'width', 300, 1346 'Width', 'The width of this Screenlet ...', min=100, max=1000)) 1347 self.add_option(IntOption('Test', 'height', 150, 1348 'Height', 'The height of this Screenlet ...', 1349 min=100, max=1000)) 1350 self.add_option(BoolOption('General', 'is_sticky', True, 1351 'Stick to Desktop', 'Show this Screenlet always ...')) 1352 self.add_option(BoolOption('General', 'is_widget', False, 1353 'Treat as Widget', 'Treat this Screenlet as a "Widget" ...')) 1354 self.add_option(FontOption('Test', 'font', 'Sans 14', 1355 'Font', 'The font for whatever ...')) 1356 self.add_option(ColorOption('Test', 'color', (1, 0.35, 0.35, 0.7), 1357 'Color', 'The color for whatever ...')) 1358 self.add_option(FileOption('Test', 'filename', os.environ['HOME'], 1359 'Filename-Test', 'Testing a FileOption-type ...', 1360 patterns=['*.py', '*.pyc'])) 1361 self.add_option(ImageOption('Test', 'filename2', os.environ['HOME'], 1362 'Image-Test', 'Testing the ImageOption-type ...')) 1363 self.add_option(DirectoryOption('Test', 'dirname', os.environ['HOME'], 1364 'Directory-Test', 'Testing a FileOption-type ...')) 1365 self.add_option(TimeOption('Test','time', self.time, 1366 'TimeOption-Test', 'Testing a TimeOption-type ...')) 1367 # TEST 1368 self.disable_option('width') 1369 self.disable_option('height')
1370 # TEST: load options from file 1371 #self.add_options_from_file('/home/ryx/Desktop/python/screenlets/screenlets-0.0.9/src/share/screenlets/Notes/options.xml') 1372
1373 - def __setattr__(self, name, value):
1374 self.__dict__[name] = value 1375 print name + "=" + str(value)
1376
1377 - def get_short_name(self):
1378 return self.__class__.__name__[:-6]
1379 1380 1381 1382 # this is only for testing - should be a Screenlet
1383 - class TestChildObject (TestObject):
1384 1385 uses_theme = True 1386 theme_name = 'test' 1387
1388 - def __init__ (self):
1389 TestObject.__init__(self) 1390 self.add_option(StringOption('Test', 'anothertest', 'ksjhsjgd', 1391 'Another Test', 'An attribute in the subclass ...')) 1392 self.add_option(StringOption('Test', 'theme_name', self.theme_name, 1393 'Theme', 'The theme for this Screenelt ...', 1394 choices=['test1', 'test2', 'mytheme', 'blue', 'test']))
1395 1396 1397 # TEST: load/save 1398 # TEST: option-editing 1399 to = TestChildObject() 1400 #print to.export_options_as_list() 1401 se = OptionsDialog(500, 380)#, treeview=True) 1402 #img = gtk.image_new_from_stock(gtk.STOCK_ABOUT, 5) 1403 img = gtk.Image() 1404 img.set_from_file('../share/screenlets/Notes/icon.svg') 1405 se.set_info('TestOptions', 1406 'A test for an extended options-dialog with embedded about-info.' + 1407 ' Can be used for the Screenlets to have all in one ...\nNOTE:' + 1408 '<span color="red"> ONLY A TEST!</span>', 1409 '(c) RYX 2007', version='v0.0.1', icon=img) 1410 se.show_options_for_object(to) 1411 resp = se.run() 1412 if resp == gtk.RESPONSE_OK: 1413 print "OK" 1414 else: 1415 print "Cancelled." 1416 se.destroy() 1417 print to.export_options_as_list() 1418