cmds: check for errors when visualizing history
[git-cola.git] / cola / difftool.py
bloba9be720d4e249f057ef7b7048d30d27e6a635727
1 from PyQt4 import QtGui
2 from PyQt4 import QtCore
3 from PyQt4.QtCore import Qt
4 from PyQt4.QtCore import SIGNAL
6 from cola import core
7 from cola import utils
8 from cola import qtutils
9 from cola import gitcmds
10 from cola.i18n import N_
11 from cola.models import main
12 from cola.models import selection
13 from cola.widgets import completion
14 from cola.widgets import defs
15 from cola.widgets import standard
18 def run():
19 files = selection.selected_group()
20 if not files:
21 return
22 s = selection.selection()
23 model = main.model()
24 launch_with_head(files, bool(s.staged), model.head)
27 def launch_with_head(filenames, staged, head):
28 args = []
29 if staged:
30 args.append('--cached')
31 if head != 'HEAD':
32 args.append(head)
33 args.append('--')
34 args.extend(filenames)
35 launch(args)
38 def launch(args):
39 """Launches 'git difftool' with args"""
40 difftool_args = ['git', 'difftool', '--no-prompt']
41 difftool_args.extend(args)
42 core.fork(difftool_args)
45 def diff_commits(parent, a, b):
46 dlg = FileDiffDialog(parent, a=a, b=b)
47 dlg.show()
48 dlg.raise_()
49 return dlg.exec_() == QtGui.QDialog.Accepted
52 def diff_expression(parent, expr,
53 create_widget=False, hide_expr=False):
54 dlg = FileDiffDialog(parent, expr=expr, hide_expr=hide_expr)
55 if create_widget:
56 return dlg
57 dlg.show()
58 dlg.raise_()
59 return dlg.exec_() == QtGui.QDialog.Accepted
62 class FileDiffDialog(QtGui.QDialog):
64 def __init__(self, parent, a=None, b=None, expr=None, title=None,
65 hide_expr=False):
66 QtGui.QDialog.__init__(self, parent)
67 self.setAttribute(Qt.WA_MacMetalStyle)
69 self.a = a
70 self.b = b
71 self.expr = expr
73 if title is None:
74 title = N_('git-cola diff')
76 self.setWindowTitle(title)
77 self.setWindowModality(QtCore.Qt.WindowModal)
79 self._expr = completion.GitRefLineEdit(parent=self)
80 if expr is not None:
81 self._expr.setText(expr)
83 if expr is None or hide_expr:
84 self._expr.hide()
86 self._tree = standard.TreeWidget(self)
87 self._tree.setSelectionMode(self._tree.ExtendedSelection)
88 self._tree.setHeaderHidden(True)
90 self._diff_btn = QtGui.QPushButton(N_('Compare'))
91 self._diff_btn.setIcon(qtutils.ok_icon())
92 self._diff_btn.setEnabled(False)
94 self._close_btn = QtGui.QPushButton(N_('Close'))
95 self._close_btn.setIcon(qtutils.close_icon())
97 self._button_layt = QtGui.QHBoxLayout()
98 self._button_layt.setMargin(0)
99 self._button_layt.addStretch()
100 self._button_layt.addWidget(self._diff_btn)
101 self._button_layt.addWidget(self._close_btn)
103 self._layt = QtGui.QVBoxLayout()
104 self._layt.setMargin(defs.margin)
105 self._layt.setSpacing(defs.spacing)
107 self._layt.addWidget(self._expr)
108 self._layt.addWidget(self._tree)
109 self._layt.addLayout(self._button_layt)
110 self.setLayout(self._layt)
112 self.connect(self._tree, SIGNAL('itemSelectionChanged()'),
113 self._tree_selection_changed)
115 self.connect(self._tree,
116 SIGNAL('itemDoubleClicked(QTreeWidgetItem*,int)'),
117 self._tree_double_clicked)
119 self.connect(self._expr, SIGNAL('textChanged(QString)'),
120 self.text_changed)
122 self.connect(self._expr, SIGNAL('returnPressed()'),
123 self.refresh)
125 qtutils.connect_button(self._diff_btn, self.diff)
126 qtutils.connect_button(self._close_btn, self.close)
127 qtutils.add_close_action(self)
129 self.resize(720, 420)
130 self.refresh()
132 def text_changed(self, txt):
133 self.expr = unicode(txt)
134 self.refresh()
136 def refresh(self):
137 if self.expr is not None:
138 self.diff_arg = utils.shell_split(self.expr)
139 elif self.b is None:
140 self.diff_arg = [self.a]
141 else:
142 self.diff_arg = [self.a, self.b]
143 self.refresh_filenames()
145 def refresh_filenames(self):
146 self._tree.clear()
148 if self.a and self.b is None:
149 filenames = gitcmds.diff_index_filenames(self.a)
150 else:
151 filenames = gitcmds.diff(self.diff_arg)
152 if not filenames:
153 return
155 icon = qtutils.file_icon()
156 items = []
157 for filename in filenames:
158 item = QtGui.QTreeWidgetItem()
159 item.setIcon(0, icon)
160 item.setText(0, filename)
161 item.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(filename))
162 items.append(item)
163 self._tree.addTopLevelItems(items)
165 def _tree_selection_changed(self):
166 self._diff_btn.setEnabled(bool(self._tree.selectedItems()))
168 def _tree_double_clicked(self, item, column):
169 path = item.data(0, QtCore.Qt.UserRole).toPyObject()
170 launch(self.diff_arg + ['--', unicode(path)])
172 def diff(self):
173 items = self._tree.selectedItems()
174 if not items:
175 return
176 paths = [i.data(0, QtCore.Qt.UserRole).toPyObject() for i in items]
177 for path in paths:
178 launch(self.diff_arg + ['--', unicode(path)])