Esempio n. 1
0
class InfoDialog(object):
    """
    Non modal dialog to show selectable info in a scrolled window
    """
    def __init__(self, msg1, infotext, parent=None, monospaced=False):
        self.xml = Glade(toplevel='infodialog')

        self.top = self.xml.toplevel
        self.top.set_icon(ICON)
        self.top.set_title("%s - Gramps" % msg1)

        label = self.xml.get_object('toplabel')
        label.set_text('<span weight="bold" size="larger">%s</span>' % msg1)
        label.set_use_markup(True)

        infoview = self.xml.get_object('infoview')
        infobuffer = gtk.TextBuffer()
        infobuffer.set_text(infotext)
        if monospaced:
            startiter, enditer = infobuffer.get_bounds()
            tag = infobuffer.create_tag(family="Monospace")
            infobuffer.apply_tag(tag, startiter, enditer)
        infoview.set_buffer(infobuffer)

        if parent:
            self.top.set_transient_for(parent)
        self.top.connect('response', self.destroy)
        self.top.show()

    def destroy(self, dialog, response_id):
        #no matter how it finishes, destroy dialog
        dialog.destroy()
Esempio n. 2
0
    def __build_window(self):
        """Build the window from Glade.
        """
        from glade import Glade
        glade_xml = Glade()
        self._window = glade_xml.toplevel
        #self._window.set_transient_for(parent)

        # remember active widgets for future use
        self._swin = glade_xml.get_object('swin')
        self._drawing_area = glade_xml.get_object('drawingarea')
        self._first_button = glade_xml.get_object('first')
        self._prev_button = glade_xml.get_object('prev')
        self._next_button = glade_xml.get_object('next')
        self._last_button = glade_xml.get_object('last')
        self._pages_entry = glade_xml.get_object('entry')
        self._pages_label = glade_xml.get_object('label')
        self._zoom_fit_width_button = glade_xml.get_object('zoom_fit_width')
        self._zoom_fit_width_button.set_stock_id('gramps-zoom-fit-width')
        self._zoom_best_fit_button = glade_xml.get_object('zoom_best_fit')
        self._zoom_best_fit_button.set_stock_id('gramps-zoom-best-fit')
        self._zoom_in_button = glade_xml.get_object('zoom_in')
        self._zoom_in_button.set_stock_id('gramps-zoom-in')
        self._zoom_out_button = glade_xml.get_object('zoom_out')
        self._zoom_out_button.set_stock_id('gramps-zoom-out')

        # connect the signals
        glade_xml.connect_signals(self)
Esempio n. 3
0
class QuestionDialog2(object):
    def __init__(self, msg1, msg2, label_msg1, label_msg2, parent=None):
        self.xml = Glade(toplevel='questiondialog')

        self.top = self.xml.toplevel
        self.top.set_icon(ICON)
        self.top.set_title("%s - Gramps" % msg1)

        label1 = self.xml.get_object('qd_label1')
        label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1)
        label1.set_use_markup(True)

        label2 = self.xml.get_object('qd_label2')
        # see https://github.com/emesene/emesene/issues/723
        label2.connect('activate-link', on_activate_link)
        label2.set_text(msg2)
        label2.set_use_markup(True)

        self.xml.get_object('okbutton').set_label(label_msg1)
        self.xml.get_object('okbutton').set_use_underline(True)
        self.xml.get_object('no').set_label(label_msg2)
        self.xml.get_object('no').set_use_underline(True)

        if parent:
            self.top.set_transient_for(parent)
        self.top.show()

    def run(self):
        response = self.top.run()
        self.top.destroy()
        return (response == gtk.RESPONSE_ACCEPT)
Esempio n. 4
0
class SaveDialog(object):
    def __init__(self, msg1, msg2, task1, task2, parent=None):
        self.xml = Glade(toplevel='savedialog')

        self.top = self.xml.toplevel
        self.top.set_icon(ICON)
        self.top.set_title("%s - Gramps" % msg1)

        self.dontask = self.xml.get_object('dontask')
        self.task1 = task1
        self.task2 = task2

        label1 = self.xml.get_object('sd_label1')
        label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1)
        label1.set_use_markup(True)

        label2 = self.xml.get_object('sd_label2')
        label2.set_text(msg2)
        label2.set_use_markup(True)
        if parent:
            self.top.set_transient_for(parent)
        self.top.show()
        response = self.top.run()
        if response == gtk.RESPONSE_NO:
            self.task1()
        elif response == gtk.RESPONSE_YES:
            self.task2()

        config.set('interface.dont-ask', self.dontask.get_active())
        self.top.destroy()
Esempio n. 5
0
class QuestionDialog(object):
    def __init__(self, msg1, msg2, label, task, parent=None):
        self.xml = Glade(toplevel='questiondialog')

        self.top = self.xml.toplevel
        self.top.set_icon(ICON)
        self.top.set_title("%s - Gramps" % msg1)

        label1 = self.xml.get_object('qd_label1')
        label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1)
        label1.set_use_markup(True)

        label2 = self.xml.get_object('qd_label2')
        label2.set_text(msg2)
        label2.set_use_markup(True)

        self.xml.get_object('okbutton').set_label(label)

        if parent:
            self.top.set_transient_for(parent)
        self.top.show()
        response = self.top.run()
        self.top.destroy()
        if response == gtk.RESPONSE_ACCEPT:
            task()
Esempio n. 6
0
class SoundGen(tool.Tool, ManagedWindow.ManagedWindow):
    def __init__(self, dbstate, uistate, options_class, name, callback=None):
        self.label = _('SoundEx code generator')
        tool.Tool.__init__(self, dbstate, options_class, name)
        ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__)

        self.glade = Glade()
        self.glade.connect_signals({
            "destroy_passed_object": self.close,
            "on_help_clicked": self.on_help_clicked,
            "on_delete_event": self.close,
        })

        window = self.glade.toplevel
        self.set_window(window, self.glade.get_object('title'), self.label)

        self.value = self.glade.get_object("value")
        self.autocomp = self.glade.get_object("name_list")
        self.name = self.autocomp.child

        self.name.connect('changed', self.on_apply_clicked)

        names = []
        person = None
        for person in self.db.iter_people():
            lastname = person.get_primary_name().get_surname()
            if lastname not in names:
                names.append(lastname)

        names.sort()

        AutoComp.fill_combo(self.autocomp, names)

        if person:
            n = person.get_primary_name().get_surname()
            self.name.set_text(n)
            try:
                se_text = soundex.soundex(n)
            except UnicodeEncodeError:
                se_text = soundex.soundex('')
            self.value.set_text(se_text)
        else:
            self.name.set_text("")

        self.show()

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        GrampsDisplay.help(WIKI_HELP_PAGE, WIKI_HELP_SEC)

    def build_menu_names(self, obj):
        return (self.label, None)

    def on_apply_clicked(self, obj):
        try:
            se_text = soundex.soundex(unicode(obj.get_text()))
        except UnicodeEncodeError:
            se_text = soundex.soundex('')
        self.value.set_text(se_text)
Esempio n. 7
0
class MissingMediaDialog(object):
    def __init__(self, msg1, msg2, task1, task2, task3, parent=None):
        self.xml = Glade(toplevel='missmediadialog')

        self.top = self.xml.toplevel
        self.top.set_icon(ICON)
        self.top.set_title("%s - Gramps" % msg1)

        self.task1 = task1
        self.task2 = task2
        self.task3 = task3

        label1 = self.xml.get_object('label4')
        label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1)
        label1.set_use_markup(True)

        label2 = self.xml.get_object('label3')
        label2.set_text(msg2)
        label2.set_use_markup(True)

        check_button = self.xml.get_object('use_always')

        if parent:
            self.top.set_transient_for(parent)
        self.top.show()
        self.top.connect('delete_event', self.warn)
        response = gtk.RESPONSE_DELETE_EVENT

        # Need some magic here, because an attempt to close the dialog
        # with the X button not only emits the 'delete_event' signal
        # but also exits with the RESPONSE_DELETE_EVENT
        while response == gtk.RESPONSE_DELETE_EVENT:
            response = self.top.run()

        if response == 1:
            self.task1()
        elif response == 2:
            self.task2()
        elif response == 3:
            self.task3()
        if check_button.get_active():
            self.default_action = response
        else:
            self.default_action = 0
        self.top.destroy()

    def warn(self, obj, obj2):
        WarningDialog(
            _("Attempt to force closing the dialog"),
            _("Please do not force closing this important dialog.\n"
              "Instead select one of the available options"), self.top)
        return True
Esempio n. 8
0
    def display(self):
        # get the main window from glade
        topDialog = Glade()

        # set gramps style title for the window
        window = topDialog.toplevel
        self.set_window(window, topDialog.get_object("title"),
                        _("Database Owner Editor"))

        # move help button to the left side
        action_area = topDialog.get_object("action_area")
        help_button = topDialog.get_object("help_button")
        action_area.set_child_secondary(help_button, True)

        # connect signals
        topDialog.connect_signals({
            "on_ok_button_clicked": self.on_ok_button_clicked,
            "on_cancel_button_clicked": self.close,
            "on_help_button_clicked": self.on_help_button_clicked,
            "on_eventbox_button_press_event": self.on_button_press_event,
            "on_menu_activate": self.on_menu_activate,
            "on_delete_event": self.close,
        })

        # fetch the popup menu
        self.menu = topDialog.get_object("popup_menu")
        #topDialog.connect_signals({"on_menu_activate": self.on_menu_activate})

        # get current db owner and attach it to the entries of the window
        self.owner = self.db.get_researcher()

        self.entries = []
        entry = [
            ("name", self.owner.set_name, self.owner.get_name),
            ("address", self.owner.set_address, self.owner.get_address),
            ("locality", self.owner.set_locality, self.owner.get_locality),
            ("city", self.owner.set_city, self.owner.get_city),
            ("state", self.owner.set_state, self.owner.get_state),
            ("country", self.owner.set_country, self.owner.get_country),
            ("zip", self.owner.set_postal_code, self.owner.get_postal_code),
            ("phone", self.owner.set_phone, self.owner.get_phone),
            ("email", self.owner.set_email, self.owner.get_email),
        ]

        for (name, set_fn, get_fn) in entry:
            self.entries.append(
                MonitoredEntry(topDialog.get_object(name), set_fn, get_fn,
                               self.db.readonly))
        # ok, let's see what we've done
        self.show()
Esempio n. 9
0
class Eval(tool.Tool,ManagedWindow.ManagedWindow):
    def __init__(self,dbstate, uistate, options_class, name, callback=None):
        self.title =  _("Python evaluation window")

        tool.Tool.__init__(self,dbstate, options_class, name)
        ManagedWindow.ManagedWindow.__init__(self,uistate,[],self.__class__)

        self.glade = Glade()

        window = self.glade.toplevel
        self.dbuf = self.glade.get_object("display").get_buffer()
        self.ebuf = self.glade.get_object("ebuf").get_buffer()
        self.error = self.glade.get_object("error").get_buffer()
        self.dbstate = dbstate

        self.glade.connect_signals({
            "on_apply_clicked" : self.apply_clicked,
            "on_close_clicked" : self.close,
            "on_clear_clicked" : self.clear_clicked,
            "on_delete_event"  : self.close,
            })

        self.set_window(window,self.glade.get_object('title'),self.title)
        self.show()

    def build_menu_names(self, obj):
        return (self.title,None)

    def apply_clicked(self, obj):
        text = unicode(self.ebuf.get_text(self.ebuf.get_start_iter(),
                                          self.ebuf.get_end_iter(),False))

        outtext = cStringIO.StringIO()
        errtext = cStringIO.StringIO()
        sys.stdout = outtext
        sys.stderr = errtext
        try:
            exec(text)
        except:
            traceback.print_exc()
        self.dbuf.set_text(outtext.getvalue())
        self.error.set_text(errtext.getvalue())
        sys.stdout = sys.__stdout__
        sys.stderr = sys.__stderr__

    def clear_clicked(self, obj):
        self.dbuf.set_text("")
        self.ebuf.set_text("")
        self.error.set_text("")
Esempio n. 10
0
    def __init__(self,default_metric,default_name,default_orientation,
                 margins=[2.54,2.54,2.54,2.54], custom=[29.7,21.0]):
        gtk.HBox.__init__(self)
        glade_xml = Glade()

        self.paper_table = glade_xml.get_object('paper_table')

        
        # get all the widgets
        widgets = ('pwidth', 'pheight', 'lmargin', 'rmargin', 'tmargin',
                   'bmargin', 'lunits1', 'lunits2', 'lunits3', 'lunits4',
                   'lunits5', 'lunits6', 'metric')
        
        for w in widgets:
            setattr(self, w, glade_xml.get_object(w))
        
        # insert custom widgets
        self.papersize_menu = PaperComboBox(default_name)
        self.orientation_menu = OrientationComboBox(default_orientation)
        self.metric.set_active(default_metric)
        
        # connect all widgets
        format_table = glade_xml.get_object('format_table')
        format_table.attach(self.papersize_menu, 1, 3, 0, 1,
                            yoptions=gtk.SHRINK)
        format_table.attach(self.orientation_menu, 1, 3, 3, 4,
                            yoptions=gtk.SHRINK)

        # connect signals
        self.papersize_menu.connect('changed',self.size_changed)
        self.metric.connect('toggled',self.units_changed)

        # set initial values
        self.paper_unit = 'cm'
        self.paper_unit_multiplier = 1.0

        self.pwidth.set_text("%.2f" % custom[0])
        self.pheight.set_text("%.2f" % custom[1])
        self.lmargin.set_text("%.2f" % margins[0])
        self.rmargin.set_text("%.2f" % margins[1])
        self.tmargin.set_text("%.2f" % margins[2])
        self.bmargin.set_text("%.2f" % margins[3])
        
        self.paper_table.show_all()
        self.paper_table.reparent(self)

        self.units_changed(self.metric)
        self.size_changed(None)
