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