8 from os
.path
import exists
11 # (C) 2008 Karl Pickett
18 # To install ourselves, we add an include line in the
19 # user font config file (default ~/.fonts.conf)
20 USER_FONT_CONF
= "~/.fonts.conf"
21 USER_FONT_CONF_BACKUP
= "~/.fonts.conf.fontmanager.save"
24 PRODUCT_TITLE
= _("Font Manager %s") % VERSION
26 FM_DIR
= "~/.fontmanager"
27 FM_BLOCK_CONF
= os
.path
.join(FM_DIR
, "fontmanager.conf")
28 FM_BLOCK_CONF_TMP
= FM_BLOCK_CONF
+ ".tmp"
29 FM_GROUP_CONF
= os
.path
.join(FM_DIR
, "groups.xml")
31 FC_INCLUDE_LINE
= "<include ignore_missing=\"yes\">%s</include>" % \
34 TEST_TEXT
= _("The Hungry Penguin Ate A Big Fish")
35 TEST_TEXT
+= _("\nABCDEFGHIJKLMNOPQRSTUVWXYZ")
36 TEST_TEXT
+= _("\n1234567890")
37 TEST_TEXT
+= _("\nabcdefghijklmnopqrstuvwxyz")
39 DEFAULT_CUSTOM_TEXT
= _("Enter Your Text Here")
41 SCALABLE_SIZES
= (200, 150, 100, 72, 48, 36, 24, 18, 14, 12, 10)
43 # What style gets shown first
44 DEFAULT_STYLES
= ["Regular", "Roman", "Medium", "Normal", "Book"]
49 <menubar name="MenuBar">
51 <menuitem action="Save"/>
53 <menuitem action="Quit"/>
55 <menu action="Collection">
56 <menuitem action="NewCollection"/>
57 <menuitem action="RenameCollection"/>
59 <menuitem action="DeleteCollection"/>
61 <menuitem action="TurnOnCollection"/>
62 <menuitem action="TurnOffCollection"/>
65 <menuitem action="Copy"/>
66 <menuitem action="Cut"/>
67 <menuitem action="Paste"/>
68 <menuitem action="Remove"/>
70 <menuitem action="TurnOn"/>
71 <menuitem action="TurnOff"/>
74 <menuitem action="ViewSample"/>
75 <menuitem action="ViewCustom"/>
77 <menuitem action="ViewDetails"/>
80 <menuitem action="About"/>
87 # Names of system font families as reported by fc-list
88 g_system_families
= {}
89 # map of family to list of filenames
91 # map of namily name to Family object
95 class Pattern(object):
96 __slots__
= ("family", "style")
99 self
.family
= self
.style
= None
101 class Collection (object):
102 __slots__
= ("name", "fonts", "builtin", "enabled")
104 def __init__(self
, name
):
114 return off(self
.name
)
116 def obj_exists(self
, obj
):
123 # check duplicate reference
124 if self
.obj_exists(obj
):
126 self
.fonts
.append(obj
)
131 def num_fonts_enabled(self
):
138 def set_enabled(self
, enabled
):
142 def set_enabled_from_fonts(self
):
143 self
.enabled
= (self
.num_fonts_enabled() > 0)
145 def remove(self
, font
):
146 self
.fonts
.remove(font
)
149 class Family(object):
150 __slots__
= ("family", "user", "enabled", "pango_family")
152 def __init__(self
, family
):
156 self
.pango_family
= None
160 return on(self
.family
)
162 return off(self
.family
)
164 def cmp_family(lhs
, rhs
):
165 return cmp(lhs
.family
, rhs
.family
)
169 def add_patelt_node(parent
, type, val
):
170 pi
= parent
.newChild(None, "patelt", None)
171 pi
.setProp("name", type)
172 str = pi
.newChild(None, "string", val
)
174 def get_fontconfig_patterns(node
, patterns
):
175 for n
in node
.xpathEval('pattern'):
177 for c
in n
.xpathEval('patelt'):
178 name
= c
.prop("name")
180 p
.family
= c
.xpathEval('string')[0].content
186 def gtk_markup_escape(str):
187 str = str.replace("&", "&")
188 str = str.replace("<", "<")
189 str = str.replace(">", ">")
193 str = gtk_markup_escape(str)
194 return "<span weight='heavy'>%s</span>" % str
197 str = gtk_markup_escape(str)
198 return "<span weight='ultralight'>%s Off</span>" % str
203 def strip_fontconfig_family(family
):
208 family
= family
.replace("\\-", "-")
209 family
= family
.strip()
212 def load_fontconfig_files():
213 cmd
= "fc-list : file family"
214 for l
in os
.popen(cmd
).readlines():
218 file, family
= l
.split(":")
219 family
= strip_fontconfig_family(family
)
220 list = g_font_files
.get(family
, None)
223 g_font_files
[family
] = list
226 def load_fontconfig_system_families():
227 cmd
= "HOME= fc-list : family"
228 print "Executing %s..." % cmd
229 for l
in os
.popen(cmd
).readlines():
231 family
= strip_fontconfig_family(l
)
232 g_system_families
[family
] = 1
235 def load_fonts(widget
):
236 ctx
= widget
.get_pango_context()
237 families
= ctx
.list_families()
239 obj
= Family(f
.get_name())
241 if not g_system_families
.has_key(f
.get_name()):
243 g_fonts
[f
.get_name()] = obj
245 def find_font(family
):
246 return g_fonts
.get(family
, None)
250 def save_blacklist():
251 doc
= libxml2
.newDoc("1.0")
252 root
= doc
.newChild(None, "fontconfig", None)
253 n
= root
.newChild(None, "selectfont", None)
254 n
= n
.newChild(None, "rejectfont", None)
256 for font
in g_fonts
.itervalues():
258 p
= n
.newChild(None, "pattern", None)
259 add_patelt_node(p
, "family", font
.family
)
261 print "Writing to %s" % FM_BLOCK_CONF
262 doc
.saveFormatFile(FM_BLOCK_CONF
, format
=1)
265 def load_blacklist(filename
):
266 if not exists(filename
):
270 doc
= libxml2
.parseFile(filename
)
271 rejects
= doc
.xpathEval('//rejectfont')
273 get_fontconfig_patterns(a
, patterns
)
279 def set_blacklist(pattern
):
280 font
= find_font(pattern
.family
)
284 def enable_blacklist():
285 if exists(FM_BLOCK_CONF_TMP
):
286 if exists(FM_BLOCK_CONF
):
287 os
.unlink(FM_BLOCK_CONF
)
288 os
.rename(FM_BLOCK_CONF_TMP
, FM_BLOCK_CONF
)
290 def disable_blacklist():
291 if exists(FM_BLOCK_CONF
):
292 if exists(FM_BLOCK_CONF_TMP
):
293 os
.unlink(FM_BLOCK_CONF_TMP
)
294 os
.rename(FM_BLOCK_CONF
, FM_BLOCK_CONF_TMP
)
296 def get_filenames(family
):
299 pipe
= subprocess
.Popen(["fc-list", family
, "file"],
300 stdout
=subprocess
.PIPE
).stdout
302 ret
.append(line
.split(':')[0].strip())
308 def get_font_details_text(family
):
309 filenames
= g_font_files
.get(family
, None)
310 str = "%s\n\n" % family
313 str += "No Files Found"
317 str += "%s %d KB\n" % (f
, st
.st_size
/ 1024)
326 class FontBook(gtk
.Window
):
327 def __init__(self
, parent
=None):
328 gtk
.Window
.__init
__(self
)
329 self
.connect('destroy', lambda *w
: self
.action_quit(None))
331 self
.uimanager
= gtk
.UIManager()
332 accelgroup
= self
.uimanager
.get_accel_group()
333 self
.add_accel_group(accelgroup
)
335 self
.create_actions()
337 vb
= gtk
.VBox(False, 0)
338 vb
.pack_start(self
.menu_bar
, False, False, 0)
340 self
.DRAG_TARGETS
= [("test", gtk
.TARGET_SAME_APP
, 0)]
341 self
.DRAG_ACTIONS
= gtk
.gdk
.ACTION_LINK
343 self
.set_title(PRODUCT_TITLE
)
344 self
.set_default_size(700, 450)
345 #self.set_border_width(8)
347 hbox
= gtk
.HBox(False, 3)
348 hbox
.set_homogeneous(False)
350 w
= self
.init_collections()
351 hbox
.pack_start(w
, False)
352 w
= self
.init_families()
353 hbox
.pack_start(w
, False)
354 w
= self
.init_text_view()
357 self
.copy_buffer
= []
360 self
.custom_text
= DEFAULT_CUSTOM_TEXT
361 self
.preview_mode
= 0
363 load_fontconfig_system_families()
364 load_fontconfig_files()
366 load_blacklist(FM_BLOCK_CONF_TMP
)
370 self
.create_collections()
371 #self.show_collection(self.collections[0])
372 self
.collection_tv
.get_selection().select_path(0)
373 self
.family_tv
.get_selection().select_path(0)
377 def init_collections(self
):
378 sw
= gtk
.ScrolledWindow()
379 sw
.set_shadow_type(gtk
.SHADOW_ETCHED_IN
)
380 sw
.set_policy(gtk
.POLICY_NEVER
, gtk
.POLICY_AUTOMATIC
)
382 model
= gtk
.ListStore(gobject
.TYPE_STRING
, gobject
.TYPE_PYOBJECT
,
385 treeview
= gtk
.TreeView(model
)
386 treeview
.set_search_column(2)
387 treeview
.get_selection().connect("changed", self
.collection_changed
)
390 treeview
.connect("drag-data-received", self
.drag_data_received
)
391 treeview
.enable_model_drag_dest(self
.DRAG_TARGETS
, self
.DRAG_ACTIONS
)
392 treeview
.connect("row-activated", self
.collection_activated
)
393 treeview
.set_row_separator_func(self
.is_row_separator_collection
)
395 r
= gtk
.CellRendererText()
396 column
= gtk
.TreeViewColumn(_('Collection'), r
, markup
=0)
398 #column.set_sort_column_id(0)
399 treeview
.append_column(column
)
401 self
.collection_tv
= treeview
406 def init_families(self
):
407 sw
= gtk
.ScrolledWindow()
408 sw
.set_shadow_type(gtk
.SHADOW_ETCHED_IN
)
409 sw
.set_policy(gtk
.POLICY_NEVER
, gtk
.POLICY_AUTOMATIC
)
411 model
= gtk
.ListStore(gobject
.TYPE_STRING
, gobject
.TYPE_PYOBJECT
,
414 treeview
= gtk
.TreeView(model
)
415 treeview
.set_search_column(2)
416 treeview
.get_selection().set_mode(gtk
.SELECTION_MULTIPLE
)
417 treeview
.get_selection().connect("changed", self
.font_changed
)
418 treeview
.connect("row-activated", self
.font_activated
)
421 #treeview.connect("drag-data-get", self.drag_data_get)
422 treeview
.enable_model_drag_source(gtk
.gdk
.BUTTON1_MASK
,
423 self
.DRAG_TARGETS
, self
.DRAG_ACTIONS
)
425 column
= gtk
.TreeViewColumn(_('Font'), gtk
.CellRendererText(),
427 column
.set_sort_column_id(2)
428 treeview
.append_column(column
)
430 self
.family_tv
= treeview
435 def init_text_view(self
):
436 #self.notebook = gtk.Notebook()
438 view
= gtk
.TextView()
439 sw
= gtk
.ScrolledWindow()
440 sw
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_AUTOMATIC
)
441 self
.text_view
= view
442 self
.text_view
.set_left_margin(8)
443 self
.text_view
.set_right_margin(8)
444 self
.text_view
.set_wrap_mode(gtk
.WRAP_WORD_CHAR
)
448 #self.font_label = gtk.Label(_("Preview"))
449 self
.style_combo
= gtk
.combo_box_new_text()
450 self
.size_combo
= gtk
.combo_box_new_text()
453 vb
.pack_start(hb
, False)
455 #hb.pack_start(self.font_label, False)
456 hb
.pack_end(self
.style_combo
, False)
457 hb
.pack_end(self
.size_combo
, False)
458 self
.set_scalable_sizes()
459 self
.style_combo
.connect("changed", self
.style_changed
)
460 self
.size_combo
.connect("changed", self
.size_changed
)
465 def create_actions(self
):
466 g
= gtk
.ActionGroup('global')
468 add_action(g
, "File", None, "_File", None)
469 add_action(g
, 'Collection', None, "_Collection", None)
470 add_action(g
, 'Font', None, "Font", None)
471 add_action(g
, 'View', None, "_View", None)
472 add_action(g
, 'Help', None, "_Help", None)
474 add_action(g
, 'Quit', gtk
.STOCK_QUIT
, None,
476 add_action(g
, 'Save', gtk
.STOCK_SAVE
, None,
479 add_action(g
, 'NewCollection', gtk
.STOCK_NEW
, "_New Collection",
480 self
.action_new_collection
)
482 add_action(g
, 'About', gtk
.STOCK_ABOUT
, None,
484 self
.uimanager
.insert_action_group(g
, 0)
487 g
.add_radio_actions([
488 ('ViewSample', None, "_Sample Text", "<Control>1", None, 0),
489 ('ViewCustom', None, "_Custom Text", "<Control>2", None, 1),
490 ('ViewDetails', None, "_Font Information", "<Control>3", None, 2),
491 ], 0, self
.preview_mode_changed
)
494 # any collection selected
495 g
= gtk
.ActionGroup('collection_selected')
496 g
.set_sensitive(False)
497 add_action(g
, 'TurnOnCollection', None, "_Enable Collection",
498 self
.action_turn_on_collection
)
499 add_action(g
, 'TurnOffCollection', None, "_Disable Collection",
500 self
.action_turn_off_collection
)
501 self
.uimanager
.insert_action_group(g
, 0)
502 self
.ag_collection_selected
= g
505 # user collection selected
506 g
= gtk
.ActionGroup('user-collection_selected')
507 g
.set_sensitive(False)
508 add_action(g
, 'DeleteCollection', None, "Delete Collection",
509 self
.action_delete_collection
, "<Ctrl>d")
510 add_action(g
, 'RenameCollection', None, "Rename Collection",
511 self
.action_rename_collection
, "<Ctrl>r")
512 self
.uimanager
.insert_action_group(g
, 0)
513 self
.ag_user_collection_selected
= g
515 g
= gtk
.ActionGroup('ag-paste')
516 g
.set_sensitive(False)
517 add_action(g
, 'Paste', gtk
.STOCK_PASTE
, None,
520 self
.uimanager
.insert_action_group(g
, 0)
522 g
= gtk
.ActionGroup('ag-cut')
523 g
.set_sensitive(False)
524 add_action(g
, 'Cut', gtk
.STOCK_CUT
, None,
526 add_action(g
, 'Remove', gtk
.STOCK_DELETE
, "Remove",
529 self
.uimanager
.insert_action_group(g
, 0)
532 g
= gtk
.ActionGroup('font_selected')
533 g
.set_sensitive(False)
534 add_action(g
, 'TurnOn', None, "_Enable Font(s)",
536 add_action(g
, 'TurnOff', None, "_Disable Font(s)",
537 self
.action_turn_off
)
538 add_action(g
, 'Copy', gtk
.STOCK_COPY
, None,
540 self
.ag_font_selected
= g
541 self
.uimanager
.insert_action_group(g
, 0)
543 self
.uimanager
.add_ui_from_string(UI_XML
)
544 self
.menu_bar
= self
.uimanager
.get_widget('/MenuBar')
551 def action_save(self
, a
):
554 def action_quit(self
, a
):
558 def collection_name_exists(self
, name
):
559 for c
in self
.collections
:
564 def action_new_collection(self
, a
):
565 str = _("New Collection")
567 str = self
.get_new_collection_name(str)
570 if not self
.collection_name_exists(str):
574 self
.add_collection(c
)
576 def action_delete_collection(self
, a
):
577 c
= self
.get_current_collection()
578 self
.ag_paste
.set_sensitive(False)
579 self
.ag_collection_selected
.set_sensitive(False)
580 self
.collections
.remove(c
)
583 def action_rename_collection(self
, a
):
584 c
= self
.get_current_collection()
587 str = self
.get_new_collection_name(str)
588 if not str or c
.name
== str:
590 if not self
.collection_name_exists(str):
592 self
.update_collection_view()
595 def action_about(self
, a
):
596 d
= gtk
.AboutDialog()
597 d
.set_name(PRODUCT_TITLE
)
598 d
.set_copyright("2008 Karl Pickett/penguindev")
599 d
.set_license("GPL3")
600 d
.set_website("http://fontmanager.blogspot.com/")
604 def action_turn_on_collection(self
, a
):
605 self
.enable_collection(True)
607 def action_turn_off_collection(self
, a
):
608 self
.enable_collection(False)
610 def collection_activated(self
, tv
, path
, col
):
611 c
= self
.get_current_collection()
612 self
.enable_collection(not c
.enabled
)
614 def enable_collection(self
, enabled
):
615 c
= self
.get_current_collection()
616 if c
.builtin
and not self
.confirm_enable_collection(enabled
):
618 c
.set_enabled(enabled
)
621 def confirm_enable_collection(self
, enabled
):
622 d
= gtk
.Dialog(_("Confirm Action"),
623 self
, gtk
.DIALOG_MODAL
,
624 (gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
625 gtk
.STOCK_OK
, gtk
.RESPONSE_OK
))
626 d
.set_default_response(gtk
.RESPONSE_CANCEL
)
628 c
= self
.get_current_collection()
630 str = _("Are you sure you want to enable the \"%s\" built in collection?") % c
.name
632 str = _("Are you sure you want to disable the \"%s\" built in collection?") % c
.name
636 d
.vbox
.pack_start(text
, padding
=10)
641 return (ret
== gtk
.RESPONSE_OK
)
644 def is_row_separator_collection(self
, model
, iter):
645 obj
= model
.get(iter, 1)[0]
646 #print "is_row_separator_collection", obj, iter
651 def action_remove(self
, a
):
652 c
= self
.get_current_collection()
653 for f
in self
.iter_selected_fonts():
657 def action_cut(self
, a
):
660 def action_copy(self
, a
):
663 def action_paste(self
, a
):
664 c
= self
.get_current_collection()
665 for f
in self
.copy_buffer
:
666 if not c
.obj_exists(f
):
668 self
.add_font_to_view(f
)
671 def do_copy(self
, cut
):
672 c
= self
.get_current_collection()
673 self
.copy_buffer
= []
675 for f
in self
.iter_selected_fonts():
676 self
.copy_buffer
.append(f
)
683 self
.ag_paste
.set_sensitive(True)
686 def iter_selected_fonts(self
):
687 sel
= self
.family_tv
.get_selection()
688 m
, path_list
= sel
.get_selected_rows()
693 def action_turn_on(self
, a
):
694 for f
in self
.iter_selected_fonts():
698 def action_turn_off(self
, a
):
699 for f
in self
.iter_selected_fonts():
703 def font_activated(self
, tv
, path
, col
):
704 for f
in self
.iter_selected_fonts():
705 f
.enabled
= (not f
.enabled
)
711 def update_views(self
):
712 self
.update_collection_view()
713 self
.update_font_view()
715 def update_collection_view(self
):
716 for c
in self
.collections
:
717 c
.set_enabled_from_fonts()
719 model
= self
.collection_tv
.get_model()
720 iter = model
.get_iter_first()
722 label
, obj
= model
.get(iter, 0, 1)
724 iter = model
.iter_next(iter)
726 if obj
in self
.collections
:
727 new_label
= obj
.get_label()
728 if label
!= new_label
:
729 model
.set(iter, 0, new_label
)
730 iter = model
.iter_next(iter)
732 if not model
.remove(iter):
735 def update_font_view(self
):
736 c
= self
.get_current_collection()
737 model
= self
.family_tv
.get_model()
738 iter = model
.get_iter_first()
740 label
, obj
= model
.get(iter, 0, 1)
742 new_label
= obj
.get_label()
743 if label
!= new_label
:
744 model
.set(iter, 0, new_label
)
745 iter = model
.iter_next(iter)
747 if not model
.remove(iter):
750 def preview_mode_changed(self
, a
, b
):
751 if self
.preview_mode
== 1:
752 self
.custom_text
= self
.get_current_text()
754 self
.preview_mode
= a
.get_current_value()
755 combos_visible
= (self
.preview_mode
!= 2)
756 self
.size_combo
.set_property("visible", combos_visible
)
757 self
.style_combo
.set_property("visible", combos_visible
)
758 self
.set_preview_text(self
.current_descr
, False)
760 def get_current_text(self
):
761 print "get_current_text"
762 b
= self
.text_view
.get_buffer()
763 return b
.get_text(b
.get_start_iter(), b
.get_end_iter())
766 def get_current_collection(self
):
767 sel
= self
.collection_tv
.get_selection()
768 m
, iter = sel
.get_selected()
771 return m
.get(iter, 1)[0]
773 def collection_changed(self
, sel
):
774 c
= self
.get_current_collection()
776 print "collection_changed", c
.name
777 self
.ag_user_collection_selected
.set_sensitive(not c
.builtin
)
778 self
.ag_collection_selected
.set_sensitive(True)
780 self
.ag_paste
.set_sensitive(False)
781 elif self
.copy_buffer
:
782 self
.ag_paste
.set_sensitive(True)
783 self
.show_collection(c
)
785 self
.ag_user_collection_selected
.set_sensitive(False)
786 self
.ag_collection_selected
.set_sensitive(False)
788 self
.show_collection(None)
790 def font_changed(self
, sel
):
792 m
, path_list
= tv
.get_selection().get_selected_rows()
793 rows
= len(path_list
)
795 self
.ag_font_selected
.set_sensitive(False)
796 self
.ag_cut
.set_sensitive(False)
799 if not self
.get_current_collection().builtin
:
800 self
.ag_cut
.set_sensitive(True)
802 self
.ag_font_selected
.set_sensitive(True)
806 obj
= m
[path_list
[0]][1]
807 if isinstance(obj
, Family
):
808 #print "family changed", f.family
809 self
.change_font(obj
)
811 def get_new_collection_name(self
, old_name
):
812 d
= gtk
.Dialog(_("Enter Collection Name"),
813 self
, gtk
.DIALOG_MODAL
,
814 (gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
815 gtk
.STOCK_OK
, gtk
.RESPONSE_OK
))
816 d
.set_default_response(gtk
.RESPONSE_OK
)
820 text
.set_text(old_name
)
821 text
.set_property("activates-default", True)
822 d
.vbox
.pack_start(text
)
827 if ret
== gtk
.RESPONSE_OK
:
828 return text
.get_text().strip()
833 def drag_data_received(self
, treeview
, context
, x
, y
,
834 selection
, info
, timestamp
):
835 #print "drag_data_received"
836 drop_info
= treeview
.get_dest_row_at_pos(x
, y
)
839 model
= treeview
.get_model()
840 path
, position
= drop_info
842 collection
= model
[path
][1]
843 collection
.add(self
.get_dragged_font())
848 # GTK only supports dragging a single row? :(
849 def get_dragged_font(self
):
850 for f
in self
.iter_selected_fonts():
854 def save_config(self
):
855 if not is_installed():
858 self
.save_collection()
860 def save_collection(self
):
861 doc
= libxml2
.newDoc("1.0")
862 root
= doc
.newChild(None, "fontmanager", None)
863 for c
in self
.collections
:
866 cn
= root
.newChild(None, "fontcollection", None)
867 cn
.setProp("name", c
.name
)
869 p
= cn
.newChild(None, "pattern", None)
870 add_patelt_node(p
, "family", f
.family
)
872 doc
.saveFormatFile(FM_GROUP_CONF
, format
=1)
875 def create_collections(self
):
876 self
.collections
= []
878 c
= Collection(_("All Fonts"))
879 for f
in sorted(g_fonts
.itervalues(), Family
.cmp_family
):
881 self
.add_collection(c
)
883 c
= Collection(_("System"))
884 for f
in sorted(g_fonts
.itervalues(), Family
.cmp_family
):
887 self
.add_collection(c
)
889 c
= Collection(_("User"))
890 for f
in sorted(g_fonts
.itervalues(), Family
.cmp_family
):
893 self
.add_collection(c
)
895 # add separator - hack
896 lstore
= self
.collection_tv
.get_model()
897 iter = lstore
.append()
898 lstore
.set(iter, 1, None)
900 self
.load_user_collections()
903 def add_collection(self
, c
):
904 c
.set_enabled_from_fonts()
905 lstore
= self
.collection_tv
.get_model()
906 iter = lstore
.append()
907 lstore
.set(iter, 0, c
.get_label())
908 lstore
.set(iter, 1, c
)
909 lstore
.set(iter, 2, c
.get_text())
910 self
.collections
.append(c
)
912 def load_user_collections(self
):
913 if not exists(FM_GROUP_CONF
):
915 doc
= libxml2
.parseFile(FM_GROUP_CONF
)
916 nodes
= doc
.xpathEval('//fontcollection')
919 name
= a
.prop("name")
920 get_fontconfig_patterns(a
, patterns
)
925 font
= find_font(p
.family
)
929 self
.add_collection(c
)
930 print "Loaded user collection %s" % name
934 def size_changed(self
, combo
):
935 if combo
.get_active() < 0:
937 self
.change_font(self
.current_font
)
940 def style_changed(self
, combo
):
941 if combo
.get_active() < 0:
943 style
= combo
.get_model()[combo
.get_active()][0]
944 faces
= self
.current_font
.pango_family
.list_faces()
946 if face
.get_face_name() == style
:
947 descr
= face
.describe()
948 self
.set_preview_text(descr
)
952 def change_font(self
, font
):
953 self
.current_font
= font
954 self
.style_combo
.get_model().clear()
955 faces
= font
.pango_family
.list_faces()
962 name
= face
.get_face_name()
963 self
.style_combo
.append_text(name
)
964 if name
in DEFAULT_STYLES
or not selected_face
:
969 self
.style_combo
.set_active(active
)
970 self
.set_preview_text(selected_face
.describe())
972 def get_current_size(self
):
973 i
= self
.size_combo
.get_active()
976 model
= self
.size_combo
.get_model()
980 def set_scalable_sizes(self
):
981 for size
in SCALABLE_SIZES
:
982 self
.size_combo
.append_text(str(size
))
983 self
.size_combo
.set_active(6)
985 def set_preview_text(self
, descr
, update_custom
=True):
986 if update_custom
and self
.preview_mode
== 1:
987 self
.custom_text
= self
.get_current_text()
989 self
.text_view
.set_editable(self
.preview_mode
== 1)
991 b
= self
.text_view
.get_buffer()
994 for tag
in self
.font_tags
:
995 b
.get_tag_table().remove(tag
)
999 if self
.preview_mode
== 2:
1001 tag
= b
.create_tag(None, size_points
=size
)
1003 size
= self
.get_current_size()
1004 tag
= b
.create_tag(None, font_desc
=descr
, size_points
=size
)
1005 self
.font_tags
.append(tag
)
1007 if self
.preview_mode
== 0:
1008 b
.insert_with_tags(b
.get_end_iter(), descr
.to_string() + "\n", tag
)
1009 b
.insert_with_tags(b
.get_end_iter(), TEST_TEXT
+ "\n", tag
)
1010 elif self
.preview_mode
== 1:
1011 b
.insert_with_tags(b
.get_end_iter(), self
.custom_text
, tag
)
1013 text
= get_font_details_text(self
.current_font
.family
)
1014 b
.insert_with_tags(b
.get_end_iter(), text
, tag
)
1016 self
.current_descr
= descr
1021 def show_collection(self
, c
):
1022 lstore
= self
.family_tv
.get_model()
1029 self
.add_font_to_view(f
)
1031 def add_font_to_view(self
, f
):
1032 lstore
= self
.family_tv
.get_model()
1033 iter = lstore
.append(None)
1034 lstore
.set(iter, 0, f
.get_label())
1035 lstore
.set(iter, 1, f
)
1036 lstore
.set(iter, 2, f
.family
)
1039 def add_action(g
, action
, stock
, label
, cb
, accel
=None):
1040 g
.add_actions([(action
, stock
, label
, accel
, None, cb
)])
1044 if not exists(USER_FONT_CONF
):
1045 print "User conf file %s does not exist" % USER_FONT_CONF
1048 for l
in open(USER_FONT_CONF
):
1049 if l
.strip() == FC_INCLUDE_LINE
:
1050 print "Include exists in %s" % USER_FONT_CONF
1052 print "Include does not exist in %s" % USER_FONT_CONF
1055 # put an include into ~/.fonts.conf
1057 if not exists(USER_FONT_CONF
):
1058 print "Making empty user conf file %s" % USER_FONT_CONF
1059 f
= open(USER_FONT_CONF
, "w")
1060 f
.write("<fontconfig>\n</fontconfig>\n")
1063 tmpname
= USER_FONT_CONF
+ ".fontmanager.tmp"
1064 print "Starting install, adding %s to %s" % (FC_INCLUDE_LINE
, USER_FONT_CONF
)
1065 print "Backup will be saved as %s" % USER_FONT_CONF_BACKUP
1066 tmp
= open(tmpname
, "w")
1067 for l
in open(USER_FONT_CONF
):
1068 if l
.strip() == "</fontconfig>":
1069 tmp
.write(FC_INCLUDE_LINE
+ "\n")
1072 print "Saving backup %s" % USER_FONT_CONF_BACKUP
1073 os
.rename(USER_FONT_CONF
, USER_FONT_CONF_BACKUP
)
1074 print "Overwriting %s" % USER_FONT_CONF
1075 os
.rename(tmpname
, USER_FONT_CONF
)
1079 def update_home(path
):
1080 return path
.replace("~", os
.getenv("HOME"))
1083 if not exists(FM_DIR
):
1084 print "Creating %s" % (FM_DIR
)
1087 print "Disabling blacklist temporarily..."
1092 print "Reenabling blacklist"
1097 if __name__
== '__main__':
1098 FM_DIR
= update_home(FM_DIR
)
1099 FM_BLOCK_CONF
= update_home(FM_BLOCK_CONF
)
1100 FM_BLOCK_CONF_TMP
= update_home(FM_BLOCK_CONF_TMP
)
1101 FM_GROUP_CONF
= update_home(FM_GROUP_CONF
)
1103 USER_FONT_CONF
= update_home(USER_FONT_CONF
)
1104 USER_FONT_CONF_BACKUP
= update_home(USER_FONT_CONF_BACKUP
)