Esempio n. 11
0
class EditUrl(EditSecondary):
    def __init__(self, dbstate, uistate, track, name, url, callback):

        EditSecondary.__init__(self, dbstate, uistate, track, url, callback)

    def _local_init(self):
        self.width_key = 'interface.url-width'
        self.height_key = 'interface.url-height'

        self.top = Glade()
        self.jump = self.top.get_object('jump')

        self.set_window(self.top.toplevel, self.top.get_object("title"),
                        _('Internet Address Editor'))

    def _connect_signals(self):
        self.jump.connect('clicked', self.jump_to)
        self.define_cancel_button(self.top.get_object('button125'))
        self.define_ok_button(self.top.get_object('button124'), self.save)
        self.define_help_button(self.top.get_object('button130'))

    def jump_to(self, obj):
        if self.obj.get_path():
            import GrampsDisplay
            GrampsDisplay.url(self.obj.get_path())

    def _setup_fields(self):
        self.des = MonitoredEntry(self.top.get_object("url_des"),
                                  self.obj.set_description,
                                  self.obj.get_description, self.db.readonly)

        self.addr = MonitoredEntry(self.top.get_object("url_addr"),
                                   self.obj.set_path, self.obj.get_path,
                                   self.db.readonly)

        self.priv = PrivacyButton(self.top.get_object("priv"), self.obj,
                                  self.db.readonly)

        self.type_sel = MonitoredDataType(self.top.get_object("type"),
                                          self.obj.set_type, self.obj.get_type,
                                          self.db.readonly)

    def build_menu_names(self, obj):
        etitle = _('Internet Address Editor')
        return (etitle, etitle)

    def save(self, *obj):
        self.callback(self.obj)
        self.close()
Esempio n. 12
0
    def __init__(self, state, uistate, track, handle):
        xml = Glade()
        top = xml.toplevel

        self.dbstate = state
        ManagedWindow.ManagedWindow.__init__(self, uistate, track, self)

        self.person = self.dbstate.db.get_person_from_handle(handle)
        self.parent_list = self.person.get_parent_family_handle_list()
        self.family_list = self.person.get_family_handle_list()

        penable = len(self.parent_list) > 1
        fenable = len(self.family_list) > 1

        self.set_window(top, None, _("Reorder Relationships"))

        self.ptree = xml.get_object('ptree')
        self.pmodel = ListModel.ListModel(self.ptree, PARENT_TITLES)

        self.ftree = xml.get_object('ftree')
        self.fmodel = ListModel.ListModel(self.ftree, FAMILY_TITLES)

        xml.get_object('ok').connect('clicked', self.ok_clicked)
        xml.get_object('cancel').connect('clicked', self.cancel_clicked)

        fup = xml.get_object('fup')
        fup.connect('clicked', self.fup_clicked)
        fup.set_sensitive(fenable)

        fdown = xml.get_object('fdown')
        fdown.connect('clicked', self.fdown_clicked)
        fdown.set_sensitive(fenable)

        pup = xml.get_object('pup')
        pup.connect('clicked', self.pup_clicked)
        pup.set_sensitive(penable)

        pdown = xml.get_object('pdown')
        pdown.connect('clicked', self.pdown_clicked)
        pdown.set_sensitive(penable)

        self.fill_data()

        self.show()
Esempio n. 13
0
def check_in(dbase, filename, callback, cursor_func=None):
    """
    Checks in the specified file into RCS
    """
    init = ["rcs", '-x,v', '-i', '-U', '-q', '-t-"Gramps database"']
    ci_cmd = ["ci", '-x,v', "-q", "-f"]
    archive_name = filename + ",v"

    glade = Glade(toplevel='comment')
    top = glade.toplevel
    text = glade.get_object('description')
    top.run()
    comment = text.get_text()
    top.destroy()

    if not os.path.isfile(archive_name):
        cmd = init + [archive_name]
        proc = subprocess.Popen(cmd, stderr=subprocess.PIPE)
        status = proc.wait()
        message = "\n".join(proc.stderr.readlines())
        proc.stderr.close()
        del proc

        if status != 0:
            ErrorDialog(
                _("Archiving failed"),
                _("An attempt to create the archive failed "
                  "with the following message:\n\n%s") % message)

    if cursor_func:
        cursor_func(_("Creating data to be archived..."))

    plugin_manager = GuiPluginManager.get_instance()
    for plugin in plugin_manager.get_export_plugins():
        if plugin.get_extension() == "gramps":
            export_function = plugin.get_export_function()
            export_function(dbase, filename, None, callback)

    if cursor_func:
        cursor_func(_("Saving archive..."))

    cmd = ci_cmd + ['-m%s' % comment, filename, archive_name]
    proc = subprocess.Popen(cmd, stderr=subprocess.PIPE)

    status = proc.wait()
    message = "\n".join(proc.stderr.readlines())
    proc.stderr.close()
    del proc

    if status != 0:
        ErrorDialog(
            _("Archiving failed"),
            _("An attempt to archive the data failed "
              "with the following message:\n\n%s") % message)
Esempio n. 14
0
def importData(database, filename, callback=None):
    """
    Try to handle ANSEL encoded files that are not really ANSEL encoded
    """

    if DbMixin not in database.__class__.__bases__:
        database.__class__.__bases__ = (DbMixin,) +  \
                                        database.__class__.__bases__

    try:
        ifile = open(filename, "r")
    except IOError:
        return

    ansel = False
    gramps = False
    for index in range(50):
        line = ifile.readline().split()
        if len(line) == 0:
            break
        if len(line) > 2 and line[1][0:4] == 'CHAR' and line[2] == "ANSEL":
            ansel = True
        if len(line) > 2 and line[1][0:4] == 'SOUR' and line[2] == "GRAMPS":
            gramps = True
    ifile.close()

    if not gramps and ansel:
        top = Glade()
        code = top.get_object('codeset')
        code.set_active(0)
        dialog = top.toplevel
        dialog.run()
        enc = ['ANSEL', 'ANSEL', 'ANSI', 'ASCII', 'UTF-8']
        code_set = enc[code.get_active()]
        dialog.destroy()
    else:
        code_set = ""

    assert (isinstance(code_set, basestring))

    try:
        ifile = open(filename, "rU")
        stage_one = libgedcom.GedcomStageOne(ifile)
        stage_one.parse()

        if code_set:
            stage_one.set_encoding(code_set)
        ifile.seek(0)
        gedparse = libgedcom.GedcomParser(
            database, ifile, filename, callback, stage_one,
            config.get('preferences.default-source'))
    except IOError, msg:
        ErrorDialog(_("%s could not be opened\n") % filename, str(msg))
        return
Esempio n. 15
0
    def __init__(self, uistate):

        ManagedWindow.ManagedWindow.__init__(self, uistate, [], self)
        
        xml = Glade()
        window = xml.toplevel
        self.set_window(window, 
                        xml.get_object("title"), 
                        _("Tip of the Day"), 
                        _("Tip of the Day"))
        
        self.tip = xml.get_object("tip")
        self.use = xml.get_object('usetips')
        self.use.set_active(config.get('behavior.use-tips'))
        image = xml.get_object('image')
        image.set_from_file(os.path.join(const.IMAGE_DIR, 'splash.jpg'))

        next = xml.get_object('next')
        next.connect("clicked", self.next_tip_cb)
        close = xml.get_object('close')
        close.connect("clicked", self.close_cb)
        
        try:
            tparser = TipParser()
        except (IOError,ExpatError), e:
            self.close()
            ErrorDialog(
                _("Failed to display tip of the day"),
                _("Unable to read the tips from external file.\n\n%s")%e)
            return
Esempio n. 16
0
class OptionDialog(object):
    def __init__(self,
                 msg1,
                 msg2,
                 btnmsg1,
                 task1,
                 btnmsg2,
                 task2,
                 parent=None):
        self.xml = Glade(toplevel='optiondialog')

        self.top = self.xml.toplevel
        self.top.set_icon(ICON)
        self.top.set_title("%s - Gramps" % msg1)

        label1 = self.xml.get_object('od_label1')
        label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1)
        label1.set_use_markup(True)

        label2 = self.xml.get_object('od_label2')
        label2.set_text(msg2)
        label2.set_use_markup(True)

        self.xml.get_object('option1').set_label(btnmsg1)
        self.xml.get_object('option2').set_label(btnmsg2)
        if parent:
            self.top.set_transient_for(parent)
        self.top.show()
        self.response = self.top.run()
        if self.response == gtk.RESPONSE_NO:
            if task1:
                task1()
        else:
            if task2:
                task2()
        self.top.destroy()

    def get_response(self):
        return self.response
Esempio n. 17
0
    def run(self):

        top = Glade(toplevel="mergecitations")

        # retrieve options
        fields = self.options.handler.options_dict['fields']
        dont_merge_notes = self.options.handler.options_dict['dont_merge_notes']

        my_menu = gtk.ListStore(str, object)
        for val in sorted(_val2label):
            my_menu.append([_val2label[val], val])

        self.notes_obj = top.get_object("notes")
        self.notes_obj.set_active(dont_merge_notes)
        self.notes_obj.show()
        
        self.menu = top.get_object("menu")
        self.menu.set_model(my_menu)
        self.menu.set_active(fields)

        window = top.toplevel
        window.show()
#        self.set_window(window, top.get_object('title'),
#                        _('Merge citations'))
        self.set_window(window, top.get_object('title2'),
                        _("Notes, media objects and data-items of matching "
                        "citations will be combined."))
        
        top.connect_signals({
            "on_merge_ok_clicked"   : self.on_merge_ok_clicked,
            "destroy_passed_object" : self.cancel,
            "on_help_clicked"       : self.on_help_clicked,
            "on_delete_merge_event" : self.close,
            "on_delete_event"       : self.close,
            })

        self.show()
Esempio n. 18
0
class MessageHideDialog(object):
    def __init__(self, title, message, key, parent=None):
        self.xml = Glade(toplevel='hidedialog')

        self.top = self.xml.toplevel
        self.top.set_icon(ICON)
        self.top.set_title("%s - Gramps" % title)

        dont_show = self.xml.get_object('dont_show')
        dont_show.set_active(config.get(key))
        title_label = self.xml.get_object('title')
        title_label.set_text('<span size="larger" weight="bold">%s</span>' %
                             title)
        title_label.set_use_markup(True)

        self.xml.get_object('message').set_text(message)

        dont_show.connect('toggled', self.update_checkbox, key)
        self.top.run()
        self.top.destroy()

    def update_checkbox(self, obj, constant):
        config.set(constant, obj.get_active())
        config.save()
Esempio n. 19
0
class WarnHandler(RotateHandler):
    def __init__(self, capacity, button):
        RotateHandler.__init__(self, capacity)
        self.setLevel(logging.WARN)
        self.button = button
        button.on_clicked(self.display)
        self.timer = None
        self.last_line = '-1'

    def emit(self, record):
        if self.timer is None:
            #check every 3 minutes if warn button can disappear
            self.timer = gobject.timeout_add(3 * 60 * 1000, self._check_clear)
        RotateHandler.emit(self, record)
        self.button.show()

    def _check_clear(self):
        new_last_line = self.get_buffer()[-1]
        if self.last_line == new_last_line:
            #buffer has not changed for 3 minutes, let's clear it:
            self._clear()
            return False
        else:
            self.last_line = new_last_line
            return True

    def _clear(self):
        self.button.hide()
        self.set_capacity(self._capacity)
        self.last_line = '-1'
        self.timer = None

    def display(self, obj):
        obj.hide()
        self.glade = Glade()
        top = self.glade.toplevel
        msg = self.glade.get_object('msg')
        buf = msg.get_buffer()
        for i in self.get_formatted_log():
            buf.insert_at_cursor(i + '\n')
        top.run()
        top.destroy()
Esempio n. 20
0
class DesBrowse(tool.ActivePersonTool, ManagedWindow.ManagedWindow):

    def __init__(self, dbstate, uistate, options_class, name, callback=None):

        tool.ActivePersonTool.__init__(self, dbstate, uistate, options_class,
                                       name)
        if self.fail:
            return

        self.dbstate = dbstate
        active_handle = uistate.get_active('Person')
        self.active = dbstate.db.get_person_from_handle(active_handle)
        self.callback = callback
        self.active_name = _("Descendant Browser: %s") % (
                                name_displayer.display(self.active)
                                )

        ManagedWindow.ManagedWindow.__init__(self, uistate, [], self)

        self.glade = Glade()
        self.glade.connect_signals({
            "destroy_passed_object" : self.close,
            "on_help_clicked"       : self.on_help_clicked,
            "on_delete_event"       : self.close,
            })

        window = self.glade.toplevel
        self.set_window(window,self.glade.get_object('title'),
                        self.active_name)
        
        self.tree = self.glade.get_object("tree1")
        col = gtk.TreeViewColumn('',gtk.CellRendererText(),text=0)
        self.tree.append_column(col)
        self.tree.set_rules_hint(True)
        self.tree.set_headers_visible(False)
        self.tree.connect('event',self.button_press_event)
        self.make_new_model()

        self.show()

    def build_menu_names(self, obj):
        return (self.active_name,_("Descendant Browser tool"))

    def make_new_model(self):
        self.model = gtk.TreeStore(str, object)
        self.tree.set_model(self.model)
        self.add_to_tree(None, None, self.active.get_handle())
        self.tree.expand_all()

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        GrampsDisplay.help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC)

    def add_to_tree(self, parent_id, sib_id, person_handle):
        item_id = self.model.insert_after(parent_id, sib_id)
        person = self.db.get_person_from_handle(person_handle)
        
        self.model.set(item_id, 0, name_displayer.display(person))
        self.model.set(item_id, 1, person_handle)
        prev_id = None
        for family_handle in person.get_family_handle_list():
            family = self.db.get_family_from_handle(family_handle)
            for child_ref in family.get_child_ref_list():
                prev_id = self.add_to_tree(item_id, prev_id, child_ref.ref)
        return item_id
    
    def button_press_event(self, obj,event):
        if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
            store, node = self.tree.get_selection().get_selected()
            if node:
                person_handle = store.get_value(node, 1)
                person = self.db.get_person_from_handle(person_handle)
                EditPerson(self.dbstate, self.uistate, self.track, person,
                           self.this_callback)

    def this_callback(self, obj):
        self.callback()
        self.make_new_model()
