1 """This controller handles the compare commits dialog."""
6 from cola
import qtutils
7 from cola
.qobserver
import QObserver
8 from cola
.views
import CompareView
9 from cola
.views
import BranchCompareView
10 from cola
.controllers
.repobrowser
import select_file_from_repo
11 from cola
.controllers
.util
import choose_from_list
13 def compare(model
, parent
):
15 model
.create(descriptions_start
=[], descriptions_end
=[],
16 revisions_start
=[], revisions_end
=[],
17 revision_start
='', revision_end
='',
18 compare_files
=[], num_results
=100,
20 view
= CompareView(parent
)
21 ctl
= CompareController(model
, view
)
24 def branch_compare(model
, parent
):
26 model
.create(left_combo
=['Local', 'Remote'],
27 right_combo
=['Local', 'Remote'],
34 left_list_selected
=False,
35 right_list_selected
=False,
37 view
= BranchCompareView(parent
)
38 ctl
= BranchCompareController(model
, view
)
41 class BranchCompareController(QObserver
):
42 BRANCH_POINT
= '*** Branch Point ***'
43 SANDBOX
= '*** Sandbox ***'
45 def init(self
, model
, view
):
46 self
.add_observables('left_combo', 'right_combo',
47 'left_list', 'right_list',
50 self
.add_callbacks(button_compare
=
51 self
.diff_files_doubleclick
,
53 self
.gen_update_combo_boxes(left
=True),
55 self
.gen_update_combo_boxes(left
=False),
57 self
.update_diff_files
,
59 self
.update_diff_files
)
62 # Pre-select the 0th elements
63 self
.view
.right_combo
.setCurrentIndex(1)
64 item
= self
.view
.left_list
.item(0)
65 self
.view
.left_list
.setCurrentItem(item
)
66 self
.view
.left_list
.setItemSelected(item
, True)
68 item
= self
.view
.right_list
.item(0)
69 self
.view
.right_list
.setCurrentItem(item
)
70 self
.view
.right_list
.setItemSelected(item
, True)
72 def update_diff_files(self
, *rest
):
73 if (not self
.model
.has_param('left_list_item') or
74 not self
.model
.has_param('right_list_item')):
76 left_item
= self
.model
.get_left_list_item()
77 right_item
= self
.model
.get_right_list_item()
78 if (not left_item
or not right_item
or
79 left_item
== right_item
):
80 self
.model
.set_diff_files([])
82 left_item
= self
.get_remote_ref(left_item
)
83 right_item
= self
.get_remote_ref(right_item
)
85 if (left_item
== BranchCompareController
.SANDBOX
or
86 right_item
== BranchCompareController
.SANDBOX
):
87 self
.use_sandbox
= True
88 if left_item
== BranchCompareController
.SANDBOX
:
89 self
.diff_arg
= right_item
91 self
.diff_arg
= left_item
93 self
.diff_arg
= '%s..%s' % (left_item
, right_item
)
94 self
.use_sandbox
= False
96 self
.start
= left_item
99 files
= self
.model
.get_diff_filenames(self
.diff_arg
)
100 self
.model
.set_diff_files(files
)
101 icon
= qtutils
.get_icon('script.png')
102 for idx
in xrange(0, self
.view
.diff_files
.topLevelItemCount()):
103 item
= self
.view
.diff_files
.topLevelItem(idx
)
104 item
.setIcon(0, icon
)
106 def get_diff_arg(self
, start
, end
):
107 if start
== BranchCompareController
.SANDBOX
:
109 elif end
== BranchCompareController
.SANDBOX
:
112 return '%s..%s' % (start
, end
)
114 def get_remote_ref(self
, branch
):
115 if branch
== BranchCompareController
.BRANCH_POINT
:
116 # Compare against the branch point so find the merge-base
117 branch
= self
.model
.get_currentbranch()
118 remote
= self
.model
.get_corresponding_remote_ref()
119 return self
.model
.git
.merge_base(branch
, remote
)
121 # Compare against the remote branch
125 def gen_update_combo_boxes(self
, left
=False):
126 """Returns a closure which modifies the listwidgets based on the
129 def update_combo_boxes(notused
):
131 which
= self
.model
.get_left_combo_item()
134 which
= self
.model
.get_right_combo_item()
139 new_list
= ([BranchCompareController
.SANDBOX
]+
140 self
.model
.get_local_branches())
142 new_list
= ([BranchCompareController
.BRANCH_POINT
] +
143 self
.model
.get_remote_branches())
144 # Update the list widget
145 self
.model
.set_notify(True)
146 self
.model
.set_param(param
, new_list
)
148 return update_combo_boxes
150 def diff_files_doubleclick(self
):
151 tree_widget
= self
.view
.diff_files
152 id_num
, selected
= qtutils
.get_selected_treeitem(tree_widget
)
154 qtutils
.information('Oops!', 'Please select a file to compare')
156 filename
= self
.model
.get_diff_files()[id_num
]
157 self
.__compare
_file
(filename
)
159 def __compare_file(self
, filename
):
162 kwargs
= git
.transform_kwargs(no_prompt
=True,
163 tool
=self
.model
.get_mergetool(),
164 commit
=self
.diff_arg
)
166 kwargs
= git
.transform_kwargs(no_prompt
=True,
167 tool
=self
.model
.get_mergetool(),
170 args
= (['git', 'difftool'] + kwargs
+ ['--', filename
])
174 class CompareController(QObserver
):
175 """Drives the Commit->Compare Commits dialog.
177 def init (self
, model
, view
):
178 self
.add_observables('descriptions_start', 'descriptions_end',
179 'revision_start', 'revision_end',
180 'compare_files', 'num_results',
183 self
.add_actions(num_results
= self
.update_results
)
184 self
.add_actions(show_versions
= self
.update_results
)
186 self
.add_callbacks(descriptions_start
=
187 self
.gen_update_widgets(True),
189 self
.gen_update_widgets(False),
191 self
.compare_selected_file
)
193 revisions
= self
.update_results()
194 last
= len(revisions
)
195 # if we can, preselect the latest commit
197 and self
.view
.descriptions_start
.topLevelItemCount() > last
-1
198 and self
.view
.descriptions_end
.topLevelItemCount() > last
-1):
199 # select the 2nd item on the left treewidget
200 startitem
= self
.view
.descriptions_start
.topLevelItem(last
-2)
201 self
.view
.descriptions_start
.setCurrentItem(startitem
)
202 self
.view
.descriptions_start
.setItemSelected(startitem
, True)
203 # select the 1st item on the right treewidget
204 enditem
= self
.view
.descriptions_end
.topLevelItem(last
-1)
205 self
.view
.descriptions_end
.setCurrentItem(enditem
)
206 self
.view
.descriptions_end
.setItemSelected(enditem
, True)
208 def get_distance_from_end(self
, tree_widget
):
209 item_id
, item_selected
= qtutils
.get_selected_treeitem(tree_widget
)
211 item_count
= tree_widget
.topLevelItemCount()
212 item_delta
= item_count
- item_id
213 return (item_selected
, item_delta
)
215 return (item_selected
, 0)
217 def select_nth_item_from_end(self
, tree_widget
, delta
):
218 """selects an item relative to the end of the treeitem list.
219 We select from the end to properly handle changes in the number of
220 displayed commits."""
221 count
= self
.view
.descriptions_start
.topLevelItemCount()
223 qtutils
.set_selected_item(tree_widget
, idx
)
225 def update_results(self
, *args
):
227 tree_widget
= self
.view
.descriptions_start
228 start_selected
, start_delta
= self
.get_distance_from_end(tree_widget
)
230 tree_widget
= self
.view
.descriptions_end
231 end_selected
, end_delta
= self
.get_distance_from_end(tree_widget
)
233 self
.model
.set_notify(True)
234 show_versions
= self
.model
.get_show_versions()
235 revs
= self
.model
.update_revision_lists(show_versions
=show_versions
)
237 tree_widget
= self
.view
.descriptions_start
238 self
.select_nth_item_from_end(tree_widget
, start_delta
)
241 tree_widget
= self
.view
.descriptions_end
242 self
.select_nth_item_from_end(tree_widget
, end_delta
)
246 def gen_update_widgets(self
, left
=True):
248 self
.update_widgets(left
=left
)
251 def update_widgets(self
, left
=True):
253 tree_widget
= self
.view
.descriptions_start
254 revisions_param
= 'revisions_start'
255 revision_param
= 'revision_start'
257 tree_widget
= self
.view
.descriptions_end
258 revisions_param
= 'revisions_end'
259 revision_param
= 'revision_end'
261 id_num
, selected
= qtutils
.get_selected_treeitem(tree_widget
)
264 revision
= self
.model
.get_param(revisions_param
)[id_num
]
265 self
.model
.set_param(revision_param
, revision
)
267 # get the changed files list
268 start
= self
.model
.get_revision_start()
269 end
= self
.model
.get_revision_end()
270 files
= self
.model
.get_changed_files(start
, end
)
272 # get the old name of any renamed files, and prune them
273 # from the changes list
274 renamed_files
= self
.model
.get_renamed_files(start
, end
)
275 for renamed
in renamed_files
:
277 files
.remove(renamed
)
280 self
.model
.set_compare_files(files
)
281 icon
= qtutils
.get_icon('script.png')
282 for idx
in xrange(0, self
.view
.compare_files
.topLevelItemCount()):
283 item
= self
.view
.compare_files
.topLevelItem(idx
)
284 item
.setIcon(0, icon
)
285 qtutils
.set_clipboard(self
.model
.get_param(revision_param
))
287 def compare_selected_file(self
):
288 tree_widget
= self
.view
.compare_files
289 id_num
, selected
= qtutils
.get_selected_treeitem(tree_widget
)
291 qtutils
.information('Oops!', 'Please select a file to compare')
293 filename
= self
.model
.get_compare_files()[id_num
]
294 self
.__compare
_file
(filename
)
296 def compare_files_doubleclick(self
, tree_item
, column
):
297 idx
= self
.view
.compare_files
.indexOfTopLevelItem(tree_item
)
298 filename
= self
.model
.get_compare_files()[idx
]
299 self
.__compare
_file
(filename
)
301 def __compare_file(self
, filename
):
303 start
= self
.model
.get_revision_start()
304 end
= self
.model
.get_revision_end()
305 kwargs
= git
.transform_kwargs(no_prompt
=True,
306 tool
=self
.model
.get_mergetool(),
309 args
= (['git', 'difftool'] + kwargs
+ ['--', filename
])