1# Copyright (C) 2011-2013 Kai Willadsen <kai.willadsen@gmail.com>
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation, either version 2 of the License, or (at
6# your option) any later version.
7#
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11# General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16import enum
17
18from gi.repository import Gio
19from gi.repository import GLib
20from gi.repository import GObject
21from gi.repository import Gtk
22
23from meld.conf import _
24from meld.melddoc import LabeledObjectMixin
25from meld.recent import recent_comparisons
26from meld.ui import gnomeglade
27
28
29class DiffType(enum.IntEnum):
30    # TODO: This should probably live in MeldWindow
31    Unselected = -1
32    File = 0
33    Folder = 1
34    Version = 2
35
36    def supports_blank(self):
37        return self in (self.File, self.Folder)
38
39
40class NewDiffTab(LabeledObjectMixin, GObject.GObject, gnomeglade.Component):
41
42    __gtype_name__ = "NewDiffTab"
43
44    __gsignals__ = {
45        'close': (GObject.SignalFlags.RUN_FIRST, None, (bool,)),
46        'diff-created': (GObject.SignalFlags.RUN_FIRST, None, (object,)),
47    }
48
49    label_text = _("New comparison")
50
51    def __init__(self, parentapp):
52        GObject.GObject.__init__(self)
53        gnomeglade.Component.__init__(
54            self, "tab-placeholder.ui", "new_comparison_tab",
55            [
56                "filechooserdialog0",
57                "filechooserdialog1",
58                "filechooserdialog2",
59            ]
60        )
61        self.map_widgets_into_lists(
62            ["file_chooser", "dir_chooser", "vc_chooser", "filechooserdialog"])
63        self.button_types = [
64            self.button_type_file,
65            self.button_type_dir,
66            self.button_type_vc,
67        ]
68        self.diff_methods = {
69            DiffType.File: parentapp.append_filediff,
70            DiffType.Folder: parentapp.append_dirdiff,
71            DiffType.Version: parentapp.append_vcview,
72        }
73        self.diff_type = DiffType.Unselected
74
75        default_path = GLib.get_home_dir()
76        for chooser in self.file_chooser:
77            chooser.set_current_folder(default_path)
78
79        self.widget.show()
80
81    def on_button_type_toggled(self, button, *args):
82        if not button.get_active():
83            if not any([b.get_active() for b in self.button_types]):
84                button.set_active(True)
85            return
86
87        for b in self.button_types:
88            if b is not button:
89                b.set_active(False)
90
91        self.diff_type = DiffType(self.button_types.index(button))
92        self.choosers_notebook.set_current_page(self.diff_type + 1)
93        # FIXME: Add support for new blank for VcView
94        self.button_new_blank.set_sensitive(
95            self.diff_type.supports_blank())
96        self.button_compare.set_sensitive(True)
97
98    def on_three_way_checkbutton_toggled(self, button, *args):
99        if button is self.file_three_way_checkbutton:
100            self.file_chooser2.set_sensitive(button.get_active())
101        else:  # button is self.dir_three_way_checkbutton
102            self.dir_chooser2.set_sensitive(button.get_active())
103
104    def on_file_set(self, filechooser, *args):
105        gfile = filechooser.get_file()
106        if not gfile:
107            return
108
109        parent = gfile.get_parent()
110        if not parent:
111            return
112
113        if parent.query_file_type(
114                Gio.FileQueryInfoFlags.NONE, None) == Gio.FileType.DIRECTORY:
115            for chooser in self.file_chooser:
116                if not chooser.get_file():
117                    chooser.set_current_folder_file(parent)
118
119        # TODO: We could do checks here to prevent errors: check to see if
120        # we've got binary files; check for null file selections; sniff text
121        # encodings; check file permissions.
122
123    def _get_num_paths(self):
124        if self.diff_type in (DiffType.File, DiffType.Folder):
125            three_way_buttons = (
126                self.file_three_way_checkbutton,
127                self.dir_three_way_checkbutton,
128            )
129            three_way = three_way_buttons[self.diff_type].get_active()
130            num_paths = 3 if three_way else 2
131        else:  # DiffType.Version
132            num_paths = 1
133        return num_paths
134
135    def on_button_compare_clicked(self, *args):
136        type_choosers = (self.file_chooser, self.dir_chooser, self.vc_chooser)
137        choosers = type_choosers[self.diff_type][:self._get_num_paths()]
138        compare_gfiles = [chooser.get_file() for chooser in choosers]
139
140        compare_kwargs = {}
141        if self.diff_type == DiffType.File:
142            chooserdialogs = self.filechooserdialog[:self._get_num_paths()]
143            encodings = [chooser.get_encoding() for chooser in chooserdialogs]
144            compare_kwargs = {'encodings': encodings}
145
146        tab = self.diff_methods[self.diff_type](
147            compare_gfiles, **compare_kwargs)
148        recent_comparisons.add(tab)
149        self.emit('diff-created', tab)
150
151    def on_button_new_blank_clicked(self, *args):
152        # TODO: This doesn't work the way I'd like for DirDiff and VCView.
153        # It should do something similar to FileDiff; give a tab with empty
154        # file entries and no comparison done.
155
156        # File comparison wants None for its paths here. Folder mode
157        # needs an actual directory.
158        if self.diff_type == DiffType.File:
159            gfiles = [None] * self._get_num_paths()
160        else:
161            gfiles = [Gio.File.new_for_path("")] * self._get_num_paths()
162        tab = self.diff_methods[self.diff_type](gfiles)
163        self.emit('diff-created', tab)
164
165    def on_container_switch_in_event(self, *args):
166        self.label_changed()
167
168    def on_container_switch_out_event(self, *args):
169        pass
170
171    def on_delete_event(self, *args):
172        self.emit('close', 0)
173        return Gtk.ResponseType.OK
174