Esempio n. 21
0
class EditChildRef(EditSecondary):
    """
    Displays a dialog that allows the user to edit an address.
    """
    def __init__(self, name, dbstate, uistate, track, childref, callback):
        """
        Displays the dialog box.

        parent - The class that called the ChildRef editor.
        addr - The address that is to be edited
        """
        self.name = name
        EditSecondary.__init__(self, dbstate, uistate, track, childref,
                               callback)

    def _local_init(self):
        self.width_key = 'interface.child-ref-width'
        self.height_key = 'interface.child-ref-height'

        self.top = Glade()
        self.set_window(self.top.toplevel, self.top.get_object("title"),
                        self.name, _('Child Reference Editor'))

        self.ok_button = self.top.get_object('ok')
        self.edit_button = self.top.get_object('edit')
        self.name_label = self.top.get_object('name')
        self.name_label.set_text(self.name)

    def _setup_fields(self):
        self.frel = MonitoredDataType(self.top.get_object('frel'),
                                      self.obj.set_father_relation,
                                      self.obj.get_father_relation,
                                      self.db.readonly,
                                      self.db.get_child_reference_types())

        self.mrel = MonitoredDataType(self.top.get_object('mrel'),
                                      self.obj.set_mother_relation,
                                      self.obj.get_mother_relation,
                                      self.db.readonly,
                                      self.db.get_child_reference_types())

        self.priv = PrivacyButton(self.top.get_object("private"), self.obj,
                                  self.db.readonly)

    def _connect_signals(self):
        self.define_help_button(self.top.get_object('help'))
        self.define_cancel_button(self.top.get_object('cancel'))
        self.define_ok_button(self.ok_button, self.save)
        self.edit_button.connect('button-press-event', self.edit_child)
        self.edit_button.connect('key-press-event', self.edit_child)

    def _connect_db_signals(self):
        """
        Connect any signals that need to be connected. 
        Called by the init routine of the base class (_EditPrimary).
        """
        self._add_db_signal('person-update', self.person_change)
        self._add_db_signal('person-rebuild', self.close)
        self._add_db_signal('person-delete', self.check_for_close)

    def _create_tabbed_pages(self):
        """
        Create the notebook tabs and inserts them into the main
        window.
        """
        notebook = gtk.Notebook()

        self.srcref_list = CitationEmbedList(self.dbstate, self.uistate,
                                             self.track,
                                             self.obj.get_citation_list())
        self._add_tab(notebook, self.srcref_list)
        self.track_ref_for_deletion("srcref_list")

        self.note_tab = NoteTab(self.dbstate,
                                self.uistate,
                                self.track,
                                self.obj.get_note_list(),
                                notetype=NoteType.CHILDREF)
        self._add_tab(notebook, self.note_tab)
        self.track_ref_for_deletion("note_tab")

        self._setup_notebook_tabs(notebook)
        notebook.show_all()
        self.top.get_object('vbox').pack_start(notebook, True)

    def _post_init(self):
        self.ok_button.grab_focus()

    def build_menu_names(self, obj):
        return (_('Child Reference'), _('Child Reference Editor'))

    def edit_child(self, obj, event):
        if button_activated(event, _LEFT_BUTTON):
            from editperson import EditPerson
            handle = self.obj.ref
            try:
                person = self.db.get_person_from_handle(handle)
                EditPerson(self.dbstate, self.uistate, self.track, person)
            except Errors.WindowActiveError:
                pass

    def person_change(self, handles):
        # check to see if the handle matches the current object
        if self.obj.ref in handles:
            p = self.dbstate.db.get_person_from_handle(self.obj.ref)
            self.name = name_displayer.display(p)
            self.name_label.set_text(self.name)

    def save(self, *obj):
        """
        Called when the OK button is pressed. Gets data from the
        form and updates the ChildRef data structure.
        """
        if self.callback:
            self.callback(self.obj)
        self.close()

    def check_for_close(self, handles):
        """
        Callback method for delete signals. 
        If there is a delete signal of the primary object we are editing, the
        editor (and all child windows spawned) should be closed
        """
        if self.obj.ref in handles:
            self.close()
Esempio n. 22
0
class EventComparison(tool.Tool, ManagedWindow.ManagedWindow):
    def __init__(self, dbstate, uistate, options_class, name, callback=None):
        self.dbstate = dbstate
        self.uistate = uistate

        tool.Tool.__init__(self, dbstate, options_class, name)
        ManagedWindow.ManagedWindow.__init__(self, uistate, [], self)
        self.qual = 0

        self.filterDialog = Glade(toplevel="filters")
        self.filterDialog.connect_signals({
            "on_apply_clicked": self.on_apply_clicked,
            "on_editor_clicked": self.filter_editor_clicked,
            "on_help_clicked": self.on_help_clicked,
            "destroy_passed_object": self.close,
            "on_write_table": self.__dummy,
        })

        window = self.filterDialog.toplevel
        window.show()
        self.filters = self.filterDialog.get_object("filter_list")
        self.label = _('Event comparison filter selection')
        self.set_window(window, self.filterDialog.get_object('title'),
                        self.label)

        self.on_filters_changed('Person')
        uistate.connect('filters-changed', self.on_filters_changed)

        self.show()

    def __dummy(self, obj):
        """dummy callback, needed because widget is in same glade file
        as another widget, so callbacks must be defined to avoid warnings.
        """
        pass

    def on_filters_changed(self, name_space):
        if name_space == 'Person':
            all_filter = GenericFilter()
            all_filter.set_name(_("Entire Database"))
            all_filter.add_rule(Rules.Person.Everyone([]))
            self.filter_model = build_filter_model('Person', [all_filter])
            self.filters.set_model(self.filter_model)
            self.filters.set_active(0)

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        GrampsDisplay.help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC)

    def build_menu_names(self, obj):
        return (_("Filter selection"), _("Event Comparison tool"))

    def filter_editor_clicked(self, obj):
        try:
            FilterEditor('Person', const.CUSTOM_FILTERS, self.dbstate,
                         self.uistate)
        except Errors.WindowActiveError:
            pass

    def on_apply_clicked(self, obj):
        cfilter = self.filter_model[self.filters.get_active()][1]

        progress_bar = ProgressMeter(_('Comparing events'), '')
        progress_bar.set_pass(_('Selecting people'), 1)

        plist = cfilter.apply(self.db, self.db.iter_person_handles())

        progress_bar.step()
        progress_bar.close()
        self.options.handler.options_dict['filter'] = self.filters.get_active()
        # Save options
        self.options.handler.save_options()

        if len(plist) == 0:
            WarningDialog(_("No matches were found"))
        else:
            DisplayChart(self.dbstate, self.uistate, plist, self.track)
Esempio n. 23
0
class DisplayChart(ManagedWindow.ManagedWindow):
    def __init__(self, dbstate, uistate, people_list, track):
        self.dbstate = dbstate
        self.uistate = uistate

        ManagedWindow.ManagedWindow.__init__(self, uistate, track, self)

        self.db = dbstate.db
        self.my_list = people_list
        self.row_data = []
        self.save_form = None

        self.topDialog = Glade()
        self.topDialog.connect_signals({
            "on_write_table": self.on_write_table,
            "destroy_passed_object": self.close,
            "on_help_clicked": self.on_help_clicked,
            "on_apply_clicked": self.__dummy,
            "on_editor_clicked": self.__dummy,
        })

        window = self.topDialog.toplevel
        window.show()
        self.set_window(window, self.topDialog.get_object('title'),
                        _('Event Comparison Results'))

        self.eventlist = self.topDialog.get_object('treeview')
        self.sort = Sort.Sort(self.db)
        self.my_list.sort(self.sort.by_last_name)

        self.event_titles = self.make_event_titles()

        self.table_titles = [_("Person"), _("ID")]
        for event_name in self.event_titles:
            self.table_titles.append(
                _("%(event_name)s Date") % {'event_name': event_name})
            self.table_titles.append('sort')  # This won't be shown in a tree
            self.table_titles.append(
                _("%(event_name)s Place") % {'event_name': event_name})

        self.build_row_data()
        self.draw_display()
        self.show()

    def __dummy(self, obj):
        """dummy callback, needed because widget is in same glade file
        as another widget, so callbacks must be defined to avoid warnings.
        """
        pass

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        GrampsDisplay.help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC)

    def build_menu_names(self, obj):
        return (_("Event Comparison Results"), None)

    def draw_display(self):

        model_index = 0
        tree_index = 0
        mylist = []
        renderer = gtk.CellRendererText()
        for title in self.table_titles:
            mylist.append(str)
            if title == 'sort':
                # This will override the previously defined column
                self.eventlist.get_column(tree_index -
                                          1).set_sort_column_id(model_index)
            else:
                column = gtk.TreeViewColumn(title, renderer, text=model_index)
                column.set_sort_column_id(model_index)
                self.eventlist.append_column(column)
                # This one numbers the tree columns: increment on new column
                tree_index += 1
            # This one numbers the model columns: always increment
            model_index += 1

        model = gtk.ListStore(*mylist)
        self.eventlist.set_model(model)

        self.progress_bar.set_pass(_('Building display'), len(self.row_data))
        for data in self.row_data:
            model.append(row=list(data))
            self.progress_bar.step()
        self.progress_bar.close()

    def build_row_data(self):
        self.progress_bar = ProgressMeter(_('Comparing Events'), '')
        self.progress_bar.set_pass(_('Building data'), len(self.my_list))
        for individual_id in self.my_list:
            individual = self.db.get_person_from_handle(individual_id)
            name = individual.get_primary_name().get_name()
            gid = individual.get_gramps_id()

            the_map = defaultdict(list)
            for ievent_ref in individual.get_event_ref_list():
                ievent = self.db.get_event_from_handle(ievent_ref.ref)
                event_name = str(ievent.get_type())
                the_map[event_name].append(ievent_ref.ref)

            first = True
            done = False
            while not done:
                added = False
                tlist = [name, gid] if first else ["", ""]

                for ename in self.event_titles:
                    if ename in the_map and len(the_map[ename]) > 0:
                        event_handle = the_map[ename][0]
                        del the_map[ename][0]
                        date = place = ""

                        if event_handle:
                            event = self.db.get_event_from_handle(event_handle)
                            date = DateHandler.get_date(event)
                            sortdate = "%09d" % (
                                event.get_date_object().get_sort_value())
                            place_handle = event.get_place_handle()
                            if place_handle:
                                place = self.db.get_place_from_handle(
                                    place_handle).get_title()
                        tlist += [date, sortdate, place]
                        added = True
                    else:
                        tlist += [""] * 3

                if first:
                    first = False
                    self.row_data.append(tlist)
                elif not added:
                    done = True
                else:
                    self.row_data.append(tlist)
            self.progress_bar.step()

    def make_event_titles(self):
        """
        Create the list of unique event types, along with the person's
        name, birth, and death.
        This should be the column titles of the report.
        """
        the_map = defaultdict(int)
        for individual_id in self.my_list:
            individual = self.db.get_person_from_handle(individual_id)
            for event_ref in individual.get_event_ref_list():
                event = self.db.get_event_from_handle(event_ref.ref)
                name = str(event.get_type())
                if not name:
                    break
                the_map[name] += 1

        unsort_list = sorted([(d, k) for k, d in the_map.iteritems()],
                             by_value)

        sort_list = [item[1] for item in unsort_list]
        ## Presently there's no Birth and Death. Instead there's Birth Date and
        ## Birth Place, as well as Death Date and Death Place.
        ##         # Move birth and death to the begining of the list
        ##         if _("Death") in the_map:
        ##             sort_list.remove(_("Death"))
        ##             sort_list = [_("Death")] + sort_list

        ##         if _("Birth") in the_map:
        ##             sort_list.remove(_("Birth"))
        ##             sort_list = [_("Birth")] + sort_list

        return sort_list

    def on_write_table(self, obj):
        f = gtk.FileChooserDialog(_("Select filename"),
                                  action=gtk.FILE_CHOOSER_ACTION_SAVE,
                                  buttons=(gtk.STOCK_CANCEL,
                                           gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE,
                                           gtk.RESPONSE_OK))

        f.set_current_folder(os.getcwd())
        status = f.run()
        f.hide()

        if status == gtk.RESPONSE_OK:
            name = Utils.get_unicode_path_from_file_chooser(f.get_filename())
            doc = ODSTab(len(self.row_data))
            doc.creator(self.db.get_researcher().get_name())

            spreadsheet = TableReport(name, doc)

            new_titles = []
            skip_columns = []
            index = 0
            for title in self.table_titles:
                if title == 'sort':
                    skip_columns.append(index)
                else:
                    new_titles.append(title)
                index += 1
            spreadsheet.initialize(len(new_titles))

            spreadsheet.write_table_head(new_titles)

            index = 0
            for top in self.row_data:
                spreadsheet.set_row(index % 2)
                index += 1
                spreadsheet.write_table_data(top, skip_columns)

            spreadsheet.finalize()
        f.destroy()
