Merge pull request #275 from prculley/expdialog

8250 and 9736: avoid all other operations during export and fixes for export popup windows hidden.
This commit is contained in:
Sam Manzi 2016-12-01 09:56:09 +11:00 committed by GitHub
commit b556b29b25
8 changed files with 124 additions and 54 deletions

View File

@ -60,7 +60,7 @@ class BaseDoc(metaclass=ABCMeta):
such as OpenOffice, AbiWord, and LaTeX are derived from this base such as OpenOffice, AbiWord, and LaTeX are derived from this base
class, providing a common interface to all document generators. class, providing a common interface to all document generators.
""" """
def __init__(self, styles, paper_style): def __init__(self, styles, paper_style, track=[]):
""" """
Create a BaseDoc instance, which provides a document generation Create a BaseDoc instance, which provides a document generation
interface. This class should never be instantiated directly, but interface. This class should never be instantiated directly, but
@ -70,9 +70,11 @@ class BaseDoc(metaclass=ABCMeta):
:param paper_style: :class:`.PaperStyle` instance containing information :param paper_style: :class:`.PaperStyle` instance containing information
about the paper. If set to None, then the document about the paper. If set to None, then the document
is not a page oriented document (e.g. HTML) is not a page oriented document (e.g. HTML)
:param track: used in quick reports for GUI window management
""" """
self.paper = paper_style self.paper = paper_style
self._style_sheet = styles self._style_sheet = styles
self.track = track
self._creator = "" self._creator = ""
self.init_called = False self.init_called = False

View File

@ -408,6 +408,7 @@ class DisplayState(Callback):
self.disprel_defpers = None self.disprel_defpers = None
self.disprel_active = None self.disprel_active = None
self.set_relationship_class() self.set_relationship_class()
self.export = False
formatter = logging.Formatter('%(levelname)s %(name)s: %(message)s') formatter = logging.Formatter('%(levelname)s %(name)s: %(message)s')
warnbtn = status.get_warning_button() warnbtn = status.get_warning_button()
@ -527,6 +528,16 @@ class DisplayState(Callback):
else: else:
return "" return ""
def set_export_mode(self, value):
self.set_busy_cursor(value)
if value == self.export:
return
else:
self.export = value
def get_export_mode(self):
return self.export
def set_busy_cursor(self, value): def set_busy_cursor(self, value):
if value == self.busy: if value == self.busy:
return return

View File

@ -139,6 +139,21 @@ class GrampsWindowManager:
# Return None if the ID is not found # Return None if the ID is not found
return self.id2item.get(item_id, None) return self.id2item.get(item_id, None)
def get_item_from_window(self, window):
""" This finds a ManagedWindow from a Gtk top_level object (typicaly
a window).
For example, to find my managedwindow track within a class of Gtk
widget:
mywindow = self.get_toplevel() # finds top level Gtk object
managed_window = self.uistate.gwm.get_item_from_window(mywindow)
track = managed_window.track
"""
for key, item in self.id2item.items():
if item.window == window:
return self.id2item[key]
return None
def close_track(self, track): def close_track(self, track):
# This is called when item needs to be closed # This is called when item needs to be closed
# Closes all its children and then removes the item from the tree. # Closes all its children and then removes the item from the tree.
@ -311,7 +326,7 @@ class ManagedWindow:
menu, keeping track of child windows, closing them on close/delete menu, keeping track of child windows, closing them on close/delete
event, and presenting itself when selected or attempted to create again. event, and presenting itself when selected or attempted to create again.
""" """
def __init__(self, uistate, track, obj): def __init__(self, uistate, track, obj, modal=False):
""" """
Create child windows and add itself to menu, if not there already. Create child windows and add itself to menu, if not there already.
@ -321,18 +336,19 @@ class ManagedWindow:
from .managedwindow import ManagedWindow from .managedwindow import ManagedWindow
class SomeWindowClass(ManagedWindow): class SomeWindowClass(ManagedWindow):
def __init__(self,uistate,dbstate,track): def __init__(self, uistate, dbstate, track, modal):
window_id = self # Or e.g. window_id = person.handle window_id = self # Or e.g. window_id = person.handle
submenu_label = None # This window cannot have children
menu_label = 'Menu label for this window'
ManagedWindow.__init__(self, ManagedWindow.__init__(self,
uistate, uistate,
track, track,
window_id, window_id,
submenu_label, modal=False)
menu_label)
# Proceed with the class. # Proceed with the class.
... ...
def build_menu_names(self, obj):
submenu_label = None # This window cannot have children
menu_label = 'Menu label for this window'
return (menu_label, submenu_label)
:param uistate: gramps uistate :param uistate: gramps uistate
:param track: {list of parent windows, [] if the main GRAMPS window :param track: {list of parent windows, [] if the main GRAMPS window
@ -342,7 +358,17 @@ class ManagedWindow:
which works on this obj and creates menu labels which works on this obj and creates menu labels
for use in the Gramps Window Menu. for use in the Gramps Window Menu.
If self.submenu_label ='' then leaf, otherwise branch If self.submenu_label ='' then leaf, otherwise branch
:param modal: True/False, if True, this window is made modal
(always on top, and always has focus). Any child
windows are also automatically made modal by moving
the modal flag to the child. On close of a child
the modal flag is sent back to the parent.
If a modal window is used and has children, its and any child 'track'
parameters must properly be set to the parents 'self.track'.
Only one modal window can be supported by Gtk without potentially
hiding of a modal window while it has focus. So don't use direct
non managed Gtk windows as children and set them modal.
""" """
window_key = self.build_window_key(obj) window_key = self.build_window_key(obj)
@ -354,6 +380,7 @@ class ManagedWindow:
self.horiz_position_key = None self.horiz_position_key = None
self.vert_position_key = None self.vert_position_key = None
self.__refs_for_deletion = [] self.__refs_for_deletion = []
self.modal = modal
if uistate and uistate.gwm.get_item_from_id(window_key): if uistate and uistate.gwm.get_item_from_id(window_key):
uistate.gwm.get_item_from_id(window_key).present() uistate.gwm.get_item_from_id(window_key).present()
@ -382,10 +409,13 @@ class ManagedWindow:
parent_item_track.append(0) parent_item_track.append(0)
# Based on the track, get item and then window object # Based on the track, get item and then window object
self.parent_window = self.uistate.gwm.get_item_from_track( managed_parent = self.uistate.gwm.get_item_from_track(
parent_item_track).window parent_item_track)
self.parent_window = managed_parent.window
self.parent_modal = managed_parent.modal
else: else:
# On the top level: we use gramps top window # On the top level: we use gramps top window
self.parent_modal = False
if self.uistate: if self.uistate:
self.parent_window = self.uistate.window self.parent_window = self.uistate.window
else: else:
@ -412,11 +442,18 @@ class ManagedWindow:
self.titlelabel = title self.titlelabel = title
if self.isWindow : if self.isWindow :
set_titles(self, title, text, msg) set_titles(self, title, text, msg)
self.window = self
else : else :
set_titles(window, title, text, msg) set_titles(window, title, text, msg)
#closing the Gtk.Window must also close ManagedWindow #closing the Gtk.Window must also close ManagedWindow
self.window = window self.window = window
self.window.connect('delete-event', self.close) self.window.connect('delete-event', self.close)
if self.modal:
self.window.set_modal(True)
if self.parent_modal:
self.parent_window.set_modal(False)
self.window.set_modal(True)
self.modal = True
def get_window(self): def get_window(self):
""" """
@ -513,6 +550,8 @@ class ManagedWindow:
self.clean_up() self.clean_up()
self.uistate.gwm.close_track(self.track) self.uistate.gwm.close_track(self.track)
self.opened = False self.opened = False
if self.parent_modal:
self.parent_window.set_modal(True)
self.parent_window.present() self.parent_window.present()
def present(self): def present(self):

View File

@ -109,12 +109,15 @@ class ExportAssistant(Gtk.Assistant, ManagedWindow) :
self.writestarted = False self.writestarted = False
self.confirm = None self.confirm = None
# set export mode and busy mode to avoid all other operations
self.uistate.set_export_mode(True)
#set up Assistant #set up Assistant
Gtk.Assistant.__init__(self) Gtk.Assistant.__init__(self)
#set up ManagedWindow #set up ManagedWindow
self.top_title = _("Export Assistant") self.top_title = _("Export Assistant")
ManagedWindow.__init__(self, uistate, [], self.__class__) ManagedWindow.__init__(self, uistate, [], self.__class__, modal=True)
#set_window is present in both parent classes #set_window is present in both parent classes
ManagedWindow.set_window(self, self, None, ManagedWindow.set_window(self, self, None,
@ -156,7 +159,7 @@ class ExportAssistant(Gtk.Assistant, ManagedWindow) :
def build_menu_names(self, obj): def build_menu_names(self, obj):
"""Override ManagedWindow method.""" """Override ManagedWindow method."""
return (self.top_title, None) return (self.top_title, self.top_title)
def create_page_intro(self): def create_page_intro(self):
"""Create the introduction page.""" """Create the introduction page."""
@ -272,7 +275,8 @@ class ExportAssistant(Gtk.Assistant, ManagedWindow) :
list(map(vbox.remove, vbox.get_children())) list(map(vbox.remove, vbox.get_children()))
# add new content # add new content
if config_box_class: if config_box_class:
self.option_box_instance = config_box_class(self.person, self.dbstate, self.uistate) self.option_box_instance = config_box_class(
self.person, self.dbstate, self.uistate, track=self.track)
box = self.option_box_instance.get_option_box() box = self.option_box_instance.get_option_box()
vbox.add(box) vbox.add(box)
else: else:
@ -387,6 +391,7 @@ class ExportAssistant(Gtk.Assistant, ManagedWindow) :
pass pass
def do_close(self): def do_close(self):
self.uistate.set_export_mode(False)
if self.writestarted : if self.writestarted :
pass pass
else : else :
@ -609,11 +614,9 @@ class ExportAssistant(Gtk.Assistant, ManagedWindow) :
page.set_child_visible(True) page.set_child_visible(True)
self.show_all() self.show_all()
self.uistate.set_busy_cursor(True)
self.set_busy_cursor(1) self.set_busy_cursor(1)
def post_save(self): def post_save(self):
self.uistate.set_busy_cursor(False)
self.set_busy_cursor(0) self.set_busy_cursor(0)
self.progressbar.hide() self.progressbar.hide()
self.writestarted = False self.writestarted = False

View File

@ -106,10 +106,11 @@ class WriterOptionBox:
the options. the options.
""" """
def __init__(self, person, dbstate, uistate): def __init__(self, person, dbstate, uistate, track=[]):
self.person = person self.person = person
self.dbstate = dbstate self.dbstate = dbstate
self.uistate = uistate self.uistate = uistate
self.track = track
self.preview_dbase = None self.preview_dbase = None
self.preview_button = None self.preview_button = None
self.preview_proxy_button = {} self.preview_proxy_button = {}
@ -247,7 +248,8 @@ class WriterOptionBox:
run_quick_report_by_name(dbstate, run_quick_report_by_name(dbstate,
self.uistate, self.uistate,
'filterbyname', 'filterbyname',
'all') 'all',
track=self.track)
def preview(self, widget): def preview(self, widget):
""" """
@ -658,7 +660,7 @@ class WriterOptionBox:
else: else:
the_filter = GenericFilterFactory(namespace)() the_filter = GenericFilterFactory(namespace)()
if the_filter: if the_filter:
EditFilter(namespace, self.dbstate, self.uistate, [], EditFilter(namespace, self.dbstate, self.uistate, self.track,
the_filter, filterdb, the_filter, filterdb,
lambda : self.edit_filter_save(filterdb, namespace)) lambda : self.edit_filter_save(filterdb, namespace))
else: # can't edit this filter else: # can't edit this filter

View File

@ -179,7 +179,7 @@ def get_quick_report_list(qv_category=None):
return names return names
def run_quick_report_by_name(dbstate, uistate, report_name, handle, def run_quick_report_by_name(dbstate, uistate, report_name, handle,
container=None, **kwargs): container=None, track=[], **kwargs):
""" """
Run a QuickView by name. Run a QuickView by name.
**kwargs provides a way of passing special quick views additional **kwargs provides a way of passing special quick views additional
@ -193,7 +193,8 @@ def run_quick_report_by_name(dbstate, uistate, report_name, handle,
break break
if report: if report:
return run_report(dbstate, uistate, report.category, return run_report(dbstate, uistate, report.category,
handle, report, container=container, **kwargs) handle, report, container=container,
track=track, **kwargs)
else: else:
raise AttributeError("No such quick report '%s'" % report_name) raise AttributeError("No such quick report '%s'" % report_name)
@ -226,7 +227,7 @@ def run_quick_report_by_name_direct(report_name, database, document, handle):
raise AttributeError("No such quick report id = '%s'" % report_name) raise AttributeError("No such quick report id = '%s'" % report_name)
def run_report(dbstate, uistate, category, handle, pdata, container=None, def run_report(dbstate, uistate, category, handle, pdata, container=None,
**kwargs): track=[], **kwargs):
""" """
Run a Quick Report. Run a Quick Report.
Optionally container can be passed, rather than putting the report Optionally container can be passed, rather than putting the report
@ -241,7 +242,7 @@ def run_report(dbstate, uistate, category, handle, pdata, container=None,
return return
func = eval('mod.' + pdata.runfunc) func = eval('mod.' + pdata.runfunc)
if handle: if handle:
d = TextBufDoc(make_basic_stylesheet(), None) d = TextBufDoc(make_basic_stylesheet(), None, track=track)
d.dbstate = dbstate d.dbstate = dbstate
d.uistate = uistate d.uistate = uistate
if isinstance(handle, str): # a handle if isinstance(handle, str): # a handle

View File

@ -75,6 +75,12 @@ class QuickTable(SimpleTable):
self._callback_leftdouble = callback self._callback_leftdouble = callback
def button_press_event(self, treeview, event): def button_press_event(self, treeview, event):
wid = treeview.get_toplevel()
try:
winmgr = self.simpledoc.doc.uistate.gwm
self.track = winmgr.get_item_from_window(wid).track
except:
self.track = []
index = None index = None
button_code = None button_code = None
event_time = None event_time = None
@ -112,46 +118,50 @@ class QuickTable(SimpleTable):
treeview.grab_focus() treeview.grab_focus()
treeview.set_cursor(path, col, 0) treeview.set_cursor(path, col, 0)
if store and node: if store and node:
index = store.get_value(node, 0) # index Below, index = store.get_value(node, 0) # index Below,
# you need index, treeview, path, button_code, # you need index, treeview, path, button_code,
# func, and event_time # func, and event_time
if index is not None: if index is not None:
if self._link[index]:
objclass, handle = self._link[index]
else:
return False
if (self.simpledoc.doc.uistate.get_export_mode() and
objclass != 'Filter'):
return False # avoid edition during export
self.popup = Gtk.Menu() self.popup = Gtk.Menu()
popup = self.popup popup = self.popup
menu_item = Gtk.MenuItem(label=_("Copy all")) menu_item = Gtk.MenuItem(label=_("Copy all"))
menu_item.connect("activate", lambda widget: text_to_clipboard(model_to_text(treeview.get_model()))) menu_item.connect("activate", lambda widget: text_to_clipboard(
model_to_text(treeview.get_model())))
popup.append(menu_item) popup.append(menu_item)
menu_item.show() menu_item.show()
# Now add more items to popup menu, if available # Now add more items to popup menu, if available
if (index is not None and self._link[index]):
# See details (edit, etc): # See details (edit, etc):
objclass, handle = self._link[index] menu_item = Gtk.MenuItem(label=_("the object|See %s details") %
menu_item = Gtk.MenuItem(label=_("the object|See %s details") % glocale.trans_objclass(objclass)) glocale.trans_objclass(objclass))
menu_item.connect(
"activate", lambda widget: self.on_table_doubleclick(treeview))
popup.append(menu_item)
menu_item.show()
# Add other items to menu:
if objclass == 'Person':
menu_item = Gtk.MenuItem(label=_("the object|Make %s active")
% glocale.trans_objclass('Person'))
menu_item.connect("activate", menu_item.connect("activate",
lambda widget: self.on_table_doubleclick(treeview)) lambda widget: self.on_table_click(treeview))
popup.append(menu_item) popup.append(menu_item)
menu_item.show() menu_item.show()
# Add other items to menu:
if (self._callback_leftclick or
(index is not None and self._link[index])):
objclass, handle = self._link[index]
if objclass == 'Person':
menu_item = Gtk.MenuItem(label=_("the object|Make %s active") % glocale.trans_objclass('Person'))
menu_item.connect("activate",
lambda widget: self.on_table_click(treeview))
popup.append(menu_item)
menu_item.show()
if (self.simpledoc.doc.dbstate.db != if (self.simpledoc.doc.dbstate.db !=
self.simpledoc.doc.dbstate.db.basedb and self.simpledoc.doc.dbstate.db.basedb):
(index is not None and self._link[index])):
objclass, handle = self._link[index]
if (objclass == 'Filter' and if (objclass == 'Filter' and
handle[0] in ['Person', 'Family', 'Place', 'Event', handle[0] in ['Person', 'Family', 'Place', 'Event',
'Repository', 'Note', 'Media', 'Repository', 'Note', 'Media',
'Citation', 'Source']): 'Citation', 'Source']):
menu_item = Gtk.MenuItem(label=_("See data not in Filter")) menu_item = Gtk.MenuItem(label=_("See data not in Filter"))
menu_item.connect("activate", menu_item.connect(
lambda widget: self.show_not_in_filter(handle[0])) "activate",
lambda widget: self.show_not_in_filter(handle[0]))
popup.append(menu_item) popup.append(menu_item)
menu_item.show() menu_item.show()
# Show the popup menu: # Show the popup menu:
@ -163,7 +173,8 @@ class QuickTable(SimpleTable):
run_quick_report_by_name(self.simpledoc.doc.dbstate, run_quick_report_by_name(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate, self.simpledoc.doc.uistate,
'filterbyname', 'filterbyname',
'Inverse %s' % obj_class) 'Inverse %s' % obj_class,
track=self.track)
def on_table_doubleclick(self, obj): def on_table_doubleclick(self, obj):
""" """
@ -269,14 +280,15 @@ class QuickTable(SimpleTable):
self.simpledoc.doc.uistate, self.simpledoc.doc.uistate,
'filterbyname', 'filterbyname',
'list of people', 'list of people',
handles=handle) handle=handle,
track=self.track)
elif objclass == 'Filter': elif objclass == 'Filter':
if isinstance(handle, list): if isinstance(handle, list):
handle = handle[0] handle = handle[0]
run_quick_report_by_name(self.simpledoc.doc.dbstate, run_quick_report_by_name(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate, self.simpledoc.doc.uistate,
'filterbyname', 'filterbyname',
handle) handle, track=self.track)
return False # didn't handle event return False # didn't handle event
def on_table_click(self, obj): def on_table_click(self, obj):

View File

@ -53,14 +53,14 @@ LEFT,RIGHT,CENTER = 'LEFT','RIGHT','CENTER'
_WIDTH_IN_CHARS = 72 _WIDTH_IN_CHARS = 72
class DisplayBuf(ManagedWindow): class DisplayBuf(ManagedWindow):
def __init__(self, title, document): def __init__(self, title, document, track=[]):
self.title = title self.title = title
ManagedWindow.__init__(self, document.uistate, [], ManagedWindow.__init__(self, document.uistate, track, document)
document) self.set_window(Gtk.Dialog(title="",
self.set_window(Gtk.Dialog("", document.uistate.window, flags=Gtk.DialogFlags.DESTROY_WITH_PARENT,
Gtk.DialogFlags.DESTROY_WITH_PARENT, buttons=(_('_Close'),
(_('_Close'), Gtk.ResponseType.CLOSE)), Gtk.ResponseType.CLOSE)),
None, title) None, title, True)
self.window.set_size_request(600,400) self.window.set_size_request(600,400)
scrolled_window = Gtk.ScrolledWindow() scrolled_window = Gtk.ScrolledWindow()
scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC,Gtk.PolicyType.AUTOMATIC) scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC,Gtk.PolicyType.AUTOMATIC)
@ -69,7 +69,7 @@ class DisplayBuf(ManagedWindow):
self.window.connect('response', self.close) self.window.connect('response', self.close)
scrolled_window.add(document.text_view) scrolled_window.add(document.text_view)
self.window.vbox.pack_start(scrolled_window, True, True, 0) self.window.vbox.pack_start(scrolled_window, True, True, 0)
self.window.show_all() self.show() # should use ManagedWindow version of show
def build_menu_names(self, obj): def build_menu_names(self, obj):
return ('View', _('Quick View')) return ('View', _('Quick View'))
@ -154,7 +154,7 @@ class TextBufDoc(BaseDoc, TextDoc):
if container: if container:
return DocumentManager(_('Quick View'), self, container) return DocumentManager(_('Quick View'), self, container)
else: else:
DisplayBuf(_('Quick View'), self) DisplayBuf(_('Quick View'), self, track=self.track)
return return
#-------------------------------------------------------------------- #--------------------------------------------------------------------