widgets: Use the brushed metal style in more dialogs
[git-cola.git] / cola / widgets / createbranch.py
blob7c6cd47cbc3d7bd33952d9642b16b42bba7376ea
1 from PyQt4 import QtGui
2 from PyQt4.QtCore import Qt
3 from PyQt4.QtCore import SIGNAL
5 from cola import gitcmds
6 from cola import qt
7 from cola import qtutils
8 from cola import utils
9 from cola.widgets import defs
10 from cola.widgets import standard
11 from cola.main.model import MainModel
14 def create_new_branch(revision=''):
15 """Launches a dialog for creating a new branch"""
16 model = MainModel()
17 model.update_status()
18 view = CreateBranchDialog(model, qtutils.active_window())
19 if revision:
20 view.set_revision(revision)
21 view.show()
22 return view
25 class CreateBranchDialog(standard.Dialog):
26 """A dialog for creating branches."""
28 def __init__(self, model, parent=None):
29 super(CreateBranchDialog, self).__init__(parent=parent)
30 self.setAttribute(Qt.WA_MacMetalStyle)
31 self.model = model
33 self.setWindowTitle(self.tr('Create Branch'))
35 self.branch_name_label = QtGui.QLabel()
36 self.branch_name_label.setText(self.tr('Branch Name'))
38 self.local_branch = QtGui.QLineEdit()
40 self.rev_label = QtGui.QLabel()
41 self.rev_label.setText(self.tr('Revision Expression:'))
43 self.revision = QtGui.QLineEdit()
45 self.local_radio = QtGui.QRadioButton()
46 self.local_radio.setText(self.tr('Local Branch'))
47 self.local_radio.setChecked(True)
49 self.remote_radio = QtGui.QRadioButton()
50 self.remote_radio.setText(self.tr('Tracking Branch'))
52 self.tag_radio = QtGui.QRadioButton()
53 self.tag_radio.setText(self.tr('Tag'))
55 self.branch_list = QtGui.QListWidget()
57 self.update_existing_label = QtGui.QLabel()
58 self.update_existing_label.setText(self.tr('Update Existing Branch:'))
60 self.no_update_radio = QtGui.QRadioButton()
61 self.no_update_radio.setText(self.tr('No'))
63 self.ffwd_only_radio = QtGui.QRadioButton()
64 self.ffwd_only_radio.setText(self.tr('Fast Forward Only'))
65 self.ffwd_only_radio.setChecked(True)
67 self.reset_radio = QtGui.QRadioButton()
68 self.reset_radio.setText(self.tr('Reset'))
70 self.options_bottom_layout = QtGui.QHBoxLayout()
71 self.options_checkbox_layout = QtGui.QVBoxLayout()
73 self.fetch_checkbox = QtGui.QCheckBox()
74 self.fetch_checkbox.setText(self.tr('Fetch Tracking Branch'))
75 self.fetch_checkbox.setChecked(True)
76 self.options_checkbox_layout.addWidget(self.fetch_checkbox)
78 self.checkout_checkbox = QtGui.QCheckBox()
79 self.checkout_checkbox.setText(self.tr('Checkout After Creation'))
80 self.checkout_checkbox.setChecked(True)
81 self.options_checkbox_layout.addWidget(self.checkout_checkbox)
83 self.options_bottom_layout.addLayout(self.options_checkbox_layout)
84 self.options_bottom_layout.addStretch()
86 self.create_button = qt.create_button(text='Create Branch',
87 icon=qtutils.git_icon())
88 self.create_button.setDefault(True)
90 self.cancel_button = qt.create_button(text='Cancel')
92 self.branch_name_layout = QtGui.QHBoxLayout()
93 self.branch_name_layout.addWidget(self.branch_name_label)
94 self.branch_name_layout.addWidget(self.local_branch)
96 self.rev_start_radiobtn_layout = QtGui.QHBoxLayout()
97 self.rev_start_radiobtn_layout.addWidget(self.local_radio)
98 self.rev_start_radiobtn_layout.addWidget(self.remote_radio)
99 self.rev_start_radiobtn_layout.addWidget(self.tag_radio)
100 self.rev_start_radiobtn_layout.addStretch()
102 self.rev_start_textinput_layout = QtGui.QHBoxLayout()
103 self.rev_start_textinput_layout.setMargin(0)
104 self.rev_start_textinput_layout.setSpacing(defs.spacing)
105 self.rev_start_textinput_layout.addWidget(self.rev_label)
106 self.rev_start_textinput_layout.addWidget(self.revision)
108 self.rev_start_group = QtGui.QGroupBox()
109 self.rev_start_group.setTitle(self.tr('Starting Revision'))
111 self.rev_start_layout = QtGui.QVBoxLayout(self.rev_start_group)
112 self.rev_start_layout.setMargin(defs.margin)
113 self.rev_start_layout.setSpacing(defs.spacing)
114 self.rev_start_layout.addLayout(self.rev_start_radiobtn_layout)
115 self.rev_start_layout.addWidget(self.branch_list)
116 self.rev_start_layout.addLayout(self.rev_start_textinput_layout)
118 self.options_radio_layout = QtGui.QHBoxLayout()
119 self.options_radio_layout.addWidget(self.update_existing_label)
120 self.options_radio_layout.addWidget(self.no_update_radio)
121 self.options_radio_layout.addWidget(self.ffwd_only_radio)
122 self.options_radio_layout.addWidget(self.reset_radio)
124 self.option_group = QtGui.QGroupBox()
125 self.option_group.setTitle(self.tr('Options'))
127 self.options_grp_layout = QtGui.QVBoxLayout(self.option_group)
128 self.options_grp_layout.setMargin(defs.margin)
129 self.options_grp_layout.setSpacing(defs.spacing)
130 self.options_grp_layout.addLayout(self.options_radio_layout)
131 self.options_grp_layout.addLayout(self.options_bottom_layout)
133 self.buttons_layout = QtGui.QHBoxLayout()
134 self.buttons_layout.setMargin(defs.margin)
135 self.buttons_layout.setSpacing(defs.spacing)
136 self.buttons_layout.addWidget(self.create_button)
137 self.buttons_layout.addWidget(self.cancel_button)
139 self.options_section_layout = QtGui.QHBoxLayout()
140 self.options_section_layout.setMargin(defs.margin)
141 self.options_section_layout.setSpacing(defs.spacing)
142 self.options_section_layout.addWidget(self.option_group)
143 self.options_section_layout.addLayout(self.buttons_layout)
145 self.main_layout = QtGui.QVBoxLayout()
146 self.main_layout.setMargin(defs.margin)
147 self.main_layout.setSpacing(defs.spacing)
148 self.main_layout.addLayout(self.branch_name_layout)
149 self.main_layout.addWidget(self.rev_start_group)
150 self.main_layout.addLayout(self.options_section_layout)
151 self.setLayout(self.main_layout)
153 qtutils.connect_button(self.cancel_button, self.reject)
154 qtutils.connect_button(self.create_button, self.create_branch)
155 qtutils.connect_button(self.local_radio, self.display_model)
156 qtutils.connect_button(self.remote_radio, self.display_model)
157 qtutils.connect_button(self.tag_radio, self.display_model)
159 self.connect(self.branch_list, SIGNAL('itemSelectionChanged()'),
160 self.branch_item_changed)
162 if self.parent():
163 self.resize(self.parent().width(), self.parent().height())
164 else:
165 self.resize(555, 333)
167 self.display_model()
169 def set_revision(self, revision):
170 self.revision.setText(revision)
172 def create_branch(self):
173 """Creates a branch; called by the "Create Branch" button"""
175 revision = unicode(self.revision.text())
176 branch = unicode(self.local_branch.text())
177 existing_branches = self.model.local_branches
179 if not branch or not revision:
180 qtutils.critical('Missing Data',
181 'Please provide both a branch '
182 'name and revision expression.')
183 return
185 check_branch = False
186 if branch in existing_branches:
187 if self.no_update_radio.isChecked():
188 msg = self.tr("Branch '%s' already exists.")
189 msg = unicode(msg) % branch
190 qtutils.critical('Branch Exists', msg)
191 return
192 # Whether we should prompt the user for lost commits
193 commits = gitcmds.rev_list_range(revision, branch)
194 check_branch = bool(commits)
196 if check_branch:
197 msg = self.tr("Resetting '%s' to '%s' will "
198 "lose the following commits:")
199 lines = [ unicode(msg) % (branch, revision) ]
201 for idx, commit in enumerate(commits):
202 subject = commit[1][0:min(len(commit[1]),16)]
203 if len(subject) < len(commit[1]):
204 subject += '...'
205 lines.append('\t' + commit[0][:8]
206 +'\t' + subject)
207 if idx >= 5:
208 skip = len(commits) - 5
209 lines.append('\t(%d skipped)' % skip)
210 break
212 lines.extend([
213 unicode(self.tr('Recovering lost commits may not be easy.')),
216 if not qtutils.confirm('Reset Branch?',
217 '\n'.join(lines),
218 'Reset "%s" to "%s"?' % (branch, revision),
219 'Reset Branch',
220 default=False,
221 icon=qtutils.icon('undo.svg')):
222 return
224 # TODO handle fetch
225 track = self.remote_radio.isChecked()
226 fetch = self.fetch_checkbox.isChecked()
227 ffwd = self.ffwd_only_radio.isChecked()
228 reset = self.reset_radio.isChecked()
229 chkout = self.checkout_checkbox.isChecked()
231 status, output = self.model.create_branch(branch, revision, track=track)
232 qtutils.log(status, output)
233 if status == 0 and chkout:
234 status, output = self.model.git.checkout(branch,
235 with_status=True,
236 with_stderr=True)
237 qtutils.log(status, output)
238 self.accept()
240 def branch_item_changed(self, *rest):
241 """This callback is called when the branch selection changes"""
243 # When the branch selection changes then we should update
244 # the "Revision Expression" accordingly.
245 qlist = self.branch_list
246 (row, selected) = qtutils.selected_row(qlist)
247 if not selected:
248 return
250 sources = self.branch_sources()
251 rev = sources[row]
253 # Update the model with the selection
254 self.revision.setText(rev)
256 # Only set the branch name field if we're
257 # branching from a remote branch.
258 if not self.remote_radio.isChecked():
259 return
260 branch = utils.basename(rev)
261 if branch == 'HEAD':
262 return
264 # Signal that we've clicked on a remote branch
265 self.local_branch.setText(branch)
267 def display_model(self):
268 """Sets the branch list to the available branches
270 branches = self.branch_sources()
271 qtutils.set_items(self.branch_list, branches)
273 def branch_sources(self):
274 """Get the list of items for populating the branch root list.
276 if self.local_radio.isChecked():
277 return self.model.local_branches
278 elif self.remote_radio.isChecked():
279 return self.model.remote_branches
280 elif self.tag_radio.isChecked():
281 return self.model.tags