Esempio n. 24
0
class EditLocation(EditSecondary):
    def __init__(self, dbstate, uistate, track, location, callback):
        EditSecondary.__init__(self, dbstate, uistate, track, location,
                               callback)

    def _local_init(self):
        self.width_key = 'interface.location-width'
        self.height_key = 'interface.location-height'
        self.top = Glade()
        self.set_window(self.top.toplevel, None, _('Location Editor'))

    def _setup_fields(self):
        self.street = MonitoredEntry(self.top.get_object("street"),
                                     self.obj.set_street, self.obj.get_street,
                                     self.db.readonly)

        self.locality = MonitoredEntry(self.top.get_object("locality"),
                                       self.obj.set_locality,
                                       self.obj.get_locality, self.db.readonly)

        self.city = MonitoredEntry(self.top.get_object("city"),
                                   self.obj.set_city, self.obj.get_city,
                                   self.db.readonly)

        self.state = MonitoredEntry(self.top.get_object("state"),
                                    self.obj.set_state, self.obj.get_state,
                                    self.db.readonly)

        self.postal = MonitoredEntry(self.top.get_object("postal"),
                                     self.obj.set_postal_code,
                                     self.obj.get_postal_code,
                                     self.db.readonly)

        self.phone = MonitoredEntry(self.top.get_object("phone"),
                                    self.obj.set_phone, self.obj.get_phone,
                                    self.db.readonly)

        self.parish = MonitoredEntry(self.top.get_object("parish"),
                                     self.obj.set_parish, self.obj.get_parish,
                                     self.db.readonly)

        self.county = MonitoredEntry(self.top.get_object("county"),
                                     self.obj.set_county, self.obj.get_county,
                                     self.db.readonly)

        self.country = MonitoredEntry(self.top.get_object("country"),
                                      self.obj.set_country,
                                      self.obj.get_country, self.db.readonly)

    def _connect_signals(self):
        self.define_cancel_button(self.top.get_object('button119'))
        self.define_ok_button(self.top.get_object('button118'), self.save)
        self.define_help_button(self.top.get_object('button128'))

    def save(self, *obj):
        if self.callback:
            self.callback(self.obj)
        self.close()
Esempio n. 25
0
class DbManager(CLIDbManager):
    """
    Database Manager. Opens a database manager window that allows users to
    create, rename, delete and open databases.
    """
    ICON_MAP = {
        CLIDbManager.ICON_NONE: '',
        CLIDbManager.ICON_RECOVERY: gtk.STOCK_DIALOG_ERROR,
        CLIDbManager.ICON_LOCK: 'gramps-lock',
        CLIDbManager.ICON_OPEN: gtk.STOCK_OPEN,
    }

    ERROR = ErrorDialog

    def __init__(self, dbstate, parent=None):
        """
        Create the top level window from the glade description, and extracts
        the GTK widgets that are needed.
        """
        CLIDbManager.__init__(self, dbstate)
        self.glade = Glade()
        self.top = self.glade.toplevel

        if parent:
            self.top.set_transient_for(parent)

        for attr in [
                'connect', 'cancel', 'new', 'remove', 'dblist', 'rename',
                'repair', 'rcs', 'msg'
        ]:
            setattr(self, attr, self.glade.get_object(attr))

        self.model = None
        self.column = None
        self.lock_file = None
        self.data_to_delete = None

        self.selection = self.dblist.get_selection()
        self.dblist.set_rules_hint(True)

        self.__connect_signals()
        self.__build_interface()
        self._populate_model()

    def __connect_signals(self):
        """
        Connects the signals to the buttons on the interface. 
        """
        ddtargets = [DdTargets.URI_LIST.target()]
        self.top.drag_dest_set(gtk.DEST_DEFAULT_ALL, ddtargets, ACTION_COPY)

        self.remove.connect('clicked', self.__remove_db)
        self.new.connect('clicked', self.__new_db)
        self.rename.connect('clicked', self.__rename_db)
        self.repair.connect('clicked', self.__repair_db)
        self.selection.connect('changed', self.__selection_changed)
        self.dblist.connect('button-press-event', self.__button_press)
        self.dblist.connect('key-press-event', self.__key_press)
        self.top.connect('drag_data_received', self.__drag_data_received)
        self.top.connect('drag_motion', drag_motion)
        self.top.connect('drag_drop', drop_cb)

        if _RCS_FOUND:
            self.rcs.connect('clicked', self.__rcs)

    def __button_press(self, obj, event):
        """
        Checks for a double click event. In the tree view, we want to 
        treat a double click as if it was OK button press. However, we have
        to make sure that an item was selected first.
        """
        if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
            if self.connect.get_property('sensitive'):
                self.top.response(gtk.RESPONSE_OK)
                return True
        return False

    def __key_press(self, obj, event):
        """
        Grab ENTER so it does not start editing the cell, but behaves
        like double click instead
        """
        if event.keyval in (_RETURN, _KP_ENTER):
            if self.connect.get_property('sensitive'):
                self.top.response(gtk.RESPONSE_OK)
                return True
        return False

    def __selection_changed(self, selection):
        """
        Called when the selection is changed in the TreeView. 
        """
        self.__update_buttons(selection)

    def __update_buttons(self, selection):
        """
        What we are trying to detect is the selection or unselection of a row.
        When a row is unselected, the Open, Rename, and Remove buttons
        are set insensitive. If a row is selected, the rename and remove
        buttons are disabled, and the Open button is disabled if the
        row represents a open database.
        """

        # Get the current selection
        store, node = selection.get_selected()

        # if nothing is selected
        if not node:
            self.connect.set_sensitive(False)
            self.rename.set_sensitive(False)
            self.rcs.set_sensitive(False)
            self.repair.set_sensitive(False)
            self.remove.set_sensitive(False)
            return

        path = self.model.get_path(node)
        if path is None:
            return

        is_rev = len(path) > 1
        self.rcs.set_label(RCS_BUTTON[is_rev])

        if store.get_value(node, STOCK_COL) == gtk.STOCK_OPEN:
            self.connect.set_sensitive(False)
            if _RCS_FOUND:
                self.rcs.set_sensitive(True)
        else:
            self.connect.set_sensitive(not is_rev)
            if _RCS_FOUND and is_rev:
                self.rcs.set_sensitive(True)
            else:
                self.rcs.set_sensitive(False)

        if store.get_value(node, STOCK_COL) == gtk.STOCK_DIALOG_ERROR:
            path = get_unicode_path_from_env_var(
                store.get_value(node, PATH_COL))
            backup = os.path.join(path, "person.gbkp")
            self.repair.set_sensitive(os.path.isfile(backup))
        else:
            self.repair.set_sensitive(False)

        self.rename.set_sensitive(True)
        self.remove.set_sensitive(True)

    def __build_interface(self):
        """
        Builds the columns for the TreeView. The columns are:

        Icon, Database Name, Last Modified

        The Icon column gets its data from column 6 of the database model.
        It is expecting either None, or a GTK stock icon name

        The Database Name column is an editable column. We connect to the
        'edited' signal, so that we can change the name when the user changes
        the column.

        The last accessed column simply displays the last time famtree was 
        opened.
        """

        # build the database name column
        render = gtk.CellRendererText()
        render.set_property('ellipsize', pango.ELLIPSIZE_END)
        render.connect('edited', self.__change_name)
        render.connect('editing-canceled', self.__stop_edit)
        render.connect('editing-started', self.__start_edit)
        self.column = gtk.TreeViewColumn(_('Family tree name'),
                                         render,
                                         text=NAME_COL)
        self.column.set_sort_column_id(NAME_COL)
        self.column.set_resizable(True)
        self.column.set_min_width(275)
        self.dblist.append_column(self.column)
        self.name_renderer = render

        # build the icon column
        render = gtk.CellRendererPixbuf()
        icon_column = gtk.TreeViewColumn(_('Status'),
                                         render,
                                         stock_id=STOCK_COL)
        self.dblist.append_column(icon_column)

        # build the last accessed column
        render = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_('Last accessed'), render, text=DATE_COL)
        column.set_sort_column_id(DSORT_COL)
        self.dblist.append_column(column)

        # set the rules hit
        self.dblist.set_rules_hint(True)

    def __populate(self):
        """
        Builds the data and the display model.
        """
        self._populate_cli()
        self._populate_model()

    def _populate_model(self):
        """
        Builds the display model.
        """
        self.model = gtk.TreeStore(str, str, str, str, int, bool, str)

        #use current names to set up the model
        for items in self.current_names:
            data = list(items[:7])
            node = self.model.append(None, data)
            for rdata in find_revisions(os.path.join(items[1], ARCHIVE_V)):
                data = [rdata[2], rdata[0], items[1], rdata[1], 0, False, ""]
                self.model.append(node, data)
        self.dblist.set_model(self.model)

    def existing_name(self, name, skippath=None):
        """
        Return true if a name is present in the model already.
        If skippath given, the name of skippath is not considered
        """
        iter = self.model.get_iter_first()
        while (iter):
            path = self.model.get_path(iter)
            if path == skippath:
                continue
            itername = self.model.get_value(iter, NAME_COL)
            if itername.strip() == name.strip():
                return True
            iter = self.model.iter_next(iter)
        return False

    def run(self):
        """
        Runs the dialog, returning None if nothing has been chosen,
        or the path and name if something has been selected
        """
        while True:
            value = self.top.run()
            if value == gtk.RESPONSE_OK:
                store, node = self.selection.get_selected()
                # don't open a locked file
                if store.get_value(node, STOCK_COL) == 'gramps-lock':
                    self.__ask_to_break_lock(store, node)
                    continue
                # don't open a version
                if len(store.get_path(node)) > 1:
                    continue
                if node:
                    self.top.destroy()
                    del self.selection
                    del self.name_renderer
                    path = get_unicode_path_from_env_var(
                        store.get_value(node, PATH_COL))
                    return (path, store.get_value(node, NAME_COL))
            else:
                self.top.destroy()
                del self.selection
                del self.name_renderer
                return None

    def __ask_to_break_lock(self, store, node):
        """
        Prompts the user for permission to break the lock file that another
        process has set on the file.
        """
        path = store.get_path(node)
        self.lock_file = store[path][PATH_COL]

        QuestionDialog(
            _("Break the lock on the '%s' database?") % store[path][0],
            _("Gramps believes that someone else is actively editing "
              "this database. You cannot edit this database while it "
              "is locked. If no one is editing the database you may "
              "safely break the lock. However, if someone else is editing "
              "the database and you break the lock, you may corrupt the "
              "database."), _("Break lock"), self.__really_break_lock)

    def __really_break_lock(self):
        """
        Deletes the lock file associated with the selected database, then updates
        the display appropriately.
        """
        try:
            self.break_lock(self.lock_file)
            store, node = self.selection.get_selected()
            dbpath = get_unicode_path_from_env_var(
                store.get_value(node, PATH_COL))
            (tval, last) = time_val(dbpath)
            store.set_value(node, OPEN_COL, 0)
            store.set_value(node, STOCK_COL, "")
            store.set_value(node, DATE_COL, last)
            store.set_value(node, DSORT_COL, tval)
        except IOError:
            return

    def __stop_edit(self, *args):
        self.name_renderer.set_property('editable', False)
        self.__update_buttons(self.selection)

    def __start_edit(self, *args):
        """
        Do no allow to click Load while changing name, to force users to finish
        the action of renaming. Hack around the fact that clicking button
        sends a 'editing-canceled' signal loosing the new name
        """
        self.connect.set_sensitive(False)
        self.rename.set_sensitive(False)

    def __change_name(self, renderer_sel, path, new_text):
        """
        Change the name of the database. This is a callback from the
        column, which has been marked as editable. 

        If the new string is empty, do nothing. Otherwise, renaming the	
        database is simply changing the contents of the name file.
        """
        if len(new_text) > 0:
            node = self.model.get_iter(path)
            old_text = self.model.get_value(node, NAME_COL)
            if not old_text.strip() == new_text.strip():
                #If there is a ":" in path, then it as revision
                if ":" in path:
                    self.__rename_revision(path, new_text)
                else:
                    self.__rename_database(path, new_text)

        self.name_renderer.set_property('editable', False)
        self.__update_buttons(self.selection)

    def __rename_revision(self, path, new_text):
        """
        Renames the RCS revision using the rcs command. The rcs command 
        is in the format of:

           rcs -mREV:NEW_NAME archive

        """
        node = self.model.get_iter(path)
        db_dir = self.model.get_value(node, FILE_COL)
        rev = self.model.get_value(node, PATH_COL)
        archive = os.path.join(db_dir, ARCHIVE_V)

        cmd = ["rcs", "-x,v", "-m%s:%s" % (rev, new_text), archive]

        proc = subprocess.Popen(cmd, stderr=subprocess.PIPE)
        status = proc.wait()
        message = "\n".join(proc.stderr.readlines())
        proc.stderr.close()
        del proc

        if status != 0:
            DbManager.ERROR(
                _("Rename failed"),
                _("An attempt to rename a version failed "
                  "with the following message:\n\n%s") % message)
        else:
            self.model.set_value(node, NAME_COL, new_text)

    def __rename_database(self, path, new_text):
        """
        Renames the database by writing the new value to the name.txt file
        """
        new_text = new_text.strip()
        node = self.model.get_iter(path)
        filename = self.model.get_value(node, FILE_COL)
        if self.existing_name(new_text, skippath=path):
            DbManager.ERROR(
                _("Could not rename the Family Tree."),
                _("Family Tree already exists, choose a unique name."))
            return
        old_text, new_text = self.rename_database(filename, new_text)
        if not (old_text is None):
            RecentFiles.rename_filename(old_text, new_text)
            self.model.set_value(node, NAME_COL, new_text)

    def __rcs(self, obj):
        """
        Callback for the RCS button. If the tree path is > 1, then we are
        on an RCS revision, in which case we can check out. If not, then
        we can only check in.
        """
        store, node = self.selection.get_selected()
        tree_path = store.get_path(node)
        if len(tree_path) > 1:
            parent_node = store.get_iter((tree_path[0], ))
            parent_name = store.get_value(parent_node, NAME_COL)
            name = store.get_value(node, NAME_COL)
            revision = store.get_value(node, PATH_COL)
            db_path = store.get_value(node, FILE_COL)

            self.__checkout_copy(parent_name, name, revision, db_path)
        else:
            base_path = self.dbstate.db.get_save_path()
            archive = os.path.join(base_path, ARCHIVE)
            check_in(self.dbstate.db, archive, None, self.__start_cursor)
            self.__end_cursor()

        self.__populate()

    def __checkout_copy(self, parent_name, name, revision, db_path):
        """
        Create a new database, then extracts a revision from RCS and
        imports it into the db
        """
        new_path, newname = self._create_new_db("%s : %s" %
                                                (parent_name, name))

        self.__start_cursor(_("Extracting archive..."))
        dbclass = DbBsddb
        dbase = dbclass()
        dbase.load(new_path, None)

        self.__start_cursor(_("Importing archive..."))
        check_out(dbase, revision, db_path, None)
        self.__end_cursor()
        dbase.close()

    def __remove_db(self, obj):
        """
        Callback associated with the Remove button. Get the selected
        row and data, then call the verification dialog.
        """
        store, node = self.selection.get_selected()
        path = store.get_path(node)
        self.data_to_delete = store[path]

        if len(path) == 1:
            QuestionDialog(
                _("Remove the '%s' family tree?") % self.data_to_delete[0],
                _("Removing this family tree will permanently destroy the data."
                  ), _("Remove family tree"), self.__really_delete_db)
        else:
            rev = self.data_to_delete[0]
            parent = store[(path[0], )][0]
            QuestionDialog(
                _("Remove the '%(revision)s' version of '%(database)s'") % {
                    'revision': rev,
                    'database': parent
                },
                _("Removing this version will prevent you from "
                  "extracting it in the future."), _("Remove version"),
                self.__really_delete_version)

    def __really_delete_db(self):
        """
        Delete the selected database. If the database is open, close it first.
        Then scan the database directory, deleting the files, and finally
        removing the directory.
        """

        # close the database if the user has requested to delete the
        # active database
        if self.data_to_delete[PATH_COL] == self.active:
            self.dbstate.no_database()

        store, node = self.selection.get_selected()
        path = store.get_path(node)
        node = self.model.get_iter(path)
        filename = self.model.get_value(node, FILE_COL)
        try:
            name_file = open(filename, "r")
            file_name_to_delete = name_file.read()
            name_file.close()
            RecentFiles.remove_filename(file_name_to_delete)
            for (top, dirs, files) in os.walk(self.data_to_delete[1]):
                for filename in files:
                    os.unlink(os.path.join(top, filename))
            os.rmdir(self.data_to_delete[1])
        except (IOError, OSError), msg:
            DbManager.ERROR(_("Could not delete family tree"), str(msg))
        # rebuild the display
        self.__populate()
