New export assistant

svn: r8857
This commit is contained in:
Benny Malengier 2007-08-23 11:58:36 +00:00
parent 980f5a3a51
commit 167e4288a1
7 changed files with 54 additions and 426 deletions

View File

@ -1,3 +1,11 @@
2007-08-23 Benny Malengier <bm@cage.ugent.be>
* src/ExportAssistant.py: finished, new export assistant
* src/ViewManager.py : delete temporary hook new export assistant
* src/Makefile.am : delete Exporter.py
* po/POTFILES.in : delete Exporter.py
* src/Assistant.py : comment to use gtk.Assistant - deprecated
* src/Exporter.py : delete
2007-08-23 Stephane Charette <stephanecharette@gmail.com>
* src/plugins/NarrativeWeb.py: moved the source reference code from
IndividualPage into BasePage so it can also be used by media objects

View File

@ -20,7 +20,6 @@ src/DdTargets.py
src/DisplayState.py
src/Errors.py
src/ExportAssistant.py
src/Exporter.py
src/FontScale.py
src/GrampsCfg.py
src/GrampsDisplay.py

View File

@ -67,7 +67,10 @@ _format = '<span weight="bold" size="xx-large">%s</span>'
#
#-------------------------------------------------------------------------
class Assistant(gtk.Object,ManagedWindow.ManagedWindow):
""" A tabbed dialog box used to implement Assistant interfaces."""
""" A tabbed dialog box used to implement Assistant interfaces.
Deprecated. Please use gtk.Assistant class from now on.
See eg. example use in ExportAssistant
"""
__gproperties__ = {}

View File

@ -103,7 +103,6 @@ class ExportAssistant(gtk.Assistant, ManagedWindow.ManagedWindow) :
#set up Assisant
gtk.Assistant.__init__(self)
self.set_title('test')
#set up ManagedWindow
self.top_title = _("Export Assistant")
@ -135,6 +134,9 @@ class ExportAssistant(gtk.Assistant, ManagedWindow.ManagedWindow) :
#no progress page, use uistate progressbar
self.create_page_summary()
#we need our own forward function as options page must not always be shown
self.set_forward_page_func(self.forward_func, None)
#ManagedWindow show method
ManagedWindow.ManagedWindow.show(self)
@ -198,11 +200,8 @@ class ExportAssistant(gtk.Assistant, ManagedWindow.ManagedWindow) :
self.append_page(page)
self.set_page_header_image(page, self.logo)
self.set_page_title(page, _('Choose the format you want to export to'))
#there is always one radio button selected
self.set_page_complete(page, True)
self.set_page_type(page, gtk.ASSISTANT_PAGE_CONTENT)
#After selecting an export type, we need to decide to show options or not
self.set_forward_page_func(self.forward_func, None)
def create_page_options(self):
@ -261,9 +260,8 @@ class ExportAssistant(gtk.Assistant, ManagedWindow.ManagedWindow) :
self.chooser.set_local_only(False)
self.chooser.set_do_overwrite_confirmation(True)
folder, name = self.suggest_filename()
self.chooser.set_current_folder(folder)
self.chooser.set_current_name(name)
#created, folder and name not set
self.folder_is_set = False
#connect changes in filechooser with check to mark page complete
self.chooser.connect("selection-changed", self.check_fileselect)
@ -274,7 +272,6 @@ class ExportAssistant(gtk.Assistant, ManagedWindow.ManagedWindow) :
# do not release button, click forward. We expect user not to do this
# In case he does, recheck on confirmation page!
self.chooser.show_all()
page = self.chooser
@ -360,38 +357,55 @@ class ExportAssistant(gtk.Assistant, ManagedWindow.ManagedWindow) :
else :
back = False
#remember previous page for next time
self.__previous_page = page_number
if back :
#when moving backward, show page as it was
pass
#when moving backward, show page as it was,
#page we come from is set incomplete so as to disallow user jumping
# to last page after backward move
self.set_page_complete(self.get_nth_page(self.__previous_page),
False)
elif page_number == _ExportAssistant_pages['options'] :
self.create_options()
self.set_page_complete(page, True)
elif page == self.chooser :
# next page is the file chooser, reset filename, keep folder where user was
folder, name = self.suggest_filename()
page.set_current_name(name)
if self.folder_is_set :
page.set_current_name(name)
else :
page.set_current_name(name)
page.set_current_folder(folder)
self.folder_is_set = True
# see if page is complete with above
self.check_fileselect(page)
elif self.get_page_type(page) == gtk.ASSISTANT_PAGE_CONFIRM :
# The confirm page with apply button
# Present user with what will happen
filename = unicode(self.chooser.get_filename(),
sys.getfilesystemencoding())
name = os.path.split(filename)[1]
folder = os.path.split(filename)[0]
ix = self.get_selected_format_index()
format = self.exportformats[ix][1].replace('_','')
confirm_text = _(
#Allow for exotic error: file is still not correct
self.check_fileselect(self.chooser)
if self.get_page_complete(self.chooser) :
filename = unicode(self.chooser.get_filename(),
sys.getfilesystemencoding())
name = os.path.split(filename)[1]
folder = os.path.split(filename)[0]
confirm_text = _(
'The data will be saved as follows:\n\n'
'Format:\t%s\nName:\t%s\nFolder:\t%s\n\n'
'Press Apply to proceed, Back to revisit '
'your options, or Cancel to abort') % (format, name, folder)
self.set_page_complete(page, True)
else :
confirm_text = _(
'The selected file and folder to save to '
'cannot be created or found.\n\n'
'Press Back to return and select a valid filename.'
)
self.set_page_complete(page, False)
page.set_label(confirm_text)
elif self.get_page_type(page) == gtk.ASSISTANT_PAGE_SUMMARY :
@ -428,6 +442,13 @@ class ExportAssistant(gtk.Assistant, ManagedWindow.ManagedWindow) :
'a copy of your data that failed to save.')
page.set_label(conclusion_text)
self.set_page_title(page, conclusion_title)
self.set_page_complete(page, True)
else :
#whatever other page, if we show it, it is complete to
self.set_page_complete(page, True)
#remember previous page for next time
self.__previous_page = page_number
def close(self, *obj) :
#clean up ManagedWindow menu, then destroy window, bring forward parent

