dag: update column allocation algorithm description
[git-cola.git] / cola / difftool.py
blob5025286bb00b351e11738018aa9f20424ff46352
1 from __future__ import division, absolute_import, unicode_literals
3 from qtpy import QtWidgets
4 from qtpy.QtCore import Qt
6 from . import cmds
7 from . import gitcmds
8 from . import hotkeys
9 from . import icons
10 from . import qtutils
11 from . import utils
12 from .i18n import N_
13 from .widgets import completion
14 from .widgets import defs
15 from .widgets import filetree
18 def diff_commits(parent, a, b):
19 """Show a dialog for diffing two commits"""
20 dlg = FileDiffDialog(parent, a=a, b=b)
21 dlg.show()
22 dlg.raise_()
23 return dlg.exec_() == QtWidgets.QDialog.Accepted
26 def diff_expression(parent, expr,
27 create_widget=False,
28 hide_expr=False,
29 focus_tree=False):
30 """Show a diff dialog for diff expressions"""
31 dlg = FileDiffDialog(parent,
32 expr=expr,
33 hide_expr=hide_expr,
34 focus_tree=focus_tree)
35 if create_widget:
36 return dlg
37 dlg.show()
38 dlg.raise_()
39 return dlg.exec_() == QtWidgets.QDialog.Accepted
42 class FileDiffDialog(QtWidgets.QDialog):
44 def __init__(self, parent, a=None, b=None, expr=None, title=None,
45 hide_expr=False, focus_tree=False):
46 """Show files with differences and launch difftool"""
48 QtWidgets.QDialog.__init__(self, parent)
50 self.a = a
51 self.b = b
52 self.diff_expr = expr
54 if title is None:
55 title = N_('git-cola diff')
57 self.setWindowTitle(title)
58 self.setWindowModality(Qt.WindowModal)
60 self.expr = completion.GitRefLineEdit(parent=self)
61 if expr is not None:
62 self.expr.setText(expr)
64 if expr is None or hide_expr:
65 self.expr.hide()
67 self.tree = filetree.FileTree(parent=self)
69 self.diff_button = qtutils.create_button(text=N_('Compare'),
70 icon=icons.diff(),
71 enabled=False)
72 self.diff_button.setShortcut(hotkeys.DIFF)
74 self.diff_all_button = qtutils.create_button(text=N_('Compare All'),
75 icon=icons.diff())
76 self.edit_button = qtutils.edit_button()
77 self.edit_button.setShortcut(hotkeys.EDIT)
79 self.close_button = qtutils.close_button()
81 self.button_layout = qtutils.hbox(defs.no_margin, defs.spacing,
82 self.diff_button,
83 self.diff_all_button,
84 self.edit_button,
85 qtutils.STRETCH,
86 self.close_button)
88 self.main_layout = qtutils.vbox(defs.margin, defs.spacing,
89 self.expr, self.tree,
90 self.button_layout)
91 self.setLayout(self.main_layout)
93 self.tree.itemSelectionChanged.connect(self.tree_selection_changed)
94 self.tree.itemDoubleClicked.connect(self.tree_double_clicked)
95 self.tree.up.connect(self.focus_input)
97 self.expr.textChanged.connect(self.text_changed)
99 self.expr.activated.connect(self.focus_tree)
100 self.expr.down.connect(self.focus_tree)
101 self.expr.enter.connect(self.focus_tree)
103 qtutils.connect_button(self.diff_button, self.diff)
104 qtutils.connect_button(self.diff_all_button,
105 lambda: self.diff(dir_diff=True))
106 qtutils.connect_button(self.edit_button, self.edit)
107 qtutils.connect_button(self.close_button, self.close)
109 qtutils.add_action(self, 'Focus Input', self.focus_input, hotkeys.FOCUS)
110 qtutils.add_action(self, 'Diff All', lambda: self.diff(dir_diff=True),
111 hotkeys.CTRL_ENTER, hotkeys.CTRL_RETURN)
112 qtutils.add_close_action(self)
114 self.resize(720, 420)
115 self.refresh()
117 if focus_tree:
118 self.focus_tree()
120 def focus_tree(self):
121 """Focus the files tree"""
122 self.tree.setFocus()
124 def focus_input(self):
125 """Focus the expression input"""
126 self.expr.setFocus()
128 def text_changed(self, txt):
129 self.diff_expr = txt
130 self.refresh()
132 def refresh(self):
133 """Redo the diff when the expression changes"""
134 if self.diff_expr is not None:
135 self.diff_arg = utils.shell_split(self.diff_expr)
136 elif self.b is None:
137 self.diff_arg = [self.a]
138 else:
139 self.diff_arg = [self.a, self.b]
140 self.refresh_filenames()
142 def refresh_filenames(self):
143 if self.a and self.b is None:
144 filenames = gitcmds.diff_index_filenames(self.a)
145 else:
146 filenames = gitcmds.diff(self.diff_arg)
147 self.tree.set_filenames(filenames, select=True)
149 def tree_selection_changed(self):
150 has_selection = self.tree.has_selection()
151 self.diff_button.setEnabled(has_selection)
152 self.diff_all_button.setEnabled(has_selection)
154 def tree_double_clicked(self, item, column):
155 path = self.tree.filename_from_item(item)
156 left, right = self._left_right_args()
157 cmds.difftool_launch(left=left, right=right, paths=[path])
159 def diff(self, dir_diff=False):
160 paths = self.tree.selected_filenames()
161 left, right = self._left_right_args()
162 cmds.difftool_launch(left=left, right=right, paths=paths,
163 dir_diff=dir_diff)
165 def _left_right_args(self):
166 if self.diff_arg:
167 left = self.diff_arg[0]
168 else:
169 left = None
170 if len(self.diff_arg) > 1:
171 right = self.diff_arg[1]
172 else:
173 right = None
174 return (left, right)
176 def edit(self):
177 paths = self.tree.selected_filenames()
178 cmds.do(cmds.Edit, paths)