1# -*- coding: utf-8 -*-
2
3# Copyright (C) 2005 Osmo Salomaa
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18"""Dialog for selecting a subtitle file to save."""
19
20import aeidon
21import gaupol
22import os
23
24from aeidon.i18n   import _
25from gi.repository import GObject
26from gi.repository import Gtk
27
28__all__ = ("SaveDialog",)
29
30
31class SaveDialog(Gtk.FileChooserDialog, gaupol.FileDialog):
32
33    """Dialog for selecting a subtitle file to save."""
34
35    _widgets = (
36        "encoding_combo",
37        "format_combo",
38        "framerate_combo",
39        "framerate_label",
40        "newline_combo",
41    )
42
43    def __init__(self, parent, title, mode):
44        """Initialize a :class:`SaveDialog` instance."""
45        GObject.GObject.__init__(self)
46        self._mode = mode
47        self._init_dialog(parent, title)
48        self._init_extra_widget()
49        self._init_filters()
50        self._init_format_combo()
51        self._init_encoding_combo()
52        self._init_newline_combo()
53        self._init_framerate_combo()
54        self._init_values()
55
56    def get_format(self):
57        """Return the selected format."""
58        index = self._format_combo.get_active()
59        return aeidon.formats[index]
60
61    def get_framerate(self):
62        """Return the selected framerate."""
63        index = self._framerate_combo.get_active()
64        return aeidon.framerates[index]
65
66    def get_newline(self):
67        """Return the selected newline."""
68        index = self._newline_combo.get_active()
69        return aeidon.newlines[index]
70
71    def _init_dialog(self, parent, title):
72        """Initialize the dialog."""
73        self.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL)
74        self.add_button(_("_Save"), Gtk.ResponseType.OK)
75        self.set_default_response(Gtk.ResponseType.OK)
76        self.set_transient_for(parent)
77        self.set_title(title)
78        self.connect("response", self._on_response)
79        save_button = self.get_widget_for_response(Gtk.ResponseType.OK)
80        save_button.connect("event", self._on_save_button_event)
81        self.set_action(Gtk.FileChooserAction.SAVE)
82        self.set_do_overwrite_confirmation(True)
83
84    def _init_extra_widget(self):
85        """Initialize the extra widget from UI definition file."""
86        ui_file_path = os.path.join(aeidon.DATA_DIR, "ui", "save-dialog.ui")
87        builder = Gtk.Builder()
88        builder.set_translation_domain("gaupol")
89        builder.add_from_file(ui_file_path)
90        builder.connect_signals(self)
91        for name in self._widgets:
92            widget = builder.get_object(name)
93            setattr(self, "_{}".format(name), widget)
94        vbox = gaupol.util.new_vbox(spacing=0)
95        main_vbox = builder.get_object("main_vbox")
96        main_vbox.get_parent().remove(main_vbox)
97        vbox.add(main_vbox)
98        vbox.show_all()
99        self.set_extra_widget(vbox)
100
101    def _init_format_combo(self):
102        """Initialize the format combo box."""
103        store = Gtk.ListStore(str)
104        self._format_combo.set_model(store)
105        for name in (x.label for x in aeidon.formats):
106            if name == "SubRip":
107                # Mark the SubRip format as recommended, since
108                # it's the most common one and best supported,
109                # both in Gaupol and elsewhere.
110                name = _("{} (recommended)").format(name)
111            store.append((name,))
112        view = self._format_combo.get_child()
113        path = gaupol.util.tree_row_to_path(0)
114        view.set_displayed_row(path)
115        renderer = Gtk.CellRendererText()
116        self._format_combo.pack_start(renderer, expand=True)
117        self._format_combo.add_attribute(renderer, "text", 0)
118
119    def _init_framerate_combo(self):
120        """Initialize the framerate combo box."""
121        store = Gtk.ListStore(str)
122        self._framerate_combo.set_model(store)
123        for name in (x.label for x in aeidon.framerates):
124            store.append((name,))
125        view = self._framerate_combo.get_child()
126        path = gaupol.util.tree_row_to_path(0)
127        view.set_displayed_row(path)
128        renderer = Gtk.CellRendererText()
129        self._framerate_combo.pack_start(renderer, expand=True)
130        self._framerate_combo.add_attribute(renderer, "text", 0)
131
132    def _init_newline_combo(self):
133        """Initialize the newline combo box."""
134        store = Gtk.ListStore(str)
135        self._newline_combo.set_model(store)
136        for name in (x.label for x in aeidon.newlines):
137            store.append((name,))
138        view = self._newline_combo.get_child()
139        path = gaupol.util.tree_row_to_path(0)
140        view.set_displayed_row(path)
141        renderer = Gtk.CellRendererText()
142        self._newline_combo.pack_start(renderer, expand=True)
143        self._newline_combo.add_attribute(renderer, "text", 0)
144
145    def _init_values(self):
146        """Initialize default values for widgets."""
147        if os.path.isdir(gaupol.conf.file.directory):
148            self.set_current_folder(gaupol.conf.file.directory)
149        self.set_encoding(gaupol.conf.file.encoding)
150        self.set_format(gaupol.conf.file.format)
151        self.set_newline(gaupol.conf.file.newline)
152        self.set_framerate(gaupol.conf.editor.framerate)
153        self._framerate_combo.hide()
154        self._framerate_label.hide()
155
156    def _on_format_combo_changed(self, *args):
157        """Change the extension of the current filename."""
158        format = self.get_format()
159        path = self.get_filename()
160        if path is not None:
161            dirname = os.path.dirname(path)
162            basename = os.path.basename(path)
163            if not path.endswith(format.extension):
164                basename = aeidon.util.replace_extension(basename, format)
165                path = os.path.join(dirname, basename)
166                self.unselect_filename(path)
167                self.set_current_name(basename)
168                self.set_filename(path)
169        visible = (format.mode != self._mode)
170        self._framerate_combo.set_visible(visible)
171        self._framerate_label.set_visible(visible)
172
173    def _on_response(self, dialog, response):
174        """Save default values for widgets."""
175        directory = self.get_current_folder()
176        if directory is not None:
177            gaupol.conf.file.directory = directory
178        gaupol.conf.file.encoding = self.get_encoding()
179        gaupol.conf.file.format = self.get_format()
180        gaupol.conf.file.newline = self.get_newline()
181        gaupol.conf.editor.framerate = self.get_framerate()
182        if (response == Gtk.ResponseType.OK and
183            not self.get_filename().endswith(self.get_format().extension)):
184            # If the filename is lacking the extension, add it, stop this
185            # response and emit a new one so that overwrite confirmation gets
186            # called with the full filename. The filename extension might have
187            # already been added in self._on_save_button_event, but not
188            # necessarily if the user hit Enter on the keyboard.
189            self._format_combo.emit("changed")
190            gaupol.util.iterate_main()
191            self.stop_emission("response")
192            return self.response(Gtk.ResponseType.OK)
193
194    def _on_save_button_event(self, button, event):
195        """Ensure that the filename contains an extension."""
196        # Add possibly lacking extension to the filename.
197        self._format_combo.emit("changed")
198        gaupol.util.iterate_main()
199
200    def set_format(self, format):
201        """Set the selected format."""
202        if format is None: return
203        self._format_combo.set_active(format)
204
205    def set_framerate(self, framerate):
206        """Set the selected framerate."""
207        if framerate is None: return
208        self._framerate_combo.set_active(framerate)
209
210    def set_name(self, path):
211        """Set the selected filename."""
212        if os.path.isfile(path):
213            return self.set_filename(path)
214        return self.set_current_name(path)
215
216    def set_newline(self, newline):
217        """Set the selected newline."""
218        if newline is None: return
219        self._newline_combo.set_active(newline)
220