View File

@ -1,394 +0,0 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2004-2006 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
# Written by Alex Roitman
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import os
import sys
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# set up logging
#
#-------------------------------------------------------------------------
import logging
log = logging.getLogger(".Exporter")
#-------------------------------------------------------------------------
#
# Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import const
import Utils
from PluginUtils import export_list
import QuestionDialog
import Config
import GrampsDisplay
import Assistant
import Errors
from GrampsDbUtils import gramps_db_writer_factory
#-------------------------------------------------------------------------
#
# Exporter
#
#-------------------------------------------------------------------------
class Exporter:
"""
This class creates Gnome Druid to guide the user through the various
Save as/Export options. The overall goal is to keep things simple by
presenting few choice options on each druid page.
The export formats and options are obtained from the plugins, with the
exception of a native save. Native save as just copies file to another
name.
"""
def __init__(self,dbstate,uistate):
"""
Set up the window, the druid, and build all the druid's pages.
Some page elements are left empty, since their contents depends
on the user choices and on the success of the attempted save.
"""
self.dbstate = dbstate
self.uistate = uistate
self.callback = self.uistate.pulse_progressbar
if self.dbstate.active:
self.person = self.dbstate.get_active_person()
else:
self.person = self.dbstate.db.find_initial_person()
self.build_exports()
self.format_option = None
try:
self.w = Assistant.Assistant(uistate,self.__class__,self.complete,
_("Export Assistant"))
except Errors.WindowActiveError:
return
self.w.add_text_page(_('Saving your data'),self.get_intro_text())
self.format_page = self.w.add_page(_('Choosing the format to save'),
self.build_format_page())
self.file_sel_page = self.w.add_page(_('Selecting the file name'),
self.build_file_sel_page())
self.confirm_page = self.w.add_text_page('','')
self.conclusion_page = self.w.add_text_page('','')
self.w.connect('before-page-next',self.on_before_page_next)
self.w.connect('after-page-next' ,self.on_after_page_next)
self.w.show()
def complete(self):
pass
def on_before_page_next(self,obj,page,data=None):
if page == self.format_page:
self.build_options()
self.suggest_filename()
elif page == self.file_sel_page:
#we might have a bad file if user deleted without selecting the file
if self.check_valid_file(self.chooser) :
self.build_confirmation(True)
else :
#we need to prevent going to next page
QuestionDialog.ErrorDialog(_('No valid filename given'))
self.build_confirmation(False)
elif page == self.confirm_page:
success = self.save()
self.build_conclusion(success)
def on_after_page_next(self,obj,page,data=None):
if page == self.confirm_page :
#we have a file from the file chooser, make sure it is usable
self.check_valid_file(self.chooser)
def help(self,obj):
"""
Help handler.
"""
GrampsDisplay.help('export-data')
def get_intro_text(self):
return _('Under normal circumstances, GRAMPS does not require you '
'to directly save your changes. All changes you make are '
'immediately saved to the database.\n\n'
'This process will help you save a copy of your data '
'in any of the several formats supported by GRAMPS. '
'This can be used to make a copy of your data, backup '
'your data, or convert it to a format that will allow '
'you to transfer it to a different program.\n\n'
'If you change your mind during this process, you '
'can safely press the Cancel button at any time and your '
'present database will still be intact.')
def build_confirmation(self, valid):
"""
Build the text of the confirmation label. This should query
the selected options (format, filename) and present the summary
of the proposed action.
"""
if valid :
filename = unicode(self.chooser.get_filename(),
sys.getfilesystemencoding())
name = os.path.split(filename)[1]
folder = os.path.split(filename)[0]
ix = self.get_selected_format_index()
format = self.exports[ix][1].replace('_','')
confirm_text = _(
'The data will be saved as follows:\n\n'
'Format:\t%s\nName:\t%s\nFolder:\t%s\n\n'
'Press OK to proceed, Cancel to abort, or Back to '
'revisit your options.') % (format, name, folder)
else :
confirm_text = _(
'Return and select valid file' )
self.w.remove_page(self.confirm_page)
self.confirm_page = self.w.insert_text_page(_('Final confirmation'),
confirm_text,
self.confirm_page)
def save(self):
"""
Perform the actual Save As/Export operation.
Depending on the success status, set the text for the final page.
"""
filename = unicode(self.chooser.get_filename(),
sys.getfilesystemencoding())
Config.set(Config.RECENT_EXPORT_DIR,os.path.split(filename)[0])
ix = self.get_selected_format_index()
self.pre_save()
if self.exports[ix][3]:
success = self.exports[ix][0](self.dbstate.db,
filename,self.person,
self.option_box_instance,
self.callback)
else:
success = self.exports[ix][0](self.dbstate.db,
filename,self.person,
self.callback)
self.post_save()
return success
def pre_save(self):
self.uistate.set_busy_cursor(1)
self.w.set_busy_cursor(1)
self.uistate.progress.show()
def post_save(self):
self.uistate.set_busy_cursor(0)
self.w.set_busy_cursor(0)
self.uistate.progress.hide()
def build_conclusion(self,success):
if success:
conclusion_title = _('Your data has been saved')
conclusion_text = _(
'The copy of your data has been '
'successfully saved. You may press OK button '
'now to continue.\n\n'
'Note: the database currently opened in your GRAMPS '
'window is NOT the file you have just saved. '
'Future editing of the currently opened database will '
'not alter the copy you have just made. ')
else:
conclusion_title = _('Saving failed'),
conclusion_text = _(
'There was an error while saving your data. '
'You may try starting the export again.\n\n'
'Note: your currently opened database is safe. '
'It was only '
'a copy of your data that failed to save.')
self.w.remove_page(self.conclusion_page)
self.conclusion_page = self.w.insert_text_page(conclusion_title,
conclusion_text,
self.conclusion_page)
def build_format_page(self):
"""
Build a page with the table of format radio buttons and
their descriptions.
"""
self.format_buttons = []
box = gtk.VBox()
box.set_spacing(12)
table = gtk.Table(2*len(self.exports),2)
table.set_row_spacings(6)
table.set_col_spacings(6)
tip = gtk.Tooltips()
group = None
for ix in range(len(self.exports)):
title = self.exports[ix][1]
description= self.exports[ix][2]
button = gtk.RadioButton(group,title)
if not group:
group = button
self.format_buttons.append(button)
table.attach(button,0,2,2*ix,2*ix+1)
tip.set_tip(button,description)
box.add(table)
return box
def build_options(self):
"""
Build an extra page with the options specific for the chosen format.
If there's already an entry for this format in self.extra_pages then
do nothing, otherwise add a page.
If the chosen format does not have options then remove all
extra pages that are already there (from previous user passes
through the assistant).
"""
ix = self.get_selected_format_index()
if self.exports[ix][3]:
if ix == self.format_option:
return
elif self.format_option:
self.w.remove_page(self.option_page)
self.format_option = None
title = self.exports[ix][3][0]
option_box_class = self.exports[ix][3][1]
self.option_box_instance = option_box_class(self.person)
box = self.option_box_instance.get_option_box()
self.option_page = self.w.insert_page(title,box,
self.format_page+1)
self.file_sel_page += 1
self.confirm_page += 1
self.conclusion_page += 1
self.format_option = ix
box.show_all()
elif self.format_option:
self.w.remove_page(self.option_page)
self.format_option = None
def build_file_sel_page(self):
"""
Build a druid page embedding the FileChooserWidget.
"""
self.chooser = gtk.FileChooserWidget(gtk.FILE_CHOOSER_ACTION_SAVE)
self.chooser.set_local_only(False)
box = gtk.VBox()
box.set_spacing(12)
box.add(self.chooser)
# Dirty hack to enable proper EXPAND/FILL properties of the chooser
box.set_child_packing(self.chooser,1,1,0,gtk.PACK_START)
return box
def suggest_filename(self):
"""
Prepare suggested filename and set it in the file chooser.
"""
ix = self.get_selected_format_index()
ext = self.exports[ix][4]
# Suggested folder: try last export, then last import, then home.
default_dir = Config.get(Config.RECENT_EXPORT_DIR)
if len(default_dir)<=1:
default_dir = Config.get(Config.RECENT_IMPORT_DIR)
if len(default_dir)<=1:
default_dir = const.user_home
if ext == 'gramps':
new_filename = os.path.join(default_dir,'data.gramps')
elif ext == 'burn':
new_filename = os.path.basename(self.dbstate.db.get_save_path())
else:
new_filename = Utils.get_new_filename(ext,default_dir)
self.chooser.set_current_folder(default_dir)
self.chooser.set_current_name(os.path.split(new_filename)[1])
def check_valid_file(self, filechooser):
filename = filechooser.get_filename()
folder = filechooser.get_current_folder()
if filename and filename.strip and Utils.find_folder(filename) == '' \
and folder and Utils.find_folder(folder):
return True
else :
self.w.ok.set_sensitive(False)
return False
def get_selected_format_index(self):
"""
Query the format radiobuttons and return the index number
of the selected one.
"""
for ix in range(len(self.format_buttons)):
button = self.format_buttons[ix]
if button.get_active():
return ix
else:
return 0
def native_export(self,database,filename,person,callback=None):
"""
Native database export.
In the future, filter and other options may be added.
"""
try:
gramps_db_writer_factory(const.app_gramps)(database,
filename,
person,
callback)
return 1
except IOError, msg:
QuestionDialog.ErrorDialog(
_("Could not write file: %s") % filename,
_('System message was: %s') % msg )
return 0
def build_exports(self):
"""
This method builds its own list of available exports.
The list is built from the PluginMgr.export_list list
and from the locally defined exports (i.e. native export defined here).
"""
self.exports = [item for item in export_list]