Esempio n. 26
0
class BookListDisplay(object):
    """
    Interface into a dialog with the list of available books. 

    Allows the user to select and/or delete a book from the list.
    """
    def __init__(self, booklist, nodelete=0, dosave=0):
        """
        Create a BookListDisplay object that displays the books in BookList.

        booklist:   books that are displayed
        nodelete:   if not 0 then the Delete button is hidden
        dosave:     if 1 then the book list is saved on hitting OK
        """

        self.booklist = booklist
        self.dosave = dosave
        self.xml = Glade()
        self.top = self.xml.toplevel
        self.unsaved_changes = False

        ManagedWindow.set_titles(self.top, self.xml.get_object('title'),
                                 _('Available Books'))

        if nodelete:
            delete_button = self.xml.get_object("delete_button")
            delete_button.hide()
        self.xml.connect_signals({
            "on_booklist_cancel_clicked": self.on_booklist_cancel_clicked,
            "on_booklist_ok_clicked": self.on_booklist_ok_clicked,
            "on_booklist_delete_clicked": self.on_booklist_delete_clicked,
            "on_book_ok_clicked": self.do_nothing,
            "destroy_passed_object": self.do_nothing,
            "on_setup_clicked": self.do_nothing,
            "on_down_clicked": self.do_nothing,
            "on_up_clicked": self.do_nothing,
            "on_remove_clicked": self.do_nothing,
            "on_add_clicked": self.do_nothing,
            "on_edit_clicked": self.do_nothing,
            "on_open_clicked": self.do_nothing,
            "on_save_clicked": self.do_nothing,
            "on_clear_clicked": self.do_nothing
        })

        title_label = self.xml.get_object('title')
        title_label.set_text(Utils.title(_('Book List')))
        title_label.set_use_markup(True)

        self.blist = ListModel.ListModel(
            self.xml.get_object("list"),
            [('Name', -1, 10)],
        )
        self.redraw()
        self.selection = None
        self.top.run()

    def redraw(self):
        """Redraws the list of currently available books"""

        self.blist.model.clear()
        names = self.booklist.get_book_names()
        if not len(names):
            return
        for name in names:
            the_iter = self.blist.add([name])
        if the_iter:
            self.blist.selection.select_iter(the_iter)

    def on_booklist_ok_clicked(self, obj):
        """Return selected book. Saves the current list into xml file."""
        store, the_iter = self.blist.get_selected()
        if the_iter:
            data = self.blist.get_data(the_iter, [0])
            self.selection = self.booklist.get_book(unicode(data[0]))
        if self.dosave:
            self.booklist.save()

    def on_booklist_delete_clicked(self, obj):
        """
        Deletes selected book from the list.
        
        This change is not final. OK button has to be clicked to save the list.
        """
        store, the_iter = self.blist.get_selected()
        if not the_iter:
            return
        data = self.blist.get_data(the_iter, [0])
        self.booklist.delete_book(unicode(data[0]))
        self.blist.remove(the_iter)
        self.unsaved_changes = True
        self.top.run()

    def on_booklist_cancel_clicked(self, obj):
        if self.unsaved_changes:
            from QuestionDialog import QuestionDialog2
            q = QuestionDialog2(
                _('Discard Unsaved Changes'),
                _('You have made changes which have not been saved.'),
                _('Proceed'), _('Cancel'))
            if q.run():
                return
            else:
                self.top.run()

    def do_nothing(self, object):
        pass
