widgets.remote: retain focus when showing remote messages
[git-cola.git] / cola / widgets / merge.py
blob4a9407fe7d02d685eace8cfb80effa49ec6a489d
1 from qtpy import QtWidgets
2 from qtpy.QtCore import Qt
4 from ..i18n import N_
5 from ..interaction import Interaction
6 from ..qtutils import get
7 from .. import cmds
8 from .. import icons
9 from .. import qtutils
10 from . import completion
11 from . import standard
12 from . import defs
15 def local_merge(context):
16 """Provides a dialog for merging branches"""
17 view = Merge(context, qtutils.active_window())
18 view.show()
19 view.raise_()
20 return view
23 class Merge(standard.Dialog):
24 """Provides a dialog for merging branches."""
26 def __init__(self, context, parent=None, ref=None):
27 standard.Dialog.__init__(self, parent=parent)
28 self.context = context
29 self.cfg = cfg = context.cfg
30 self.model = context.model
31 if parent is not None:
32 self.setWindowModality(Qt.WindowModal)
34 # Widgets
35 self.title_label = QtWidgets.QLabel()
36 self.revision_label = QtWidgets.QLabel()
37 self.revision_label.setText(N_('Revision to Merge'))
39 self.revision = completion.GitRefLineEdit(context)
40 self.revision.setToolTip(N_('Revision to Merge'))
41 if ref:
42 self.revision.set_value(ref)
44 self.radio_local = qtutils.radio(text=N_('Local Branch'), checked=True)
45 self.radio_remote = qtutils.radio(text=N_('Tracking Branch'))
46 self.radio_tag = qtutils.radio(text=N_('Tag'))
48 self.revisions = QtWidgets.QListWidget()
49 self.revisions.setAlternatingRowColors(True)
51 self.button_viz = qtutils.create_button(
52 text=N_('Visualize'), icon=icons.visualize()
55 tooltip = N_('Squash the merged commits into a single commit')
56 self.checkbox_squash = qtutils.checkbox(text=N_('Squash'), tooltip=tooltip)
58 tooltip = N_(
59 'Always create a merge commit when enabled, '
60 'even when the merge is a fast-forward update'
62 self.checkbox_noff = qtutils.checkbox(
63 text=N_('No fast forward'), tooltip=tooltip, checked=False
65 self.checkbox_noff_state = False
67 tooltip = N_(
68 'Commit the merge if there are no conflicts. '
69 'Uncheck to leave the merge uncommitted'
71 self.checkbox_commit = qtutils.checkbox(
72 text=N_('Commit'), tooltip=tooltip, checked=True
74 self.checkbox_commit_state = True
76 text = N_('Create Signed Commit')
77 checked = cfg.get('cola.signcommits', False)
78 tooltip = N_('GPG-sign the merge commit')
79 self.checkbox_sign = qtutils.checkbox(
80 text=text, checked=checked, tooltip=tooltip
82 self.button_close = qtutils.close_button()
84 icon = icons.merge()
85 self.button_merge = qtutils.create_button(
86 text=N_('Merge'), icon=icon, default=True
89 # Layouts
90 self.revlayt = qtutils.hbox(
91 defs.no_margin,
92 defs.spacing,
93 self.revision_label,
94 self.revision,
95 qtutils.STRETCH,
96 self.title_label,
99 self.radiolayt = qtutils.hbox(
100 defs.no_margin,
101 defs.spacing,
102 self.radio_local,
103 self.radio_remote,
104 self.radio_tag,
107 self.buttonlayt = qtutils.hbox(
108 defs.no_margin,
109 defs.button_spacing,
110 self.button_viz,
111 self.checkbox_squash,
112 self.checkbox_noff,
113 self.checkbox_commit,
114 self.checkbox_sign,
115 qtutils.STRETCH,
116 self.button_close,
117 self.button_merge,
120 self.mainlayt = qtutils.vbox(
121 defs.margin,
122 defs.spacing,
123 self.radiolayt,
124 self.revisions,
125 self.revlayt,
126 self.buttonlayt,
128 self.setLayout(self.mainlayt)
130 # Signal/slot connections
131 # pylint: disable=no-member
132 self.revision.textChanged.connect(self.update_title)
133 self.revision.enter.connect(self.merge_revision)
134 self.revisions.itemSelectionChanged.connect(self.revision_selected)
136 qtutils.connect_released(self.radio_local, self.update_revisions)
137 qtutils.connect_released(self.radio_remote, self.update_revisions)
138 qtutils.connect_released(self.radio_tag, self.update_revisions)
139 qtutils.connect_button(self.button_merge, self.merge_revision)
140 qtutils.connect_button(self.checkbox_squash, self.toggle_squash)
141 qtutils.connect_button(self.button_viz, self.viz_revision)
142 qtutils.connect_button(self.button_close, self.reject)
144 # Observer messages
145 self.model.updated.connect(self.update_all)
146 self.update_all()
148 self.init_size(parent=parent)
149 self.revision.setFocus()
151 def update_all(self):
152 """Set the branch name for the window title and label."""
153 self.update_title()
154 self.update_revisions()
156 def update_title(self, _txt=None):
157 branch = self.model.currentbranch
158 revision = self.revision.text()
159 if revision:
160 txt = N_('Merge "%(revision)s" into "%(branch)s"') % {
161 'revision': revision,
162 'branch': branch,
164 else:
165 txt = N_('Merge into "%s"') % branch
166 self.button_merge.setEnabled(bool(revision))
167 self.title_label.setText(txt)
168 self.setWindowTitle(txt)
170 def toggle_squash(self):
171 """Toggles the commit checkbox based on the squash checkbox."""
172 if get(self.checkbox_squash):
173 self.checkbox_commit_state = self.checkbox_commit.checkState()
174 self.checkbox_commit.setCheckState(Qt.Unchecked)
175 self.checkbox_commit.setDisabled(True)
176 self.checkbox_noff_state = self.checkbox_noff.checkState()
177 self.checkbox_noff.setCheckState(Qt.Unchecked)
178 self.checkbox_noff.setDisabled(True)
179 else:
180 self.checkbox_noff.setDisabled(False)
181 oldstateff = self.checkbox_noff_state
182 self.checkbox_noff.setCheckState(oldstateff)
183 self.checkbox_commit.setDisabled(False)
184 oldstate = self.checkbox_commit_state
185 self.checkbox_commit.setCheckState(oldstate)
187 def update_revisions(self):
188 """Update the revision list whenever a radio button is clicked"""
189 self.revisions.clear()
190 self.revisions.addItems(self.current_revisions())
192 def revision_selected(self):
193 """Update the revision field when a list item is selected"""
194 revlist = self.current_revisions()
195 widget = self.revisions
196 revision = qtutils.selected_item(widget, revlist)
197 if revision is not None:
198 self.revision.setText(revision)
200 def current_revisions(self):
201 """Retrieve candidate items to merge"""
202 if get(self.radio_local):
203 return self.model.local_branches
204 if get(self.radio_remote):
205 return self.model.remote_branches
206 if get(self.radio_tag):
207 return self.model.tags
208 return []
210 def viz_revision(self):
211 """Launch a gitk-like viewer on the selection revision"""
212 revision = self.revision.text()
213 if not revision:
214 Interaction.information(
215 N_('No Revision Specified'), N_('You must specify a revision to view.')
217 return
218 cmds.do(cmds.VisualizeRevision, self.context, revision)
220 def merge_revision(self):
221 """Merge the selected revision/branch"""
222 revision = self.revision.text()
223 if not revision:
224 Interaction.information(
225 N_('No Revision Specified'), N_('You must specify a revision to merge.')
227 return
229 noff = get(self.checkbox_noff)
230 no_commit = not get(self.checkbox_commit)
231 squash = get(self.checkbox_squash)
232 sign = get(self.checkbox_sign)
233 context = self.context
234 cmds.do(cmds.Merge, context, revision, no_commit, squash, noff, sign)
235 self.accept()
237 def export_state(self):
238 """Export persistent settings"""
239 state = super().export_state()
240 state['no-ff'] = get(self.checkbox_noff)
241 state['sign'] = get(self.checkbox_sign)
242 state['commit'] = get(self.checkbox_commit)
243 return state
245 def apply_state(self, state):
246 """Apply persistent settings"""
247 result = super().apply_state(state)
248 self.checkbox_noff.setChecked(state.get('no-ff', False))
249 self.checkbox_sign.setChecked(state.get('sign', False))
250 self.checkbox_commit.setChecked(state.get('commit', True))
251 return result