View File

@ -49,7 +49,6 @@ gdir_PYTHON = \
DisplayState.py\
Errors.py\
ExportAssistant.py\
Exporter.py\
FontScale.py\
GrampsCfg.py\
GrampsDisplay.py\

View File

@ -110,7 +110,6 @@ UIDEFAULT = '''<ui>
<separator/>
<menuitem action="Import"/>
<menuitem action="Export"/>
<menuitem action="ExportNew"/>
<placeholder name="LocalExport"/>
<separator/>
<menuitem action="Abandon"/>
@ -363,8 +362,6 @@ class ViewManager:
None, self.save_as_activate),
('Export', 'gramps-export', _('_Export'), "<control>e", None,
self.export_data),
('ExportNew', 'gramps-export', _('_ExportNew'), None, None,
self.exportnew_data),
('Abandon', gtk.STOCK_REVERT_TO_SAVED,
_('_Abandon changes and quit'), None, None, self.abort),
('Reports', 'gramps-reports', _('_Reports'), None,
@ -1186,11 +1183,6 @@ class ViewManager:
pass
def export_data(self, obj):
if self.state.db.db_is_open:
import Exporter
Exporter.Exporter(self.state, self.uistate)
def exportnew_data(self, obj):
if self.state.db.db_is_open:
import ExportAssistant
try: