4 from PyQt4
import QtGui
5 from PyQt4
import QtCore
6 from PyQt4
.QtGui
import QDialog
7 from PyQt4
.QtGui
import QMessageBox
8 from PyQt4
.QtGui
import QMenu
9 from qobserver
import QObserver
14 from views
import GitPushDialog
15 from views
import GitBranchDialog
16 from views
import GitCreateBranchDialog
17 from views
import GitCommitBrowser
18 from repobrowsercontroller
import GitRepoBrowserController
19 from createbranchcontroller
import GitCreateBranchController
20 from pushcontroller
import GitPushController
22 class GitController(QObserver
):
23 '''The controller is a mediator between the model and view.
24 It allows for a clean decoupling between view and model classes.'''
26 def __init__(self
, model
, view
):
27 QObserver
.__init
__(self
, model
, view
)
29 # The diff-display context menu
31 self
.__staged
_diff
_in
_view
= True
33 # Diff display context menu
34 view
.displayText
.controller
= self
35 view
.displayText
.contextMenuEvent
= self
.__menu
_event
37 # Default to creating a new commit(i.e. not an amend commit)
38 view
.newCommitRadio
.setChecked(True)
40 # Binds a specific model attribute to a view widget,
42 self
.model_to_view('commitmsg', 'commitText')
43 self
.model_to_view('staged', 'stagedList')
44 self
.model_to_view('all_unstaged', 'unstagedList')
46 # When a model attribute changes, this runs a specific action
47 self
.add_actions('staged', self
.action_staged
)
48 self
.add_actions('all_unstaged', self
.action_all_unstaged
)
50 # Routes signals for multiple widgets to our callbacks
52 self
.add_signals('textChanged()', view
.commitText
)
53 self
.add_signals('stateChanged(int)', view
.untrackedCheckBox
)
55 self
.add_signals('released()',
56 view
.stageButton
, view
.commitButton
,
57 view
.pushButton
, view
.signOffButton
,)
59 self
.add_signals('triggered()',
61 view
.createBranch
, view
.checkoutBranch
,
62 view
.rebaseBranch
, view
.deleteBranch
,
63 view
.setCommitMessage
, view
.commit
,
64 view
.stageChanged
, view
.stageUntracked
,
65 view
.stageSelected
, view
.unstageAll
,
68 view
.browseBranch
, view
.browseOtherBranch
,
69 view
.visualizeAll
, view
.visualizeCurrent
,
70 view
.exportPatches
, view
.cherryPick
,
72 view
.cut
, view
.copy
, view
.paste
, view
.delete
,
73 view
.selectAll
, view
.undo
, view
.redo
,)
75 self
.add_signals('itemClicked(QListWidgetItem *)',
76 view
.stagedList
, view
.unstagedList
,)
78 self
.add_signals('itemSelectionChanged()',
79 view
.stagedList
, view
.unstagedList
,)
81 self
.add_signals('splitterMoved(int,int)',
82 view
.splitter_top
, view
.splitter_bottom
)
85 self
.connect(QtGui
.qApp
, 'lastWindowClosed()',
86 self
.last_window_closed
)
88 # These callbacks are called in response to the signals
89 # defined above. One property of the QObserver callback
90 # mechanism is that the model is passed in as the first
91 # argument to the callback. This allows for a single
92 # controller to manage multiple models, though this
93 # isn't used at the moment.
95 # Actions that delegate directly to the model
96 'signOffButton': model
.add_signoff
,
97 'setCommitMessage': model
.get_prev_commitmsg
,
99 'stageButton': self
.stage_selected
,
100 'commitButton': self
.commit
,
101 'pushButton': self
.push
,
103 'stagedList': self
.diff_staged
,
104 'unstagedList': self
.diff_unstaged
,
106 'untrackedCheckBox': self
.rescan
,
108 'rescan': self
.rescan
,
109 'createBranch': self
.branch_create
,
110 'deleteBranch': self
.branch_delete
,
111 'checkoutBranch': self
.checkout_branch
,
112 'rebaseBranch': self
.rebase
,
113 'commit': self
.commit
,
114 'stageChanged': self
.stage_changed
,
115 'stageUntracked': self
.stage_untracked
,
116 'stageSelected': self
.stage_selected
,
117 'unstageAll': self
.unstage_all
,
118 'unstageSelected': self
.unstage_selected
,
119 'showDiffstat': self
.show_diffstat
,
120 'browseBranch': self
.browse_current
,
121 'browseOtherBranch': self
.browse_other
,
122 'visualizeCurrent': self
.viz_current
,
123 'visualizeAll': self
.viz_all
,
124 'exportPatches': self
.export_patches
,
125 'cherryPick': self
.cherry_pick
,
126 'loadCommitMsg': self
.load_commitmsg
,
130 'delete': self
.delete
,
131 'selectAll': self
.select_all
,
132 'undo': self
.view
.commitText
.undo
,
135 'splitter_top': self
.splitter_top_event
,
136 'splitter_bottom': self
.splitter_bottom_event
,
139 # Handle double-clicks in the staged/unstaged lists.
140 # These are vanilla signal/slots since the qobserver
141 # signal routing is already handling these lists' signals.
142 self
.connect(view
.unstagedList
,
143 'itemDoubleClicked(QListWidgetItem*)',
146 self
.connect(view
.stagedList
,
147 'itemDoubleClicked(QListWidgetItem*)',
148 self
.unstage_selected
)
150 # Delegate window move events here
151 self
.view
.moveEvent
= self
.move_event
152 self
.view
.resizeEvent
= self
.resize_event
155 self
.__read
_config
_settings
()
158 # Setup the inotify watchdog
159 self
.__start
_inotify
_thread
()
161 #####################################################################
162 # Actions triggered during model updates
164 def action_staged(self
, widget
):
165 self
.__update
_listwidget
(widget
,
166 self
.model
.get_staged(), staged
=True)
168 def action_all_unstaged(self
, widget
):
169 self
.__update
_listwidget
(widget
,
170 self
.model
.get_unstaged(), staged
=False)
172 if self
.view
.untrackedCheckBox
.isChecked():
173 self
.__update
_listwidget
(widget
,
174 self
.model
.get_untracked(),
179 #####################################################################
182 def branch_create(self
):
183 view
= GitCreateBranchDialog(self
.view
)
184 controller
= GitCreateBranchController(self
.model
, view
)
186 result
= view
.exec_()
187 if result
== QDialog
.Accepted
:
190 def branch_delete(self
):
191 dlg
= GitBranchDialog(self
.view
, branches
=cmds
.git_branch())
192 branch
= dlg
.getSelectedBranch()
193 if not branch
: return
194 qtutils
.show_command(self
.view
,
195 cmds
.git_branch(name
=branch
, delete
=True))
197 def browse_current(self
):
198 self
.__browse
_branch
(cmds
.git_current_branch())
200 def browse_other(self
):
201 # Prompt for a branch to browse
202 branches
= self
.model
.all_branches()
203 dialog
= GitBranchDialog(self
.view
, branches
=branches
)
205 # Launch the repobrowser
206 self
.__browse
_branch
(dialog
.getSelectedBranch())
208 def checkout_branch(self
):
209 dlg
= GitBranchDialog(self
.view
, cmds
.git_branch())
210 branch
= dlg
.getSelectedBranch()
211 if not branch
: return
212 qtutils
.show_command(self
.view
, cmds
.git_checkout(branch
))
215 def cherry_pick(self
):
216 '''Starts a cherry-picking session.'''
217 (revs
, summaries
) = cmds
.git_log(all
=True)
218 selection
, idxs
= self
.__select
_commits
(revs
, summaries
)
219 if not selection
: return
220 output
= cmds
.git_cherry_pick(selection
)
221 self
.__show
_command
(self
.tr(output
))
224 '''Sets up data and calls cmds.commit.'''
225 msg
= self
.model
.get_commitmsg()
227 error_msg
= self
.tr(""
228 + "Please supply a commit message.\n"
230 + "A good commit message has the following format:\n"
232 + "- First line: Describe in one sentence what you did.\n"
233 + "- Second line: Blank\n"
234 + "- Remaining lines: Describe why this change is good.\n")
236 self
.__show
_command
(error_msg
)
239 files
= self
.model
.get_staged()
242 + "No changes to commit.\n"
244 + "You must stage at least 1 file before you can commit.\n")
245 self
.__show
_command
(errmsg
)
249 output
= cmds
.git_commit(msg
,
250 amend
=self
.view
.amendRadio
.isChecked())
253 self
.view
.newCommitRadio
.setChecked(True)
254 self
.view
.amendRadio
.setChecked(False)
255 self
.model
.set_commitmsg('')
256 self
.__show
_command
(output
)
258 def commit_sha1_selected(self
, browser
, revs
):
259 '''This callback is called when a commit browser's
260 item is selected. This callback puts the current
261 revision sha1 into the commitText field.
262 This callback also puts shows the commit in the
263 browser's commit textedit and copies it into
264 the global clipboard/selection.'''
265 current
= browser
.commitList
.currentRow()
266 item
= browser
.commitList
.item(current
)
267 if not item
.isSelected():
268 browser
.commitText
.setText('')
269 browser
.revisionLine
.setText('')
272 # Get the sha1 and put it in the revision line
274 browser
.revisionLine
.setText(sha1
)
275 browser
.revisionLine
.selectAll()
277 # Lookup the sha1's commit
278 commit_diff
= cmds
.git_diff(commit
=sha1
,cached
=False)
279 browser
.commitText
.setText(commit_diff
)
281 # Copy the sha1 into the clipboard
282 qtutils
.set_clipboard(sha1
)
284 # use *rest to handle being called from different signals
285 def diff_staged(self
, *rest
):
286 self
.__staged
_diff
_in
_view
= True
287 widget
= self
.view
.stagedList
288 row
, selected
= qtutils
.get_selected_row(widget
)
291 self
.__reset
_display
()
294 filename
= self
.model
.get_staged()[row
]
295 diff
= cmds
.git_diff(filename
=filename
, cached
=True)
297 if os
.path
.exists(filename
):
298 self
.__set
_info
(self
.tr('Staged for commit'))
300 self
.__set
_info
(self
.tr('Staged for removal'))
302 self
.view
.displayText
.setText(diff
)
304 # use *rest to handle being called from different signals
305 def diff_unstaged(self
,*rest
):
306 self
.__staged
_diff
_in
_view
= False
307 widget
= self
.view
.unstagedList
309 row
, selected
= qtutils
.get_selected_row(widget
)
311 self
.__reset
_display
()
314 filename
=(self
.model
.get_unstaged()
315 + self
.model
.get_untracked())[row
]
316 if os
.path
.isdir(filename
):
317 self
.__set
_info
(self
.tr('Untracked directory'))
318 cmd
= 'ls -la %s' % utils
.shell_quote(filename
)
319 output
= commands
.getoutput(cmd
)
320 self
.view
.displayText
.setText(output
)
323 if filename
in self
.model
.get_unstaged():
324 diff
= cmds
.git_diff(filename
=filename
, cached
=False)
326 self
.__set
_info
(self
.tr('Modified, not staged'))
329 cmd
= 'file -b %s' % utils
.shell_quote(filename
)
330 file_type
= commands
.getoutput(cmd
)
332 if 'binary' in file_type
or 'data' in file_type
:
333 sq_filename
= utils
.shell_quote(filename
)
334 cmd
= 'hexdump -C %s' % sq_filename
335 contents
= commands
.getoutput(cmd
)
337 if os
.path
.exists(filename
):
338 file = open(filename
, 'r')
339 contents
= file.read()
344 self
.__set
_info
(self
.tr('Untracked, not staged')
348 self
.view
.displayText
.setText(msg
)
350 def copy_display(self
):
351 cursor
= self
.view
.displayText
.textCursor()
352 selection
= cursor
.selection().toPlainText()
353 qtutils
.set_clipboard(selection
)
355 def export_patches(self
):
356 '''Launches the commit browser and exports the selected
359 (revs
, summaries
) = cmds
.git_log()
360 selection
, idxs
= self
.__select
_commits
(revs
, summaries
)
361 if not selection
: return
363 # now get the selected indices to determine whether
364 # a range of consecutive commits were selected
365 selected_range
= range(idxs
[0], idxs
[-1] + 1)
366 export_range
= len(idxs
) > 1 and idxs
== selected_range
368 output
= cmds
.git_format_patch(selection
, export_range
)
369 self
.__show
_command
(output
)
371 def get_commit_msg(self
):
372 self
.model
.retrieve_latest_commitmsg()
374 def last_window_closed(self
):
375 '''Save config settings and cleanup the any inotify threads.'''
377 self
.__save
_config
_settings
()
379 if not self
.inotify_thread
: return
380 if not self
.inotify_thread
.isRunning(): return
382 self
.inotify_thread
.abort
= True
383 self
.inotify_thread
.quit()
384 self
.inotify_thread
.wait()
386 def load_commitmsg(self
):
387 file = qtutils
.open_dialog(self
.view
,
388 self
.tr('Load Commit Message...'),
392 defaults
.DIRECTORY
= os
.path
.dirname(file)
393 slushy
= utils
.slurp(file)
394 self
.model
.set_commitmsg(slushy
)
398 dlg
= GitBranchDialog(self
.view
, cmds
.git_branch())
399 dlg
.setWindowTitle("Select the current branch's new root")
400 branch
= dlg
.getSelectedBranch()
401 if not branch
: return
402 qtutils
.show_command(self
.view
, cmds
.git_rebase(branch
))
404 # use *rest to handle being called from the checkbox signal
405 def rescan(self
, *rest
):
406 '''Populates view widgets with results from "git status."'''
408 self
.view
.statusBar().showMessage(
409 self
.tr('Scanning for modified files ...'))
411 # Rescan for repo updates
412 self
.model
.update_status()
414 # Scan for branch changes
415 self
.__set
_branch
_ui
_items
()
417 if not self
.model
.has_squash_msg(): return
419 if self
.model
.get_commitmsg():
420 answer
= qtutils
.question(self
.view
,
421 self
.tr('Import Commit Message?'),
422 self
.tr('A commit message from an in-progress'
423 + ' merge was found.\nImport it?'))
425 if not answer
: return
427 # Set the new commit message
428 self
.model
.set_commitmsg(self
.model
.get_squash_msg())
431 model
= self
.model
.clone()
432 view
= GitPushDialog(self
.view
)
433 controller
= GitPushController(model
,view
)
442 cursor
= self
.view
.commitText
.textCursor()
443 selection
= cursor
.selection().toPlainText()
444 qtutils
.set_clipboard(selection
)
446 def paste(self
): self
.view
.commitText
.paste()
447 def undo(self
): self
.view
.commitText
.undo()
448 def redo(self
): self
.view
.commitText
.redo()
449 def select_all(self
): self
.view
.commitText
.selectAll()
451 self
.view
.commitText
.textCursor().removeSelectedText()
453 def show_diffstat(self
):
454 '''Show the diffstat from the latest commit.'''
455 self
.__show
_command
(cmds
.git_diff_stat(), rescan
=False)
458 #####################################################################
461 def __diff_selection(self
):
462 cursor
= self
.view
.displayText
.textCursor()
463 offset
= cursor
.position()
464 selection
= cursor
.selection().toPlainText()
465 num_selected_lines
= selection
.count(os
.linesep
)
466 return offset
, selection
468 def process_diff_selection(self
,
474 filename
= qtutils
.get_selected_item(widget
, items
)
475 if not filename
: return
477 parser
= utils
.DiffParser(
478 *cmds
.git_diff(filename
=filename
, with_diff_header
=True,
479 cached
=cached
, reverse
=cached
))
481 # Always index into the non-reversed diff
483 cmds
.git_diff(filename
=filename
, with_diff_header
=True,
484 cached
=cached
, reverse
=False)
486 offset
, selection
= self
.__diff
_selection
()
488 start
= diff
.index(selection
)
489 end
= start
+ len(selection
)
490 parser
.set_diffs_to_range(start
, end
)
492 parser
.set_diff_to_offset(offset
)
495 if not parser
.diffs
: return
497 # Process diff selection only
499 for idx
in parser
.selected
:
500 contents
= parser
.get_diff_subset(idx
, start
, end
)
502 tmpfile
= utils
.get_tmp_filename()
503 utils
.write(tmpfile
, contents
)
504 self
.model
.apply_diff(tmpfile
)
507 # Process a complete hunk
509 for idx
, diff
in enumerate(parser
.diffs
):
510 tmpfile
= utils
.get_tmp_filename()
511 if parser
.write_diff(tmpfile
,idx
):
512 self
.model
.apply_diff(tmpfile
)
516 def stage_hunk(self
):
517 self
.process_diff_selection(
518 self
.model
.get_unstaged(),
519 self
.view
.unstagedList
,
522 def stage_hunks(self
):
523 self
.process_diff_selection(
524 self
.model
.get_unstaged(),
525 self
.view
.unstagedList
,
529 def unstage_hunk(self
, cached
=True):
530 self
.process_diff_selection(
531 self
.model
.get_staged(),
532 self
.view
.stagedList
,
535 def unstage_hunks(self
):
536 self
.process_diff_selection(
537 self
.model
.get_staged(),
538 self
.view
.stagedList
,
542 # #######################################################################
545 def stage_changed(self
):
546 '''Stage all changed files for commit.'''
547 output
= cmds
.git_add(self
.model
.get_unstaged())
548 self
.__show
_command
(output
)
550 def stage_untracked(self
):
551 '''Stage all untracked files for commit.'''
552 output
= cmds
.git_add(self
.model
.get_untracked())
553 self
.__show
_command
(output
)
555 # use *rest to handle being called from different signals
556 def stage_selected(self
,*rest
):
557 '''Use "git add" to add items to the git index.
558 This is a thin wrapper around __apply_to_list.'''
559 command
= cmds
.git_add_or_remove
560 widget
= self
.view
.unstagedList
561 items
= self
.model
.get_all_unstaged()
562 self
.__show
_command
(self
.__apply
_to
_list
(command
,widget
,items
))
564 # use *rest to handle being called from different signals
565 def unstage_selected(self
, *rest
):
566 '''Use "git reset" to remove items from the git index.
567 This is a thin wrapper around __apply_to_list.'''
568 command
= cmds
.git_reset
569 widget
= self
.view
.stagedList
570 items
= self
.model
.get_staged()
571 self
.__apply
_to
_list
(command
, widget
, items
)
573 def unstage_all(self
):
574 '''Use "git reset" to remove all items from the git index.'''
575 cmds
.git_reset(self
.model
.get_staged())
579 '''Visualizes the entire git history using gitk.'''
580 utils
.fork('gitk','--all')
582 def viz_current(self
):
583 '''Visualizes the current branch's history using gitk.'''
584 utils
.fork('gitk', cmds
.git_current_branch())
586 # These actions monitor window resizes, splitter changes, etc.
587 def move_event(self
, event
):
588 defaults
.X
= event
.pos().x()
589 defaults
.Y
= event
.pos().y()
591 def resize_event(self
, event
):
592 defaults
.WIDTH
= event
.size().width()
593 defaults
.HEIGHT
= event
.size().height()
595 def splitter_top_event(self
,*rest
):
596 sizes
= self
.view
.splitter_top
.sizes()
597 defaults
.SPLITTER_TOP_0
= sizes
[0]
598 defaults
.SPLITTER_TOP_1
= sizes
[1]
600 def splitter_bottom_event(self
,*rest
):
601 sizes
= self
.view
.splitter_bottom
.sizes()
602 defaults
.SPLITTER_BOTTOM_0
= sizes
[0]
603 defaults
.SPLITTER_BOTTOM_1
= sizes
[1]
605 #####################################################################
608 def __apply_to_list(self
, command
, widget
, items
):
609 '''This is a helper method that retrieves the current
610 selection list, applies a command to that list,
611 displays a dialog showing the output of that command,
612 and calls rescan to pickup changes.'''
613 apply_items
= qtutils
.get_selection_list(widget
, items
)
614 output
= command(apply_items
)
618 def __browse_branch(self
, branch
):
619 if not branch
: return
620 # Clone the model to allow opening multiple browsers
621 # with different sets of data
622 model
= self
.model
.clone()
623 model
.set_branch(branch
)
624 view
= GitCommitBrowser()
625 controller
= GitRepoBrowserController(model
, view
)
629 def __menu_about_to_show(self
):
631 unstaged_item
= qtutils
.get_selected_item(
632 self
.view
.unstagedList
,
633 self
.model
.get_all_unstaged())
635 is_tracked
= unstaged_item
not in self
.model
.get_untracked()
639 and not self
.__staged
_diff
_in
_view
643 self
.__staged
_diff
_in
_view
644 and qtutils
.get_selected_item(
645 self
.view
.stagedList
,
646 self
.model
.get_staged()))
648 self
.__stage
_hunk
_action
.setEnabled(bool(enable_staged
))
649 self
.__stage
_hunks
_action
.setEnabled(bool(enable_staged
))
651 self
.__unstage
_hunk
_action
.setEnabled(bool(enable_unstaged
))
652 self
.__unstage
_hunks
_action
.setEnabled(bool(enable_unstaged
))
654 def __menu_event(self
, event
):
656 textedit
= self
.view
.displayText
657 self
.__menu
.exec_(textedit
.mapToGlobal(event
.pos()))
659 def __menu_setup(self
):
660 if self
.__menu
: return
662 menu
= self
.__menu
= QMenu(self
.view
)
663 self
.__stage
_hunk
_action
= menu
.addAction(
664 self
.tr('Stage Hunk For Commit'),
667 self
.__stage
_hunks
_action
= menu
.addAction(
668 self
.tr('Stage Selected Lines'),
671 self
.__unstage
_hunk
_action
= menu
.addAction(
672 self
.tr('Unstage Hunk From Commit'),
675 self
.__unstage
_hunks
_action
= menu
.addAction(
676 self
.tr('Unstage Selected Lines'),
679 self
.__copy
_action
= menu
.addAction(
683 self
.connect(self
.__menu
, 'aboutToShow()', self
.__menu
_about
_to
_show
)
685 def __file_to_widget_item(self
, filename
, staged
, untracked
=False):
686 '''Given a filename, return a QListWidgetItem suitable
687 for adding to a QListWidget. "staged" controls whether
688 to use icons for the staged or unstaged list widget.'''
690 icon_file
= utils
.get_staged_icon(filename
)
692 icon_file
= utils
.get_untracked_icon()
694 icon_file
= utils
.get_icon(filename
)
696 return qtutils
.create_listwidget_item(filename
, icon_file
)
698 def __read_config_settings(self
):
701 sb0
,sb1
) = utils
.parse_geom(cmds
.git_config('ugit.geometry'))
702 self
.view
.resize(w
,h
)
704 self
.view
.splitter_top
.setSizes([st0
,st1
])
705 self
.view
.splitter_bottom
.setSizes([sb0
,sb1
])
707 def __save_config_settings(self
):
708 cmds
.git_config('ugit.geometry', utils
.get_geom())
710 def __select_commits(self
, revs
, summaries
):
711 '''Use the GitCommitBrowser to select commits from a list.'''
713 msg
= self
.tr('ERROR: No commits exist in this branch.')
714 self
.__show
_command
(msg
)
717 browser
= GitCommitBrowser(self
.view
)
718 self
.connect(browser
.commitList
,
719 'itemSelectionChanged()',
720 lambda: self
.commit_sha1_selected(
723 qtutils
.set_items(browser
.commitList
, summaries
)
726 result
= browser
.exec_()
727 if result
!= QDialog
.Accepted
:
730 list_widget
= browser
.commitList
731 selection
= qtutils
.get_selection_list(list_widget
, revs
)
732 if not selection
: return([],[])
734 # also return the selected index numbers
735 index_nums
= range(len(revs
))
736 idxs
= qtutils
.get_selection_list(list_widget
, index_nums
)
738 return(selection
, idxs
)
740 def __set_branch_ui_items(self
):
741 '''Sets up items that mention the current branch name.'''
742 branch
= cmds
.git_current_branch()
744 status_text
= self
.tr('Current Branch:') + ' ' + branch
745 self
.view
.statusBar().showMessage(status_text
)
747 project
= self
.model
.get_project()
748 title
= '%s [%s]' % ( project
, branch
)
750 self
.view
.setWindowTitle(title
)
752 def __reset_display(self
):
753 self
.view
.displayText
.setText('')
756 def __set_info(self
,text
):
757 self
.view
.displayLabel
.setText(text
)
759 def __start_inotify_thread(self
):
760 # Do we have inotify? If not, return.
761 # Recommend installing inotify if we're on Linux.
762 self
.inotify_thread
= None
764 from inotify
import GitNotifier
767 if platform
.system() == 'Linux':
768 msg
=(self
.tr('Unable import pyinotify.\n'
769 + 'inotify support has been'
773 plat
= platform
.platform().lower()
774 if 'debian' in plat
or 'ubuntu' in plat
:
775 msg
+= (self
.tr('Hint:')
776 + 'sudo apt-get install'
777 + ' python-pyinotify')
779 qtutils
.information(self
.view
,
780 self
.tr('inotify disabled'), msg
)
783 self
.inotify_thread
= GitNotifier(os
.getcwd())
784 self
.connect(self
.inotify_thread
,
785 'timeForRescan()', self
.rescan
)
787 # Start the notification thread
788 self
.inotify_thread
.start()
790 def __show_command(self
, output
, rescan
=True):
791 '''Shows output and optionally rescans for changes.'''
792 qtutils
.show_command(self
.view
, output
)
793 if rescan
: self
.rescan()
795 def __update_listwidget(self
, widget
, items
,
796 staged
, untracked
=False, append
=False):
797 '''Populate a QListWidget with the custom icon items.'''
798 if not append
: widget
.clear()
799 qtutils
.add_items( widget
,
800 [ self
.__file
_to
_widget
_item
(i
, staged
, untracked
)