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', '/usr/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):
129 Option.__init__(self, group, name, default,label, desc, **keyword_args)
130 self.choices = choices
131 self.password = password
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 keyring_list = gnomekeyring.list_keyring_names_sync()
238 if len(keyring_list) == 0:
239 raise Exception(_('No keyrings found. Please create one first!'))
240 else:
241
242 if keyring_list.count('default') > 0:
243 self.keyring = 'default'
244 else:
245 print _("Warning: No default keyring found, storage is not permanent!")
246 self.keyring = 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 pw = gnomekeyring.item_get_info_sync('session',
259 int(auth_token)).get_secret()
260 except Exception, ex:
261 print _("ERROR: Unable to read password from keyring: %s") % ex
262 pw = ''
263
264 return (name, pw)
265 else:
266 raise Exception(_('Illegal value in AccountOption.on_import.'))
267
269 """Export the given tuple/list containing a username and a password. The
270 function stores the password in the gnomekeyring and returns a
271 string in form 'username:auth_token'."""
272
273 attribs = dict(name=value[0])
274 auth_token = gnomekeyring.item_create_sync('session',
275 gnomekeyring.ITEM_GENERIC_SECRET, value[0], attribs, value[1], True)
276
277 return value[0] + ':' + str(auth_token)
278
279 """#TEST:
280 o = AccountOption('None', 'pop3_account', ('',''), 'Username/Password', 'Enter username/password here ...')
281 # save option to keyring
282 exported_account = o.on_export(('RYX', 'mysecretpassword'))
283 print exported_account
284 # and read option back from keyring
285 print o.on_import(exported_account)
286
287
288 import sys
289 sys.exit(0)"""
290
292 """An Option-subclass for string-values that contain dates."""
293
294
295
296
297
298
300 """Create an Option from an XML-node with option-metadata."""
301
302 otype = node.getAttribute("type")
303 oname = node.getAttribute("name")
304 ohidden = node.getAttribute("hidden")
305 odefault = None
306 oinfo = ''
307 olabel = ''
308 omin = None
309 omax = None
310 oincrement = 1
311 ochoices = ''
312 odigits = None
313 if otype and oname:
314
315 for attr in node.childNodes:
316 if attr.nodeType == Node.ELEMENT_NODE:
317 if attr.nodeName == 'label':
318 olabel = attr.firstChild.nodeValue
319 elif attr.nodeName == 'info':
320 oinfo = attr.firstChild.nodeValue
321 elif attr.nodeName == 'default':
322 odefault = attr.firstChild.nodeValue
323 elif attr.nodeName == 'min':
324 omin = attr.firstChild.nodeValue
325 elif attr.nodeName == 'max':
326 omax = attr.firstChild.nodeValue
327 elif attr.nodeName == 'increment':
328 oincrement = attr.firstChild.nodeValue
329 elif attr.nodeName == 'choices':
330 ochoices = attr.firstChild.nodeValue
331 elif attr.nodeName == 'digits':
332 odigits = attr.firstChild.nodeValue
333
334 if odefault:
335
336 cls = otype[0].upper() + otype.lower()[1:] + 'Option'
337
338
339 clsobj = getattr(__import__(__name__), cls)
340 opt = clsobj(groupname, oname, None, olabel, oinfo)
341 opt.default = opt.on_import(odefault)
342
343 if cls == 'IntOption':
344 if omin:
345 opt.min = int(omin)
346 if omax:
347 opt.max = int(omax)
348 if oincrement:
349 opt.increment = int(oincrement)
350 elif cls == 'FloatOption':
351 if odigits:
352 opt.digits = int(odigits)
353 if omin:
354 opt.min = float(omin)
355 if omax:
356 opt.max = float(omax)
357 if oincrement:
358 opt.increment = float(oincrement)
359 elif cls == 'StringOption':
360 if ochoices:
361 opt.choices = ochoices
362 return opt
363 return None
364
365
367 """The EditableOptions can be inherited from to allow objects to export
368 editable options for editing them with the OptionsEditor-class.
369 NOTE: This could use some improvement and is very poorly coded :) ..."""
370
372 self.__options__ = []
373 self.__options_groups__ = {}
374
375 self.__options_groups_ordered__ = []
376
377 - def add_option (self, option, callback=None, realtime=True):
378 """Add an editable option to this object. Editable Options can be edited
379 and configured using the OptionsDialog. The optional callback-arg can be
380 used to set a callback that gets notified when the option changes its
381 value."""
382
383
384 for o in self.__options__:
385 if o.name == option.name:
386 return False
387 self.__dict__[option.name] = option.default
388
389 option.realtime = realtime
390
391 try:
392 self.__options_groups__[option.group]['options'].append(option)
393 except:
394 print _("Options: Error - group %s not defined.") % option.group
395 return False
396
397 self.__options__.append(option)
398
399 if callback:
400 option.connect("option_changed", callback)
401 return True
402
403
405 """Add a new options-group to this Options-object"""
406 self.__options_groups__[name] = {'label':name,
407 'info':group_info, 'options':[]}
408 self.__options_groups_ordered__.append(name)
409
410
412 """Disable the inputs for a certain Option."""
413 for o in self.__options__:
414 if o.name == name:
415 o.disabled = True
416 return True
417 return False
418
420 """Returns all editable options within a list (without groups)
421 as key/value tuples."""
422 lst = []
423 for o in self.__options__:
424 lst.append((o.name, getattr(self, o.name)))
425 return lst
426
428 """Returns an option in this Options by it's name (or None).
429 TODO: this gives wrong results in childclasses ... maybe access
430 as class-attribute??"""
431 for o in self.__options__:
432 if o.name == name:
433 return o
434 return None
435
437 """Remove an option from this Options."""
438 for o in self.__options__:
439 if o.name == name:
440 del o
441 return True
442 return True
443
445 """This function creates options from an XML-file with option-metadata.
446 TODO: make this more reusable and place it into module (once the groups
447 are own objects)"""
448
449 try:
450 doc = xml.dom.minidom.parse(filename)
451 except:
452 raise Exception(_('Invalid XML in metadata-file (or file missing): "%s".') % filename)
453
454 root = doc.firstChild
455 if not root or root.nodeName != 'screenlet':
456 raise Exception(_('Missing or invalid rootnode in metadata-file: "%s".') % filename)
457
458 groups = []
459 for node in root.childNodes:
460
461 if node.nodeType == Node.ELEMENT_NODE:
462
463 if node.nodeName != 'group' or not node.hasChildNodes():
464
465 raise Exception(_('Error in metadata-file "%s" - only <group>-tags allowed in first level. Groups must contain at least one <info>-element.') % filename)
466 else:
467
468 group = {}
469 group['name'] = node.getAttribute("name")
470 if not group['name']:
471 raise Exception(_('No name for group defined in "%s".') % filename)
472 group['info'] = ''
473 group['options'] = []
474
475 for on in node.childNodes:
476 if on.nodeType == Node.ELEMENT_NODE:
477 if on.nodeName == 'info':
478
479 group['info'] = on.firstChild.nodeValue
480 elif on.nodeName == 'option':
481
482 opt = create_option_from_node (on, group['name'])
483
484 if opt:
485 group['options'].append(opt)
486 else:
487 raise Exception(_('Invalid option-node found in "%s".') % filename)
488
489
490 if len(group['options']):
491 self.add_options_group(group['name'], group['info'])
492 for o in group['options']:
493 self.add_option(o)
494
495
496
497
498
499
500
502 """An editing dialog used for editing options of the ListOption-type."""
503
504 model = None
505 tree = None
506 buttonbox = None
507
508
510 super(ListOptionDialog, self).__init__("Edit List",
511 flags=gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR,
512 buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
513 gtk.STOCK_OK, gtk.RESPONSE_OK))
514
515 self.resize(300, 370)
516 self.set_keep_above(True)
517
518 self.model = gtk.ListStore(str)
519
520 self.create_ui()
521
523 """Create the user-interface for this dialog."""
524
525 hbox = gtk.HBox()
526 hbox.set_border_width(10)
527 hbox.set_spacing(10)
528
529 self.tree = gtk.TreeView(model=self.model)
530 self.tree.set_headers_visible(False)
531 self.tree.set_reorderable(True)
532
533 col = gtk.TreeViewColumn('')
534 cell = gtk.CellRendererText()
535
536 cell.set_property('foreground', 'black')
537 col.pack_start(cell, False)
538 col.set_attributes(cell, text=0)
539 self.tree.append_column(col)
540 self.tree.show()
541 hbox.pack_start(self.tree, True, True)
542
543
544
545
546 self.buttonbox = bb = gtk.VButtonBox()
547 self.buttonbox.set_layout(gtk.BUTTONBOX_START)
548 b1 = gtk.Button(stock=gtk.STOCK_ADD)
549 b2 = gtk.Button(stock=gtk.STOCK_EDIT)
550 b3 = gtk.Button(stock=gtk.STOCK_REMOVE)
551 b1.connect('clicked', self.button_callback, 'add')
552 b2.connect('clicked', self.button_callback, 'edit')
553 b3.connect('clicked', self.button_callback, 'remove')
554 bb.add(b1)
555 bb.add(b2)
556 bb.add(b3)
557 self.buttonbox.show_all()
558
559 hbox.pack_end(self.buttonbox, False)
560
561 hbox.show()
562 self.vbox.add(hbox)
563
565 """Set the list to be edited in this editor."""
566 for el in lst:
567 self.model.append([el])
568
570 """Return the list that is currently being edited in this editor."""
571 lst = []
572 for i in self.model:
573 lst.append(i[0])
574 return lst
575
577 """Remove the currently selected item."""
578 sel = self.tree.get_selection()
579 if sel:
580 it = sel.get_selected()[1]
581 if it:
582 print self.model.get_value(it, 0)
583 self.model.remove(it)
584
585 - def entry_dialog (self, default = ''):
586 """Show entry-dialog and return string."""
587 entry = gtk.Entry()
588 entry.set_text(default)
589 entry.show()
590 dlg = gtk.Dialog("Add/Edit Item", flags=gtk.DIALOG_DESTROY_WITH_PARENT,
591 buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK,
592 gtk.RESPONSE_OK))
593 dlg.set_keep_above(True)
594 dlg.vbox.add(entry)
595 resp = dlg.run()
596 ret = None
597 if resp == gtk.RESPONSE_OK:
598 ret = entry.get_text()
599 dlg.destroy()
600 return ret
601
619
620
621
622 """dlg = ListOptionDialog()
623 dlg.set_list(['test1', 'afarew34s', 'fhjh23faj', 'yxcdfs58df', 'hsdf7jsdfh'])
624 dlg.run()
625 print "RESULT: " + str(dlg.get_list())
626 dlg.destroy()
627 import sys
628 sys.exit(1)"""
629
630
632 """A dynamic options-editor for editing Screenlets which are implementing
633 the EditableOptions-class."""
634
635 __shown_object = None
636
638
639 super(OptionsDialog, self).__init__(
640 _("Edit Options"), flags=gtk.DIALOG_DESTROY_WITH_PARENT |
641 gtk.DIALOG_NO_SEPARATOR,
642 buttons = (
643 gtk.STOCK_CLOSE, gtk.RESPONSE_OK))
644
645 self.resize(width, height)
646 self.set_keep_above(True)
647 self.set_border_width(10)
648
649 self.page_about = None
650 self.page_options = None
651 self.page_themes = None
652 self.vbox_editor = None
653 self.hbox_about = None
654 self.infotext = None
655 self.infoicon = None
656
657 self.liststore = gtk.ListStore(object)
658 self.tree = gtk.TreeView(model=self.liststore)
659
660 self.main_notebook = gtk.Notebook()
661 self.main_notebook.show()
662 self.vbox.add(self.main_notebook)
663
664 self.create_about_page()
665 self.create_themes_page()
666 self.create_options_page()
667
668 self.tooltips = gtk.Tooltips()
669
670
671
673 """Reset all entries for the currently shown object to their default
674 values (the values the object has when it is first created).
675 NOTE: This function resets ALL options, so BE CARFEUL!"""
676 if self.__shown_object:
677 for o in self.__shown_object.__options__:
678
679 setattr(self.__shown_object, o.name, o.default)
680
681 - def set_info (self, name, info, copyright='', version='', icon=None):
682 """Update the "About"-page with the given information."""
683
684 info = info.replace("\n", "")
685 info = info.replace("\t", " ")
686
687 markup = '\n<b><span size="xx-large">' + name + '</span></b>'
688 if version:
689 markup += ' <span size="large"><b>' + version + '</b></span>'
690 markup += '\n\n'+info+'\n<span size="small">\n'+copyright+'</span>'
691 self.infotext.set_markup(markup)
692
693 if icon:
694
695 if self.infoicon:
696 self.infoicon.destroy()
697
698 self.infoicon = icon
699 self.infoicon.set_alignment(0.0, 0.10)
700 self.infoicon.show()
701 self.hbox_about.pack_start(self.infoicon, 0, 1, 10)
702 else:
703 self.infoicon.hide()
704
706 """Update the OptionsEditor to show the options for the given Object.
707 The Object needs to be an EditableOptions-subclass.
708 NOTE: This needs heavy improvement and should use OptionGroups once
709 they exist"""
710 self.__shown_object = obj
711
712 notebook = gtk.Notebook()
713 self.vbox_editor.add(notebook)
714 for group in obj.__options_groups_ordered__:
715 group_data = obj.__options_groups__[group]
716
717 page = gtk.VBox()
718 page.set_border_width(10)
719 if group_data['info'] != '':
720 info = gtk.Label(group_data['info'])
721 info.show()
722 info.set_alignment(0, 0)
723 page.pack_start(info, 0, 0, 7)
724 sep = gtk.HSeparator()
725 sep.show()
726
727
728 box = gtk.VBox()
729 box.show()
730 box.set_border_width(5)
731
732 page.add(box)
733 page.show()
734
735 label = gtk.Label(group_data['label'])
736 label.show()
737 notebook.append_page(page, label)
738
739 for option in group_data['options']:
740 if option.hidden == False:
741 val = getattr(obj, option.name)
742 w = self.get_widget_for_option(option, val)
743 if w:
744 box.pack_start(w, 0, 0)
745 w.show()
746 notebook.show()
747
748 if obj.uses_theme and obj.theme_name != '':
749 self.show_themes_for_screenlet(obj)
750 else:
751 self.page_themes.hide()
752
754 """Update the Themes-page to display the available themes for the
755 given Screenlet-object."""
756
757 found_themes = []
758
759 for path in screenlets.SCREENLETS_PATH:
760 p = path + '/' + obj.get_short_name() + '/themes'
761 print p
762
763 try:
764 dircontent = os.listdir(p)
765 except:
766 print _("Path %s not found.") % p
767 continue
768
769 for name in dircontent:
770
771 if found_themes.count(name):
772 continue
773 found_themes.append(name)
774
775 theme_conf = p + '/' + name + '/theme.conf'
776
777 if os.access(theme_conf, os.F_OK):
778
779 ini = screenlets.utils.IniReader()
780 if ini.load(theme_conf):
781
782 if ini.has_section('Theme'):
783
784 th_fullname = ini.get_option('name',
785 section='Theme')
786 th_info = ini.get_option('info',
787 section='Theme')
788 th_version = ini.get_option('version',
789 section='Theme')
790 th_author = ini.get_option('author',
791 section='Theme')
792
793 info = [name, th_fullname, th_info, th_author,
794 th_version]
795 self.liststore.append([info])
796 else:
797
798 self.liststore.append([[name, '-', '-', '-', '-']])
799
800 if name == obj.theme_name:
801
802 print _("active theme is: %s") % name
803 sel = self.tree.get_selection()
804 if sel:
805 it = self.liststore.get_iter_from_string(\
806 str(len(self.liststore)-1))
807 if it:
808 sel.select_iter(it)
809
810
811
813 """Create the "About"-tab."""
814 self.page_about = gtk.HBox()
815
816 self.hbox_about = gtk.HBox()
817 self.hbox_about.show()
818 self.page_about.add(self.hbox_about)
819
820 self.infoicon = gtk.Image()
821 self.infoicon.show()
822 self.page_about.pack_start(self.infoicon, 0, 1, 10)
823
824 self.infotext = gtk.Label()
825 self.infotext.use_markup = True
826 self.infotext.set_line_wrap(True)
827 self.infotext.set_alignment(0.0, 0.0)
828 self.infotext.show()
829 self.page_about.pack_start(self.infotext, 1, 1, 5)
830
831 self.page_about.show()
832 self.main_notebook.append_page(self.page_about, gtk.Label(_('About ')))
833
835 """Create the "Options"-tab."""
836 self.page_options = gtk.HBox()
837
838 self.vbox_editor = gtk.VBox(spacing=3)
839 self.vbox_editor.set_border_width(5)
840 self.vbox_editor.show()
841 self.page_options.add(self.vbox_editor)
842
843 self.page_options.show()
844 self.main_notebook.append_page(self.page_options, gtk.Label(_('Options ')))
845
847 """Create the "Themes"-tab."""
848 self.page_themes = gtk.VBox(spacing=5)
849 self.page_themes.set_border_width(10)
850
851 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.'))
852 txt.set_size_request(450, -1)
853 txt.set_line_wrap(True)
854 txt.set_alignment(0.0, 0.0)
855 txt.show()
856 self.page_themes.pack_start(txt, False, True)
857
858 self.tree.set_headers_visible(False)
859 self.tree.connect('cursor-changed', self.__tree_cursor_changed)
860 self.tree.show()
861 col = gtk.TreeViewColumn('')
862 cell = gtk.CellRendererText()
863 col.pack_start(cell, True)
864
865 col.set_cell_data_func(cell, self.__render_cell)
866 self.tree.append_column(col)
867
868 sw = gtk.ScrolledWindow()
869 sw.set_shadow_type(gtk.SHADOW_IN)
870 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
871 sw.add(self.tree)
872 sw.show()
873
874 vbox = gtk.VBox()
875 vbox.pack_start(sw, True, True)
876 vbox.show()
877
878 self.page_themes.add(vbox)
879 self.page_themes.show()
880 self.main_notebook.append_page(self.page_themes, gtk.Label(_('Themes ')))
881
883 """Callback for rendering the cells in the theme-treeview."""
884
885 attrib = model.get_value(iter, 0)
886
887
888 col = '555555'
889 name_uc = attrib[0][0].upper() + attrib[0][1:]
890
891 if attrib[1] == '-' and attrib[2] == '-':
892 mu = '<b><span weight="ultrabold" size="large">' + name_uc + \
893 '</span></b> (' + _('no info available') + ')'
894 else:
895 if attrib[1] == None : attrib[1] = '-'
896 if attrib[2] == None : attrib[2] = '-'
897 if attrib[3] == None : attrib[3] = '-'
898 if attrib[4] == None : attrib[4] = '-'
899 mu = '<b><span weight="ultrabold" size="large">' + name_uc + \
900 '</span></b> v' + attrib[4] + '\n<small><span color="#555555' +\
901 '">' + attrib[2].replace('\\n', '\n') + \
902 '</span></small>\n<i><small>by '+str(attrib[3])+'</small></i>'
903
904 cell.set_property('markup', mu)
905
906
907
909 """Callback for handling selection changes in the Themes-treeview."""
910 sel = self.tree.get_selection()
911 if sel:
912 s = sel.get_selected()
913 if s:
914 it = s[1]
915 if it:
916 attribs = self.liststore.get_value(it, 0)
917 if attribs and self.__shown_object:
918
919
920 if self.__shown_object.theme_name != attribs[0]:
921 self.__shown_object.theme_name = attribs[0]
922
923
924
1015
1016 def but_callback (widget):
1017 dlg = gtk.FileChooserDialog(buttons=(gtk.STOCK_CANCEL,
1018 gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
1019 dlg.set_title(_("Choose Image"))
1020 dlg.set_keep_above(True)
1021 dlg.set_filename(entry.get_text())
1022 flt = gtk.FileFilter()
1023 flt.add_pixbuf_formats()
1024 dlg.set_filter(flt)
1025 prev = gtk.Image()
1026 box = gtk.VBox()
1027 box.set_size_request(150, -1)
1028 box.add(prev)
1029 prev.show()
1030
1031 def preview_callback(widget):
1032 fname = dlg.get_preview_filename()
1033 if fname and os.path.isfile(fname):
1034 pb = gtk.gdk.pixbuf_new_from_file_at_size(fname, 150, -1)
1035 if pb:
1036 prev.set_from_pixbuf(pb)
1037 dlg.set_preview_widget_active(True)
1038 else:
1039 dlg.set_preview_widget_active(False)
1040 dlg.set_preview_widget_active(True)
1041 dlg.connect('selection-changed', preview_callback)
1042 dlg.set_preview_widget(box)
1043
1044 response = dlg.run()
1045 if response == gtk.RESPONSE_OK:
1046 entry.set_text(dlg.get_filename())
1047 but.set_image(create_preview(dlg.get_filename()))
1048 self.options_callback(dlg, option)
1049 dlg.destroy()
1050
1051 but.set_image(create_preview(value))
1052 but.connect('clicked', but_callback)
1053
1054 widget = gtk.HBox()
1055 widget.add(entry)
1056 widget.add(but)
1057 but.show()
1058 widget.show()
1059
1060
1061 self.tooltips.set_tip(but, option.desc)
1062 elif t == ListOption:
1063 entry= gtk.Entry()
1064 entry.set_editable(False)
1065 entry.set_text(str(value))
1066 entry.show()
1067 img = gtk.Image()
1068 img.set_from_stock(gtk.STOCK_EDIT, 1)
1069 but = gtk.Button('')
1070 but.set_image(img)
1071 def open_listeditor(event):
1072
1073 dlg = ListOptionDialog()
1074
1075
1076 dlg.set_list(option.on_import(entry.get_text()))
1077 resp = dlg.run()
1078 if resp == gtk.RESPONSE_OK:
1079
1080 entry.set_text(str(dlg.get_list()))
1081
1082 self.options_callback(dlg, option)
1083 dlg.destroy()
1084 but.show()
1085 but.connect("clicked", open_listeditor)
1086 self.tooltips.set_tip(but, _('Open List-Editor ...'))
1087 self.tooltips.set_tip(entry, option.desc)
1088 widget = gtk.HBox()
1089 widget.add(entry)
1090 widget.add(but)
1091 elif t == AccountOption:
1092 widget = gtk.HBox()
1093 vb = gtk.VBox()
1094 input_name = gtk.Entry()
1095 input_name.set_text(value[0])
1096 input_name.show()
1097 input_pass = gtk.Entry()
1098 input_pass.set_visibility(False)
1099 input_pass.set_text(value[1])
1100 input_pass.show()
1101 but = gtk.Button('Apply', gtk.STOCK_APPLY)
1102 but.show()
1103 but.connect("clicked", self.apply_options_callback, option, widget)
1104 vb.add(input_name)
1105 vb.add(input_pass)
1106 vb.show()
1107 self.tooltips.set_tip(but, _('Apply username/password ...'))
1108 self.tooltips.set_tip(input_name, _('Enter username here ...'))
1109 self.tooltips.set_tip(input_pass, _('Enter password here ...'))
1110 widget.add(vb)
1111 widget.add(but)
1112 elif t == TimeOption:
1113 widget = gtk.HBox()
1114 input_hour = gtk.SpinButton()
1115 input_minute = gtk.SpinButton()
1116 input_second = gtk.SpinButton()
1117 input_hour.set_range(0, 23)
1118 input_hour.set_max_length(2)
1119 input_hour.set_increments(1, 1)
1120 input_hour.set_numeric(True)
1121 input_hour.set_value(value[0])
1122 input_minute.set_range(0, 59)
1123 input_minute.set_max_length(2)
1124 input_minute.set_increments(1, 1)
1125 input_minute.set_numeric(True)
1126 input_minute.set_value(value[1])
1127 input_second.set_range(0, 59)
1128 input_second.set_max_length(2)
1129 input_second.set_increments(1, 1)
1130 input_second.set_numeric(True)
1131 input_second.set_value(value[2])
1132 input_hour.connect('value-changed', self.options_callback, option)
1133 input_minute.connect('value-changed', self.options_callback, option)
1134 input_second.connect('value-changed', self.options_callback, option)
1135 self.tooltips.set_tip(input_hour, option.desc)
1136 self.tooltips.set_tip(input_minute, option.desc)
1137 self.tooltips.set_tip(input_second, option.desc)
1138 widget.add(input_hour)
1139 widget.add(gtk.Label(':'))
1140 widget.add(input_minute)
1141 widget.add(gtk.Label(':'))
1142 widget.add(input_second)
1143 widget.add(gtk.Label('h'))
1144 widget.show_all()
1145 else:
1146 widget = gtk.Entry()
1147 print _("unsupported type ''") % str(t)
1148 hbox = gtk.HBox()
1149 label = gtk.Label()
1150 label.set_alignment(0.0, 0.0)
1151 label.set_label(option.label)
1152 label.set_size_request(180, 28)
1153 label.show()
1154 hbox.pack_start(label, 0, 1)
1155 if widget:
1156 if option.disabled:
1157 widget.set_sensitive(False)
1158 label.set_sensitive(False)
1159
1160 self.tooltips.set_tip(widget, option.desc)
1161 widget.show()
1162
1163 if option.realtime == False:
1164 but = gtk.Button(_('Apply'), gtk.STOCK_APPLY)
1165 but.show()
1166 but.connect("clicked", self.apply_options_callback,
1167 option, widget)
1168 b = gtk.HBox()
1169 b.show()
1170 b.pack_start(widget, 0, 0)
1171 b.pack_start(but, 0, 0)
1172 hbox.pack_start(b, 0, 0)
1173 else:
1174
1175 hbox.pack_start(widget, 0, 0)
1176 return hbox
1177
1229
1230
1231
1232
1234 """Callback for handling changed-events on entries."""
1235 print _("Changed: %s") % optionobj.name
1236 if self.__shown_object:
1237
1238 if optionobj.realtime == False:
1239 return False
1240
1241 val = self.read_option_from_widget(widget, optionobj)
1242 if val != None:
1243
1244
1245 setattr(self.__shown_object, optionobj.name, val)
1246
1247 optionobj.emit("option_changed", optionobj)
1248 return False
1249
1251 """Callback for handling Apply-button presses."""
1252 if self.__shown_object:
1253
1254 val = self.read_option_from_widget(entry, optionobj)
1255 if val != None:
1256
1257
1258 setattr(self.__shown_object, optionobj.name, val)
1259
1260 optionobj.emit("option_changed", optionobj)
1261 return False
1262
1263
1264
1265
1266 if __name__ == "__main__":
1267
1268 import os
1269
1270
1272
1273 testlist = ['test1', 'test2', 3, 5, 'Noch ein Test']
1274 pop3_account = ('Username', '')
1275
1276
1277 pin_x = 100
1278 pin_y = 6
1279 text_x = 19
1280 text_y = 35
1281 font_name = 'Sans 12'
1282 rgba_color = (0.0, 0.0, 1.0, 1.0)
1283 text_prefix = '<b>'
1284 text_suffix = '</b>'
1285 note_text = ""
1286 random_pin_pos = True
1287 opt1 = 'testval 1'
1288 opt2 = 'testval 2'
1289 filename2 = ''
1290 filename = ''
1291 dirname = ''
1292 font = 'Sans 12'
1293 color = (0.1, 0.5, 0.9, 0.9)
1294 name = 'a name'
1295 name2 = 'another name'
1296 combo_test = 'el2'
1297 flt = 0.5
1298 x = 10
1299 y = 25
1300 width = 30
1301 height = 50
1302 is_sticky = False
1303 is_widget = False
1304 time = (12, 32, 49)
1305
1307 EditableOptions.__init__(self)
1308
1309 self.add_options_group('General',
1310 'The general options for this Object ...')
1311 self.add_options_group('Window',
1312 'The Window-related options for this Object ...')
1313 self.add_options_group('Test', 'A Test-group ...')
1314
1315 self.add_option(ListOption('Test', 'testlist', self.testlist,
1316 'ListOption-Test', 'Testing a ListOption-type ...'))
1317 self.add_option(StringOption('Window', 'name', 'TESTNAME',
1318 'Testname', 'The name/id of this Screenlet-instance ...'),
1319 realtime=False)
1320 self.add_option(AccountOption('Test', 'pop3_account',
1321 self.pop3_account, 'Username/Password',
1322 'Enter username/password here ...'))
1323 self.add_option(StringOption('Window', 'name2', 'TESTNAME2',
1324 'String2', 'Another string-test ...'))
1325 self.add_option(StringOption('Test', 'combo_test', "el1", 'Combo',
1326 'A StringOption displaying a drop-down-list with choices...',
1327 choices=['el1', 'el2', 'element 3']))
1328 self.add_option(FloatOption('General', 'flt', 30,
1329 'A Float', 'Testing a FLOAT-type ...',
1330 min=0, max=gtk.gdk.screen_width(), increment=0.01, digits=4))
1331 self.add_option(IntOption('General', 'x', 30,
1332 'X-Position', 'The X-position of this Screenlet ...',
1333 min=0, max=gtk.gdk.screen_width()))
1334 self.add_option(IntOption('General', 'y', 30,
1335 'Y-Position', 'The Y-position of this Screenlet ...',
1336 min=0, max=gtk.gdk.screen_height()))
1337 self.add_option(IntOption('Test', 'width', 300,
1338 'Width', 'The width of this Screenlet ...', min=100, max=1000))
1339 self.add_option(IntOption('Test', 'height', 150,
1340 'Height', 'The height of this Screenlet ...',
1341 min=100, max=1000))
1342 self.add_option(BoolOption('General', 'is_sticky', True,
1343 'Stick to Desktop', 'Show this Screenlet always ...'))
1344 self.add_option(BoolOption('General', 'is_widget', False,
1345 'Treat as Widget', 'Treat this Screenlet as a "Widget" ...'))
1346 self.add_option(FontOption('Test', 'font', 'Sans 14',
1347 'Font', 'The font for whatever ...'))
1348 self.add_option(ColorOption('Test', 'color', (1, 0.35, 0.35, 0.7),
1349 'Color', 'The color for whatever ...'))
1350 self.add_option(FileOption('Test', 'filename', os.environ['HOME'],
1351 'Filename-Test', 'Testing a FileOption-type ...',
1352 patterns=['*.py', '*.pyc']))
1353 self.add_option(ImageOption('Test', 'filename2', os.environ['HOME'],
1354 'Image-Test', 'Testing the ImageOption-type ...'))
1355 self.add_option(DirectoryOption('Test', 'dirname', os.environ['HOME'],
1356 'Directory-Test', 'Testing a FileOption-type ...'))
1357 self.add_option(TimeOption('Test','time', self.time,
1358 'TimeOption-Test', 'Testing a TimeOption-type ...'))
1359
1360 self.disable_option('width')
1361 self.disable_option('height')
1362
1363
1364
1366 self.__dict__[name] = value
1367 print name + "=" + str(value)
1368
1370 return self.__class__.__name__[:-6]
1371
1372
1373
1374
1376
1377 uses_theme = True
1378 theme_name = 'test'
1379
1381 TestObject.__init__(self)
1382 self.add_option(StringOption('Test', 'anothertest', 'ksjhsjgd',
1383 'Another Test', 'An attribute in the subclass ...'))
1384 self.add_option(StringOption('Test', 'theme_name', self.theme_name,
1385 'Theme', 'The theme for this Screenelt ...',
1386 choices=['test1', 'test2', 'mytheme', 'blue', 'test']))
1387
1388
1389
1390
1391 to = TestChildObject()
1392
1393 se = OptionsDialog(500, 380)
1394
1395 img = gtk.Image()
1396 img.set_from_file('../share/screenlets/Notes/icon.svg')
1397 se.set_info('TestOptions',
1398 'A test for an extended options-dialog with embedded about-info.' +
1399 ' Can be used for the Screenlets to have all in one ...\nNOTE:' +
1400 '<span color="red"> ONLY A TEST!</span>',
1401 '(c) RYX 2007', version='v0.0.1', icon=img)
1402 se.show_options_for_object(to)
1403 resp = se.run()
1404 if resp == gtk.RESPONSE_OK:
1405 print "OK"
1406 else:
1407 print "Cancelled."
1408 se.destroy()
1409 print to.export_options_as_list()
1410