Implement Gramps bottombar
svn: r16360
This commit is contained in:
		| @@ -15,6 +15,7 @@ pkgdatadir = $(datadir)/@PACKAGE@/gui | ||||
| pkgdata_PYTHON = \ | ||||
| 	__init__.py \ | ||||
| 	basesidebar.py \ | ||||
| 	bottombar.py \ | ||||
| 	columnorder.py \ | ||||
| 	configure.py \ | ||||
| 	dbguielement.py \ | ||||
|   | ||||
							
								
								
									
										421
									
								
								src/gui/bottombar.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										421
									
								
								src/gui/bottombar.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,421 @@ | ||||
| # | ||||
| # Gramps - a GTK+/GNOME based genealogy program | ||||
| # | ||||
| # Copyright (C) 2011 Nick Hall | ||||
| # | ||||
| # This program is free software; you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation; either version 2 of the License, or | ||||
| # (at your option) any later version. | ||||
| # | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software | ||||
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| # | ||||
| # $Id$ | ||||
|  | ||||
| #------------------------------------------------------------------------- | ||||
| # | ||||
| # Python modules | ||||
| # | ||||
| #------------------------------------------------------------------------- | ||||
| from gen.ggettext import gettext as _ | ||||
|  | ||||
| #------------------------------------------------------------------------- | ||||
| # | ||||
| # GNOME modules | ||||
| # | ||||
| #------------------------------------------------------------------------- | ||||
| import gtk | ||||
| import time | ||||
| import os | ||||
|  | ||||
| #------------------------------------------------------------------------- | ||||
| # | ||||
| # Gramps modules | ||||
| # | ||||
| #------------------------------------------------------------------------- | ||||
| import ConfigParser | ||||
| import const | ||||
| from gui.widgets.grampletpane import (AVAILABLE_GRAMPLETS, | ||||
|                                       GET_AVAILABLE_GRAMPLETS, | ||||
|                                       get_gramplet_opts, | ||||
|                                       get_gramplet_options_by_tname, | ||||
|                                       get_gramplet_options_by_name, | ||||
|                                       make_requested_gramplet) | ||||
| from ListModel import ListModel, NOSORT | ||||
|  | ||||
| #------------------------------------------------------------------------- | ||||
| # | ||||
| # Constants | ||||
| # | ||||
| #------------------------------------------------------------------------- | ||||
| NL = "\n" | ||||
|  | ||||
| #------------------------------------------------------------------------- | ||||
| # | ||||
| # Bottombar class | ||||
| # | ||||
| #------------------------------------------------------------------------- | ||||
| class Bottombar(object): | ||||
|     """ | ||||
|     A class which defines the graphical representation of the Gramps bottom bar. | ||||
|     """ | ||||
|     def __init__(self, dbstate, uistate, configfile, close_callback, defaults): | ||||
|  | ||||
|         self.dbstate = dbstate | ||||
|         self.uistate  = uistate | ||||
|         self.configfile = os.path.join(const.VERSION_DIR, "%s.ini" % configfile) | ||||
|         self.close_callback = close_callback | ||||
|         self.gramplet_map = {} # title->gramplet | ||||
|  | ||||
|         self.top = gtk.HBox() | ||||
|         self.notebook = gtk.Notebook() | ||||
|         self.notebook.set_show_border(False) | ||||
|         self.notebook.set_scrollable(True) | ||||
|         self.notebook.connect('switch_page', self.__switch_page) | ||||
|  | ||||
|         vbox = gtk.VBox() | ||||
|  | ||||
|         close_button = gtk.Button() | ||||
|         img = gtk.image_new_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU) | ||||
|         close_button.set_image(img) | ||||
|         close_button.set_relief(gtk.RELIEF_NONE) | ||||
|         close_button.connect('clicked', self.__close_clicked) | ||||
|         vbox.pack_start(close_button, False) | ||||
|          | ||||
|         delete_button = gtk.Button() | ||||
|         img = gtk.image_new_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_MENU) | ||||
|         delete_button.set_image(img) | ||||
|         delete_button.set_relief(gtk.RELIEF_NONE) | ||||
|         delete_button.connect('clicked', self.__delete_clicked) | ||||
|         vbox.pack_end(delete_button, False) | ||||
|  | ||||
|         add_button = gtk.Button() | ||||
|         img = gtk.image_new_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_MENU) | ||||
|         add_button.set_image(img) | ||||
|         add_button.set_relief(gtk.RELIEF_NONE) | ||||
|         add_button.connect('clicked', self.__add_clicked) | ||||
|         vbox.pack_end(add_button, False) | ||||
|  | ||||
|         self.top.pack_start(self.notebook, True) | ||||
|         self.top.pack_start(vbox, False) | ||||
|          | ||||
|         vbox.show_all() | ||||
|         self.notebook.show() | ||||
|  | ||||
|         self.default_gramplets = defaults | ||||
|         config_settings = self.load_gramplets() | ||||
|  | ||||
|         for (name, opts) in config_settings[1]: | ||||
|             all_opts = get_gramplet_opts(name, opts) | ||||
|             gramplet = make_requested_gramplet(self, name, all_opts,  | ||||
|                                                self.dbstate, self.uistate) | ||||
|             self.gramplet_map[all_opts["title"]] = gramplet | ||||
|  | ||||
|         gramplets = [g for g in self.gramplet_map.itervalues()  | ||||
|                         if g is not None] | ||||
|         gramplets.sort(key=lambda x: x.page) | ||||
|         for gramplet in gramplets: | ||||
|             gramplet.scrolledwindow.set_size_request(-1, 200) | ||||
|             self.notebook.append_page(gramplet.mainframe, | ||||
|                                       gtk.Label(gramplet.title)) | ||||
|             self.notebook.set_tab_reorderable(gramplet.mainframe, True) | ||||
|  | ||||
|         if config_settings[0][0]: | ||||
|             self.top.show() | ||||
|         self.notebook.set_current_page(config_settings[0][1]) | ||||
|          | ||||
|     def load_gramplets(self): | ||||
|         """ | ||||
|         Load the gramplets from the configuration file. | ||||
|         """ | ||||
|         retval = [] | ||||
|         visible = False | ||||
|         default_page = 0 | ||||
|         filename = self.configfile | ||||
|         if filename and os.path.exists(filename): | ||||
|             cp = ConfigParser.ConfigParser() | ||||
|             cp.read(filename) | ||||
|             for sec in cp.sections(): | ||||
|                 if sec == "Bar Options": | ||||
|                     if "visible" in cp.options(sec): | ||||
|                         visible = cp.get(sec, "visible") == "True" | ||||
|                     if "page" in cp.options(sec): | ||||
|                         default_page = int(cp.get(sec, "page")) | ||||
|                 else: | ||||
|                     data = {"title": sec} | ||||
|                     for opt in cp.options(sec): | ||||
|                         if opt.startswith("data["): | ||||
|                             temp = data.get("data", {}) | ||||
|                             #temp.append(cp.get(sec, opt).strip()) | ||||
|                             pos = int(opt[5:-1]) | ||||
|                             temp[pos] = cp.get(sec, opt).strip() | ||||
|                             data["data"] = temp | ||||
|                         else: | ||||
|                             data[opt] = cp.get(sec, opt).strip() | ||||
|                     if "data" in data: | ||||
|                         data["data"] = [data["data"][key] | ||||
|                                         for key in sorted(data["data"].keys())] | ||||
|                     if "name" not in data: | ||||
|                         data["name"] = "Unnamed Gramplet" | ||||
|                         data["tname"]= _("Unnamed Gramplet") | ||||
|                     retval.append((data["name"], data)) # name, opts | ||||
|         else: | ||||
|             # give defaults as currently known | ||||
|             for name in self.default_gramplets: | ||||
|                 if name in AVAILABLE_GRAMPLETS(): | ||||
|                     retval.append((name, GET_AVAILABLE_GRAMPLETS(name))) | ||||
|         return ((visible, default_page), retval) | ||||
|  | ||||
|     def save(self): | ||||
|         """ | ||||
|         Save the gramplet configuration. | ||||
|         """ | ||||
|         if len(self.gramplet_map) == 0: | ||||
|             return # something is the matter | ||||
|         filename = self.configfile | ||||
|         try: | ||||
|             fp = open(filename, "w") | ||||
|         except: | ||||
|             print "Failed writing '%s'; gramplets not saved" % filename | ||||
|             return | ||||
|         fp.write(";; Gramps bar configuration file" + NL) | ||||
|         fp.write((";; Automatically created at %s" % | ||||
|                                  time.strftime("%Y/%m/%d %H:%M:%S")) + NL + NL) | ||||
|         fp.write("[Bar Options]" + NL) | ||||
|         fp.write(("visible=%s" + NL) % self.top.get_property('visible')) | ||||
|         fp.write(("page=%d" + NL) % self.notebook.get_current_page()) | ||||
|         fp.write(NL)  | ||||
|  | ||||
|         for page_num in range(self.notebook.get_n_pages()): | ||||
|             title = get_title(self.notebook, page_num) | ||||
|             gramplet = self.gramplet_map[title] | ||||
|  | ||||
|             opts = get_gramplet_options_by_name(gramplet.name) | ||||
|             if opts is not None: | ||||
|                 base_opts = opts.copy() | ||||
|                 for key in base_opts: | ||||
|                     if key in gramplet.__dict__: | ||||
|                         base_opts[key] = gramplet.__dict__[key] | ||||
|                 fp.write(("[%s]" + NL) % gramplet.title) | ||||
|                 for key in base_opts: | ||||
|                     if key == "content": continue | ||||
|                     elif key == "title": continue | ||||
|                     elif key == "row": continue | ||||
|                     elif key == "column": continue | ||||
|                     elif key == "page": continue | ||||
|                     elif key == "version": continue # code, don't save | ||||
|                     elif key == "gramps": continue # code, don't save | ||||
|                     elif key == "data": | ||||
|                         if not isinstance(base_opts["data"], (list, tuple)): | ||||
|                             fp.write(("data[0]=%s" + NL) % base_opts["data"]) | ||||
|                         else: | ||||
|                             cnt = 0 | ||||
|                             for item in base_opts["data"]: | ||||
|                                 fp.write(("data[%d]=%s" + NL) % (cnt, item)) | ||||
|                                 cnt += 1 | ||||
|                     else: | ||||
|                         fp.write(("%s=%s" + NL)% (key, base_opts[key])) | ||||
|                 fp.write(("page=%d" + NL) % page_num) | ||||
|                 fp.write(NL) | ||||
|  | ||||
|         fp.close() | ||||
|  | ||||
|     def set_active(self): | ||||
|         """ | ||||
|         Called with the view is set as active. | ||||
|         """ | ||||
|         page = self.notebook.get_current_page() | ||||
|         title = get_title(self.notebook, page) | ||||
|         if self.gramplet_map[title].pui: | ||||
|             self.gramplet_map[title].pui.active = True | ||||
|             if self.gramplet_map[title].pui.dirty: | ||||
|                 self.gramplet_map[title].pui.update() | ||||
|  | ||||
|     def set_inactive(self): | ||||
|         """ | ||||
|         Called with the view is set as inactive. | ||||
|         """ | ||||
|         page = self.notebook.get_current_page() | ||||
|         title = get_title(self.notebook, page) | ||||
|         if self.gramplet_map[title].pui: | ||||
|             if self.gramplet_map[title].state != "detached": | ||||
|                 self.gramplet_map[title].pui.active = False | ||||
|  | ||||
|     def on_delete(self): | ||||
|         """ | ||||
|         Called when the view is closed. | ||||
|         """ | ||||
|         gramplets = (g for g in self.gramplet_map.itervalues()  | ||||
|                         if g is not None) | ||||
|         for gramplet in gramplets: | ||||
|             # this is the only place where the gui runs user code directly | ||||
|             if gramplet.pui: | ||||
|                 gramplet.pui.on_save() | ||||
|         self.save() | ||||
|  | ||||
|     def get_display(self): | ||||
|         """ | ||||
|         Return the top container widget for the GUI. | ||||
|         """ | ||||
|         return self.top | ||||
|  | ||||
|     def show(self): | ||||
|         """ | ||||
|         Show the bottom bar. | ||||
|         """ | ||||
|         return self.top.show() | ||||
|  | ||||
|     def hide(self): | ||||
|         """ | ||||
|         Hide the bottom bar. | ||||
|         """ | ||||
|         return self.top.hide() | ||||
|  | ||||
|     def __close_clicked(self, button): | ||||
|         """ | ||||
|         Called when the sidebar is closed. | ||||
|         """ | ||||
|         self.close_callback() | ||||
|          | ||||
|     def __add_clicked(self, button): | ||||
|         """ | ||||
|         Called when the add button is clicked. | ||||
|         """ | ||||
|         names = [GET_AVAILABLE_GRAMPLETS(key)["tname"] for key  | ||||
|                  in AVAILABLE_GRAMPLETS()] | ||||
|         skip = [gramplet.tname for gramplet in self.gramplet_map.values()] | ||||
|         gramplet_list = [name for name in names if name not in skip] | ||||
|         gramplet_list.sort() | ||||
|         dialog = ChooseGrampletDialog(_("Select Gramplet"), gramplet_list) | ||||
|         tname = dialog.run() | ||||
|         if not tname: | ||||
|             return | ||||
|  | ||||
|         all_opts = get_gramplet_options_by_tname(tname) | ||||
|         gramplet = make_requested_gramplet(self, all_opts["name"], all_opts,  | ||||
|                                            self.dbstate, self.uistate) | ||||
|         if not gramplet: | ||||
|             print "Problem creating ", tname | ||||
|             return | ||||
|  | ||||
|         title = all_opts["title"] | ||||
|         self.gramplet_map[title] = gramplet | ||||
|         gramplet.scrolledwindow.set_size_request(-1, gramplet.height) | ||||
|         page_num = self.notebook.append_page(gramplet.mainframe, | ||||
|                                              gtk.Label(title)) | ||||
|         self.notebook.set_tab_reorderable(gramplet.mainframe, True) | ||||
|         self.notebook.set_current_page(page_num) | ||||
|  | ||||
|     def __delete_clicked(self, button): | ||||
|         """ | ||||
|         Called when the delete button is clicked. | ||||
|         """ | ||||
|         page_num = self.notebook.get_current_page() | ||||
|         title = get_title(self.notebook, page_num) | ||||
|         del self.gramplet_map[title] | ||||
|         self.notebook.remove_page(page_num) | ||||
|          | ||||
|     def __switch_page(self, notebook, unused, new_page): | ||||
|         """ | ||||
|         Called when the user has switched to a new bottombar page. | ||||
|         """ | ||||
|         old_page = notebook.get_current_page() | ||||
|         #print "switch from", old_page, "to", new_page | ||||
|         if old_page >= 0: | ||||
|             title = get_title(notebook, old_page) | ||||
|             if self.gramplet_map[title].pui: | ||||
|                 if self.gramplet_map[title].state != "detached": | ||||
|                     self.gramplet_map[title].pui.active = False | ||||
|  | ||||
|         title = get_title(notebook, new_page) | ||||
|         if self.gramplet_map[title].pui: | ||||
|             self.gramplet_map[title].pui.active = True | ||||
|             if self.gramplet_map[title].pui.dirty: | ||||
|                 self.gramplet_map[title].pui.update() | ||||
|  | ||||
| def get_title(notebook, page_num): | ||||
|     """ | ||||
|     Reurn the title of a given page in a notebook. | ||||
|     """ | ||||
|     return notebook.get_tab_label_text(notebook.get_nth_page(page_num)) | ||||
|  | ||||
| #------------------------------------------------------------------------- | ||||
| # | ||||
| # Choose Gramplet Dialog | ||||
| # | ||||
| #------------------------------------------------------------------------- | ||||
| class ChooseGrampletDialog(object): | ||||
|     """ | ||||
|     A dialog to choose a gramplet | ||||
|     """ | ||||
|     def __init__(self, title, names): | ||||
|         self.title = title | ||||
|         self.names = names | ||||
|         self.namelist = None | ||||
|         self.namemodel = None | ||||
|         self.top = self._create_dialog() | ||||
|  | ||||
|     def run(self): | ||||
|         """ | ||||
|         Run the dialog and return the result. | ||||
|         """ | ||||
|         self._populate_model() | ||||
|         response = self.top.run() | ||||
|         result = None | ||||
|         if response == gtk.RESPONSE_OK: | ||||
|             store, iter_ = self.namemodel.get_selected() | ||||
|             if iter_: | ||||
|                 result = store.get_value(iter_, 0) | ||||
|         self.top.destroy() | ||||
|         return result | ||||
|  | ||||
|     def _populate_model(self): | ||||
|         """ | ||||
|         Populate the model. | ||||
|         """ | ||||
|         self.namemodel.clear() | ||||
|         for name in self.names: | ||||
|             self.namemodel.add([name]) | ||||
|          | ||||
|     def _create_dialog(self): | ||||
|         """ | ||||
|         Create a dialog box to organize tags. | ||||
|         """ | ||||
|         # pylint: disable-msg=E1101 | ||||
|         title = _("%(title)s - Gramps") % {'title': self.title} | ||||
|         top = gtk.Dialog(title) | ||||
|         top.set_default_size(400, 350) | ||||
|         top.set_modal(True) | ||||
|         top.set_has_separator(False) | ||||
|         top.vbox.set_spacing(5) | ||||
|         label = gtk.Label('<span size="larger" weight="bold">%s</span>' | ||||
|                           % self.title) | ||||
|         label.set_use_markup(True) | ||||
|         top.vbox.pack_start(label, 0, 0, 5) | ||||
|         box = gtk.HBox() | ||||
|         top.vbox.pack_start(box, 1, 1, 5) | ||||
|          | ||||
|         name_titles = [(_('Name'), NOSORT, 200)] | ||||
|         self.namelist = gtk.TreeView() | ||||
|         self.namemodel = ListModel(self.namelist, name_titles) | ||||
|  | ||||
|         slist = gtk.ScrolledWindow() | ||||
|         slist.add_with_viewport(self.namelist) | ||||
|         slist.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | ||||
|         box.pack_start(slist, 1, 1, 5) | ||||
|         bbox = gtk.VButtonBox() | ||||
|         bbox.set_layout(gtk.BUTTONBOX_START) | ||||
|         bbox.set_spacing(6) | ||||
|         top.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) | ||||
|         top.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) | ||||
|         box.pack_start(bbox, 0, 0, 5) | ||||
|         top.show_all() | ||||
|         return top | ||||
|  | ||||
| @@ -50,6 +50,7 @@ import Errors | ||||
| from gui.dbguielement import DbGUIElement | ||||
| from gui.widgets.menutoolbuttonaction import MenuToolButtonAction | ||||
| from gui.sidebar import Sidebar | ||||
| from gui.bottombar import Bottombar | ||||
| from gui.widgets.grampletpane import GrampletPane | ||||
| from gui.configure import ConfigureDialog | ||||
| from config import config | ||||
| @@ -116,6 +117,7 @@ class PageView(DbGUIElement): | ||||
|             <menu action="ViewMenu"> | ||||
|               <placeholder name="Bars"> | ||||
|                 <menuitem action="Sidebar"/> | ||||
|                 <menuitem action="Bottombar"/> | ||||
|               </placeholder> | ||||
|             </menu> | ||||
|           </menubar> | ||||
| @@ -150,6 +152,7 @@ class PageView(DbGUIElement): | ||||
|         self.top = None | ||||
|         self.gramplet_pane = None | ||||
|         self.sidebar = None | ||||
|         self.bottombar = None | ||||
|  | ||||
|         DbGUIElement.__init__(self, dbstate.db) | ||||
|  | ||||
| @@ -159,16 +162,22 @@ class PageView(DbGUIElement): | ||||
|         Returns a gtk container widget. | ||||
|         """ | ||||
|         self.sidebar = Sidebar(self.sidebar_changed, self.sidebar_closed) | ||||
|         defaults = self.get_default_gramplets()[1] | ||||
|         self.bottombar = Bottombar(self.dbstate, self.uistate, | ||||
|                                    self.ident + "_bottombar", | ||||
|                                    self.bottombar_closed, | ||||
|                                    defaults) | ||||
|         hpane = gtk.HPaned() | ||||
|         vpane = gtk.VPaned() | ||||
|         hpane.pack1(vpane, resize=True, shrink=True) | ||||
|         hpane.pack1(vpane, resize=True, shrink=False) | ||||
|         hpane.pack2(self.sidebar.get_display(), resize=False, shrink=False) | ||||
|         hpane.show() | ||||
|         vpane.show() | ||||
|  | ||||
|         widget = self.build_widget() | ||||
|         widget.show_all() | ||||
|         vpane.add1(widget) | ||||
|         vpane.pack1(widget, resize=True, shrink=False) | ||||
|         vpane.pack2(self.bottombar.get_display(), resize=False, shrink=False) | ||||
|         initial_page = self._config.get('sidebar.page') | ||||
|          | ||||
|         self.gramplet_pane = self.__create_gramplet_pane() | ||||
| @@ -205,9 +214,11 @@ class PageView(DbGUIElement): | ||||
|         """ | ||||
|         Create a gramplet pane. | ||||
|         """ | ||||
|         defaults = self.get_default_gramplets()[0] | ||||
|         gramplet_pane = GrampletPane(self.ident + "_sidebar",  | ||||
|                                self, self.dbstate, self.uistate,  | ||||
|                                column_count=1) | ||||
|                                column_count=1,  | ||||
|                                default_gramplets=defaults) | ||||
|         gramplet_pane.show_all() | ||||
|         self.sidebar.add(_('Gramplets'), gramplet_pane, GRAMPLET_PAGE) | ||||
|         return gramplet_pane | ||||
| @@ -232,6 +243,17 @@ class PageView(DbGUIElement): | ||||
|             self.sidebar_changed(None, False, None) | ||||
|         self._config.set('sidebar.visible', active) | ||||
|  | ||||
|     def __bottombar_toggled(self, action): | ||||
|         """ | ||||
|         Called when the bottombar is toggled. | ||||
|         """ | ||||
|         active = action.get_active() | ||||
|         if active: | ||||
|             self.bottombar.show() | ||||
|         else: | ||||
|             self.bottombar.hide() | ||||
|         self._config.set('bottombar.visible', active) | ||||
|  | ||||
|     def sidebar_changed(self, page_type, active, index): | ||||
|         """ | ||||
|         Called when the sidebar page is changed. | ||||
| @@ -246,6 +268,23 @@ class PageView(DbGUIElement): | ||||
|         uimanager = self.uistate.uimanager | ||||
|         uimanager.get_action('/MenuBar/ViewMenu/Bars/Sidebar').activate() | ||||
|  | ||||
|     def bottombar_closed(self): | ||||
|         """ | ||||
|         Called when the bottombar close button is clicked. | ||||
|         """ | ||||
|         uimanager = self.uistate.uimanager | ||||
|         uimanager.get_action('/MenuBar/ViewMenu/Bars/Bottombar').activate() | ||||
|  | ||||
|     def get_default_gramplets(self): | ||||
|         """ | ||||
|         Get the default gramplets for the Gramps sidebar and bottombar. | ||||
|         Returns a 2-tuple.  The first element is a tuple of sidebar gramplets | ||||
|         and the second element is a tuple of bottombar gramplets. | ||||
|  | ||||
|         Views should override this method to define default gramplets.  | ||||
|         """ | ||||
|         return ((), ()) | ||||
|  | ||||
|     def key_press_handler(self, widget, event): | ||||
|         """ | ||||
|         A general keypress handler. Override if you want to handle | ||||
| @@ -337,6 +376,7 @@ class PageView(DbGUIElement): | ||||
|         then we rebuild the data. | ||||
|         """ | ||||
|         self.gramplet_pane.set_active() | ||||
|         self.bottombar.set_active() | ||||
|         self.active = True | ||||
|         if self.dirty: | ||||
|             self.uistate.set_busy_cursor(True) | ||||
| @@ -348,6 +388,7 @@ class PageView(DbGUIElement): | ||||
|         Marks page as being inactive (not currently displayed) | ||||
|         """ | ||||
|         self.gramplet_pane.set_inactive() | ||||
|         self.bottombar.set_inactive() | ||||
|         self.active = False | ||||
|  | ||||
|     def build_tree(self): | ||||
| @@ -443,6 +484,9 @@ class PageView(DbGUIElement): | ||||
|         self._add_toggle_action('Sidebar', None, _('_Sidebar'),  | ||||
|              None, None, self.__sidebar_toggled, | ||||
|              self._config.get('sidebar.visible')) | ||||
|         self._add_toggle_action('Bottombar', None, _('_Bottombar'),  | ||||
|              None, None, self.__bottombar_toggled, | ||||
|              self._config.get('bottombar.visible')) | ||||
|         self._add_action("AddGramplet", gtk.STOCK_ADD, _("Add a gramplet")) | ||||
|         self._add_action("RestoreGramplet", None, _("Restore a gramplet")) | ||||
|  | ||||
| @@ -562,6 +606,7 @@ class PageView(DbGUIElement): | ||||
|         that should be called when quiting the main application. | ||||
|         """ | ||||
|         self.gramplet_pane.on_delete() | ||||
|         self.bottombar.on_delete() | ||||
|         self._config.save() | ||||
|  | ||||
|     def init_config(self): | ||||
| @@ -584,8 +629,10 @@ class PageView(DbGUIElement): | ||||
|                                                use_config_path=True) | ||||
|         for section, value in self.CONFIGSETTINGS: | ||||
|             self._config.register(section, value) | ||||
|         self._config.register('sidebar.visible', True) | ||||
|         self._config.register('sidebar.visible', False) | ||||
|         self._config.register('sidebar.page', 0) | ||||
|         self._config.register('bottombar.visible', False) | ||||
|         self._config.register('bottombar.page', 0) | ||||
|         self._config.init() | ||||
|         self.config_connect() | ||||
|  | ||||
|   | ||||
| @@ -332,6 +332,7 @@ class GuiGramplet(object): | ||||
|         self.detached_height = int(kwargs.get("detached_height", 300)) | ||||
|         self.detached_width = int(kwargs.get("detached_width", 400)) | ||||
|         self.row = int(kwargs.get("row", -1)) | ||||
|         self.page = int(kwargs.get("page", -1)) | ||||
|         self.state = kwargs.get("state", "maximized") | ||||
|         self.data = kwargs.get("data", []) | ||||
|         self.help_url = kwargs.get("help_url", WIKI_HELP_PAGE) | ||||
| @@ -360,12 +361,16 @@ class GuiGramplet(object): | ||||
|         self.titlelabel.get_children()[0].set_use_markup(True) | ||||
|         self.titlelabel.connect("clicked", self.edit_title) | ||||
|         self.titlelabel_entry = None | ||||
|         self.titlelabel.hide() | ||||
|         self.gvclose = self.xml.get_object('gvclose') | ||||
|         self.gvclose.connect('clicked', self.close) | ||||
|         self.gvclose.hide() | ||||
|         self.gvstate = self.xml.get_object('gvstate') | ||||
|         self.gvstate.connect('clicked', self.change_state) | ||||
|         self.gvstate.hide() | ||||
|         self.gvproperties = self.xml.get_object('gvproperties') | ||||
|         self.gvproperties.connect('clicked', self.set_properties) | ||||
|         self.gvproperties.hide() | ||||
|         self.xml.get_object('gvcloseimage').set_from_stock(gtk.STOCK_CLOSE, | ||||
|                                                            gtk.ICON_SIZE_MENU) | ||||
|         self.xml.get_object('gvstateimage').set_from_stock(gtk.STOCK_REMOVE, | ||||
|   | ||||
| @@ -9,6 +9,7 @@ pkgdata_PYTHON = \ | ||||
| 	AgeOnDateGramplet.py \ | ||||
| 	AgeStats.py \ | ||||
| 	AttributesGramplet.py \ | ||||
| 	bottombar.gpr.py \ | ||||
| 	CalendarGramplet.py \ | ||||
| 	DescendGramplet.py \ | ||||
| 	FanChartGramplet.py \ | ||||
| @@ -16,6 +17,10 @@ pkgdata_PYTHON = \ | ||||
| 	GivenNameGramplet.py \ | ||||
| 	gramplet.gpr.py \ | ||||
| 	PedigreeGramplet.py \ | ||||
| 	PersonAttributes.py \ | ||||
| 	PersonDetails.py \ | ||||
| 	PersonGallery.py \ | ||||
| 	PersonResidence.py \ | ||||
| 	PluginManagerGramplet.py\ | ||||
| 	QuickViewGramplet.py \ | ||||
| 	RelativeGramplet.py \ | ||||
|   | ||||
							
								
								
									
										74
									
								
								src/plugins/gramplet/PersonAttributes.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/plugins/gramplet/PersonAttributes.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| # Gramps - a GTK+/GNOME based genealogy program | ||||
| # | ||||
| # Copyright (C) 2011 Nick Hall | ||||
| # | ||||
| # This program is free software; you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation; either version 2 of the License, or | ||||
| # (at your option) any later version. | ||||
| # | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software | ||||
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| # | ||||
| # $Id$ | ||||
| # | ||||
|  | ||||
| from ListModel import ListModel, NOSORT | ||||
| from QuickReports import run_quick_report_by_name | ||||
| from gen.plug import Gramplet | ||||
| import gtk | ||||
|  | ||||
| class PersonAttributes(Gramplet): | ||||
|     """ | ||||
|     Displays the attributes of a person. | ||||
|     """ | ||||
|     def init(self): | ||||
|         self.gui.WIDGET = self.build_gui() | ||||
|         self.gui.get_container_widget().remove(self.gui.textview) | ||||
|         self.gui.get_container_widget().add_with_viewport(self.gui.WIDGET) | ||||
|         self.gui.WIDGET.show() | ||||
|  | ||||
|     def build_gui(self): | ||||
|         """ | ||||
|         Build the GUI interface. | ||||
|         """ | ||||
|         top = gtk.TreeView() | ||||
|         titles = [(_('Key'), 1, 100), | ||||
|                   (_('Value'), 2, 100)] | ||||
|         self.model = ListModel(top, titles, event_func=self.display_report) | ||||
|         return top | ||||
|          | ||||
|     def db_changed(self): | ||||
|         self.dbstate.db.connect('person-update', self.update) | ||||
|         self.update() | ||||
|  | ||||
|     def active_changed(self, handle): | ||||
|         self.update() | ||||
|  | ||||
|     def main(self): # return false finishes | ||||
|         active_handle = self.get_active('Person') | ||||
|         active_person = self.dbstate.db.get_person_from_handle(active_handle) | ||||
|         if not active_person: | ||||
|             return | ||||
|              | ||||
|         self.model.clear() | ||||
|         for attr in active_person.get_attribute_list(): | ||||
|             self.model.add((attr.get_type(), attr.get_value())) | ||||
|  | ||||
|     def display_report(self, treeview): | ||||
|         """ | ||||
|         Display the quick report for matching attribute key. | ||||
|         """ | ||||
|         model, iter_ = treeview.get_selection().get_selected() | ||||
|         if iter_: | ||||
|             key = model.get_value(iter_, 0) | ||||
|             run_quick_report_by_name(self.dbstate,  | ||||
|                                      self.uistate,  | ||||
|                                      'attribute_match',  | ||||
|                                      key) | ||||
							
								
								
									
										232
									
								
								src/plugins/gramplet/PersonDetails.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								src/plugins/gramplet/PersonDetails.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,232 @@ | ||||
| # Gramps - a GTK+/GNOME based genealogy program | ||||
| # | ||||
| # Copyright (C) 2011 Nick Hall | ||||
| # | ||||
| # This program is free software; you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation; either version 2 of the License, or | ||||
| # (at your option) any later version. | ||||
| # | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software | ||||
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| # | ||||
| # $Id$ | ||||
| # | ||||
|  | ||||
| from gen.lib import EventType, EventRoleType | ||||
| from gen.plug import Gramplet | ||||
| from gen.display.name import displayer as name_displayer | ||||
| from gen.ggettext import gettext as _ | ||||
| import DateHandler | ||||
| import Utils | ||||
| import gtk | ||||
| import pango | ||||
|  | ||||
| class PersonDetails(Gramplet): | ||||
|     """ | ||||
|     Displays details for a person. | ||||
|     """ | ||||
|     def init(self): | ||||
|         self.gui.WIDGET = self.build_gui() | ||||
|         self.gui.get_container_widget().remove(self.gui.textview) | ||||
|         self.gui.get_container_widget().add_with_viewport(self.gui.WIDGET) | ||||
|         self.gui.WIDGET.show() | ||||
|  | ||||
|     def build_gui(self): | ||||
|         """ | ||||
|         Build the GUI interface. | ||||
|         """ | ||||
|         self.load_obj = None | ||||
|         self.load_rect = None | ||||
|         top = gtk.HBox() | ||||
|         vbox = gtk.VBox() | ||||
|         self.obj_photo = gtk.Image() | ||||
|         self.name = gtk.Label() | ||||
|         self.name.set_alignment(0, 0) | ||||
|         self.name.modify_font(pango.FontDescription('sans bold 12')) | ||||
|         vbox.pack_start(self.name, fill=True, expand=False, padding=10) | ||||
|         table = gtk.Table(2, 2) | ||||
|         self.father = self.make_row(table, 0, _('Father')) | ||||
|         self.mother = self.make_row(table, 1, _('Mother')) | ||||
|         vbox.pack_start(table, fill=True, expand=False, padding=5) | ||||
|         table = gtk.Table(4, 2) | ||||
|         self.birth = self.make_row(table, 0, _('Birth')) | ||||
|         self.baptism = self.make_row(table, 1, _('Baptism')) | ||||
|         self.death = self.make_row(table, 2, _('Death')) | ||||
|         self.burial = self.make_row(table, 3, _('Burial')) | ||||
|         vbox.pack_start(table, fill=True, expand=False, padding=5) | ||||
|         table = gtk.Table(1, 2) | ||||
|         self.occupation = self.make_row(table, 0, _('Occupation')) | ||||
|         vbox.pack_start(table, fill=True, expand=False, padding=5) | ||||
|         vbox.show_all() | ||||
|         top.pack_start(self.obj_photo, fill=True, expand=False, padding=5) | ||||
|         top.pack_start(vbox, fill=True, expand=True, padding=10) | ||||
|         return top | ||||
|  | ||||
|     def make_row(self, table, row, title): | ||||
|         """ | ||||
|         Make a row in a table. | ||||
|         """ | ||||
|         label = gtk.Label(title + ':') | ||||
|         label.set_alignment(1, 0) | ||||
|         widget = gtk.Label() | ||||
|         widget.set_alignment(0, 0) | ||||
|         table.attach(label, 0, 1, row, row + 1, xoptions=gtk.FILL, xpadding=10) | ||||
|         table.attach(widget, 1, 2, row, row + 1) | ||||
|         return (label, widget) | ||||
|          | ||||
|     def db_changed(self): | ||||
|         self.dbstate.db.connect('person-update', self.update) | ||||
|         self.update() | ||||
|  | ||||
|     def active_changed(self, handle): | ||||
|         self.update() | ||||
|  | ||||
|     def main(self): # return false finishes | ||||
|         active_handle = self.get_active('Person') | ||||
|         active_person = self.dbstate.db.get_person_from_handle(active_handle) | ||||
|         if not active_person: | ||||
|             return | ||||
|  | ||||
|         self.load_person_image(active_person) | ||||
|         self.name.set_text(name_displayer.display(active_person)) | ||||
|         self.display_parents(active_person) | ||||
|         self.display_type(active_person, self.birth, EventType.BIRTH) | ||||
|         self.display_type(active_person, self.baptism, EventType.BAPTISM) | ||||
|         self.display_type(active_person, self.death, EventType.DEATH) | ||||
|         self.display_type(active_person, self.burial, EventType.BURIAL) | ||||
|         occupation_text = self.get_attribute(active_person, 'Occupation') | ||||
|         self.occupation[1].set_text(occupation_text) | ||||
|  | ||||
|     def display_parents(self, active_person): | ||||
|         """ | ||||
|         Display the parents of the active person. | ||||
|         """ | ||||
|         family_handle = active_person.get_main_parents_family_handle() | ||||
|         if family_handle: | ||||
|             family = self.dbstate.db.get_family_from_handle(family_handle) | ||||
|             handle = family.get_father_handle() | ||||
|             if handle: | ||||
|                 father = self.dbstate.db.get_person_from_handle(handle) | ||||
|                 self.father[1].set_text(name_displayer.display(father)) | ||||
|             else: | ||||
|                 self.father[1].set_text(_('Unknown')) | ||||
|             handle = family.get_mother_handle() | ||||
|             if handle: | ||||
|                 mother = self.dbstate.db.get_person_from_handle(handle) | ||||
|                 self.mother[1].set_text(name_displayer.display(mother)) | ||||
|             else: | ||||
|                 self.mother[1].set_text(_('Unknown')) | ||||
|         else: | ||||
|                 self.father[1].set_text(_('Unknown')) | ||||
|                 self.mother[1].set_text(_('Unknown'))             | ||||
|  | ||||
|     def get_attribute(self, person, attr_key): | ||||
|         """ | ||||
|         Return an attribute with the given key. | ||||
|         """ | ||||
|         for attr in person.get_attribute_list(): | ||||
|             if attr.get_type() == attr_key: | ||||
|                     return attr.get_value() | ||||
|         return _('Unknown') | ||||
|  | ||||
|     def display_type(self, active_person, widget, event_type): | ||||
|         """ | ||||
|         Display an event type row. | ||||
|         """ | ||||
|         event = self.get_event(active_person, event_type) | ||||
|         if event: | ||||
|             widget[1].set_text(self.format_event(event)) | ||||
|             widget[0].show() | ||||
|             widget[1].show() | ||||
|         else: | ||||
|             widget[1].set_text('') | ||||
|             widget[0].hide() | ||||
|             widget[1].hide() | ||||
|  | ||||
|     def get_event(self, person, event_type): | ||||
|         """ | ||||
|         Return an event of the given type. | ||||
|         """ | ||||
|         for event_ref in person.get_event_ref_list(): | ||||
|             if int(event_ref.get_role()) == EventRoleType.PRIMARY: | ||||
|                 event = self.dbstate.db.get_event_from_handle(event_ref.ref) | ||||
|                 if int(event.get_type()) == event_type: | ||||
|                     return event | ||||
|         return None | ||||
|  | ||||
|     def format_event(self, event): | ||||
|         """ | ||||
|         Format the event for display. | ||||
|         """ | ||||
|         date = DateHandler.get_date(event) | ||||
|         handle = event.get_place_handle() | ||||
|         if handle: | ||||
|             place = self.dbstate.db.get_place_from_handle(handle).get_title() | ||||
|             retval = _('%s - %s.') % (date, place) | ||||
|         else: | ||||
|             retval = _('%s.') % date | ||||
|         return retval | ||||
|          | ||||
|     def load_person_image(self, person): | ||||
|         """ | ||||
|         Load the primary image if it exists. | ||||
|         """ | ||||
|         media_list = person.get_media_list() | ||||
|         if media_list: | ||||
|             photo = media_list[0] | ||||
|             object_handle = photo.get_reference_handle() | ||||
|             obj = self.dbstate.db.get_object_from_handle(object_handle) | ||||
|             full_path = Utils.media_path_full(self.dbstate.db, obj.get_path()) | ||||
|             #reload if different media, or different rectangle | ||||
|             if self.load_obj != full_path or \ | ||||
|                     self.load_rect != photo.get_rectangle(): | ||||
|                 mime_type = obj.get_mime_type() | ||||
|                 if mime_type and mime_type.startswith("image"): | ||||
|                     self.load_photo(full_path, photo.get_rectangle()) | ||||
|                 else: | ||||
|                     self.load_photo(None) | ||||
|         else: | ||||
|             self.load_photo(None) | ||||
|  | ||||
|     def load_photo(self, path, rectangle=None): | ||||
|         """ | ||||
|         Load, scale and display the person's main photo from the path. | ||||
|         """ | ||||
|         self.load_obj = path | ||||
|         self.load_rect = rectangle | ||||
|         if path is None: | ||||
|             self.obj_photo.hide() | ||||
|         else: | ||||
|             try: | ||||
|                 i = gtk.gdk.pixbuf_new_from_file(path) | ||||
|                 width = i.get_width() | ||||
|                 height = i.get_height() | ||||
|  | ||||
|                 if rectangle is not None: | ||||
|                     upper_x = min(rectangle[0], rectangle[2])/100. | ||||
|                     lower_x = max(rectangle[0], rectangle[2])/100. | ||||
|                     upper_y = min(rectangle[1], rectangle[3])/100. | ||||
|                     lower_y = max(rectangle[1], rectangle[3])/100. | ||||
|                     sub_x = int(upper_x * width) | ||||
|                     sub_y = int(upper_y * height) | ||||
|                     sub_width = int((lower_x - upper_x) * width) | ||||
|                     sub_height = int((lower_y - upper_y) * height) | ||||
|                     if sub_width > 0 and sub_height > 0: | ||||
|                         i = i.subpixbuf(sub_x, sub_y, sub_width, sub_height) | ||||
|  | ||||
|                 ratio = float(max(i.get_height(), i.get_width())) | ||||
|                 scale = float(190.0)/ratio | ||||
|                 x = int(scale*(i.get_width())) | ||||
|                 y = int(scale*(i.get_height())) | ||||
|                 i = i.scale_simple(x, y, gtk.gdk.INTERP_BILINEAR) | ||||
|                 self.obj_photo.set_from_pixbuf(i) | ||||
|                 self.obj_photo.show() | ||||
|             except: | ||||
|                 self.obj_photo.hide() | ||||
							
								
								
									
										125
									
								
								src/plugins/gramplet/PersonGallery.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								src/plugins/gramplet/PersonGallery.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | ||||
| # Gramps - a GTK+/GNOME based genealogy program | ||||
| # | ||||
| # Copyright (C) 2011 Nick Hall | ||||
| # | ||||
| # This program is free software; you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation; either version 2 of the License, or | ||||
| # (at your option) any later version. | ||||
| # | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software | ||||
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| # | ||||
| # $Id$ | ||||
| # | ||||
|  | ||||
| from gui.utils import open_file_with_default_application | ||||
| from gen.plug import Gramplet | ||||
| import Utils | ||||
| import gtk | ||||
|  | ||||
| class PersonGallery(Gramplet): | ||||
|     """ | ||||
|     Displays details for a person. | ||||
|     """ | ||||
|     def init(self): | ||||
|         self.gui.WIDGET = self.build_gui() | ||||
|         self.gui.get_container_widget().remove(self.gui.textview) | ||||
|         self.gui.get_container_widget().add_with_viewport(self.gui.WIDGET) | ||||
|         self.gui.WIDGET.show() | ||||
|  | ||||
|     def build_gui(self): | ||||
|         """ | ||||
|         Build the GUI interface. | ||||
|         """ | ||||
|         self.image_list = [] | ||||
|         self.top = gtk.HBox(False, 3) | ||||
|         return self.top | ||||
|          | ||||
|     def db_changed(self): | ||||
|         self.dbstate.db.connect('person-update', self.update) | ||||
|         self.update() | ||||
|  | ||||
|     def active_changed(self, handle): | ||||
|         self.update() | ||||
|  | ||||
|     def main(self): # return false finishes | ||||
|         active_handle = self.get_active('Person') | ||||
|         active_person = self.dbstate.db.get_person_from_handle(active_handle) | ||||
|         if not active_person: | ||||
|             return | ||||
|  | ||||
|         self.clear_images() | ||||
|         self.load_person_images(active_person) | ||||
|  | ||||
|     def clear_images(self): | ||||
|         """ | ||||
|         Remove all images from the Gramplet. | ||||
|         """ | ||||
|         for image in self.image_list: | ||||
|             self.top.remove(image) | ||||
|         self.image_list = [] | ||||
|  | ||||
|     def load_person_images(self, person): | ||||
|         """ | ||||
|         Load the primary image into the main form if it exists. | ||||
|         """ | ||||
|         media_list = person.get_media_list() | ||||
|         for photo in media_list: | ||||
|             object_handle = photo.get_reference_handle() | ||||
|             obj = self.dbstate.db.get_object_from_handle(object_handle) | ||||
|             full_path = Utils.media_path_full(self.dbstate.db, obj.get_path()) | ||||
|             mime_type = obj.get_mime_type() | ||||
|             if mime_type and mime_type.startswith("image"): | ||||
|                 pb = self.get_pixbuf(full_path, photo.get_rectangle()) | ||||
|                 eb = gtk.EventBox() | ||||
|                 eb.connect('button-press-event', self.display_image, full_path) | ||||
|                 image = gtk.Image() | ||||
|                 eb.add(image) | ||||
|                 self.image_list.append(eb) | ||||
|                 image.set_from_pixbuf(pb) | ||||
|                 eb.show_all() | ||||
|                 self.top.pack_start(eb, expand=False, fill=False) | ||||
|  | ||||
|     def display_image(self, widget, event, path): | ||||
|         """ | ||||
|         Display the image with the default application. | ||||
|         """ | ||||
|         if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1: | ||||
|             open_file_with_default_application(path) | ||||
|          | ||||
|     def get_pixbuf(self, path, rectangle=None): | ||||
|         """ | ||||
|         Load, scale and display the person's main photo from the path. | ||||
|         """ | ||||
|         try: | ||||
|             i = gtk.gdk.pixbuf_new_from_file(path) | ||||
|             width = i.get_width() | ||||
|             height = i.get_height() | ||||
|  | ||||
|             if rectangle is not None: | ||||
|                 upper_x = min(rectangle[0], rectangle[2])/100. | ||||
|                 lower_x = max(rectangle[0], rectangle[2])/100. | ||||
|                 upper_y = min(rectangle[1], rectangle[3])/100. | ||||
|                 lower_y = max(rectangle[1], rectangle[3])/100. | ||||
|                 sub_x = int(upper_x * width) | ||||
|                 sub_y = int(upper_y * height) | ||||
|                 sub_width = int((lower_x - upper_x) * width) | ||||
|                 sub_height = int((lower_y - upper_y) * height) | ||||
|                 if sub_width > 0 and sub_height > 0: | ||||
|                     i = i.subpixbuf(sub_x, sub_y, sub_width, sub_height) | ||||
|  | ||||
|             ratio = float(max(i.get_height(), i.get_width())) | ||||
|             scale = float(180.0)/ratio | ||||
|             x = int(scale*(i.get_width())) | ||||
|             y = int(scale*(i.get_height())) | ||||
|             i = i.scale_simple(x, y, gtk.gdk.INTERP_BILINEAR) | ||||
|             return i | ||||
|         except: | ||||
|             return None | ||||
							
								
								
									
										92
									
								
								src/plugins/gramplet/PersonResidence.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/plugins/gramplet/PersonResidence.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| # Gramps - a GTK+/GNOME based genealogy program | ||||
| # | ||||
| # Copyright (C) 2011 Nick Hall | ||||
| # | ||||
| # This program is free software; you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation; either version 2 of the License, or | ||||
| # (at your option) any later version. | ||||
| # | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software | ||||
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| # | ||||
| # $Id$ | ||||
| # | ||||
|  | ||||
| from gen.lib import EventType, EventRoleType | ||||
| from gui.editors import EditEvent | ||||
| from ListModel import ListModel, NOSORT | ||||
| from gen.plug import Gramplet | ||||
| import DateHandler | ||||
| import gtk | ||||
|  | ||||
| class PersonResidence(Gramplet): | ||||
|     """ | ||||
|     Displays residence events for a person. | ||||
|     """ | ||||
|     def init(self): | ||||
|         self.gui.WIDGET = self.build_gui() | ||||
|         self.gui.get_container_widget().remove(self.gui.textview) | ||||
|         self.gui.get_container_widget().add_with_viewport(self.gui.WIDGET) | ||||
|         self.gui.WIDGET.show() | ||||
|  | ||||
|     def build_gui(self): | ||||
|         """ | ||||
|         Build the GUI interface. | ||||
|         """ | ||||
|         top = gtk.TreeView() | ||||
|         titles = [('', NOSORT, 50,), | ||||
|                   (_('Date'), 1, 200), | ||||
|                   (_('Place'), 2, 200)] | ||||
|         self.model = ListModel(top, titles, event_func=self.edit_event) | ||||
|         return top | ||||
|          | ||||
|     def db_changed(self): | ||||
|         self.dbstate.db.connect('person-update', self.update) | ||||
|         self.update() | ||||
|  | ||||
|     def active_changed(self, handle): | ||||
|         self.update() | ||||
|  | ||||
|     def main(self): # return false finishes | ||||
|         active_handle = self.get_active('Person') | ||||
|         active_person = self.dbstate.db.get_person_from_handle(active_handle) | ||||
|         if not active_person: | ||||
|             return | ||||
|              | ||||
|         self.model.clear() | ||||
|         for event_ref in active_person.get_event_ref_list(): | ||||
|             if int(event_ref.get_role()) == EventRoleType.PRIMARY: | ||||
|                 event = self.dbstate.db.get_event_from_handle(event_ref.ref) | ||||
|                 if int(event.get_type()) == EventType.RESIDENCE: | ||||
|                     self.add_residence(event) | ||||
|  | ||||
|     def add_residence(self, event): | ||||
|         """ | ||||
|         Add a residence event to the model. | ||||
|         """ | ||||
|         date = DateHandler.get_date(event) | ||||
|         place = '' | ||||
|         handle = event.get_place_handle() | ||||
|         if handle: | ||||
|             place = self.dbstate.db.get_place_from_handle(handle).get_title() | ||||
|         self.model.add((event.get_handle(), date, place)) | ||||
|  | ||||
|     def edit_event(self, treeview): | ||||
|         """ | ||||
|         Edit the selected event. | ||||
|         """ | ||||
|         model, iter_ = treeview.get_selection().get_selected() | ||||
|         if iter_: | ||||
|             handle = model.get_value(iter_, 0) | ||||
|             try: | ||||
|                 event = self.dbstate.db.get_event_from_handle(handle) | ||||
|                 EditEvent(self.dbstate, self.uistate, [], event) | ||||
|             except Errors.WindowActiveError: | ||||
|                 pass | ||||
							
								
								
									
										78
									
								
								src/plugins/gramplet/bottombar.gpr.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/plugins/gramplet/bottombar.gpr.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| # | ||||
| # Gramps - a GTK+/GNOME based genealogy program | ||||
| # | ||||
| # Copyright (C) 2011 Nick Hall | ||||
| # | ||||
| # This program is free software; you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation; either version 2 of the License, or | ||||
| # (at your option) any later version. | ||||
| # | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software | ||||
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| # | ||||
|  | ||||
| # $Id$ | ||||
|  | ||||
| #------------------------------------------------------------------------ | ||||
| # | ||||
| # Register Gramplet | ||||
| # | ||||
| #------------------------------------------------------------------------ | ||||
| register(GRAMPLET,  | ||||
|          id="Person Details Gramplet",  | ||||
|          name=_("Person Details Gramplet"),  | ||||
|          description = _("Gramplet showing details of a person"), | ||||
|          version="1.0.0", | ||||
|          gramps_target_version="3.3", | ||||
|          status = STABLE, | ||||
|          fname="PersonDetails.py", | ||||
|          height=200, | ||||
|          gramplet = 'PersonDetails', | ||||
|          gramplet_title=_("Details"), | ||||
|          ) | ||||
|  | ||||
| register(GRAMPLET,  | ||||
|          id="Person Gallery Gramplet",  | ||||
|          name=_("Person Gallery Gramplet"),  | ||||
|          description = _("Gramplet showing media objects for a person"), | ||||
|          version="1.0.0", | ||||
|          gramps_target_version="3.3", | ||||
|          status = STABLE, | ||||
|          fname="PersonGallery.py", | ||||
|          height=200, | ||||
|          gramplet = 'PersonGallery', | ||||
|          gramplet_title=_("Gallery"), | ||||
|          ) | ||||
|  | ||||
| register(GRAMPLET,  | ||||
|          id="Person Residence Gramplet",  | ||||
|          name=_("Person Residence Gramplet"),  | ||||
|          description = _("Gramplet showing residence events for a person"), | ||||
|          version="1.0.0", | ||||
|          gramps_target_version="3.3", | ||||
|          status = STABLE, | ||||
|          fname="PersonResidence.py", | ||||
|          height=200, | ||||
|          gramplet = 'PersonResidence', | ||||
|          gramplet_title=_("Residence"), | ||||
|          ) | ||||
|  | ||||
| register(GRAMPLET,  | ||||
|          id="Person Attributes Gramplet",  | ||||
|          name=_("Person Attributes Gramplet"),  | ||||
|          description = _("Gramplet showing the attributes of a person"), | ||||
|          version="1.0.0", | ||||
|          gramps_target_version="3.3", | ||||
|          status = STABLE, | ||||
|          fname="PersonAttributes.py", | ||||
|          height=200, | ||||
|          gramplet = 'PersonAttributes', | ||||
|          gramplet_title=_("Attributes"), | ||||
|          ) | ||||
| @@ -440,3 +440,13 @@ class BasePersonView(ListView): | ||||
|         person = self.dbstate.db.get_person_from_handle(person_handle) | ||||
|         person.add_tag(tag_handle) | ||||
|         self.dbstate.db.commit_person(person, transaction) | ||||
|          | ||||
|     def get_default_gramplets(self): | ||||
|         """ | ||||
|         Define the default gramplets for the sidebar and bottombar. | ||||
|         """ | ||||
|         return (("Welcome Gramplet",), | ||||
|                 ("Person Details Gramplet", | ||||
|                  "Person Gallery Gramplet", | ||||
|                  "Person Residence Gramplet", | ||||
|                  "Person Attributes Gramplet")) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user