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 self.gtk_screen = self.main_notebook.get_screen()
664 colormap = self.gtk_screen.get_rgba_colormap()
665 if colormap:
666 gtk.widget_set_default_colormap(colormap)
667
668 self.create_about_page()
669 self.create_themes_page()
670 self.create_options_page()
671
672 self.tooltips = gtk.Tooltips()
673
674
675
677 """Reset all entries for the currently shown object to their default
678 values (the values the object has when it is first created).
679 NOTE: This function resets ALL options, so BE CARFEUL!"""
680 if self.__shown_object:
681 for o in self.__shown_object.__options__:
682
683 setattr(self.__shown_object, o.name, o.default)
684
685 - def set_info (self, name, info, copyright='', version='', icon=None):
686 """Update the "About"-page with the given information."""
687
688 info = info.replace("\n", "")
689 info = info.replace("\t", " ")
690
691 markup = '\n<b><span size="xx-large">' + name + '</span></b>'
692 if version:
693 markup += ' <span size="large"><b>' + version + '</b></span>'
694 markup += '\n\n'+info+'\n<span size="small">\n'+copyright+'</span>'
695 self.infotext.set_markup(markup)
696
697 if icon:
698
699 if self.infoicon:
700 self.infoicon.destroy()
701
702 self.infoicon = icon
703 self.infoicon.set_alignment(0.0, 0.10)
704 self.infoicon.show()
705 self.hbox_about.pack_start(self.infoicon, 0, 1, 10)
706 else:
707 self.infoicon.hide()
708
710 """Update the OptionsEditor to show the options for the given Object.
711 The Object needs to be an EditableOptions-subclass.
712 NOTE: This needs heavy improvement and should use OptionGroups once
713 they exist"""
714 self.__shown_object = obj
715
716 notebook = gtk.Notebook()
717 self.vbox_editor.add(notebook)
718 for group in obj.__options_groups_ordered__:
719 group_data = obj.__options_groups__[group]
720
721 page = gtk.VBox()
722 page.set_border_width(10)
723 if group_data['info'] != '':
724 info = gtk.Label(group_data['info'])
725 info.show()
726 info.set_alignment(0, 0)
727 page.pack_start(info, 0, 0, 7)
728 sep = gtk.HSeparator()
729 sep.show()
730
731
732 box = gtk.VBox()
733 box.show()
734 box.set_border_width(5)
735
736 page.add(box)
737 page.show()
738
739 label = gtk.Label(group_data['label'])
740 label.show()
741 notebook.append_page(page, label)
742
743 for option in group_data['options']:
744 if option.hidden == False:
745 val = getattr(obj, option.name)
746 w = self.get_widget_for_option(option, val)
747 if w:
748 box.pack_start(w, 0, 0)
749 w.show()
750 notebook.show()
751
752 if obj.uses_theme and obj.theme_name != '':
753 self.show_themes_for_screenlet(obj)
754 else:
755 self.page_themes.hide()
756
758 """Update the Themes-page to display the available themes for the
759 given Screenlet-object."""
760
761 found_themes = []
762
763 for path in screenlets.SCREENLETS_PATH:
764 p = path + '/' + obj.get_short_name() + '/themes'
765 print p
766
767 try:
768 dircontent = os.listdir(p)
769 except:
770 print _("Path %s not found.") % p
771 continue
772
773 for name in dircontent:
774
775 if found_themes.count(name):
776 continue
777 found_themes.append(name)
778
779 theme_conf = p + '/' + name + '/theme.conf'
780
781 if os.access(theme_conf, os.F_OK):
782
783 ini = screenlets.utils.IniReader()
784 if ini.load(theme_conf):
785
786 if ini.has_section('Theme'):
787
788 th_fullname = ini.get_option('name',
789 section='Theme')
790 th_info = ini.get_option('info',
791 section='Theme')
792 th_version = ini.get_option('version',
793 section='Theme')
794 th_author = ini.get_option('author',
795 section='Theme')
796
797 info = [name, th_fullname, th_info, th_author,
798 th_version]
799 self.liststore.append([info])
800 else:
801
802 self.liststore.append([[name, '-', '-', '-', '-']])
803
804 if name == obj.theme_name:
805
806 print _("active theme is: %s") % name
807 sel = self.tree.get_selection()
808 if sel:
809 it = self.liststore.get_iter_from_string(\
810 str(len(self.liststore)-1))
811 if it:
812 sel.select_iter(it)
813
814
815
817 """Create the "About"-tab."""
818 self.page_about = gtk.HBox()
819
820 self.hbox_about = gtk.HBox()
821 self.hbox_about.show()
822 self.page_about.add(self.hbox_about)
823
824 self.infoicon = gtk.Image()
825 self.infoicon.show()
826 self.page_about.pack_start(self.infoicon, 0, 1, 10)
827
828 self.infotext = gtk.Label()
829 self.infotext.use_markup = True
830 self.infotext.set_line_wrap(True)
831 self.infotext.set_alignment(0.0, 0.0)
832 self.infotext.show()
833 self.page_about.pack_start(self.infotext, 1, 1, 5)
834
835 self.page_about.show()
836 self.main_notebook.append_page(self.page_about, gtk.Label(_('About ')))
837
839 """Create the "Options"-tab."""
840 self.page_options = gtk.HBox()
841
842 self.vbox_editor = gtk.VBox(spacing=3)
843 self.vbox_editor.set_border_width(5)
844 self.vbox_editor.show()
845 self.page_options.add(self.vbox_editor)
846
847 self.page_options.show()
848 self.main_notebook.append_page(self.page_options, gtk.Label(_('Options ')))
849
851 """Create the "Themes"-tab."""
852 self.page_themes = gtk.VBox(spacing=5)
853 self.page_themes.set_border_width(10)
854
855 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.'))
856 txt.set_size_request(450, -1)
857 txt.set_line_wrap(True)
858 txt.set_alignment(0.0, 0.0)
859 txt.show()
860 self.page_themes.pack_start(txt, False, True)
861
862 self.tree.set_headers_visible(False)
863 self.tree.connect('cursor-changed', self.__tree_cursor_changed)
864 self.tree.show()
865 col = gtk.TreeViewColumn('')
866 cell = gtk.CellRendererText()
867 col.pack_start(cell, True)
868
869 col.set_cell_data_func(cell, self.__render_cell)
870 self.tree.append_column(col)
871
872 sw = gtk.ScrolledWindow()
873 sw.set_shadow_type(gtk.SHADOW_IN)
874 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
875 sw.add(self.tree)
876 sw.show()
877
878 vbox = gtk.VBox()
879 vbox.pack_start(sw, True, True)
880 vbox.show()
881
882 self.page_themes.add(vbox)
883 self.page_themes.show()
884 self.main_notebook.append_page(self.page_themes, gtk.Label(_('Themes ')))
885
887 """Callback for rendering the cells in the theme-treeview."""
888
889 attrib = model.get_value(iter, 0)
890
891 col = '555555'
892 name_uc = attrib[0][0].upper() + attrib[0][1:]
893
894 if attrib[1] == '-' and attrib[2] == '-':
895 mu = '<b><span weight="ultrabold" size="large">' + name_uc + \
896 '</span></b> (' + _('no info available') + ')'
897 else:
898 mu = '<b><span weight="ultrabold" size="large">' + name_uc + \
899 '</span></b> v' + attrib[4] + '\n<small><span color="#555555' +\
900 '">' + attrib[2].replace('\\n', '\n') + \
901 '</span></small>\n<i><small>by '+str(attrib[3])+'</small></i>'
902
903 cell.set_property('markup', mu)
904
905
906
908 """Callback for handling selection changes in the Themes-treeview."""
909 sel = self.tree.get_selection()
910 if sel:
911 s = sel.get_selected()
912 if s:
913 it = s[1]
914 if it:
915 attribs = self.liststore.get_value(it, 0)
916 if attribs and self.__shown_object:
917
918
919 if self.__shown_object.theme_name != attribs[0]:
920 self.__shown_object.theme_name = attribs[0]
921
922
923
1014
1015 def but_callback (widget):
1016 dlg = gtk.FileChooserDialog(buttons=(gtk.STOCK_CANCEL,
1017 gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
1018 dlg.set_title(_("Choose Image"))
1019 dlg.set_keep_above(True)
1020 dlg.set_filename(entry.get_text())
1021 flt = gtk.FileFilter()
1022 flt.add_pixbuf_formats()
1023 dlg.set_filter(flt)
1024 prev = gtk.Image()
1025 box = gtk.VBox()
1026 box.set_size_request(150, -1)
1027 box.add(prev)
1028 prev.show()
1029
1030 def preview_callback(widget):
1031 fname = dlg.get_preview_filename()
1032 if fname and os.path.isfile(fname):
1033 pb = gtk.gdk.pixbuf_new_from_file_at_size(fname, 150, -1)
1034 if pb:
1035 prev.set_from_pixbuf(pb)
1036 dlg.set_preview_widget_active(True)
1037 else:
1038 dlg.set_preview_widget_active(False)
1039 dlg.set_preview_widget_active(True)
1040 dlg.connect('selection-changed', preview_callback)
1041 dlg.set_preview_widget(box)
1042
1043 response = dlg.run()
1044 if response == gtk.RESPONSE_OK:
1045 entry.set_text(dlg.get_filename())
1046 but.set_image(create_preview(dlg.get_filename()))
1047 self.options_callback(dlg, option)
1048 dlg.destroy()
1049
1050 but.set_image(create_preview(value))
1051 but.connect('clicked', but_callback)
1052
1053 widget = gtk.HBox()
1054 widget.add(entry)
1055 widget.add(but)
1056 but.show()
1057 widget.show()
1058
1059
1060 self.tooltips.set_tip(but, option.desc)
1061 elif t == ListOption:
1062 entry= gtk.Entry()
1063 entry.set_editable(False)
1064 entry.set_text(str(value))
1065 entry.show()
1066 img = gtk.Image()
1067 img.set_from_stock(gtk.STOCK_EDIT, 1)
1068 but = gtk.Button('')
1069 but.set_image(img)
1070 def open_listeditor(event):
1071
1072 dlg = ListOptionDialog()
1073
1074
1075 dlg.set_list(option.on_import(entry.get_text()))
1076 resp = dlg.run()
1077 if resp == gtk.RESPONSE_OK:
1078
1079 entry.set_text(str(dlg.get_list()))
1080
1081 self.options_callback(dlg, option)
1082 dlg.destroy()
1083 but.show()
1084 but.connect("clicked", open_listeditor)
1085 self.tooltips.set_tip(but, _('Open List-Editor ...'))
1086 self.tooltips.set_tip(entry, option.desc)
1087 widget = gtk.HBox()
1088 widget.add(entry)
1089 widget.add(but)
1090 elif t == AccountOption:
1091 widget = gtk.HBox()
1092 vb = gtk.VBox()
1093 input_name = gtk.Entry()
1094 input_name.set_text(value[0])
1095 input_name.show()
1096 input_pass = gtk.Entry()
1097 input_pass.set_visibility(False)
1098 input_pass.set_text(value[1])
1099 input_pass.show()
1100 but = gtk.Button('Apply', gtk.STOCK_APPLY)
1101 but.show()
1102 but.connect("clicked", self.apply_options_callback, option, widget)
1103 vb.add(input_name)
1104 vb.add(input_pass)
1105 vb.show()
1106 self.tooltips.set_tip(but, _('Apply username/password ...'))
1107 self.tooltips.set_tip(input_name, _('Enter username here ...'))
1108 self.tooltips.set_tip(input_pass, _('Enter password here ...'))
1109 widget.add(vb)
1110 widget.add(but)
1111 elif t == TimeOption:
1112 widget = gtk.HBox()
1113 input_hour = gtk.SpinButton()
1114 input_minute = gtk.SpinButton()
1115 input_second = gtk.SpinButton()
1116 input_hour.set_range(0, 23)
1117 input_hour.set_max_length(2)
1118 input_hour.set_increments(1, 1)
1119 input_hour.set_numeric(True)
1120 input_hour.set_value(value[0])
1121 input_minute.set_range(0, 59)
1122 input_minute.set_max_length(2)
1123 input_minute.set_increments(1, 1)
1124 input_minute.set_numeric(True)
1125 input_minute.set_value(value[1])
1126 input_second.set_range(0, 59)
1127 input_second.set_max_length(2)
1128 input_second.set_increments(1, 1)
1129 input_second.set_numeric(True)
1130 input_second.set_value(value[2])
1131 input_hour.connect('value-changed', self.options_callback, option)
1132 input_minute.connect('value-changed', self.options_callback, option)
1133 input_second.connect('value-changed', self.options_callback, option)
1134 self.tooltips.set_tip(input_hour, option.desc)
1135 self.tooltips.set_tip(input_minute, option.desc)
1136 self.tooltips.set_tip(input_second, option.desc)
1137 widget.add(input_hour)
1138 widget.add(gtk.Label(':'))
1139 widget.add(input_minute)
1140 widget.add(gtk.Label(':'))
1141 widget.add(input_second)
1142 widget.add(gtk.Label('h'))
1143 widget.show_all()
1144 else:
1145 widget = gtk.Entry()
1146 print _("unsupported type ''") % str(t)
1147 hbox = gtk.HBox()
1148 label = gtk.Label()
1149 label.set_alignment(0.0, 0.0)
1150 label.set_label(option.label)
1151 label.set_size_request(180, 28)
1152 label.show()
1153 hbox.pack_start(label, 0, 1)
1154 if widget:
1155 if option.disabled:
1156 widget.set_sensitive(False)
1157 label.set_sensitive(False)
1158
1159 self.tooltips.set_tip(widget, option.desc)
1160 widget.show()
1161
1162 if option.realtime == False:
1163 but = gtk.Button(_('Apply'), gtk.STOCK_APPLY)
1164 but.show()
1165 but.connect("clicked", self.apply_options_callback,
1166 option, widget)
1167 b = gtk.HBox()
1168 b.show()
1169 b.pack_start(widget, 0, 0)
1170 b.pack_start(but, 0, 0)
1171 hbox.pack_start(b, 0, 0)
1172 else:
1173
1174 hbox.pack_start(widget, 0, 0)
1175 return hbox
1176
1228
1229
1230
1231
1233 """Callback for handling changed-events on entries."""
1234 print _("Changed: %s") % optionobj.name
1235 if self.__shown_object:
1236
1237 if optionobj.realtime == False:
1238 return False
1239
1240 val = self.read_option_from_widget(widget, optionobj)
1241 if val != None:
1242
1243
1244 setattr(self.__shown_object, optionobj.name, val)
1245
1246 optionobj.emit("option_changed", optionobj)
1247 return False
1248
1250 """Callback for handling Apply-button presses."""
1251 if self.__shown_object:
1252
1253 val = self.read_option_from_widget(entry, optionobj)
1254 if val != None:
1255
1256
1257 setattr(self.__shown_object, optionobj.name, val)
1258
1259 optionobj.emit("option_changed", optionobj)
1260 return False
1261
1262
1263
1264
1265 if __name__ == "__main__":
1266
1267 import os
1268
1269
1271
1272 testlist = ['test1', 'test2', 3, 5, 'Noch ein Test']
1273 pop3_account = ('Username', '')
1274
1275
1276 pin_x = 100
1277 pin_y = 6
1278 text_x = 19
1279 text_y = 35
1280 font_name = 'Sans 12'
1281 rgba_color = (0.0, 0.0, 1.0, 1.0)
1282 text_prefix = '<b>'
1283 text_suffix = '</b>'
1284 note_text = ""
1285 random_pin_pos = True
1286 opt1 = 'testval 1'
1287 opt2 = 'testval 2'
1288 filename2 = ''
1289 filename = ''
1290 dirname = ''
1291 font = 'Sans 12'
1292 color = (0.1, 0.5, 0.9, 0.9)
1293 name = 'a name'
1294 name2 = 'another name'
1295 combo_test = 'el2'
1296 flt = 0.5
1297 x = 10
1298 y = 25
1299 width = 30
1300 height = 50
1301 is_sticky = False
1302 is_widget = False
1303 time = (12, 32, 49)
1304
1306 EditableOptions.__init__(self)
1307
1308 self.add_options_group('General',
1309 'The general options for this Object ...')
1310 self.add_options_group('Window',
1311 'The Window-related options for this Object ...')
1312 self.add_options_group('Test', 'A Test-group ...')
1313
1314 self.add_option(ListOption('Test', 'testlist', self.testlist,
1315 'ListOption-Test', 'Testing a ListOption-type ...'))
1316 self.add_option(StringOption('Window', 'name', 'TESTNAME',
1317 'Testname', 'The name/id of this Screenlet-instance ...'),
1318 realtime=False)
1319 self.add_option(AccountOption('Test', 'pop3_account',
1320 self.pop3_account, 'Username/Password',
1321 'Enter username/password here ...'))
1322 self.add_option(StringOption('Window', 'name2', 'TESTNAME2',
1323 'String2', 'Another string-test ...'))
1324 self.add_option(StringOption('Test', 'combo_test', "el1", 'Combo',
1325 'A StringOption displaying a drop-down-list with choices...',
1326 choices=['el1', 'el2', 'element 3']))
1327 self.add_option(FloatOption('General', 'flt', 30,
1328 'A Float', 'Testing a FLOAT-type ...',
1329 min=0, max=gtk.gdk.screen_width(), increment=0.01, digits=4))
1330 self.add_option(IntOption('General', 'x', 30,
1331 'X-Position', 'The X-position of this Screenlet ...',
1332 min=0, max=gtk.gdk.screen_width()))
1333 self.add_option(IntOption('General', 'y', 30,
1334 'Y-Position', 'The Y-position of this Screenlet ...',
1335 min=0, max=gtk.gdk.screen_height()))
1336 self.add_option(IntOption('Test', 'width', 300,
1337 'Width', 'The width of this Screenlet ...', min=100, max=1000))
1338 self.add_option(IntOption('Test', 'height', 150,
1339 'Height', 'The height of this Screenlet ...',
1340 min=100, max=1000))
1341 self.add_option(BoolOption('General', 'is_sticky', True,
1342 'Stick to Desktop', 'Show this Screenlet always ...'))
1343 self.add_option(BoolOption('General', 'is_widget', False,
1344 'Treat as Widget', 'Treat this Screenlet as a "Widget" ...'))
1345 self.add_option(FontOption('Test', 'font', 'Sans 14',
1346 'Font', 'The font for whatever ...'))
1347 self.add_option(ColorOption('Test', 'color', (1, 0.35, 0.35, 0.7),
1348 'Color', 'The color for whatever ...'))
1349 self.add_option(FileOption('Test', 'filename', os.environ['HOME'],
1350 'Filename-Test', 'Testing a FileOption-type ...',
1351 patterns=['*.py', '*.pyc']))
1352 self.add_option(ImageOption('Test', 'filename2', os.environ['HOME'],
1353 'Image-Test', 'Testing the ImageOption-type ...'))
1354 self.add_option(DirectoryOption('Test', 'dirname', os.environ['HOME'],
1355 'Directory-Test', 'Testing a FileOption-type ...'))
1356 self.add_option(TimeOption('Test','time', self.time,
1357 'TimeOption-Test', 'Testing a TimeOption-type ...'))
1358
1359 self.disable_option('width')
1360 self.disable_option('height')
1361
1362
1363
1365 self.__dict__[name] = value
1366 print name + "=" + str(value)
1367
1369 return self.__class__.__name__[:-6]
1370
1371
1372
1373
1375
1376 uses_theme = True
1377 theme_name = 'test'
1378
1380 TestObject.__init__(self)
1381 self.add_option(StringOption('Test', 'anothertest', 'ksjhsjgd',
1382 'Another Test', 'An attribute in the subclass ...'))
1383 self.add_option(StringOption('Test', 'theme_name', self.theme_name,
1384 'Theme', 'The theme for this Screenelt ...',
1385 choices=['test1', 'test2', 'mytheme', 'blue', 'test']))
1386
1387
1388
1389
1390 to = TestChildObject()
1391
1392 se = OptionsDialog(500, 380)
1393
1394 img = gtk.Image()
1395 img.set_from_file('../share/screenlets/Notes/icon.svg')
1396 se.set_info('TestOptions',
1397 'A test for an extended options-dialog with embedded about-info.' +
1398 ' Can be used for the Screenlets to have all in one ...\nNOTE:' +
1399 '<span color="red"> ONLY A TEST!</span>',
1400 '(c) RYX 2007', version='v0.0.1', icon=img)
1401 se.show_options_for_object(to)
1402 resp = se.run()
1403 if resp == gtk.RESPONSE_OK:
1404 print "OK"
1405 else:
1406 print "Cancelled."
1407 se.destroy()
1408 print to.export_options_as_list()
1409