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 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
38 import gettext
39 gettext.textdomain('screenlets')
40 gettext.bindtextdomain('screenlets', screenlets.INSTALL_PREFIX + '/share/locale')
41
43 return gettext.gettext(s)
44
45
46
47
48
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
68 self.group= group
69
70 self.callback = callback
71
72 self.realtime = True
73
74 self.protected = protected
75
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
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
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
107 """An Option-subclass for string-values that contain filenames of
108 image-files."""
109
110
112 """An Option-subclass for filename-strings that contain directories."""
113
114
116 """An Option for boolean values."""
117
119 if strvalue == "True":
120 return True
121 return False
122
123
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):
132
133
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
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
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
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
172 """An Option for fonts (a simple StringOption)."""
173
174
176 """An Option for colors. Stored as a list with 4 values (r, g, b, a)."""
177
179 """Import (r, g, b, a) from comma-separated string."""
180
181 strvalue = strvalue.lstrip('(')
182 strvalue = strvalue.rstrip(')')
183 strvalue = strvalue.strip()
184
185 tmpval = strvalue.split(',')
186 outval = []
187 for f in tmpval:
188
189 outval.append(float(f.strip()))
190 return outval
191
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
204 """An Option-type for list of strings."""
205
207 """Import python-style list from a string (like [1, 2, 'test'])"""
208 lst = eval(strvalue)
209 return lst
210
212 """Export list as string."""
213 return str(value)
214
215
216 import gnomekeyring
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
232 if not gnomekeyring.is_available():
233 raise Exception(_('GnomeKeyring is not available!!'))
234
235
236
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
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
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
253
254 (name, auth_token) = strvalue.split(':', 1)
255 if name and auth_token:
256
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
268 return (name, pw)
269 else:
270 raise Exception(_('Illegal value in AccountOption.on_import.'))
271
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
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
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
300 """An Option-subclass for string-values that contain dates."""
301
302
303
304
305
306
308 """Create an Option from an XML-node with option-metadata."""
309
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
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
342 if odefault:
343
344 cls = otype[0].upper() + otype.lower()[1:] + 'Option'
345
346
347 clsobj = getattr(__import__(__name__), cls)
348 opt = clsobj(groupname, oname, None, olabel, oinfo)
349 opt.default = opt.on_import(odefault)
350
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
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
380 self.__options__ = []
381 self.__options_groups__ = {}
382
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
391
392 for o in self.__options__:
393 if o.name == option.name:
394 return False
395 self.__dict__[option.name] = option.default
396
397 option.realtime = realtime
398
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
405 self.__options__.append(option)
406
407 if callback:
408 option.connect("option_changed", callback)
409 return True
410
411
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
418
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
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
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
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
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
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
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
466 groups = []
467 for node in root.childNodes:
468
469 if node.nodeType == Node.ELEMENT_NODE:
470
471 if node.nodeName != 'group' or not node.hasChildNodes():
472
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
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
483 for on in node.childNodes:
484 if on.nodeType == Node.ELEMENT_NODE:
485 if on.nodeName == 'info':
486
487 group['info'] = on.firstChild.nodeValue
488 elif on.nodeName == 'option':
489
490 opt = create_option_from_node (on, group['name'])
491
492 if opt:
493 group['options'].append(opt)
494 else:
495 raise Exception(_('Invalid option-node found in "%s".') % filename)
496
497
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
503
504
505
506
507
508
510 """An editing dialog used for editing options of the ListOption-type."""
511
512 model = None
513 tree = None
514 buttonbox = None
515
516
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
523 self.resize(300, 370)
524 self.set_keep_above(True)
525
526 self.model = gtk.ListStore(str)
527
528 self.create_ui()
529
531 """Create the user-interface for this dialog."""
532
533 hbox = gtk.HBox()
534 hbox.set_border_width(10)
535 hbox.set_spacing(10)
536
537 self.tree = gtk.TreeView(model=self.model)
538 self.tree.set_headers_visible(False)
539 self.tree.set_reorderable(True)
540
541 col = gtk.TreeViewColumn('')
542 cell = gtk.CellRendererText()
543
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
551
552
553
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
567 hbox.pack_end(self.buttonbox, False)
568
569 hbox.show()
570 self.vbox.add(hbox)
571
573 """Set the list to be edited in this editor."""
574 for el in lst:
575 self.model.append([el])
576
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
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
627
628
629
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
638
640 """A dynamic options-editor for editing Screenlets which are implementing
641 the EditableOptions-class."""
642
643 __shown_object = None
644
646
647 super(OptionsDialog, self).__init__(
648 _("Edit Options"), flags=gtk.DIALOG_DESTROY_WITH_PARENT |
649 gtk.DIALOG_NO_SEPARATOR,
650 buttons = (
651 gtk.STOCK_CLOSE, gtk.RESPONSE_OK))
652
653 self.resize(width, height)
654 self.set_keep_above(True)
655 self.set_border_width(10)
656
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
665 self.liststore = gtk.ListStore(object)
666 self.tree = gtk.TreeView(model=self.liststore)
667
668 self.main_notebook = gtk.Notebook()
669 self.main_notebook.show()
670 self.vbox.add(self.main_notebook)
671
672 self.create_about_page()
673 self.create_themes_page()
674 self.create_options_page()
675
676 self.tooltips = gtk.Tooltips()
677
678
679
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
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
692 info = info.replace("\n", "")
693 info = info.replace("\t", " ")
694
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
701 if icon:
702
703 if self.infoicon:
704 self.infoicon.destroy()
705
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
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
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
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
735
736 box = gtk.VBox()
737 box.show()
738 box.set_border_width(5)
739
740 page.add(box)
741 page.show()
742
743 label = gtk.Label(group_data['label'])
744 label.show()
745 notebook.append_page(page, label)
746
747 for option in group_data['options']:
748 if option.hidden == False:
749 val = getattr(obj, 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
756 if obj.uses_theme and obj.theme_name != '':
757 self.show_themes_for_screenlet(obj)
758 else:
759 self.page_themes.hide()
760
762 """Update the Themes-page to display the available themes for the
763 given Screenlet-object."""
764
765 found_themes = []
766
767 for path in screenlets.SCREENLETS_PATH:
768 p = path + '/' + obj.get_short_name() + '/themes'
769 print p
770
771 try:
772 dircontent = os.listdir(p)
773 except:
774 print _("Path %s not found.") % p
775 continue
776
777 for name in dircontent:
778
779 if found_themes.count(name):
780 continue
781 found_themes.append(name)
782
783 theme_conf = p + '/' + name + '/theme.conf'
784
785 if os.access(theme_conf, os.F_OK):
786
787 ini = screenlets.utils.IniReader()
788 if ini.load(theme_conf):
789
790 if ini.has_section('Theme'):
791
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
801 info = [name, th_fullname, th_info, th_author,
802 th_version]
803 self.liststore.append([info])
804 else:
805
806 self.liststore.append([[name, '-', '-', '-', '-']])
807
808 if name == obj.theme_name:
809
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
819
821 """Create the "About"-tab."""
822 self.page_about = gtk.HBox()
823
824 self.hbox_about = gtk.HBox()
825 self.hbox_about.show()
826 self.page_about.add(self.hbox_about)
827
828 self.infoicon = gtk.Image()
829 self.infoicon.show()
830 self.page_about.pack_start(self.infoicon, 0, 1, 10)
831
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
839 self.page_about.show()
840 self.main_notebook.append_page(self.page_about, gtk.Label(_('About ')))
841
843 """Create the "Options"-tab."""
844 self.page_options = gtk.HBox()
845
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
851 self.page_options.show()
852 self.main_notebook.append_page(self.page_options, gtk.Label(_('Options ')))
853
855 """Create the "Themes"-tab."""
856 self.page_themes = gtk.VBox(spacing=5)
857 self.page_themes.set_border_width(10)
858
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
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
873 col.set_cell_data_func(cell, self.__render_cell)
874 self.tree.append_column(col)
875
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
882 vbox = gtk.VBox()
883 vbox.pack_start(sw, True, True)
884 vbox.show()
885
886 self.page_themes.add(vbox)
887 self.page_themes.show()
888 self.main_notebook.append_page(self.page_themes, gtk.Label(_('Themes ')))
889
891 """Callback for rendering the cells in the theme-treeview."""
892
893 attrib = model.get_value(iter, 0)
894
895
896 col = '555555'
897 name_uc = attrib[0][0].upper() + attrib[0][1:]
898
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
912 cell.set_property('markup', mu)
913
914
915
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
927
928 if self.__shown_object.theme_name != attribs[0]:
929 self.__shown_object.theme_name = attribs[0]
930
931
932
1023
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
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
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
1059 but.set_image(create_preview(value))
1060 but.connect('clicked', but_callback)
1061
1062 widget = gtk.HBox()
1063 widget.add(entry)
1064 widget.add(but)
1065 but.show()
1066 widget.show()
1067
1068
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
1081 dlg = ListOptionDialog()
1082
1083
1084 dlg.set_list(option.on_import(entry.get_text()))
1085 resp = dlg.run()
1086 if resp == gtk.RESPONSE_OK:
1087
1088 entry.set_text(str(dlg.get_list()))
1089
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)
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()
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:
1165 widget.set_sensitive(False)
1166 label.set_sensitive(False)
1167
1168 self.tooltips.set_tip(widget, option.desc)
1169 widget.show()
1170
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
1183 hbox.pack_start(widget, 0, 0)
1184 return hbox
1185
1237
1238
1239
1240
1242 """Callback for handling changed-events on entries."""
1243 print _("Changed: %s") % optionobj.name
1244 if self.__shown_object:
1245
1246 if optionobj.realtime == False:
1247 return False
1248
1249 val = self.read_option_from_widget(widget, optionobj)
1250 if val != None:
1251
1252
1253 setattr(self.__shown_object, optionobj.name, val)
1254
1255 optionobj.emit("option_changed", optionobj)
1256 return False
1257
1259 """Callback for handling Apply-button presses."""
1260 if self.__shown_object:
1261
1262 val = self.read_option_from_widget(entry, optionobj)
1263 if val != None:
1264
1265
1266 setattr(self.__shown_object, optionobj.name, val)
1267
1268 optionobj.emit("option_changed", optionobj)
1269 return False
1270
1271
1272
1273
1274 if __name__ == "__main__":
1275
1276 import os
1277
1278
1280
1281 testlist = ['test1', 'test2', 3, 5, 'Noch ein Test']
1282 pop3_account = ('Username', '')
1283
1284
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 = ""
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)
1313
1315 EditableOptions.__init__(self)
1316
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
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
1368 self.disable_option('width')
1369 self.disable_option('height')
1370
1371
1372
1374 self.__dict__[name] = value
1375 print name + "=" + str(value)
1376
1378 return self.__class__.__name__[:-6]
1379
1380
1381
1382
1384
1385 uses_theme = True
1386 theme_name = 'test'
1387
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
1398
1399 to = TestChildObject()
1400
1401 se = OptionsDialog(500, 380)
1402
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