Esempio n. 27
0
class EditFamily(EditPrimary):

    QR_CATEGORY = CATEGORY_QR_FAMILY

    def __init__(self, dbstate, uistate, track, family, callback=None):

        EditPrimary.__init__(self, dbstate, uistate, track, family,
                             dbstate.db.get_family_from_handle,
                             dbstate.db.get_family_from_gramps_id, callback)

        # look for the scenerio of a child and no parents on a new
        # family

        if (self.added and not self.obj.get_father_handle()
                and not self.obj.get_mother_handle()
                and len(self.obj.get_child_ref_list()) == 1):

            self.add_parent = True
            if not config.get('preferences.family-warn'):
                for i in self.hidden:
                    i.set_sensitive(False)

                MessageHideDialog(
                    _("Adding parents to a person"),
                    _("It is possible to accidentally create multiple "
                      "families with the same parents. To help avoid "
                      "this problem, only the buttons to select parents "
                      "are available when you create a new family. The "
                      "remaining fields will become available after you "
                      "attempt to select a parent."),
                    'preferences.family-warn')
        else:
            self.add_parent = False

    def _cleanup_on_exit(self):
        """Unset all things that can block garbage collection.
        Finalize rest
        """
        #FIXME, we rebind show_all below, this prevents garbage collection of
        #  the dialog, fix the rebind
        self.window.show_all = None
        EditPrimary._cleanup_on_exit(self)

    def empty_object(self):
        return gen.lib.Family()

    def _local_init(self):
        self.build_interface()

        self.added = self.obj.handle is None
        if self.added:
            self.obj.handle = Utils.create_id()

        self.load_data()

    def _connect_db_signals(self):
        """
        implement from base class DbGUIElement
        Register the callbacks we need.
        Note:
            * we do not connect to person-delete, as a delete of a person in
                the family outside of this editor will cause a family-update
                signal of this family
        """
        self.callman.register_handles({'family': [self.obj.get_handle()]})
        self.callman.register_callbacks({
            'family-update': self.check_for_family_change,
            'family-delete': self.check_for_close,
            'family-rebuild': self._do_close,
            'event-update': self.topdata_updated,  # change eg birth event fath
            'event-rebuild': self.topdata_updated,
            'event-delete': self.topdata_updated,  # delete eg birth event fath
            'person-update': self.topdata_updated,  # change eg name of father
            'person-rebuild': self._do_close,
        })
        self.callman.connect_all(keys=['family', 'event', 'person'])

    def check_for_family_change(self, handles):
        """
        Callback for family-update signal
        1. This method checks to see if the family shown has been changed. This 
            is possible eg in the relationship view. If the family was changed, 
            the view is refreshed and a warning dialog shown to indicate all 
            changes have been lost.
            If a source/note/event is deleted, this method is called too. This
            is unfortunate as the displaytabs can track themself a delete and
            correct the view for this. Therefore, these tabs are not rebuild.
            Conclusion: this method updates so that remove/change of parent or
            remove/change of children in relationship view reloads the family
            from db.
        2. Changes in other families are of no consequence to the family shown
        """
        if self.obj.get_handle() in handles:
            #rebuild data
            ## Todo: Gallery and note tab are not rebuild ??
            objreal = self.dbstate.db.get_family_from_handle(
                self.obj.get_handle())
            #update selection of data that we obtain from database change:
            maindatachanged = (
                self.obj.gramps_id != objreal.gramps_id
                or self.obj.father_handle != objreal.father_handle
                or self.obj.mother_handle != objreal.mother_handle
                or self.obj.private != objreal.private
                or self.obj.type != objreal.type
                or self.obj.get_tag_list() != objreal.get_tag_list()
                or self.obj.child_ref_list != objreal.child_ref_list)
            if maindatachanged:
                self.obj.gramps_id = objreal.gramps_id
                self.obj.father_handle = objreal.father_handle
                self.obj.mother_handle = objreal.mother_handle
                self.obj.private = objreal.private
                self.obj.type = objreal.type
                self.obj.set_tag_list(objreal.get_tag_list())
                self.obj.child_ref_list = objreal.child_ref_list
                self.reload_people()

            # No matter why the family changed (eg delete of a source), we notify
            # the user
            WarningDialog(
                _("Family has changed"),
                _("The %(object)s you are editing has changed outside this editor."
                  " This can be due to a change in one of the main views, for "
                  "example a source used here is deleted in the source view.\n"
                  "To make sure the information shown is still correct, the "
                  "data shown has been updated. Some edits you have made may have"
                  " been lost.") % {'object': _('family')},
                parent=self.window)

    def topdata_updated(self, *obj):
        """
        Callback method called if data shown in top part of family editor 
        (a parent, birth/death event of parent) changes
        Note: person events shown in the event list are not tracked, the 
              tabpage itself tracks it
        """
        self.load_data()

    def show_buttons(self):
        """
        Used to reshow hidden/showing buttons.
        """
        fhandle = self.obj.get_father_handle()
        self.update_father(fhandle)
        mhandle = self.obj.get_mother_handle()
        self.update_mother(mhandle)

    def reload_people(self):
        fhandle = self.obj.get_father_handle()
        self.update_father(fhandle)

        mhandle = self.obj.get_mother_handle()
        self.update_mother(mhandle)
        self.child_tab.rebuild()

    def get_menu_title(self):
        if self.obj and self.obj.get_handle():
            dialog_title = Utils.family_name(self.obj, self.db,
                                             _("New Family"))
            dialog_title = _("Family") + ': ' + dialog_title
        else:
            dialog_title = _("New Family")
        return dialog_title

    def build_menu_names(self, family):
        return (_('Edit Family'), self.get_menu_title())

    def build_interface(self):
        self.width_key = 'interface.family-width'
        self.height_key = 'interface.family-height'

        self.top = Glade()
        self.set_window(self.top.toplevel, None, self.get_menu_title())

        # HACK: how to prevent hidden items from showing
        #       when you use show_all?
        # Consider using show() rather than show_all()?
        # FIXME: remove if we can use show()
        self.window.show_all = self.window.show

        self.fbirth = self.top.get_object('fbirth')
        self.fdeath = self.top.get_object('fdeath')
        self.fbirth_label = self.top.get_object('label578')
        self.fdeath_label = self.top.get_object('label579')

        self.mbirth = self.top.get_object('mbirth')
        self.mdeath = self.top.get_object('mdeath')
        self.mbirth_label = self.top.get_object('label567')
        self.mdeath_label = self.top.get_object('label568')

        self.mname = self.top.get_object('mname')
        self.fname = self.top.get_object('fname')

        self.mbutton_index = self.top.get_object('mbutton_index')
        self.mbutton_add = self.top.get_object('mbutton_add')
        self.mbutton_del = self.top.get_object('mbutton_del')
        self.mbutton_edit = self.top.get_object('mbutton_edit')

        self.mbutton_index.set_tooltip_text(_("Select a person as the mother"))
        self.mbutton_add.set_tooltip_text(_("Add a new person as the mother"))
        self.mbutton_del.set_tooltip_text(_("Remove the person as the mother"))

        self.mbutton_edit.connect('button-press-event', self.edit_mother)
        self.mbutton_edit.connect('key-press-event', self.edit_mother)
        self.mbutton_index.connect('clicked', self.sel_mother_clicked)
        self.mbutton_del.connect('clicked', self.del_mother_clicked)
        self.mbutton_add.connect('clicked', self.add_mother_clicked)

        self.fbutton_index = self.top.get_object('fbutton_index')
        self.fbutton_add = self.top.get_object('fbutton_add')
        self.fbutton_del = self.top.get_object('fbutton_del')
        self.fbutton_edit = self.top.get_object('fbutton_edit')

        self.fbutton_index.set_tooltip_text(_("Select a person as the father"))
        self.fbutton_add.set_tooltip_text(_("Add a new person as the father"))
        self.fbutton_del.set_tooltip_text(_("Remove the person as the father"))

        self.fbutton_edit.connect('button-press-event', self.edit_father)
        self.fbutton_edit.connect('key-press-event', self.edit_father)
        self.fbutton_index.connect('clicked', self.sel_father_clicked)
        self.fbutton_del.connect('clicked', self.del_father_clicked)
        self.fbutton_add.connect('clicked', self.add_father_clicked)

        #allow for a context menu
        self.set_contexteventbox(self.top.get_object("eventboxtop"))

        #allow for drop:
        ftable = self.top.get_object('ftable')
        ftable.drag_dest_set(gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_DROP,
                             [DdTargets.PERSON_LINK.target()],
                             gtk.gdk.ACTION_COPY)
        ftable.connect('drag_data_received', self.on_drag_fatherdata_received)
        mtable = self.top.get_object('mtable')
        mtable.drag_dest_set(gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_DROP,
                             [DdTargets.PERSON_LINK.target()],
                             gtk.gdk.ACTION_COPY)
        mtable.connect('drag_data_received', self.on_drag_motherdata_received)

    def _connect_signals(self):
        self.define_ok_button(self.top.get_object('ok'), self.save)
        self.define_cancel_button(self.top.get_object('cancel'))
        self.define_help_button(self.top.get_object('button119'))

    def _can_be_replaced(self):
        pass

    def _setup_fields(self):

        self.private = PrivacyButton(self.top.get_object('private'), self.obj,
                                     self.db.readonly)

        self.gid = MonitoredEntry(self.top.get_object('gid'),
                                  self.obj.set_gramps_id,
                                  self.obj.get_gramps_id, self.db.readonly)

        self.tags = MonitoredTagList(self.top.get_object("tag_label"),
                                     self.top.get_object("tag_button"),
                                     self.obj.set_tag_list,
                                     self.obj.get_tag_list, self.db,
                                     self.uistate, self.track,
                                     self.db.readonly)

        self.data_type = MonitoredDataType(
            self.top.get_object('marriage_type'),
            self.obj.set_relationship,
            self.obj.get_relationship,
            self.db.readonly,
            self.db.get_family_relation_types(),
        )

    def load_data(self):
        """
        Show top data of family editor: father and mother info
        and set self.phandles with all person handles in the family
        """
        fhandle = self.obj.get_father_handle()
        self.update_father(fhandle)

        mhandle = self.obj.get_mother_handle()
        self.update_mother(mhandle)

        self.phandles = [mhandle, fhandle]
        self.phandles.extend(x.ref for x in self.obj.get_child_ref_list())

        self.phandles = filter(None, self.phandles)

    def _create_tabbed_pages(self):

        notebook = gtk.Notebook()

        self.child_list = ChildEmbedList(self.dbstate, self.uistate,
                                         self.track, self.obj)
        self.child_tab = self._add_tab(notebook, self.child_list)
        self.track_ref_for_deletion("child_list")
        self.track_ref_for_deletion("child_tab")

        self.event_list = EventEmbedList(self.dbstate, self.uistate,
                                         self.track, self.obj)
        self._add_tab(notebook, self.event_list)
        self.track_ref_for_deletion("event_list")

        self.citation_list = CitationEmbedList(self.dbstate, self.uistate,
                                               self.track,
                                               self.obj.get_citation_list(),
                                               self.get_menu_title())
        self._add_tab(notebook, self.citation_list)
        self.track_ref_for_deletion("citation_list")

        self.attr_list = FamilyAttrEmbedList(self.dbstate, self.uistate,
                                             self.track,
                                             self.obj.get_attribute_list())
        self._add_tab(notebook, self.attr_list)
        self.track_ref_for_deletion("attr_list")

        self.note_tab = NoteTab(self.dbstate,
                                self.uistate,
                                self.track,
                                self.obj.get_note_list(),
                                self.get_menu_title(),
                                notetype=gen.lib.NoteType.FAMILY)
        self._add_tab(notebook, self.note_tab)
        self.track_ref_for_deletion("note_tab")

        self.gallery_tab = GalleryTab(self.dbstate, self.uistate, self.track,
                                      self.obj.get_media_list())
        self._add_tab(notebook, self.gallery_tab)
        self.track_ref_for_deletion("gallery_tab")

        self.lds_embed = FamilyLdsEmbedList(self.dbstate, self.uistate,
                                            self.track,
                                            self.obj.get_lds_ord_list())
        self._add_tab(notebook, self.lds_embed)
        self.track_ref_for_deletion("lds_embed")

        self._setup_notebook_tabs(notebook)
        notebook.show_all()

        self.hidden = (notebook, self.top.get_object('info'))
        self.top.get_object('vbox').pack_start(notebook, True)

    def update_father(self, handle):
        self.load_parent(handle, self.fname, self.fbirth, self.fbirth_label,
                         self.fdeath, self.fdeath_label, self.fbutton_index,
                         self.fbutton_add, self.fbutton_del, self.fbutton_edit)

    def update_mother(self, handle):
        self.load_parent(handle, self.mname, self.mbirth, self.mbirth_label,
                         self.mdeath, self.mdeath_label, self.mbutton_index,
                         self.mbutton_add, self.mbutton_del, self.mbutton_edit)

    def add_mother_clicked(self, obj):
        person = gen.lib.Person()
        person.set_gender(gen.lib.Person.FEMALE)
        autoname = config.get('behavior.surname-guessing')
        #_("Father's surname"),
        #_("None"),
        #_("Combination of mother's and father's surname"),
        #_("Icelandic style"),
        if autoname == 2:
            name = self.latin_american_child("mother")
        else:
            name = self.no_name()
        person.set_primary_name(name)
        EditPerson(self.dbstate, self.uistate, self.track, person,
                   self.new_mother_added)

    def add_father_clicked(self, obj):
        person = gen.lib.Person()
        person.set_gender(gen.lib.Person.MALE)
        autoname = config.get('behavior.surname-guessing')
        #_("Father's surname"),
        #_("None"),
        #_("Combination of mother's and father's surname"),
        #_("Icelandic style"),
        if autoname == 0:
            name = self.north_american_child()
        elif autoname == 2:
            name = self.latin_american_child("father")
        else:
            name = self.no_name()
        person.set_primary_name(name)
        EditPerson(self.dbstate, self.uistate, self.track, person,
                   self.new_father_added)

    def new_mother_added(self, person):
        for i in self.hidden:
            i.set_sensitive(True)
        self.obj.set_mother_handle(person.handle)
        self.update_mother(person.handle)

    def new_father_added(self, person):
        for i in self.hidden:
            i.set_sensitive(True)
        self.obj.set_father_handle(person.handle)
        self.update_father(person.handle)

    def del_mother_clicked(self, obj):
        for i in self.hidden:
            i.set_sensitive(True)

        self.obj.set_mother_handle(None)
        self.update_mother(None)

    def sel_mother_clicked(self, obj):
        for i in self.hidden:
            i.set_sensitive(True)

        data_filter = FastFemaleFilter(self.dbstate.db)
        sel = SelectPerson(self.dbstate,
                           self.uistate,
                           self.track,
                           _("Select Mother"),
                           filter=data_filter,
                           skip=[x.ref for x in self.obj.get_child_ref_list()])
        person = sel.run()

        if person:
            self.check_for_existing_family(self.obj.get_father_handle(),
                                           person.handle, self.obj.handle)
            self.obj.set_mother_handle(person.handle)
            self.update_mother(person.handle)

    def on_change_father(self, selector_window, obj):
        if obj.__class__ == gen.lib.Person:
            try:
                person = obj
                self.obj.set_father_handle(person.get_handle())
                self.update_father(person.get_handle())
            except:
                log.warn("Failed to update father: \n"
                         "obj returned from selector was: %s\n" %
                         (repr(obj), ))
                raise

        else:
            log.warn("Object selector returned obj.__class__ = %s, it should "
                     "have been of type %s." %
                     (obj.__class__.__name__, gen.lib.Person.__name__))

        selector_window.close()

    def del_father_clicked(self, obj):
        for i in self.hidden:
            i.set_sensitive(True)

        self.obj.set_father_handle(None)
        self.update_father(None)

    def sel_father_clicked(self, obj):
        for i in self.hidden:
            i.set_sensitive(True)

        data_filter = FastMaleFilter(self.dbstate.db)
        sel = SelectPerson(self.dbstate,
                           self.uistate,
                           self.track,
                           _("Select Father"),
                           filter=data_filter,
                           skip=[x.ref for x in self.obj.get_child_ref_list()])
        person = sel.run()
        if person:
            self.check_for_existing_family(person.handle,
                                           self.obj.get_mother_handle(),
                                           self.obj.handle)
            self.obj.set_father_handle(person.handle)
            self.update_father(person.handle)

    def check_for_existing_family(self, father_handle, mother_handle,
                                  family_handle):

        if father_handle:
            father = self.dbstate.db.get_person_from_handle(father_handle)
            ffam = set(father.get_family_handle_list())
            if mother_handle:
                mother = self.dbstate.db.get_person_from_handle(mother_handle)
                mfam = set(mother.get_family_handle_list())
                common = list(mfam.intersection(ffam))
                if len(common) > 0:
                    if self.add_parent or self.obj.handle not in common:
                        WarningDialog(
                            _('Duplicate Family'),
                            _('A family with these parents already exists '
                              'in the database. If you save, you will create '
                              'a duplicate family. It is recommended that '
                              'you cancel the editing of this window, and '
                              'select the existing family'),
                            parent=self.window)

    def edit_father(self, obj, event):
        handle = self.obj.get_father_handle()
        return self.edit_person(obj, event, handle)

    def edit_mother(self, obj, event):
        handle = self.obj.get_mother_handle()
        return self.edit_person(obj, event, handle)

    def edit_person(self, obj, event, handle):
        if button_activated(event, _LEFT_BUTTON):
            try:
                person = self.db.get_person_from_handle(handle)
                EditPerson(self.dbstate, self.uistate, self.track, person)
            except Errors.WindowActiveError:
                pass

    def load_parent(self, handle, name_obj, birth_obj, birth_label, death_obj,
                    death_label, btn_index, btn_add, btn_del, btn_edit):
        # is a parent used here:
        is_used = handle is not None

        # now we display the area:
        if is_used:
            db = self.db
            person = db.get_person_from_handle(handle)
            name = "%s [%s]" % (name_displayer.display(person),
                                person.gramps_id)
            birth = get_birth_or_fallback(db, person)
            self.callman.register_handles({'person': [handle]})
            if birth:
                #if event changes it view needs to update
                self.callman.register_handles({'event': [birth.get_handle()]})
                birth_label.set_label("%s:" % birth.get_type())

            death = get_death_or_fallback(db, person)
            if death:
                #if event changes it view needs to update
                self.callman.register_handles({'event': [death.get_handle()]})
                death_label.set_label("%s:" % death.get_type())

            btn_edit.set_tooltip_text(_('Edit %s') % name)
            btn_index.hide()
            btn_add.hide()
            btn_del.show()
            btn_edit.show()
        else:
            name = ""
            birth = None
            death = None

            btn_index.show()
            btn_add.show()
            btn_del.hide()
            btn_edit.hide()

        if name_obj:
            name_obj.set_text(name)
        if birth:
            birth_str = DateHandler.displayer.display(birth.get_date_object())
        else:
            birth_str = ""
        birth_obj.set_text(birth_str)
        if death:
            death_str = DateHandler.displayer.display(death.get_date_object())
        else:
            death_str = ""
        death_obj.set_text(death_str)

    def fix_parent_handles(self, orig_handle, new_handle, trans):
        if orig_handle != new_handle:
            if orig_handle:
                person = self.db.get_person_from_handle(orig_handle)
                person.family_list.remove(self.obj.handle)
                self.db.commit_person(person, trans)
            if new_handle:
                person = self.db.get_person_from_handle(new_handle)
                person.family_list.append(self.obj.handle)
                self.db.commit_person(person, trans)

    def on_drag_fatherdata_received(self, widget, context, x, y, sel_data,
                                    info, time):
        """
        Handle the standard gtk interface for drag_data_received.
        """
        if self.obj.get_father_handle():
            return
        for i in self.hidden:
            i.set_sensitive(True)
        if sel_data and sel_data.data:
            (drag_type, idval, handle, val) = pickle.loads(sel_data.data)
            person = self.db.get_person_from_handle(handle)

            if person:
                self.check_for_existing_family(person.handle,
                                               self.obj.get_mother_handle(),
                                               self.obj.handle)
                self.obj.set_father_handle(person.handle)
                self.update_father(person.handle)

    def on_drag_motherdata_received(self, widget, context, x, y, sel_data,
                                    info, time):
        """
        Handle the standard gtk interface for drag_data_received.
        """
        if self.obj.get_mother_handle():
            return
        for i in self.hidden:
            i.set_sensitive(True)
        if sel_data and sel_data.data:
            (drag_type, idval, handle, val) = pickle.loads(sel_data.data)
            person = self.db.get_person_from_handle(handle)

            if person:
                self.check_for_existing_family(self.obj.get_father_handle(),
                                               person.handle, self.obj.handle)
                self.obj.set_mother_handle(person.handle)
                self.update_mother(person.handle)

    def object_is_empty(self):
        return (not self.obj.get_father_handle()
                and not self.obj.get_mother_handle()
                and len(self.obj.get_child_ref_list()) == 0)

    def save(self, *obj):
        try:
            self.__do_save()
        except bsddb_db.DBRunRecoveryError, msg:
            RunDatabaseRepair(msg[1])
