8128: GtkDialog mapped without a transient parent

This commit is contained in:
Josip 2015-05-03 20:04:28 +02:00
parent 1e9f1dbb3e
commit e172b6520d
12 changed files with 102 additions and 61 deletions

View File

@ -109,7 +109,7 @@ class User(user.User):
""" """
self._fileout.write("\r100%\n") self._fileout.write("\r100%\n")
def prompt(self, title, message, accept_label, reject_label): def prompt(self, title, message, accept_label, reject_label, parent=None):
""" """
Prompt the user with a message to select an alternative. Prompt the user with a message to select an alternative.

View File

@ -96,7 +96,7 @@ class DisplayNameEditor(ManagedWindow):
def __init__(self, uistate, dbstate, track, dialog): def __init__(self, uistate, dbstate, track, dialog):
# Assumes that there are two methods: dialog.name_changed_check(), # Assumes that there are two methods: dialog.name_changed_check(),
# and dialog._build_custom_name_ui() # and dialog._build_custom_name_ui()
ManagedWindow.__init__(self, uistate, [], DisplayNameEditor) ManagedWindow.__init__(self, uistate, track, DisplayNameEditor)
self.dialog = dialog self.dialog = dialog
self.dbstate = dbstate self.dbstate = dbstate
self.set_window( self.set_window(
@ -135,7 +135,7 @@ UPPERCASE keyword forces uppercase. Extra parentheses, commas are removed. Other
ManagedWindow.close(self, *obj) ManagedWindow.close(self, *obj)
def build_menu_names(self, obj): def build_menu_names(self, obj):
return (_(" Name Editor"), _("Preferences")) return (_(" Name Editor"), None)
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -229,12 +229,12 @@ class ConfigureDialog(ManagedWindow):
except TypeError: except TypeError:
print("WARNING: ignoring invalid value for '%s'" % constant) print("WARNING: ignoring invalid value for '%s'" % constant)
ErrorDialog(_("Invalid or incomplete format definition."), ErrorDialog(_("Invalid or incomplete format definition."),
obj.get_text()) obj.get_text(), parent=self.window)
obj.set_text('<b>%s</b>') obj.set_text('<b>%s</b>')
except ValueError: except ValueError:
print("WARNING: ignoring invalid value for '%s'" % constant) print("WARNING: ignoring invalid value for '%s'" % constant)
ErrorDialog(_("Invalid or incomplete format definition."), ErrorDialog(_("Invalid or incomplete format definition."),
obj.get_text()) obj.get_text(), parent=self.window)
obj.set_text('<b>%s</b>') obj.set_text('<b>%s</b>')
self.__config.set(constant, unicode(obj.get_text())) self.__config.set(constant, unicode(obj.get_text()))
@ -769,7 +769,7 @@ class GrampsPreferences(ConfigureDialog):
# check to see if this pattern already exists # check to see if this pattern already exists
if self.__check_for_name(translation, node): if self.__check_for_name(translation, node):
ErrorDialog(_("This format exists already."), ErrorDialog(_("This format exists already."),
translation) translation, parent=self.window)
self.edit_button.emit('clicked') self.edit_button.emit('clicked')
return return
# else, change the name # else, change the name
@ -1171,13 +1171,15 @@ class GrampsPreferences(ConfigureDialog):
config.set('preferences.date-format', obj.get_active()) config.set('preferences.date-format', obj.get_active())
OkDialog(_('Change is not immediate'), OkDialog(_('Change is not immediate'),
_('Changing the date format will not take ' _('Changing the date format will not take '
'effect until the next time Gramps is started.')) 'effect until the next time Gramps is started.'),
parent=self.window)
def place_format_changed(self, obj): def place_format_changed(self, obj):
config.set('preferences.place-format', obj.get_active()) config.set('preferences.place-format', obj.get_active())
OkDialog(_('Change is not immediate'), OkDialog(_('Change is not immediate'),
_('Changing the place format will not take ' _('Changing the place format will not take '
'effect until the next time Gramps is started.')) 'effect until the next time Gramps is started.'),
parent=self.window)
def date_calendar_changed(self, obj): def date_calendar_changed(self, obj):
config.set('preferences.calendar-format-report', obj.get_active()) config.set('preferences.calendar-format-report', obj.get_active())
@ -1392,13 +1394,14 @@ class GrampsPreferences(ConfigureDialog):
self.dbstate.db.set_mediapath(None) self.dbstate.db.set_mediapath(None)
def select_mediapath(self, *obj): def select_mediapath(self, *obj):
f = Gtk.FileChooserDialog( f = Gtk.FileChooserDialog(title=_("Select media directory"),
_("Select media directory"), parent=self.window,
action=Gtk.FileChooserAction.SELECT_FOLDER, action=Gtk.FileChooserAction.SELECT_FOLDER,
buttons=(Gtk.STOCK_CANCEL, buttons=(Gtk.STOCK_CANCEL,
Gtk.ResponseType.CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_APPLY, Gtk.STOCK_APPLY,
Gtk.ResponseType.OK)) Gtk.ResponseType.OK)
)
mpath = self.dbstate.db.get_mediapath() mpath = self.dbstate.db.get_mediapath()
if not mpath: if not mpath:
mpath = HOME_DIR mpath = HOME_DIR
@ -1416,13 +1419,14 @@ class GrampsPreferences(ConfigureDialog):
config.set('behavior.database-path', path) config.set('behavior.database-path', path)
def select_dbpath(self, *obj): def select_dbpath(self, *obj):
f = Gtk.FileChooserDialog( f = Gtk.FileChooserDialog(title=_("Select database directory"),
_("Select database directory"), parent=self.window,
action=Gtk.FileChooserAction.SELECT_FOLDER, action=Gtk.FileChooserAction.SELECT_FOLDER,
buttons=(Gtk.STOCK_CANCEL, buttons=(Gtk.STOCK_CANCEL,
Gtk.ResponseType.CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_APPLY, Gtk.STOCK_APPLY,
Gtk.ResponseType.OK)) Gtk.ResponseType.OK)
)
dbpath = config.get('behavior.database-path') dbpath = config.get('behavior.database-path')
if not dbpath: if not dbpath:
dbpath = os.path.join(HOME_DIR,'grampsdb') dbpath = os.path.join(HOME_DIR,'grampsdb')
@ -1475,7 +1479,7 @@ class GrampsPreferences(ConfigureDialog):
obj.set_text(str(intval)) obj.set_text(str(intval))
def build_menu_names(self, obj): def build_menu_names(self, obj):
return (_('Preferences'), None) return (_('Preferences'), _('Preferences'))
# FIXME: is this needed? # FIXME: is this needed?
def _set_button(self, stock): def _set_button(self, stock):

View File

@ -83,24 +83,24 @@ class DbLoader(CLIDbLoader):
self.import_info = None self.import_info = None
def _warn(self, title, warnmessage): def _warn(self, title, warnmessage):
WarningDialog(title, warnmessage) WarningDialog(title, warnmessage, parent=self.uistate.window)
def _errordialog(self, title, errormessage): def _errordialog(self, title, errormessage):
""" """
Show the error. Show the error.
In the GUI, the error is shown, and a return happens In the GUI, the error is shown, and a return happens
""" """
ErrorDialog(title, errormessage) ErrorDialog(title, errormessage, parent=self.uistate.window)
return 1 return 1
def _dberrordialog(self, msg): def _dberrordialog(self, msg):
import traceback import traceback
exc = traceback.format_exc() exc = traceback.format_exc()
try: try:
DBErrorDialog(str(msg.value)) DBErrorDialog(str(msg.value), parent=self.uistate.window)
_LOG.error(str(msg.value)) _LOG.error(str(msg.value))
except: except:
DBErrorDialog(str(msg)) DBErrorDialog(str(msg), parent=self.uistate.window)
_LOG.error(str(msg) +"\n" + exc) _LOG.error(str(msg) +"\n" + exc)
def _begin_progress(self): def _begin_progress(self):
@ -198,7 +198,8 @@ class DbLoader(CLIDbLoader):
_("Could not open file: %s") % filename, _("Could not open file: %s") % filename,
_('File type "%s" is unknown to Gramps.\n\n' _('File type "%s" is unknown to Gramps.\n\n'
'Valid types are: Gramps database, Gramps XML, ' 'Valid types are: Gramps database, Gramps XML, '
'Gramps package, GEDCOM, and others.') % extension) 'Gramps package, GEDCOM, and others.') % extension,
parent=self.uistate.window)
import_dialog.destroy() import_dialog.destroy()
return False return False
@ -220,13 +221,15 @@ class DbLoader(CLIDbLoader):
elif os.path.isdir(filename): elif os.path.isdir(filename):
ErrorDialog( ErrorDialog(
_('Cannot open file'), _('Cannot open file'),
_('The selected file is a directory, not a file.\n')) _('The selected file is a directory, not a file.\n'),
parent=self.uistate.window)
return True return True
elif os.path.exists(filename): elif os.path.exists(filename):
if not os.access(filename, os.R_OK): if not os.access(filename, os.R_OK):
ErrorDialog( ErrorDialog(
_('Cannot open file'), _('Cannot open file'),
_('You do not have read access to the selected file.')) _('You do not have read access to the selected file.'),
parent=self.uistate.window)
return True return True
else: else:
try: try:
@ -236,7 +239,8 @@ class DbLoader(CLIDbLoader):
except IOError: except IOError:
ErrorDialog( ErrorDialog(
_('Cannot create file'), _('Cannot create file'),
_('You do not have write access to the selected file.')) _('You do not have write access to the selected file.'),
parent=self.uistate.window)
return True return True
return False return False
@ -259,7 +263,8 @@ class DbLoader(CLIDbLoader):
_("Could not import file: %s") % filename, _("Could not import file: %s") % filename,
_("This file incorrectly identifies its character " _("This file incorrectly identifies its character "
"set, so it cannot be accurately imported. Please fix the " "set, so it cannot be accurately imported. Please fix the "
"encoding, and import again") + "\n\n %s" % msg) "encoding, and import again") + "\n\n %s" % msg,
parent=self.uistate.window)
except Exception: except Exception:
_LOG.error("Failed to import database.", exc_info=True) _LOG.error("Failed to import database.", exc_info=True)
self._end_progress() self._end_progress()

