diff --git a/gramps2/src/plugins/Checkpoint.py b/gramps2/src/plugins/Checkpoint.py index 1a6d43ec8..6fe722f17 100644 --- a/gramps2/src/plugins/Checkpoint.py +++ b/gramps2/src/plugins/Checkpoint.py @@ -39,77 +39,208 @@ from gettext import gettext as _ # #------------------------------------------------------------------------- import gtk +import gtk.glade +from gnome import help_display #------------------------------------------------------------------------- # # gramps modules # #------------------------------------------------------------------------- +import const from QuestionDialog import OkDialog, ErrorDialog import WriteXML +import Tool +import AutoComp +import Utils #------------------------------------------------------------------------- # -# +# Constant strings that we offer as custom commands # #------------------------------------------------------------------------- -def runTool(database,active_person,callback,parent=None): - try: - Checkpoint(database,callback,parent) - except: - import DisplayTrace - DisplayTrace.DisplayTrace() +cust_arch_list = [ + 'cvs ci -m "$(date)"', + ] + +cust_ret_list = [ + 'cvs up', + ] + #------------------------------------------------------------------------- # # Checkpoint # #------------------------------------------------------------------------- -class Checkpoint: +class Checkpoint(Tool.Tool): - def __init__(self,db,callback,parent): - self.cb = callback - self.db = db + def __init__(self,db,person,options_class,name,callback=None,parent=None): + Tool.Tool.__init__(self,db,person,options_class,name) + + if parent: + self.init_gui(parent) + else: + self.run_tool(cli=True) + + def init_gui(self,parent): + # Draw dialog and make it handle everything self.parent = parent - self.use_custom = False - self.custom_str = "cat > /tmp/temp.file" - self.run() + if self.parent.child_windows.has_key(self.__class__): + self.parent.child_windows[self.__class__].present(None) + return + self.win_key = self.__class__ - def run(self): + base = os.path.dirname(__file__) + glade_file = "%s/%s" % (base,"checkpoint.glade") + self.glade = gtk.glade.XML(glade_file,"top","gramps") + + self.cust_arch_cb = self.glade.get_widget("cust_arch") + self.cust_ret_cb = self.glade.get_widget("cust_ret") + self.rcs_rb = self.glade.get_widget("rcs") + self.cust_rb = self.glade.get_widget("custom") + + # Fill in the stored values + AutoComp.fill_combo(self.cust_arch_cb,cust_arch_list) + AutoComp.fill_combo(self.cust_ret_cb,cust_ret_list) + self.cust_arch_cb.child.set_text( + self.options.handler.options_dict['cacmd']) + self.cust_ret_cb.child.set_text( + self.options.handler.options_dict['crcmd']) + + # Display controls according to the state + if self.options.handler.options_dict['rcs']: + self.rcs_rb.set_active(1) + else: + self.cust_rb.set_active(1) + self.cust_arch_cb.set_sensitive(self.cust_rb.get_active()) + self.cust_ret_cb.set_sensitive(self.cust_rb.get_active()) + + self.rcs_rb.connect('toggled',self.rcs_toggled) + + self.title = _("Checkpoint Data") + self.window = self.glade.get_widget('top') + self.window.set_icon(self.parent.topWindow.get_icon()) + Utils.set_titles(self.window, + self.glade.get_widget('title'), + self.title) + + self.glade.signal_autoconnect({ + "on_close_clicked" : self.close, + "on_delete_event" : self.on_delete_event, + "on_arch_clicked" : self.on_archive_clicked, + "on_ret_clicked" : self.on_retrieve_clicked, + "on_help_clicked" : self.on_help_clicked, + }) + + self.add_itself_to_menu() + self.window.show() + + def rcs_toggled(self,obj): + self.cust_arch_cb.set_sensitive(not obj.get_active()) + self.cust_ret_cb.set_sensitive(not obj.get_active()) + + def on_help_clicked(self,obj): + """Display the relevant portion of GRAMPS manual""" + help_display('gramps-manual','index') + + def on_delete_event(self,obj,b): + self.remove_itself_from_menu() + + def close(self,obj): + self.remove_itself_from_menu() + self.window.destroy() + + def add_itself_to_menu(self): + self.parent.child_windows[self.win_key] = self + self.parent_menu_item = gtk.MenuItem(self.title) + self.parent_menu_item.connect("activate",self.present) + self.parent_menu_item.show() + self.parent.winsmenu.append(self.parent_menu_item) + + def remove_itself_from_menu(self): + del self.parent.child_windows[self.win_key] + self.parent_menu_item.destroy() + + def present(self,obj): + self.window.present() + + def on_archive_clicked(self,obj): + self.options.handler.options_dict['cacmd'] = unicode( + self.cust_arch_cb.child.get_text()) + self.options.handler.options_dict['rcs'] = int( + self.rcs_rb.get_active()) + + self.run_tool(archive=True,cli=False) + # Save options + self.options.handler.save_options() + + def on_retrieve_clicked(self,obj): + self.options.handler.options_dict['crcmd'] = unicode( + self.cust_ret_cb.child.get_text()) + self.options.handler.options_dict['rcs'] = int( + self.rcs_rb.get_active()) + + self.run_tool(archive=False,cli=False) + # Save options + self.options.handler.save_options() + + def run_tool(self,archive=True,cli=False): """ RCS will be a builtin command, since we can handle all configuration on our own. This isn't true for most versioning systems, which usually require external setup, and external communication. """ - self.parent.status_text(_("Checkpointing database...")) + if not cli: + self.parent.status_text(_("Checkpointing database...")) - if self.use_custom: - self.custom() + if self.options.handler.options_dict['rcs']: + self.rcs(archive,cli) + elif archive: + self.custom(self.options.handler.options_dict['cacmd'],cli) else: - self.rcs() + self.custom(self.options.handler.options_dict['crcmd'],cli) - self.parent.progress.set_fraction(0) - self.parent.modify_statusbar() + if not cli: + self.parent.progress.set_fraction(0) + self.parent.modify_statusbar() def timestamp(self): format = locale.nl_langinfo(locale.D_T_FMT) return unicode(time.strftime(format,time.localtime(time.time()))) - def custom(self): + def custom(self,cmd,cli): """ Passed the generated XML file to the specified command. """ - proc = popen2.Popen3(self.custom_str, True) + proc = popen2.Popen3(cmd, True) xmlwrite = WriteXML.XmlWriter(self.db,self.callback,False,False) xmlwrite.write_handle(proc.tochild) + proc.tochild.close() status = proc.wait() - if status: - ErrorDialog(_("Checkpoint failed"), - "\n".join(proc.childerr.readlines())) + message = "\n".join(proc.childerr.readlines()) del proc + + if status: + msg1 = _("Checkpoint Failed") + msg2 = _("An attempt to archive the data failed " + "with the following message:\n\n%s") % message + if cli: + print msg1 + print msg2 + else: + ErrorDialog(msg1,msg2) + else: + msg1 = _("Checkpoint Succeeded ") + msg2 = _("The data was successfully archived.") + if cli: + print msg1 + print msg2 + else: + OkDialog(msg1,msg2) - def rcs(self): + def rcs(self,checkin,cli): """ Check the generated XML file into RCS. Initialize the RCS file if it does not already exist. @@ -133,38 +264,84 @@ class Checkpoint: del proc if status: - ErrorDialog(_("Checkpoint Archive Creation Failed"), - _("No checkpointing archive was found. " - "An attempt to create it has failed with the " - "following message:\n\n%s") - % message) + msg1 = _("Checkpoint Archive Creation Failed") + msg2 = _("No checkpointing archive was found. " + "An attempt to create it has failed with the " + "following message:\n\n%s") % message + if cli: + print msg1 + print msg2 + else: + ErrorDialog(msg1,msg2) + return else: - OkDialog(_("Checkpoint Archive Created"), - _("No checkpointing archive was found, " - "so it was created to enable archiving.\n\n" - "The archive file name is %s\n" - "Deleting this file will lose the archive and make " - "impossible to extract archived data from it.") - % archive) - - # At this point, we have an existing archive file - xmlwrite = WriteXML.XmlWriter(self.db,self.callback,False,False) - xmlwrite.write(archive_base) + msg1 = _("Checkpoint Archive Created") + msg2 = _("No checkpointing archive was found, " + "so it was created to enable archiving.\n\n" + "The archive file name is %s\n" + "Deleting this file will lose the archive " + "and make impossible to extract archived data " + "from it.") % archive + if cli: + print msg1 + print msg2 + else: + OkDialog(msg1,msg2) - proc = popen2.Popen3("ci %s" % archive_base,True) - proc.tochild.write(comment) - proc.tochild.close() - status = proc.wait() - message = "\n".join(proc.childerr.readlines()) - del proc - if status: - ErrorDialog(_("Checkpoint Failed"), - _("An attempt to archive the data failed " - "with the following message:\n\n%s") % message) + if checkin: + # At this point, we have an existing archive file + xmlwrite = WriteXML.XmlWriter(self.db,self.callback,False,False) + xmlwrite.write(archive_base) + + proc = popen2.Popen3("ci %s" % archive_base,True) + proc.tochild.write(comment) + proc.tochild.close() + status = proc.wait() + message = "\n".join(proc.childerr.readlines()) + del proc + if status: + msg1 = _("Checkpoint Failed") + msg2 = _("An attempt to archive the data failed " + "with the following message:\n\n%s") % message + if cli: + print msg1 + print msg2 + else: + ErrorDialog(msg1,msg2) + else: + msg1 = _("Checkpoint Succeeded ") + msg2 = _("The data was successfully archived.") + if cli: + print msg1 + print msg2 + else: + OkDialog(msg1,msg2) else: - OkDialog(_("Checkpoint Succeeded "), - _("The data was successfully archived.")) + proc = popen2.Popen3("co -p %s > %s.gramps" + % (archive_base,archive_base), + True) + proc.tochild.close() + status = proc.wait() + message = "\n".join(proc.childerr.readlines()) + del proc + if status: + msg1 = _("Checkpoint Failed") + msg2 = _("An attempt to retrieve the data failed " + "with the following message:\n\n%s") % message + if cli: + print msg1 + print msg2 + else: + ErrorDialog(msg1,msg2) + else: + msg1 = _("Checkpoint Succeeded ") + msg2 = _("The data was successfully retrieved.") + if cli: + print msg1 + print msg2 + else: + OkDialog(msg1,msg2) def callback(self,value): """ @@ -175,6 +352,42 @@ class Checkpoint: while(gtk.events_pending()): gtk.main_iteration() +#------------------------------------------------------------------------ +# +# +# +#------------------------------------------------------------------------ +class CheckpointOptions(Tool.ToolOptions): + """ + Defines options and provides handling interface. + """ + + def __init__(self,name,person_id=None): + Tool.ToolOptions.__init__(self,name,person_id) + + def set_new_options(self): + # Options specific for this report + self.options_dict = { + 'rcs' : 1, + 'archive' : 1, + 'cacmd' : '', + 'crcmd' : '', + } + self.options_help = { + 'rcs' : ("=0/1", + "Whether to use RCS (ignores custom commands).", + ["Do not use RCS","Use RCS"], + True), + 'archive' : ("=0/1", + "Whether to archive or retrieve.", + ["Retrieve","Archive"], + True), + 'cacmd' : ("=str","Custom command line for archiving", + "Custom command string"), + 'crcmd' : ("=str","Custom command line for retrieval", + "Custom command string"), + } + #------------------------------------------------------------------------ # # @@ -183,8 +396,15 @@ class Checkpoint: from PluginMgr import register_tool register_tool( - runTool, - _("Checkpoint the database"), - category=_("Revision control"), - description=_("Store a snapshot of the current database into " - "a revision control system")) + name = 'chkpoint', + category = const.TOOL_REVCTL, + tool_class = Checkpoint, + options_class = CheckpointOptions, + modes = Tool.MODE_GUI | Tool.MODE_CLI, + translated_name = _("Checkpoint the database"), + status = _("Beta"), + author_name = "Donald N. Allingham", + author_email = "dallingham@users.sourceforge.net", + description = _("Store a snapshot of the current database into " + "a revision control system") + )