Esempio n. 28
0
class BookReportSelector(ManagedWindow.ManagedWindow):
    """
    Interface into a dialog setting up the book. 

    Allows the user to add/remove/reorder/setup items for the current book
    and to clear/load/save/edit whole books.
    """
    def __init__(self, dbstate, uistate):
        self.db = dbstate.db
        self.dbstate = dbstate
        self.uistate = uistate
        self.title = _('Book Report')
        self.file = "books.xml"

        ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__)

        self.xml = Glade(toplevel="top")
        window = self.xml.toplevel

        title_label = self.xml.get_object('title')
        self.set_window(window, title_label, self.title)
        window.show()
        self.xml.connect_signals({
            "on_add_clicked": self.on_add_clicked,
            "on_remove_clicked": self.on_remove_clicked,
            "on_up_clicked": self.on_up_clicked,
            "on_down_clicked": self.on_down_clicked,
            "on_setup_clicked": self.on_setup_clicked,
            "on_clear_clicked": self.on_clear_clicked,
            "on_save_clicked": self.on_save_clicked,
            "on_open_clicked": self.on_open_clicked,
            "on_edit_clicked": self.on_edit_clicked,
            "on_book_ok_clicked": self.on_book_ok_clicked,
            "destroy_passed_object": self.close,

            # Insert dummy handlers for second top level in the glade file
            "on_booklist_ok_clicked": lambda _: None,
            "on_booklist_delete_clicked": lambda _: None,
            "on_booklist_cancel_clicked": lambda _: None,
            "on_booklist_ok_clicked": lambda _: None,
            "on_booklist_ok_clicked": lambda _: None,
        })

        self.avail_tree = self.xml.get_object("avail_tree")
        self.book_tree = self.xml.get_object("book_tree")
        self.avail_tree.connect('button-press-event', self.avail_button_press)
        self.book_tree.connect('button-press-event', self.book_button_press)

        self.name_entry = self.xml.get_object("name_entry")
        self.name_entry.set_text(_('New Book'))

        avail_label = self.xml.get_object('avail_label')
        avail_label.set_text("<b>%s</b>" % _("_Available items"))
        avail_label.set_use_markup(True)
        avail_label.set_use_underline(True)
        book_label = self.xml.get_object('book_label')
        book_label.set_text("<b>%s</b>" % _("Current _book"))
        book_label.set_use_underline(True)
        book_label.set_use_markup(True)

        avail_titles = [(_('Name'), 0, 230), (_('Type'), 1, 80), ('', -1, 0)]

        book_titles = [(_('Item name'), -1, 230), (_('Type'), -1, 80),
                       ('', -1, 0), (_('Subject'), -1, 50)]

        self.avail_nr_cols = len(avail_titles)
        self.book_nr_cols = len(book_titles)

        self.avail_model = ListModel.ListModel(self.avail_tree, avail_titles)
        self.book_model = ListModel.ListModel(self.book_tree, book_titles)
        self.draw_avail_list()

        self.book = Book()

    def build_menu_names(self, obj):
        return (_("Book selection list"), self.title)

    def draw_avail_list(self):
        """
        Draw the list with the selections available for the book.
        
        The selections are read from the book item registry.
        """
        pmgr = GuiPluginManager.get_instance()
        regbi = pmgr.get_reg_bookitems()
        if not regbi:
            return

        available_reports = []
        for pdata in regbi:
            category = _UNSUPPORTED
            if pdata.supported and pdata.category in book_categories:
                category = book_categories[pdata.category]
            available_reports.append([pdata.name, category, pdata.id])
        for data in sorted(available_reports):
            new_iter = self.avail_model.add(data)

        self.avail_model.connect_model()

        if new_iter:
            self.avail_model.selection.select_iter(new_iter)
            path = self.avail_model.model.get_path(new_iter)
            col = self.avail_tree.get_column(0)
            self.avail_tree.scroll_to_cell(path, col, 1, 1, 0.0)

    def open_book(self, book):
        """
        Open the book: set the current set of selections to this book's items.
        
        book:   the book object to load.
        """
        if book.get_dbname() == self.db.get_save_path():
            same_db = 1
        else:
            same_db = 0
            WarningDialog(
                _('Different database'),
                _('This book was created with the references to database '
                  '%s.\n\n This makes references to the central person '
                  'saved in the book invalid.\n\n'
                  'Therefore, the central person for each item is being set '
                  'to the active person of the currently opened database.') %
                book.get_dbname())

        self.book.clear()
        self.book_model.clear()
        for saved_item in book.get_item_list():
            name = saved_item.get_name()
            item = BookItem(self.db, name)
            item.option_class = saved_item.option_class

            # The option values were loaded magically by the book parser.
            # But they still need to be applied to the menu options.
            opt_dict = item.option_class.handler.options_dict
            menu = item.option_class.menu
            for optname in opt_dict:
                menu_option = menu.get_option_by_name(optname)
                if menu_option:
                    menu_option.set_value(opt_dict[optname])

            _initialize_options(item.option_class, self.dbstate, self.uistate)
            item.set_style_name(saved_item.get_style_name())
            self.book.append_item(item)

            data = [
                item.get_translated_name(),
                item.get_category(),
                item.get_name()
            ]

            data[2] = _get_subject(item.option_class, self.db)
            self.book_model.add(data)

    def on_add_clicked(self, obj):
        """
        Add an item to the current selections. 
        
        Use the selected available item to get the item's name in the registry.
        """
        store, the_iter = self.avail_model.get_selected()
        if not the_iter:
            return
        data = self.avail_model.get_data(the_iter, range(self.avail_nr_cols))
        item = BookItem(self.db, data[2])
        _initialize_options(item.option_class, self.dbstate, self.uistate)
        data[2] = _get_subject(item.option_class, self.db)
        self.book_model.add(data)
        self.book.append_item(item)

    def on_remove_clicked(self, obj):
        """
        Remove the item from the current list of selections.
        """
        store, the_iter = self.book_model.get_selected()
        if not the_iter:
            return
        row = self.book_model.get_selected_row()
        self.book.pop_item(row)
        self.book_model.remove(the_iter)

    def on_clear_clicked(self, obj):
        """
        Clear the whole current book.
        """
        self.book_model.clear()
        self.book.clear()

    def on_up_clicked(self, obj):
        """
        Move the currently selected item one row up in the selection list.
        """
        row = self.book_model.get_selected_row()
        if not row or row == -1:
            return
        store, the_iter = self.book_model.get_selected()
        data = self.book_model.get_data(the_iter, range(self.book_nr_cols))
        self.book_model.remove(the_iter)
        self.book_model.insert(row - 1, data, None, 1)
        item = self.book.pop_item(row)
        self.book.insert_item(row - 1, item)

    def on_down_clicked(self, obj):
        """
        Move the currently selected item one row down in the selection list.
        """
        row = self.book_model.get_selected_row()
        if row + 1 >= self.book_model.count or row == -1:
            return
        store, the_iter = self.book_model.get_selected()
        data = self.book_model.get_data(the_iter, range(self.book_nr_cols))
        self.book_model.remove(the_iter)
        self.book_model.insert(row + 1, data, None, 1)
        item = self.book.pop_item(row)
        self.book.insert_item(row + 1, item)

    def on_setup_clicked(self, obj):
        """
        Configure currently selected item.
        """
        store, the_iter = self.book_model.get_selected()
        if not the_iter:
            WarningDialog(_('No selected book item'),
                          _('Please select a book item to configure.'))
            return
        data = self.book_model.get_data(the_iter, range(self.book_nr_cols))
        row = self.book_model.get_selected_row()
        item = self.book.get_item(row)
        option_class = item.option_class
        option_class.handler.set_default_stylesheet_name(item.get_style_name())
        item.is_from_saved_book = bool(self.book.get_name())
        item_dialog = BookItemDialog(self.dbstate, self.uistate, item,
                                     self.track)

        while True:
            response = item_dialog.window.run()
            if response == gtk.RESPONSE_OK:
                # dialog will be closed by connect, now continue work while
                # rest of dialog is unresponsive, release when finished
                style = option_class.handler.get_default_stylesheet_name()
                item.set_style_name(style)
                subject = _get_subject(option_class, self.db)
                self.book_model.model.set_value(the_iter, 2, subject)
                self.book.set_item(row, item)
                item_dialog.close()
                break
            elif response == gtk.RESPONSE_CANCEL:
                item_dialog.close()
                break
            elif response == gtk.RESPONSE_DELETE_EVENT:
                #just stop, in ManagedWindow, delete-event is already coupled to
                #correct action.
                break

    def book_button_press(self, obj, event):
        """
        Double-click on the current book selection is the same as setup.
        Right click evokes the context menu. 
        """
        if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
            self.on_setup_clicked(obj)
        elif gui.utils.is_right_click(event):
            self.build_book_context_menu(event)

    def avail_button_press(self, obj, event):
        """
        Double-click on the available selection is the same as add.
        Right click evokes the context menu. 
        """
        if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
            self.on_add_clicked(obj)
        elif gui.utils.is_right_click(event):
            self.build_avail_context_menu(event)

    def build_book_context_menu(self, event):
        """Builds the menu with item-centered and book-centered options."""

        store, the_iter = self.book_model.get_selected()
        if the_iter:
            sensitivity = 1
        else:
            sensitivity = 0
        entries = [
            (gtk.STOCK_GO_UP, self.on_up_clicked, sensitivity),
            (gtk.STOCK_GO_DOWN, self.on_down_clicked, sensitivity),
            (_("Setup"), self.on_setup_clicked, sensitivity),
            (gtk.STOCK_REMOVE, self.on_remove_clicked, sensitivity),
            (None, None, 0),
            (gtk.STOCK_CLEAR, self.on_clear_clicked, 1),
            (gtk.STOCK_SAVE, self.on_save_clicked, 1),
            (gtk.STOCK_OPEN, self.on_open_clicked, 1),
            (_("Edit"), self.on_edit_clicked, 1),
        ]

        menu = gtk.Menu()
        menu.set_title(_('Book Menu'))
        for stock_id, callback, sensitivity in entries:
            item = gtk.ImageMenuItem(stock_id)
            if callback:
                item.connect("activate", callback)
            item.set_sensitive(sensitivity)
            item.show()
            menu.append(item)
        menu.popup(None, None, None, event.button, event.time)

    def build_avail_context_menu(self, event):
        """Builds the menu with the single Add option."""

        store, the_iter = self.avail_model.get_selected()
        if the_iter:
            sensitivity = 1
        else:
            sensitivity = 0
        entries = [
            (gtk.STOCK_ADD, self.on_add_clicked, sensitivity),
        ]

        menu = gtk.Menu()
        menu.set_title(_('Available Items Menu'))
        for stock_id, callback, sensitivity in entries:
            item = gtk.ImageMenuItem(stock_id)
            if callback:
                item.connect("activate", callback)
            item.set_sensitive(sensitivity)
            item.show()
            menu.append(item)
        menu.popup(None, None, None, event.button, event.time)

    def on_book_ok_clicked(self, obj):
        """
        Run final BookReportDialog with the current book. 
        """
        if self.book.item_list:
            BookReportDialog(self.dbstate, self.uistate, self.book,
                             BookOptions)
        else:
            WarningDialog(_('No items'), _('This book has no items.'))
            return
        self.close()

    def on_save_clicked(self, obj):
        """
        Save the current book in the xml booklist file. 
        """
        self.book_list = BookList(self.file, self.db)
        name = unicode(self.name_entry.get_text())
        if not name:
            WarningDialog(
                _('No book name'),
                _('You are about to save away a book with no name.\n\n'
                  'Please give it a name before saving it away.'))
            return
        if name in self.book_list.get_book_names():
            from QuestionDialog import QuestionDialog2
            q = QuestionDialog2(
                _('Book name already exists'),
                _('You are about to save away a '
                  'book with a name which already exists.'), _('Proceed'),
                _('Cancel'))
            if q.run():
                self.book.set_name(name)
            else:
                return
        else:
            self.book.set_name(name)
        self.book.set_dbname(self.db.get_save_path())
        self.book_list.set_book(name, self.book)
        self.book_list.save()

    def on_open_clicked(self, obj):
        """
        Run the BookListDisplay dialog to present the choice of books to open. 
        """
        self.book_list = BookList(self.file, self.db)
        booklistdisplay = BookListDisplay(self.book_list, 1, 0)
        booklistdisplay.top.destroy()
        book = booklistdisplay.selection
        if book:
            self.open_book(book)
            self.name_entry.set_text(book.get_name())
            self.book.set_name(book.get_name())

    def on_edit_clicked(self, obj):
        """
        Run the BookListDisplay dialog to present the choice of books to delete. 
        """
        self.book_list = BookList(self.file, self.db)
        booklistdisplay = BookListDisplay(self.book_list, 0, 1)
        booklistdisplay.top.destroy()
