From b27dcf2ebdadc6c54ad09e9eabd83dd8c1c2a44c Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Mon, 5 Nov 2018 17:14:03 +0100 Subject: [PATCH] Use the builtin GTK3 FileChooser rather than our custom subclass. --- .flake8 | 2 +- .../2018-08-17-AL-deprecations.rst | 3 + lib/matplotlib/backends/backend_gtk3.py | 81 ++++++++++++------- lib/matplotlib/cbook/deprecation.py | 5 +- 4 files changed, 61 insertions(+), 30 deletions(-) diff --git a/.flake8 b/.flake8 index 3ee515ef2351..4500550227d2 100644 --- a/.flake8 +++ b/.flake8 @@ -33,7 +33,7 @@ per-file-ignores = lib/matplotlib/backends/_backend_tk.py: E501 lib/matplotlib/backends/backend_agg.py: E302 lib/matplotlib/backends/backend_cairo.py: E203, E221, E402 - lib/matplotlib/backends/backend_gtk3.py: E203, E221, E222, E225, E251, E501 + lib/matplotlib/backends/backend_gtk3.py: E203, E221, E225, E251, E501 lib/matplotlib/backends/backend_pgf.py: E731 lib/matplotlib/backends/qt_editor/_formlayout.py: E501 lib/matplotlib/font_manager.py: E203, E221, E251, E501 diff --git a/doc/api/next_api_changes/2018-08-17-AL-deprecations.rst b/doc/api/next_api_changes/2018-08-17-AL-deprecations.rst index 86808c8dcabb..6e950c1b3649 100644 --- a/doc/api/next_api_changes/2018-08-17-AL-deprecations.rst +++ b/doc/api/next_api_changes/2018-08-17-AL-deprecations.rst @@ -4,6 +4,9 @@ API deprecations The following API elements are deprecated: - ``get_py2exe_datafiles``, ``tk_window_focus``, +- ``backend_gtk3.FileChooserDialog``, + ``backend_gtk3.NavigationToolbar2GTK3.get_filechooser``, + ``backend_gtk3.SaveFigureGTK3.get_filechooser``, - ``backend_ps.PsBackendHelper``, ``backend_ps.ps_backend_helper``, - ``cbook.iterable``, - ``cbook.get_label``, ``cbook.iterable``, diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index 7b2ac7d9eead..2f449e253a2d 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -1,5 +1,7 @@ +import functools import logging import os +from pathlib import Path import sys import matplotlib @@ -521,6 +523,7 @@ def _init_toolbar(self): self.show_all() + @cbook.deprecated("3.1") def get_filechooser(self): fc = FileChooserDialog( title='Save the figure', @@ -532,24 +535,54 @@ def get_filechooser(self): return fc def save_figure(self, *args): - chooser = self.get_filechooser() - fname, format = chooser.get_filename_from_user() - chooser.destroy() - if fname: - startpath = os.path.expanduser(rcParams['savefig.directory']) - # Save dir for next time, unless empty str (i.e., use cwd). - if startpath != "": - rcParams['savefig.directory'] = os.path.dirname(fname) - try: - self.canvas.figure.savefig(fname, format=format) - except Exception as e: - error_msg_gtk(str(e), parent=self) + dialog = Gtk.FileChooserDialog( + title="Save the figure", + parent=self.canvas.get_toplevel(), + action=Gtk.FileChooserAction.SAVE, + buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, + Gtk.STOCK_SAVE, Gtk.ResponseType.OK), + ) + for name, fmts \ + in self.canvas.get_supported_filetypes_grouped().items(): + ff = Gtk.FileFilter() + ff.set_name(name) + for fmt in fmts: + ff.add_pattern("*." + fmt) + dialog.add_filter(ff) + if self.canvas.get_default_filetype() in fmts: + dialog.set_filter(ff) + + @functools.partial(dialog.connect, "notify::filter") + def on_notify_filter(*args): + name = dialog.get_filter().get_name() + fmt = self.canvas.get_supported_filetypes_grouped()[name][0] + dialog.set_current_name( + str(Path(dialog.get_current_name()).with_suffix("." + fmt))) + + dialog.set_current_folder(rcParams["savefig.directory"]) + dialog.set_current_name(self.canvas.get_default_filename()) + dialog.set_do_overwrite_confirmation(True) + + response = dialog.run() + fname = dialog.get_filename() + ff = dialog.get_filter() # Doesn't autoadjust to filename :/ + fmt = self.canvas.get_supported_filetypes_grouped()[ff.get_name()][0] + dialog.destroy() + if response == Gtk.ResponseType.CANCEL: + return + # Save dir for next time, unless empty str (which means use cwd). + if rcParams['savefig.directory']: + rcParams['savefig.directory'] = os.path.dirname(fname) + try: + self.canvas.figure.savefig(fname, format=fmt) + except Exception as e: + error_msg_gtk(str(e), parent=self) def configure_subplots(self, button): toolfig = Figure(figsize=(6, 3)) canvas = self._get_canvas(toolfig) toolfig.subplots_adjust(top=0.9) - tool = SubplotTool(self.canvas.figure, toolfig) + tool = SubplotTool(self.canvas.figure, toolfig) w = int(toolfig.bbox.width) h = int(toolfig.bbox.height) @@ -582,6 +615,7 @@ def set_history_buttons(self): self._gtk_ids['Forward'].set_sensitive(can_forward) +@cbook.deprecated("3.1") class FileChooserDialog(Gtk.FileChooserDialog): """GTK+ file selector which remembers the last file/directory selected and presents the user with a menu of supported image formats @@ -777,6 +811,7 @@ def set_message(self, s): class SaveFigureGTK3(backend_tools.SaveFigureBase): + @cbook.deprecated("3.1") def get_filechooser(self): fc = FileChooserDialog( title='Save the figure', @@ -788,21 +823,11 @@ def get_filechooser(self): return fc def trigger(self, *args, **kwargs): - chooser = self.get_filechooser() - fname, format_ = chooser.get_filename_from_user() - chooser.destroy() - if fname: - startpath = os.path.expanduser(rcParams['savefig.directory']) - if startpath == '': - # explicitly missing key or empty str signals to use cwd - rcParams['savefig.directory'] = startpath - else: - # save dir for next time - rcParams['savefig.directory'] = os.path.dirname(fname) - try: - self.figure.canvas.print_figure(fname, format=format_) - except Exception as e: - error_msg_gtk(str(e), parent=self) + + class PseudoToolbar: + canvas = self.figure.canvas + + return NavigationToolbar2GTK3.save_figure(PseudoToolbar()) class SetCursorGTK3(backend_tools.SetCursorBase): diff --git a/lib/matplotlib/cbook/deprecation.py b/lib/matplotlib/cbook/deprecation.py index 05088b2414ba..c7304f4bc367 100644 --- a/lib/matplotlib/cbook/deprecation.py +++ b/lib/matplotlib/cbook/deprecation.py @@ -191,7 +191,10 @@ def deprecate(obj, message=message, name=name, alternative=alternative, old_doc = obj.__doc__ def finalize(wrapper, new_doc): - obj.__doc__ = new_doc + try: + obj.__doc__ = new_doc + except AttributeError: # Can't set on some extension objects. + pass obj.__init__ = wrapper return obj