View File

@ -50,9 +50,10 @@ class Progress(object):
Mirros the same interface that the ExportAssistant uses in the Mirros the same interface that the ExportAssistant uses in the
selection, but this is for the preview selection. selection, but this is for the preview selection.
""" """
def __init__(self): def __init__(self, uistate):
from gi.repository import Gtk from gi.repository import Gtk
self.pm = ProgressMeter(_("Selecting Preview Data"), _('Selecting...')) self.pm = ProgressMeter(_("Selecting Preview Data"), _('Selecting...'),
parent=uistate.window)
self.progress_cnt = 0 self.progress_cnt = 0
self.title = _("Selecting...") self.title = _("Selecting...")
while Gtk.events_pending(): while Gtk.events_pending():
@ -239,7 +240,7 @@ class WriterOptionBox(object):
Calculate previews to see the selected data. Calculate previews to see the selected data.
""" """
self.parse_options() self.parse_options()
pm = Progress() pm = Progress(self.uistate)
self.preview_dbase = self.get_filtered_database(self.dbstate.db, pm, preview=True) self.preview_dbase = self.get_filtered_database(self.dbstate.db, pm, preview=True)
pm.close() pm.close()
self.preview_button.set_sensitive(0) self.preview_button.set_sensitive(0)

View File

@ -101,7 +101,9 @@ class BatchTool(Tool):
Should be used for tools using batch transactions. Should be used for tools using batch transactions.
""" """
def __init__(self, dbstate, user, options_class, name): def __init__(self, dbstate, user, options_class, name, parent=None):
if user.uistate:
parent = user.uistate.window
if not user.prompt( if not user.prompt(
_('Undo history warning'), _('Undo history warning'),
_('Proceeding with this tool will erase the undo history ' _('Proceeding with this tool will erase the undo history '
@ -110,7 +112,7 @@ class BatchTool(Tool):
'made prior to it.\n\n' 'made prior to it.\n\n'
'If you think you may want to revert running this tool, ' 'If you think you may want to revert running this tool, '
'please stop here and backup your database.'), 'please stop here and backup your database.'),
_('_Proceed with the tool'), _('_Stop')): _('_Proceed with the tool'), _('_Stop'), parent):
self.fail = True self.fail = True
return return