Esempio n. 29
0
class EditPlace(EditPrimary):

    def __init__(self, dbstate, uistate, track, place, callback=None):
        EditPrimary.__init__(self, dbstate, uistate, track, place,
                             dbstate.db.get_place_from_handle, 
                             dbstate.db.get_place_from_gramps_id, callback)

    def empty_object(self):
        return gen.lib.Place()

    def _local_init(self):
        self.width_key = 'interface.place-width'
        self.height_key = 'interface.place-height'
        
        self.top = Glade()

        self.set_window(self.top.toplevel, None,
                        self.get_menu_title())
        tblmloc =  self.top.get_object('table19')
        notebook = self.top.get_object('notebook3')
        #recreate start page as GrampsTab
        notebook.remove_page(0)
        self.mloc = MainLocTab(self.dbstate, self.uistate, self.track, 
                              _('_Location'), tblmloc)
        self.track_ref_for_deletion("mloc")


    def get_menu_title(self):
        if self.obj and self.obj.get_handle():
            title = self.obj.get_title()
            dialog_title = _('Place: %s')  % title
        else:
            dialog_title = _('New Place')
        return dialog_title

    def _connect_signals(self):
        self.define_ok_button(self.top.get_object('ok'), self.save)
        self.define_cancel_button(self.top.get_object('cancel'))
        self.define_help_button(self.top.get_object('help'))

    def _connect_db_signals(self):
        """
        Connect any signals that need to be connected. 
        Called by the init routine of the base class (_EditPrimary).
        """
        self._add_db_signal('place-rebuild', self._do_close)
        self._add_db_signal('place-delete', self.check_for_close)

    def _setup_fields(self):
        mloc = self.obj.get_main_location()
        
        self.title = MonitoredEntry(self.top.get_object("place_title"),
                                    self.obj.set_title, self.obj.get_title,
                                    self.db.readonly)
        
        self.street = MonitoredEntry(self.top.get_object("street"),
                                     mloc.set_street, mloc.get_street, 
                                     self.db.readonly)

        self.locality = MonitoredEntry(self.top.get_object("locality"),
                                     mloc.set_locality, mloc.get_locality, 
                                     self.db.readonly)

        self.city = MonitoredEntry(self.top.get_object("city"),
                                   mloc.set_city, mloc.get_city, 
                                   self.db.readonly)
        
        self.gid = MonitoredEntry(self.top.get_object("gid"),
                                  self.obj.set_gramps_id, 
                                  self.obj.get_gramps_id, self.db.readonly)
        
        self.privacy = PrivacyButton(self.top.get_object("private"), self.obj, 
                                     self.db.readonly)

        self.parish = MonitoredEntry(self.top.get_object("parish"),
                                     mloc.set_parish, mloc.get_parish, 
                                     self.db.readonly)
        
        self.county = MonitoredEntry(self.top.get_object("county"),
                                     mloc.set_county, mloc.get_county, 
                                     self.db.readonly)
        
        self.state = MonitoredEntry(self.top.get_object("state"),
                                    mloc.set_state, mloc.get_state, 
                                    self.db.readonly)

        self.phone = MonitoredEntry(self.top.get_object("phone"),
                                    mloc.set_phone, mloc.get_phone, 
                                    self.db.readonly)
        
        self.postal = MonitoredEntry(self.top.get_object("postal"),
                                     mloc.set_postal_code, 
                                     mloc.get_postal_code, self.db.readonly)

        self.country = MonitoredEntry(self.top.get_object("country"),
                                      mloc.set_country, mloc.get_country, 
                                      self.db.readonly)

        self.longitude = MonitoredEntry(
            self.top.get_object("lon_entry"),
            self.obj.set_longitude, self.obj.get_longitude,
            self.db.readonly)
        self.longitude.connect("validate", self._validate_coordinate, "lon")
        #force validation now with initial entry
        self.top.get_object("lon_entry").validate(force=True)

        self.latitude = MonitoredEntry(
            self.top.get_object("lat_entry"),
            self.obj.set_latitude, self.obj.get_latitude,
            self.db.readonly)
        self.latitude.connect("validate", self._validate_coordinate, "lat")
        #force validation now with initial entry
        self.top.get_object("lat_entry").validate(force=True)
        
    def _validate_coordinate(self, widget, text, typedeg):
        if (typedeg == 'lat') and not conv_lat_lon(text, "0", "ISO-D"):
            return ValidationError(_(u"Invalid latitude (syntax: 18\u00b09'") +
                                   _('48.21"S, -18.2412 or -18:9:48.21)'))
        elif (typedeg == 'lon') and not conv_lat_lon("0", text, "ISO-D"):
            return ValidationError(_(u"Invalid longitude (syntax: 18\u00b09'") +
                                   _('48.21"E, -18.2412 or -18:9:48.21)'))

    def build_menu_names(self, place):
        return (_('Edit Place'), self.get_menu_title())

    def _create_tabbed_pages(self):
        """
        Create the notebook tabs and inserts them into the main
        window.
        
        """
        notebook = self.top.get_object('notebook3')

        self._add_tab(notebook, self.mloc)

        self.loc_list = LocationEmbedList(self.dbstate,
                                          self.uistate,
                                          self.track,
                                          self.obj.alt_loc)
        self._add_tab(notebook, self.loc_list)
        self.track_ref_for_deletion("loc_list")
        
        self.citation_list = CitationEmbedList(self.dbstate,
                                               self.uistate,
                                               self.track,
                                               self.obj.get_citation_list(),
                                               self.get_menu_title())
        self._add_tab(notebook, self.citation_list)
        self.track_ref_for_deletion("citation_list")
        
        self.note_tab = NoteTab(self.dbstate,
                                self.uistate,
                                self.track,
                                self.obj.get_note_list(),
                                self.get_menu_title(),
                                notetype=gen.lib.NoteType.PLACE)
        self._add_tab(notebook, self.note_tab)
        self.track_ref_for_deletion("note_tab")
        
        self.gallery_tab = GalleryTab(self.dbstate,
                                      self.uistate,
                                      self.track,
                                      self.obj.get_media_list())
        self._add_tab(notebook, self.gallery_tab)
        self.track_ref_for_deletion("gallery_tab")
       
        self.web_list = WebEmbedList(self.dbstate,
                                     self.uistate,
                                     self.track,
                                     self.obj.get_url_list())
        self._add_tab(notebook, self.web_list)
        self.track_ref_for_deletion("web_list")

        self.backref_list = PlaceBackRefList(self.dbstate,
                                             self.uistate,
                                             self.track,
                             self.db.find_backlink_handles(self.obj.handle))
        self.backref_tab = self._add_tab(notebook, self.backref_list)
        self.track_ref_for_deletion("backref_list")
        self.track_ref_for_deletion("backref_tab")

        self._setup_notebook_tabs(notebook)

    def save(self, *obj):
        self.ok_button.set_sensitive(False)
        if self.object_is_empty():
            ErrorDialog(_("Cannot save place"),
                        _("No data exists for this place. Please "
                          "enter data or cancel the edit."))
            self.ok_button.set_sensitive(True)
            return

        (uses_dupe_id, id) = self._uses_duplicate_id()
        if uses_dupe_id:
            prim_object = self.get_from_gramps_id(id)
            name = prim_object.get_title()
            msg1 = _("Cannot save place. ID already exists.")
            msg2 = _("You have attempted to use the existing Gramps ID with "
                         "value %(id)s. This value is already used by '" 
                         "%(prim_object)s'. Please enter a different ID or leave "
                         "blank to get the next available ID value.") % {
                         'id' : id, 'prim_object' : name }
            ErrorDialog(msg1, msg2)
            self.ok_button.set_sensitive(True)
            return

        with DbTxn('', self.db) as trans:
            if not self.obj.get_handle():
                self.db.add_place(self.obj, trans)
                msg = _("Add Place (%s)") % self.obj.get_title()
            else:
                if not self.obj.get_gramps_id():
                    self.obj.set_gramps_id(self.db.find_next_place_gramps_id())
                self.db.commit_place(self.obj, trans)
                msg = _("Edit Place (%s)") % self.obj.get_title()
            trans.set_description(msg)
        
        self.close()
        if self.callback:
            self.callback(self.obj)
Esempio n. 30
0
class ChangeNames(tool.BatchTool, ManagedWindow.ManagedWindow):
    def __init__(self, dbstate, uistate, options_class, name, callback=None):
        self.label = _('Capitalization changes')
        self.cb = callback

        ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__)
        self.set_window(gtk.Window(), gtk.Label(), '')

        tool.BatchTool.__init__(self, dbstate, uistate, options_class, name)
        if self.fail:
            return

        self.progress = ProgressMeter(_('Checking Family Names'), '')
        self.progress.set_pass(_('Searching family names'),
                               len(self.db.get_surname_list()))
        self.name_list = []

        for name in self.db.get_surname_list():
            name.strip()
            namesplitSP = name.split()
            lSP = len(namesplitSP)
            namesplitHY = name.split('-')
            lHY = len(namesplitHY)
            if lSP == lHY == 1:
                if name != name.capitalize():
                    # Single surname without hyphen(s)
                    self.name_list.append(name)
            #if lSP == 1 and lHY > 1:
            #print "LSP==1", name, name.capitalize()
            #if name != name.capitalize():
            # Single surname with hyphen(s)
            #self.name_list.append(name)
            if lSP > 1 and lHY == 1:
                # more than one string in surname but no hyphen
                # check if first string is in prefix_list, if so test for cap in rest
                s1 = 0
                if namesplitSP[0].lower() in prefix_list:
                    s1 = 1
                for x in xrange(len(namesplitSP) - s1):
                    # check if any subsurname is not cap
                    notcap = False
                    if namesplitSP[s1 + x] != namesplitSP[s1 + x].capitalize():
                        notcap = True
                        break
                if notcap:
                    # Multiple surnames possibly after prefix
                    self.name_list.append(name)
            if lHY > 1:
                # more than one string in surname but hyphen(s) exists
                # check if first string is in prefix_list, if so test for cap
                if namesplitSP[0].lower() in prefix_list:
                    namesplitHY[0] = namesplitHY[0].replace(
                        namesplitSP[0], '').strip()
                for x in xrange(len(namesplitHY)):
                    # check if any subsurname is not cap
                    notcap = False
                    if namesplitHY[x] != namesplitHY[x].capitalize():
                        notcap = True
                        break
                if notcap:
                    # Multiple surnames possibly after frefix
                    self.name_list.append(name)

            if uistate:
                self.progress.step()

        if self.name_list:
            self.display()
        else:
            self.progress.close()
            self.close()
            OkDialog(_('No modifications made'),
                     _("No capitalization changes were detected."),
                     parent=uistate.window)

    def name_cap(self, name):
        name.strip()
        namesplitSP = name.split()
        lSP = len(namesplitSP)
        lHY = len(name.split('-'))
        namesep = ' '
        if lHY > 1:
            namesep = '-'
            namesplitSP = name.replace(namesep, ' ').split()
            lSP = len(namesplitSP)
        if lSP == lHY == 1:
            #if name != name.capitalize():
            # Single surname without space(s) or hyphen(s), normal case
            return name.capitalize()
        else:
            # more than one string in surname but no hyphen
            # check if first string is in prefix_list, if so CAP the rest
            # Names like (von) Kohl(-)Brandt
            result = ""
            s1 = 0
            if namesplitSP[0].lower() in prefix_list:
                s1 = 1
                result = namesplitSP[0].lower() + ' '
            for x in range(lSP - s1):
                # CAP all subsurnames
                result = result + namesplitSP[s1 + x].capitalize() + namesep
            return result[:-1]

    def display(self):

        self.top = Glade()
        window = self.top.toplevel
        self.top.connect_signals({
            "destroy_passed_object": self.close,
            "on_ok_clicked": self.on_ok_clicked,
            "on_help_clicked": self.on_help_clicked,
            "on_delete_event": self.close,
        })

        self.list = self.top.get_object("list")
        self.set_window(window, self.top.get_object('title'), self.label)

        self.model = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING,
                                   gobject.TYPE_STRING)

        r = gtk.CellRendererToggle()
        r.connect('toggled', self.toggled)
        c = gtk.TreeViewColumn(_('Select'), r, active=0)
        self.list.append_column(c)

        c = gtk.TreeViewColumn(_('Original Name'),
                               gtk.CellRendererText(),
                               text=1)
        self.list.append_column(c)

        c = gtk.TreeViewColumn(_('Capitalization Change'),
                               gtk.CellRendererText(),
                               text=2)
        self.list.append_column(c)

        self.list.set_model(self.model)

        self.iter_list = []
        self.progress.set_pass(_('Building display'), len(self.name_list))
        for name in self.name_list:
            handle = self.model.append()
            self.model.set_value(handle, 0, True)
            self.model.set_value(handle, 1, name)
            namecap = self.name_cap(name)
            self.model.set_value(handle, 2, namecap)
            self.iter_list.append(handle)
            self.progress.step()
        self.progress.close()

        self.show()

    def toggled(self, cell, path_string):
        path = tuple(map(int, path_string.split(':')))
        row = self.model[path]
        row[0] = not row[0]

    def build_menu_names(self, obj):
        return (self.label, None)

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        GrampsDisplay.help(WIKI_HELP_PAGE, WIKI_HELP_SEC)

    def on_ok_clicked(self, obj):
        with DbTxn(_("Capitalization changes"), self.db,
                   batch=True) as self.trans:
            self.db.disable_signals()
            changelist = set(
                self.model.get_value(node, 1) for node in self.iter_list
                if self.model.get_value(node, 0))

            #with self.db.get_person_cursor(update=True, commit=True) as cursor:
            #  for handle, data in cursor:
            for handle in self.db.get_person_handles(False):
                person = self.db.get_person_from_handle(handle)
                #person = Person(data)
                change = False
                for name in [person.get_primary_name()
                             ] + person.get_alternate_names():
                    sname = find_surname_name(handle, name.serialize())
                    if sname in changelist:
                        change = True
                        for surn in name.get_surname_list():
                            sname = self.name_cap(surn.get_surname())
                            surn.set_surname(sname)
                if change:
                    #cursor.update(handle, person.serialize())
                    self.db.commit_person(person, transaction=self.trans)

        self.db.enable_signals()
        self.db.request_rebuild()
        # FIXME: this probably needs to be removed, and bookmarks
        # should always be rebuilt on a commit_person via signals
        # self.parent.bookmarks.redraw()
        self.close()
        self.cb()