requirements: install newer versions of send2trash
[git-cola.git] / cola / widgets / selectcommits.py
blob11bc851ee3ef1d25d9b855ebf2e99c96e18bd3c2
1 """A GUI for selecting commits"""
3 from qtpy import QtWidgets
4 from qtpy.QtCore import Qt
6 from .. import gitcmds
7 from .. import qtutils
8 from ..i18n import N_
9 from ..icons import folder
10 from ..interaction import Interaction
11 from ..models import prefs
12 from . import completion
13 from . import defs
14 from .diff import DiffTextEdit
15 from .standard import Dialog
18 def select_commits(context, title, revs, summaries, multiselect=True):
19 """Use the SelectCommits to select commits from a list."""
20 model = Model(revs, summaries)
21 parent = qtutils.active_window()
22 dialog = SelectCommits(context, model, parent, title, multiselect=multiselect)
23 return dialog.select_commits()
26 def select_commits_and_output(context, title, revs, summaries, multiselect=True):
27 """Select commits from a list and output path"""
28 model = Model(revs, summaries)
29 parent = qtutils.active_window()
30 dialog = SelectCommitsAndOutput(
31 context, model, parent, title, multiselect=multiselect
33 return dialog.select_commits_and_output()
36 class Model:
37 def __init__(self, revs, summaries):
38 self.revisions = revs
39 self.summaries = summaries
42 class SelectCommits(Dialog):
43 def __init__(self, context, model, parent=None, title=None, multiselect=True):
44 Dialog.__init__(self, parent)
45 self.context = context
46 self.model = model
47 if title:
48 self.setWindowTitle(title)
50 if multiselect:
51 mode = QtWidgets.QAbstractItemView.ExtendedSelection
52 else:
53 mode = QtWidgets.QAbstractItemView.SingleSelection
54 commits = self.commits = QtWidgets.QListWidget()
55 commits.setSelectionMode(mode)
56 commits.setAlternatingRowColors(True)
58 self.commit_text = DiffTextEdit(context, self, whitespace=False)
60 self.revision_label = QtWidgets.QLabel()
61 self.revision_label.setText(N_('Revision Expression:'))
62 self.revision = completion.GitRefLineEdit(context)
63 self.revision.setReadOnly(True)
65 self.search_label = QtWidgets.QLabel()
66 self.search_label.setText(N_('Search:'))
67 self.search = QtWidgets.QLineEdit()
68 self.search.setReadOnly(False)
70 # pylint: disable=no-member
71 self.search.textChanged.connect(self.search_list)
73 self.select_button = qtutils.ok_button(N_('Select'), enabled=False)
75 # Make the list widget slightly larger
76 self.splitter = qtutils.splitter(Qt.Vertical, self.commits, self.commit_text)
77 self.splitter.setSizes([100, 150])
79 self.input_layout = qtutils.hbox(
80 defs.no_margin,
81 defs.spacing,
82 self.search_label,
83 self.search,
84 qtutils.STRETCH,
85 self.revision_label,
86 self.revision,
87 self.select_button,
90 self.main_layout = qtutils.vbox(
91 defs.margin, defs.margin, self.input_layout, self.splitter
93 self.setLayout(self.main_layout)
95 # pylint: disable=no-member
96 commits.itemSelectionChanged.connect(self.commit_oid_selected)
97 commits.itemDoubleClicked.connect(self.commit_oid_double_clicked)
99 qtutils.connect_button(self.select_button, self.accept)
101 self.init_state(None, self.resize_widget, parent)
103 def resize_widget(self, parent):
104 """Set the initial size of the widget"""
105 width, height = qtutils.default_size(parent, 720, 480)
106 self.resize(width, height)
108 def selected_commit(self):
109 return qtutils.selected_item(self.commits, self.model.revisions)
111 def selected_commits(self):
112 return qtutils.selected_items(self.commits, self.model.revisions)
114 def select_commits(self):
115 summaries = self.model.summaries
116 if not summaries:
117 msg = N_('No commits exist in this branch.')
118 Interaction.log(msg)
119 return []
120 qtutils.set_items(self.commits, summaries)
121 self.show()
122 if self.exec_() != QtWidgets.QDialog.Accepted:
123 return []
124 return self.selected_commits()
126 def commit_oid_selected(self):
127 context = self.context
128 oid = self.selected_commit()
129 selected = oid is not None
130 self.select_button.setEnabled(selected)
131 if not selected:
132 self.commit_text.set_value('')
133 self.revision.setText('')
134 return
135 self.revision.setText(oid)
136 self.revision.selectAll()
137 # Display the oid's commit
138 commit_diff = gitcmds.commit_diff(context, oid)
139 self.commit_text.setText(commit_diff)
141 def commit_oid_double_clicked(self, _item):
142 oid = self.selected_commit()
143 if oid:
144 self.accept()
146 def search_list(self, text):
147 if text:
148 for i in range(self.commits.count()):
149 self.commits.item(i).setHidden(True)
150 search_items = self.commits.findItems(text, Qt.MatchContains)
151 for items in search_items:
152 items.setHidden(False)
155 class SelectCommitsAndOutput(SelectCommits):
156 def __init__(self, context, model, parent=None, title=None, multiselect=True):
157 SelectCommits.__init__(self, context, model, parent, title, multiselect)
159 self.output_dir = prefs.patches_directory(context)
160 self.select_output = qtutils.create_button(
161 tooltip=N_('Select output dir'), icon=folder()
163 self.output_text = QtWidgets.QLineEdit()
164 self.output_text.setReadOnly(True)
165 self.output_text.setText(self.output_dir)
167 output_layout = qtutils.hbox(
168 defs.no_margin, defs.no_spacing, self.select_output, self.output_text
171 self.input_layout.insertLayout(1, output_layout)
172 qtutils.connect_button(self.select_output, self.show_output_dialog)
174 def select_commits_and_output(self):
175 to_export = SelectCommits.select_commits(self)
176 output = self.output_dir
178 return {'to_export': to_export, 'output': output}
180 def show_output_dialog(self):
181 self.output_dir = qtutils.opendir_dialog(
182 N_('Select output directory'), self.output_dir
184 if not self.output_dir:
185 return
187 self.output_text.setText(self.output_dir)