classic: Use a QWidget for proper window management
[git-cola.git] / cola / difftool.py
blob213f2ea3ef9f40be60365fe1f737ae5e33171978
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 utils
7 from cola import qtutils
8 from cola import gitcmds
9 from cola.widgets import defs
10 from cola.widgets import standard
13 def launch(args):
14 """Launches 'git difftool' with args"""
15 difftool_args = ['git', 'difftool', '--no-prompt']
16 difftool_args.extend(args)
17 utils.fork(difftool_args)
20 def diff_commits(parent, a, b):
21 dlg = FileDiffDialog(parent, a=a, b=b)
22 dlg.show()
23 dlg.raise_()
24 return dlg.exec_() == QtGui.QDialog.Accepted
27 def diff_expression(parent, expr):
28 dlg = FileDiffDialog(parent, expr=expr)
29 dlg.show()
30 dlg.raise_()
31 return dlg.exec_() == QtGui.QDialog.Accepted
34 class FileDiffDialog(QtGui.QDialog):
35 def __init__(self, parent, a=None, b=None, expr=None):
36 super(FileDiffDialog, self).__init__(parent)
37 self.setAttribute(Qt.WA_MacMetalStyle)
38 self.a = a
39 self.b = b
40 self.expr = expr
42 self.setWindowTitle('Select File(s)')
43 self.setWindowModality(QtCore.Qt.WindowModal)
45 self._tree = standard.TreeWidget(self)
46 self._tree.setRootIsDecorated(False)
47 self._tree.setSelectionMode(self._tree.ExtendedSelection)
48 self._tree.setHeaderHidden(True)
50 self._diff_btn = QtGui.QPushButton('Compare')
51 self._diff_btn.setIcon(qtutils.ok_icon())
52 self._diff_btn.setEnabled(False)
54 self._close_btn = QtGui.QPushButton('Close')
55 self._close_btn.setIcon(qtutils.close_icon())
57 self._button_layt = QtGui.QHBoxLayout()
58 self._button_layt.setMargin(0)
59 self._button_layt.addStretch()
60 self._button_layt.addWidget(self._diff_btn)
61 self._button_layt.addWidget(self._close_btn)
63 self._layt = QtGui.QVBoxLayout()
64 self._layt.setMargin(defs.margin)
65 self._layt.setSpacing(defs.spacing)
66 self._layt.addWidget(self._tree)
67 self._layt.addLayout(self._button_layt)
68 self.setLayout(self._layt)
70 qtutils.add_close_action(self)
72 self.connect(self._tree, SIGNAL('itemSelectionChanged()'),
73 self._tree_selection_changed)
75 self.connect(self._tree,
76 SIGNAL('itemDoubleClicked(QTreeWidgetItem*,int)'),
77 self._tree_double_clicked)
79 self.connect(self._diff_btn, SIGNAL('clicked()'), self.diff)
80 self.connect(self._close_btn, SIGNAL('clicked()'), self.close)
82 if self.expr:
83 self.diff_arg = tuple(utils.shell_split(self.expr))
84 elif self.b is None:
85 self.diff_arg = (self.a,)
86 else:
87 self.diff_arg = (self.a, self.b)
89 self.resize(720, 420)
92 def exec_(self):
93 if self.expr:
94 filenames = gitcmds.diff_filenames(*self.diff_arg)
95 elif self.b is None:
96 filenames = gitcmds.diff_index_filenames(self.a)
97 else:
98 filenames = gitcmds.diff_filenames(*self.diff_arg)
100 if not filenames:
101 details = ('"git diff --name-only %s" returned an empty list' %
102 ' '.join(self.diff_arg))
103 self.hide()
104 qtutils.information('git cola',
105 message='No changes to diff',
106 details=details)
107 self.close()
108 return self.Accepted
110 icon = qtutils.file_icon()
111 items = []
112 for filename in filenames:
113 item = QtGui.QTreeWidgetItem()
114 item.setIcon(0, icon)
115 item.setText(0, filename)
116 item.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(filename))
117 items.append(item)
118 self._tree.addTopLevelItems(items)
120 return QtGui.QDialog.exec_(self)
122 def _tree_selection_changed(self):
123 self._diff_btn.setEnabled(bool(self._tree.selectedItems()))
125 def _tree_double_clicked(self, item, column):
126 path = item.data(0, QtCore.Qt.UserRole).toPyObject()
127 launch(self.diff_arg + ('--', unicode(path)))
129 def diff(self):
130 items = self._tree.selectedItems()
131 if not items:
132 return
133 paths = [i.data(0, QtCore.Qt.UserRole).toPyObject() for i in items]
134 for path in paths:
135 launch(self.diff_arg + ('--', unicode(path)))