View File

@ -88,7 +88,7 @@ class User(user.User):
self._progress.close() self._progress.close()
self._progress = None self._progress = None
def prompt(self, title, message, accept_label, reject_label): def prompt(self, title, message, accept_label, reject_label, parent=None):
""" """
Prompt the user with a message to select an alternative. Prompt the user with a message to select an alternative.
@ -106,7 +106,8 @@ class User(user.User):
:returns: the user's answer to the question :returns: the user's answer to the question
:rtype: bool :rtype: bool
""" """
dialog = QuestionDialog2(title, message, accept_label, reject_label) dialog = QuestionDialog2(title, message, accept_label, reject_label,
parent)
return dialog.run() return dialog.run()
def warn(self, title, warning=""): def warn(self, title, warning=""):

View File

@ -1299,10 +1299,11 @@ class ViewManager(CLIManager):
basefile) basefile)
if os.path.exists(filename): if os.path.exists(filename):
question = QuestionDialog2( question = QuestionDialog2(
_("Backup file already exists! Overwrite?"), _("Backup file already exists! Overwrite?"),
_("The file '%s' exists.") % filename, _("The file '%s' exists.") % filename,
_("Proceed and overwrite"), _("Proceed and overwrite"),
_("Cancel the backup")) _("Cancel the backup"),
parent=self.window)
yes_no = question.run() yes_no = question.run()
if not yes_no: if not yes_no:
return return
@ -1333,7 +1334,8 @@ class ViewManager(CLIManager):
right pane, otherwise FileChooserDialog will hang. right pane, otherwise FileChooserDialog will hang.
""" """
f = Gtk.FileChooserDialog( f = Gtk.FileChooserDialog(
_("Select backup directory"), title=_("Select backup directory"),
parent=self.window,
action=Gtk.FileChooserAction.SELECT_FOLDER, action=Gtk.FileChooserAction.SELECT_FOLDER,
buttons=(Gtk.STOCK_CANCEL, buttons=(Gtk.STOCK_CANCEL,
Gtk.ResponseType.CANCEL, Gtk.ResponseType.CANCEL,

View File

@ -3,7 +3,6 @@
<interface> <interface>
<requires lib="gtk+" version="3.0"/> <requires lib="gtk+" version="3.0"/>
<object class="GtkDialog" id="check"> <object class="GtkDialog" id="check">
<property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="default_width">450</property> <property name="default_width">450</property>
<property name="default_height">400</property> <property name="default_height">400</property>

View File

@ -78,7 +78,7 @@ from gramps.gen.constfunc import handle2internal, conv_to_unicode
strip_dict = dict.fromkeys(list(range(9))+list(range(11,13))+list(range(14, 32)), " ") strip_dict = dict.fromkeys(list(range(9))+list(range(11,13))+list(range(14, 32)), " ")
class ProgressMeter(object): class ProgressMeter(object):
def __init__(self, *args): pass def __init__(self, *args, **kwargs): pass
def set_pass(self, *args): pass def set_pass(self, *args): pass
def step(self): pass def step(self): pass
def close(self): pass def close(self): pass
@ -88,7 +88,7 @@ class ProgressMeter(object):
# Low Level repair # Low Level repair
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
def cross_table_duplicates(db): def cross_table_duplicates(db, uistate):
""" """
Function to find the presence of identical handles that occur in different Function to find the presence of identical handles that occur in different
database tables. database tables.
@ -100,7 +100,11 @@ def cross_table_duplicates(db):
:returns: the presence of cross table duplicate handles :returns: the presence of cross table duplicate handles
:rtype: bool :rtype: bool
""" """
progress = ProgressMeter(_('Checking Database'),'') if uistate:
parent = uistate.window
else:
parent = None
progress = ProgressMeter(_('Checking Database'),'', parent)
progress.set_pass(_('Looking for cross table duplicates'), 9) progress.set_pass(_('Looking for cross table duplicates'), 9)
logging.info('Looking for cross table duplicates') logging.info('Looking for cross table duplicates')
total_nr_handles = 0 total_nr_handles = 0
@ -149,7 +153,7 @@ class Check(tool.BatchTool):
# As such, we run it before starting the transaction. # As such, we run it before starting the transaction.
# We only do this for the dbdir backend. # We only do this for the dbdir backend.
if self.db.__class__.__name__ == 'DbBsddb': if self.db.__class__.__name__ == 'DbBsddb':
if cross_table_duplicates(self.db): if cross_table_duplicates(self.db, uistate):
Report(uistate, _( Report(uistate, _(
"Your Family Tree contains cross table duplicate handles.\n " "Your Family Tree contains cross table duplicate handles.\n "
"This is bad and can be fixed by making a backup of your\n" "This is bad and can be fixed by making a backup of your\n"
@ -211,6 +215,11 @@ class Check(tool.BatchTool):
class CheckIntegrity(object): class CheckIntegrity(object):
def __init__(self, dbstate, uistate, trans): def __init__(self, dbstate, uistate, trans):
self.uistate = uistate
if self.uistate:
self.parent_window = self.uistate.window
else:
self.parent_window = None
self.db = dbstate.db self.db = dbstate.db
self.trans = trans self.trans = trans
self.bad_photo = [] self.bad_photo = []
@ -238,7 +247,8 @@ class CheckIntegrity(object):
self.empty_objects = defaultdict(list) self.empty_objects = defaultdict(list)
self.replaced_sourceref = [] self.replaced_sourceref = []
self.last_img_dir = config.get('behavior.addmedia-image-dir') self.last_img_dir = config.get('behavior.addmedia-image-dir')
self.progress = ProgressMeter(_('Checking Database'),'') self.progress = ProgressMeter(_('Checking Database'),'',
parent=self.parent_window)
self.explanation = Note(_('Objects referenced by this note ' self.explanation = Note(_('Objects referenced by this note '
'were referenced but missing so that is why they have been created ' 'were referenced but missing so that is why they have been created '
'when you ran Check and Repair on %s.') % 'when you ran Check and Repair on %s.') %
@ -723,7 +733,8 @@ class CheckIntegrity(object):
"keep the reference to the missing file, " "keep the reference to the missing file, "
"or select a new file." "or select a new file."
) % {'file_name' : '<b>%s</b>' % photo_name}, ) % {'file_name' : '<b>%s</b>' % photo_name},
remove_clicked, leave_clicked, select_clicked) remove_clicked, leave_clicked, select_clicked,
parent=self.uistate.window)
missmedia_action = mmd.default_action missmedia_action = mmd.default_action
elif missmedia_action == 1: elif missmedia_action == 1:
logging.warning(' FAIL: media object "%(desc)s" ' logging.warning(' FAIL: media object "%(desc)s" '

View File

@ -63,13 +63,22 @@ class DateParserDisplayTest(tool.Tool):
tool.Tool.__init__(self, dbstate, options_class, name) tool.Tool.__init__(self, dbstate, options_class, name)
if uistate: if uistate:
# Running with gui -> Show message # Running with gui -> Show message
QuestionDialog(_("Start date test?"),_("This test will create many persons and events in the current database. Do you really want to run this test?"),_("Run test"),self.run_tool) self.parent_window = uistate.window
QuestionDialog(_("Start date test?"),
_("This test will create many persons and events " \
"in the current database. Do you really want to " \
"run this test?"),
_("Run test"),
self.run_tool,
parent=self.parent_window)
else: else:
self.parent_window = None
self.run_tool() self.run_tool()
def run_tool(self): def run_tool(self):
self.progress = ProgressMeter(_('Running Date Test'),'') self.progress = ProgressMeter(_('Running Date Test'),'',
parent=self.parent_window)
self.progress.set_pass(_('Generating dates'), self.progress.set_pass(_('Generating dates'),
4) 4)
dates = [] dates = []

View File

@ -134,7 +134,6 @@ class EventComparison(tool.Tool,ManagedWindow):
}) })
window = self.filterDialog.toplevel window = self.filterDialog.toplevel
window.show()
self.filters = self.filterDialog.get_object("filter_list") self.filters = self.filterDialog.get_object("filter_list")
self.label = _('Event comparison filter selection') self.label = _('Event comparison filter selection')
self.set_window(window,self.filterDialog.get_object('title'), self.set_window(window,self.filterDialog.get_object('title'),
@ -177,7 +176,9 @@ class EventComparison(tool.Tool,ManagedWindow):
def on_apply_clicked(self, obj): def on_apply_clicked(self, obj):
cfilter = self.filter_model[self.filters.get_active()][1] cfilter = self.filter_model[self.filters.get_active()][1]
progress_bar = ProgressMeter(_('Comparing events'),'') progress_bar = ProgressMeter(_('Comparing events'),
'',
parent=self.window)
progress_bar.set_pass(_('Selecting people'),1) progress_bar.set_pass(_('Selecting people'),1)
plist = cfilter.apply(self.db, plist = cfilter.apply(self.db,
@ -190,7 +191,7 @@ class EventComparison(tool.Tool,ManagedWindow):
self.options.handler.save_options() self.options.handler.save_options()
if len(plist) == 0: if len(plist) == 0:
WarningDialog(_("No matches were found")) WarningDialog(_("No matches were found"), parent=self.window)
else: else:
DisplayChart(self.dbstate,self.uistate,plist,self.track) DisplayChart(self.dbstate,self.uistate,plist,self.track)
@ -238,7 +239,6 @@ class DisplayChart(ManagedWindow):
}) })
window = self.topDialog.toplevel window = self.topDialog.toplevel
window.show()
self.set_window(window, self.topDialog.get_object('title'), self.set_window(window, self.topDialog.get_object('title'),
_('Event Comparison Results')) _('Event Comparison Results'))
@ -306,7 +306,8 @@ class DisplayChart(ManagedWindow):
self.progress_bar.close() self.progress_bar.close()
def build_row_data(self): def build_row_data(self):
self.progress_bar = ProgressMeter(_('Comparing Events'),'') self.progress_bar = ProgressMeter(_('Comparing Events'),'',
parent=self.window)
self.progress_bar.set_pass(_('Building data'),len(self.my_list)) self.progress_bar.set_pass(_('Building data'),len(self.my_list))
for individual_id in self.my_list: for individual_id in self.my_list:
individual = self.db.get_person_from_handle(individual_id) individual = self.db.get_person_from_handle(individual_id)

View File

@ -125,11 +125,16 @@ class TestcaseGenerator(tool.BatchTool):
def __init__(self, dbstate, user, options_class, name, callback=None): def __init__(self, dbstate, user, options_class, name, callback=None):
uistate = user.uistate uistate = user.uistate
if uistate:
parent_window = uistate.window
else:
parent_window = None
self.person = None self.person = None
if dbstate.db.readonly: if dbstate.db.readonly:
return return
tool.BatchTool.__init__(self, dbstate, user, options_class, name) tool.BatchTool.__init__(self, dbstate, user, options_class, name,
parent=parent_window)
if self.fail: if self.fail:
return return
@ -188,7 +193,7 @@ class TestcaseGenerator(tool.BatchTool):
def init_gui(self,uistate): def init_gui(self,uistate):
title = "%s - Gramps" % _("Generate testcases") title = "%s - Gramps" % _("Generate testcases")
self.top = Gtk.Dialog(title) self.top = Gtk.Dialog(title, parent=uistate.window)
self.top.set_default_size(400,150) self.top.set_default_size(400,150)
self.top.vbox.set_spacing(5) self.top.vbox.set_spacing(5)
label = Gtk.Label(label='<span size="larger" weight="bold">%s</span>' % _("Generate testcases")) label = Gtk.Label(label='<span size="larger" weight="bold">%s</span>' % _("Generate testcases"))
@ -275,7 +280,8 @@ class TestcaseGenerator(tool.BatchTool):
while Gtk.events_pending(): while Gtk.events_pending():
Gtk.main_iteration() Gtk.main_iteration()
self.progress = ProgressMeter(_('Generating testcases'),'') self.progress = ProgressMeter(_('Generating testcases'),'',
parent=self.window)
self.transaction_count = 0; self.transaction_count = 0;
if self.options.handler.options_dict['lowlevel']: if self.options.handler.options_dict['lowlevel']: