Skip to content

Commit

Permalink
WIP: Print Dialog: hack to obtain exceptions raised in print dialog
Browse files Browse the repository at this point in the history
Exceptions raised in GTK code are trapped. However, the print logic
needs to know the result of the print dialog (usually communicated
through exceptions). A context manager is used to keep track of
the exception the GTK code would ideally raise.
  • Loading branch information
deeplow committed Jan 15, 2025
1 parent 772ab0f commit e9ee2f0
Showing 1 changed file with 57 additions and 10 deletions.
67 changes: 57 additions & 10 deletions export/securedrop_export/print/print_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,60 @@

logger = logging.getLogger(__name__)

def open_print_dialog(file_to_print):
app = PrintDialog(file_to_print)
app.run()

class GtkExceptionRaiser:
"""
Context manager to keep track of exceptions to be raised after GTK exits
This is a workaround for the fact that GTK does not behave like regular
libraries. Exceptions raised by the GUI code are always caught within GTK.
The context manager provides a way to store these exceptions.
Usage:
class SomeApplication(Gtk.Application):
def __init__(self, raise_later_func):
super().__init__()
self.raise_later_func = raise_later_func
[...]
def on_something_bad_happening(self):
self.raise_later_func(Exception("something happned"))
self.quit()
with GtkExceptionRaiser() as raise_later_func:
app = SomeApplication(raise_later_func)
app.run()
"""
def __init__(self):
self.exception_to_raise = None

def raise_later_func(self, exception):
self.exception_to_raise = exception

def __enter__(self):
return self.raise_later_func

def __exit__(self, exc_type, exc_val, exc_tb):
if self.exception_to_raise:
raise self.exception_to_raise


class PrintDialog(Gtk.Application):
def __init__(self, file_to_print):
def __init__(self, file_to_print, raise_later_func):
super().__init__(application_id="org.securedrop.PrintDialog")
self.file_to_print = file_to_print
self.raise_later_func = raise_later_func
self.connect("activate", self.on_activate)

def on_activate(self, app):
window = Gtk.Window(application=app)
window.hide()
self.dialog = Gtk.PrintUnixDialog.new("Print Document", window)
self.dialog.connect("response", self.on_response)
self.dialog.connect("close", self.quit)
self.dialog.show()
window.hide()

def on_response(self, parent_widget, response_id):
if response_id == Gtk.ResponseType.OK:
Expand All @@ -36,13 +73,23 @@ def on_response(self, parent_widget, response_id):
job = Gtk.PrintJob.new("print job", printer, settings, page_setup)
job.set_source_file(self.file_to_print)
job.send(self.on_job_complete, user_data=None)
elif response_id == Gtk.ResponseType.APPLY: # Preview (if available)
pass
elif response_id == Gtk.ResponseType.CANCEL:
# FIXME should this exist or should it simply cancel and not report errors
raise ExportException(sdstatus=Status.ERROR_PRINT, sderror="User canceled dialog")
self.raise_later_func(
ExportException(sdstatus=Status.ERROR_PRINT, sderror="User canceled dialog")
)
self.quit()
elif response_id == Gtk.ResponseType.DELETE_EVENT:
self.quit()

def on_job_complete(self, print_job, user_data, error):
if error:
self.quit()
raise ExportException(sdstatus=Status.ERROR_PRINT, sderror=error.message)
self.raise_later_func(
ExportException(sdstatus=Status.ERROR_PRINT, sderror=error.message)
)
self.quit()

def open_print_dialog(file_to_print):
with GtkExceptionRaiser() as raise_later_func:
app = PrintDialog(file_to_print, raise_later_func)
app.run()

0 comments on commit e9ee2f0

Please sign in to comment.