main.model: Do not depend on ObservableModel
[git-cola.git] / cola / main / view.py
blob469c9835a921aa12dd7544b7e747540f7f7b56ad
1 """This view provides the main git-cola user interface.
2 """
3 import os
5 from PyQt4 import QtCore
6 from PyQt4 import QtGui
7 from PyQt4.QtCore import Qt
8 from PyQt4.QtCore import SIGNAL
10 import cola
11 from cola import core
12 from cola import gitcmds
13 from cola import guicmds
14 from cola import merge
15 from cola import settings
16 from cola import signals
17 from cola import gitcfg
18 from cola import qtutils
19 from cola import qtcompat
20 from cola import qt
21 from cola import resources
22 from cola import stash
23 from cola import utils
24 from cola import version
25 from cola.bookmarks import manage_bookmarks
26 from cola.classic import cola_classic
27 from cola.classic import classic_widget
28 from cola.dag import git_dag
29 from cola.git import git
30 from cola.prefs import diff_font
31 from cola.prefs import PreferencesModel
32 from cola.prefs import preferences
33 from cola.qt import create_button
34 from cola.qt import create_dock
35 from cola.qt import create_menu
36 from cola.qtutils import add_action
37 from cola.qtutils import connect_action
38 from cola.qtutils import connect_action_bool
39 from cola.qtutils import connect_button
40 from cola.qtutils import emit
41 from cola.qtutils import log
42 from cola.qtutils import relay_signal
43 from cola.qtutils import tr
44 from cola.views import standard
45 from cola.widgets import cfgactions
46 from cola.widgets import remote
47 from cola.widgets.about import launch_about_dialog
48 from cola.widgets.about import show_shortcuts
49 from cola.widgets.archive import GitArchiveDialog
50 from cola.widgets.commitmsg import CommitMessageEditor
51 from cola.widgets.compare import compare_branches
52 from cola.widgets.createtag import create_tag
53 from cola.widgets.createbranch import create_new_branch
54 from cola.widgets.diff import DiffEditor
55 from cola.widgets.recent import browse_recent
56 from cola.widgets.status import StatusWidget
57 from cola.widgets.search import search
60 class MainView(standard.MainWindow):
61 def __init__(self, model, parent):
62 standard.MainWindow.__init__(self, parent)
63 # Default size; this is thrown out when save/restore is used
64 self.resize(987, 610)
65 self.model = model
66 self.prefs_model = prefs_model = PreferencesModel()
68 # Internal field used by import/export_state().
69 # Change this whenever dockwidgets are removed.
70 self.widget_version = 1
72 # Keeps track of merge messages we've seen
73 self.merge_message_hash = ''
75 self.setAcceptDrops(True)
77 # Dockwidget options
78 qtcompat.set_common_dock_options(self)
80 self.classic_dockable = gitcfg.instance().get('cola.classicdockable')
82 if self.classic_dockable:
83 self.classicdockwidget = create_dock('Classic', self)
84 self.classicwidget = classic_widget(self)
85 self.classicdockwidget.setWidget(self.classicwidget)
87 # "Actions" widget
88 self.actionsdockwidget = create_dock('Action', self)
89 self.actionsdockwidgetcontents = qt.QFlowLayoutWidget(self)
90 layout = self.actionsdockwidgetcontents.layout()
91 self.stage_button = create_button(text='Stage', layout=layout)
92 self.unstage_button = create_button(text='Unstage', layout=layout)
93 self.rescan_button = create_button(text='Rescan', layout=layout)
94 self.fetch_button = create_button(text='Fetch...', layout=layout)
95 self.push_button = create_button(text='Push...', layout=layout)
96 self.pull_button = create_button(text='Pull...', layout=layout)
97 self.stash_button = create_button(text='Stash...', layout=layout)
98 self.alt_button = create_button(text='Exit Diff Mode', layout=layout)
99 self.alt_button.hide()
100 layout.addStretch()
101 self.actionsdockwidget.setWidget(self.actionsdockwidgetcontents)
103 # "Repository Status" widget
104 self.statusdockwidget = create_dock('Status', self)
105 self.statusdockwidget.setWidget(StatusWidget(self))
107 # "Commit Message Editor" widget
108 self.position_label = QtGui.QLabel()
109 font = qtutils.default_monospace_font()
110 font.setPointSize(int(font.pointSize() * 0.8))
111 self.position_label.setFont(font)
112 self.commitdockwidget = create_dock('Commit', self)
113 titlebar = self.commitdockwidget.titleBarWidget()
114 titlebar.add_corner_widget(self.position_label)
116 self.commitmsgeditor = CommitMessageEditor(model, self)
117 relay_signal(self, self.commitmsgeditor, SIGNAL(signals.amend_mode))
118 relay_signal(self, self.commitmsgeditor, SIGNAL(signals.signoff))
119 relay_signal(self, self.commitmsgeditor,
120 SIGNAL(signals.load_previous_message))
121 self.commitdockwidget.setWidget(self.commitmsgeditor)
123 # "Command Output" widget
124 logwidget = qtutils.logger()
125 logwidget.setFont(diff_font())
126 self.logdockwidget = create_dock('Console', self)
127 self.logdockwidget.setWidget(logwidget)
129 # "Diff Viewer" widget
130 self.diffdockwidget = create_dock('Diff', self)
131 self.diff_editor = DiffEditor(self.diffdockwidget)
132 self.diffdockwidget.setWidget(self.diff_editor)
134 # All Actions
135 self.menu_unstage_all = add_action(self,
136 'Unstage All', emit(self, signals.unstage_all))
137 self.menu_unstage_all.setIcon(qtutils.icon('remove.svg'))
139 self.menu_unstage_selected = add_action(self,
140 'Unstage From Commit', emit(self, signals.unstage_selected))
141 self.menu_unstage_selected.setIcon(qtutils.icon('remove.svg'))
143 self.menu_show_diffstat = add_action(self,
144 'Diffstat', emit(self, signals.diffstat), 'Alt+D')
146 self.menu_stage_modified = add_action(self,
147 'Stage Changed Files To Commit',
148 emit(self, signals.stage_modified), 'Alt+A')
149 self.menu_stage_modified.setIcon(qtutils.icon('add.svg'))
151 self.menu_stage_untracked = add_action(self,
152 'Stage All Untracked', emit(self, signals.stage_untracked), 'Alt+U')
153 self.menu_stage_untracked.setIcon(qtutils.icon('add.svg'))
155 self.menu_export_patches = add_action(self,
156 'Export Patches...', guicmds.export_patches, 'Alt+E')
157 self.menu_preferences = add_action(self,
158 'Preferences', lambda: preferences(model=prefs_model),
159 QtGui.QKeySequence.Preferences, 'Ctrl+O')
161 self.menu_rescan = add_action(self,
162 'Rescan', emit(self, signals.rescan_and_refresh), 'Ctrl+R')
163 self.menu_rescan.setIcon(qtutils.reload_icon())
165 self.menu_browse_recent = add_action(self,
166 'Recently Modified Files...', browse_recent, 'Shift+Ctrl+E')
168 self.menu_cherry_pick = add_action(self,
169 'Cherry-Pick...', guicmds.cherry_pick, 'Ctrl+P')
171 self.menu_load_commitmsg = add_action(self,
172 'Load Commit Message...', guicmds.load_commitmsg)
174 self.menu_save_tarball = add_action(self,
175 'Save As Tarball/Zip...', self.save_archive)
177 self.menu_quit = add_action(self,
178 'Quit', self.close, 'Ctrl+Q')
179 self.menu_manage_bookmarks = add_action(self,
180 'Bookmarks...', manage_bookmarks)
181 self.menu_grep = add_action(self,
182 'Grep', guicmds.grep)
183 self.menu_merge_local = add_action(self,
184 'Merge...', merge.local_merge)
186 self.menu_merge_abort = add_action(self,
187 'Abort Merge...', merge.abort_merge)
189 self.menu_fetch = add_action(self,
190 'Fetch...', remote.fetch)
191 self.menu_push = add_action(self,
192 'Push...', remote.push)
193 self.menu_pull = add_action(self,
194 'Pull...', remote.pull)
196 self.menu_open_repo = add_action(self,
197 'Open...', guicmds.open_repo)
198 self.menu_open_repo.setIcon(qtutils.open_icon())
200 self.menu_stash = add_action(self,
201 'Stash...', stash.stash, 'Alt+Shift+S')
203 self.menu_clone_repo = add_action(self,
204 'Clone...', guicmds.clone_repo)
205 self.menu_clone_repo.setIcon(qtutils.git_icon())
207 self.menu_help_docs = add_action(self,
208 'Documentation', resources.show_html_docs,
209 QtGui.QKeySequence.HelpContents)
211 self.menu_help_shortcuts = add_action(self,
212 'Keyboard Shortcuts',
213 show_shortcuts,
214 QtCore.Qt.Key_Question)
216 self.menu_visualize_current = add_action(self,
217 'Visualize Current Branch...',
218 emit(self, signals.visualize_current))
219 self.menu_visualize_all = add_action(self,
220 'Visualize All Branches...',
221 emit(self, signals.visualize_all))
222 self.menu_search_commits = add_action(self,
223 'Search...', search)
224 self.menu_browse_branch = add_action(self,
225 'Browse Current Branch...', guicmds.browse_current)
226 self.menu_browse_other_branch = add_action(self,
227 'Browse Other Branch...', guicmds.browse_other)
228 self.menu_load_commitmsg_template = add_action(self,
229 'Get Commit Message Template',
230 emit(self, signals.load_commit_template))
231 self.menu_help_about = add_action(self,
232 'About', launch_about_dialog)
234 self.menu_branch_diff = add_action(self,
235 'SHA-1...', guicmds.branch_diff)
236 self.menu_diff_expression = add_action(self,
237 'Expression...', guicmds.diff_expression)
238 self.menu_branch_compare = add_action(self,
239 'Branches...', compare_branches)
241 self.menu_create_tag = add_action(self,
242 'Create Tag...', create_tag)
244 self.menu_create_branch = add_action(self,
245 'Create...', create_new_branch, 'Ctrl+B')
247 self.menu_delete_branch = add_action(self,
248 'Delete...', guicmds.branch_delete)
250 self.menu_checkout_branch = add_action(self,
251 'Checkout...', guicmds.checkout_branch, 'Alt+B')
252 self.menu_rebase_branch = add_action(self,
253 'Rebase...', guicmds.rebase)
254 self.menu_branch_review = add_action(self,
255 'Review...', guicmds.review_branch)
257 self.menu_classic = add_action(self,
258 'Cola Classic...', cola_classic)
259 self.menu_classic.setIcon(qtutils.git_icon())
261 self.menu_dag = add_action(self,
262 'DAG...', lambda: git_dag(self.model))
263 self.menu_dag.setIcon(qtutils.git_icon())
265 # Relayed actions
266 status_tree = self.statusdockwidget.widget().tree
267 self.addAction(status_tree.up)
268 self.addAction(status_tree.down)
269 self.addAction(status_tree.process_selection)
270 self.addAction(status_tree.launch_difftool)
272 # Create the application menu
273 self.menubar = QtGui.QMenuBar(self)
275 # File Menu
276 self.file_menu = create_menu('&File', self.menubar)
277 self.file_menu.addAction(self.menu_preferences)
278 self.file_menu.addSeparator()
279 self.file_menu.addAction(self.menu_open_repo)
280 self.file_menu.addAction(self.menu_clone_repo)
281 self.file_menu.addAction(self.menu_manage_bookmarks)
282 self.file_menu.addSeparator()
283 self.file_menu.addAction(self.menu_rescan)
284 self.file_menu.addSeparator()
285 self.file_menu.addAction(self.menu_browse_recent)
286 self.file_menu.addSeparator()
287 self.file_menu.addAction(self.menu_load_commitmsg)
288 self.file_menu.addAction(self.menu_load_commitmsg_template)
289 self.file_menu.addSeparator()
290 self.file_menu.addAction(self.menu_save_tarball)
291 self.file_menu.addAction(self.menu_quit)
292 # Add to menubar
293 self.menubar.addAction(self.file_menu.menuAction())
295 # Commit Menu
296 self.commit_menu = create_menu('Co&mmit', self.menubar)
297 self.commit_menu.setTitle(tr('Commit@@verb'))
298 self.commit_menu.addAction(self.menu_stage_modified)
299 self.commit_menu.addAction(self.menu_stage_untracked)
300 self.commit_menu.addSeparator()
301 self.commit_menu.addAction(self.menu_unstage_all)
302 self.commit_menu.addAction(self.menu_unstage_selected)
303 self.commit_menu.addSeparator()
304 self.commit_menu.addAction(self.menu_search_commits)
305 # Add to menubar
306 self.menubar.addAction(self.commit_menu.menuAction())
308 # Branch Menu
309 self.branch_menu = create_menu('B&ranch', self.menubar)
310 self.branch_menu.addAction(self.menu_branch_review)
311 self.branch_menu.addSeparator()
312 self.branch_menu.addAction(self.menu_create_branch)
313 self.branch_menu.addAction(self.menu_checkout_branch)
314 self.branch_menu.addAction(self.menu_rebase_branch)
315 self.branch_menu.addAction(self.menu_delete_branch)
316 self.branch_menu.addSeparator()
317 self.branch_menu.addAction(self.menu_browse_branch)
318 self.branch_menu.addAction(self.menu_browse_other_branch)
319 self.branch_menu.addSeparator()
320 self.branch_menu.addAction(self.menu_visualize_current)
321 self.branch_menu.addAction(self.menu_visualize_all)
322 # Add to menubar
323 self.menubar.addAction(self.branch_menu.menuAction())
325 # Actions menu
326 self.actions_menu = create_menu('Act&ions', self.menubar)
327 self.actions_menu.addAction(self.menu_merge_local)
328 self.actions_menu.addAction(self.menu_stash)
329 self.actions_menu.addSeparator()
330 self.actions_menu.addAction(self.menu_fetch)
331 self.actions_menu.addAction(self.menu_push)
332 self.actions_menu.addAction(self.menu_pull)
333 self.actions_menu.addSeparator()
334 self.actions_menu.addAction(self.menu_create_tag)
335 self.actions_menu.addSeparator()
336 self.actions_menu.addAction(self.menu_export_patches)
337 self.actions_menu.addAction(self.menu_cherry_pick)
338 self.actions_menu.addSeparator()
339 self.actions_menu.addAction(self.menu_merge_abort)
340 self.actions_menu.addAction(self.menu_grep)
341 # Add to menubar
342 self.menubar.addAction(self.actions_menu.menuAction())
344 # Diff Menu
345 self.diff_menu = create_menu('&Diff', self.menubar)
346 self.diff_menu.addAction(self.menu_branch_diff)
347 self.diff_menu.addAction(self.menu_diff_expression)
348 self.diff_menu.addAction(self.menu_branch_compare)
349 self.diff_menu.addSeparator()
350 self.diff_menu.addAction(self.menu_show_diffstat)
351 # Add to menubar
352 self.menubar.addAction(self.diff_menu.menuAction())
354 # Tools Menu
355 self.tools_menu = create_menu('&Tools', self.menubar)
356 self.tools_menu.addAction(self.menu_classic)
357 self.tools_menu.addAction(self.menu_dag)
358 self.tools_menu.addSeparator()
359 if self.classic_dockable:
360 self.tools_menu.addAction(self.classicdockwidget.toggleViewAction())
362 self.setup_dockwidget_tools_menu()
363 self.menubar.addAction(self.tools_menu.menuAction())
365 # Help Menu
366 self.help_menu = create_menu('&Help', self.menubar)
367 self.help_menu.addAction(self.menu_help_docs)
368 self.help_menu.addAction(self.menu_help_shortcuts)
369 self.help_menu.addAction(self.menu_help_about)
370 # Add to menubar
371 self.menubar.addAction(self.help_menu.menuAction())
373 # Set main menu
374 self.setMenuBar(self.menubar)
376 # Arrange dock widgets
377 top = Qt.TopDockWidgetArea
378 bottom = Qt.BottomDockWidgetArea
380 self.addDockWidget(top, self.commitdockwidget)
381 if self.classic_dockable:
382 self.addDockWidget(top, self.classicdockwidget)
383 self.addDockWidget(top, self.statusdockwidget)
384 self.addDockWidget(top, self.actionsdockwidget)
385 self.addDockWidget(bottom, self.logdockwidget)
386 if self.classic_dockable:
387 self.tabifyDockWidget(self.classicdockwidget, self.commitdockwidget)
388 self.tabifyDockWidget(self.logdockwidget, self.diffdockwidget)
390 # Listen for model notifications
391 model.add_message_observer(model.message_mode_changed,
392 self._mode_changed)
394 model.add_message_observer(model.message_updated,
395 self._update_view)
397 prefs_model.add_message_observer(prefs_model.message_config_updated,
398 self._config_updated)
400 # Set a default value
401 self.show_cursor_position(1, 0)
403 # Add button callbacks
404 connect_button(self.rescan_button,
405 emit(self, signals.rescan_and_refresh))
406 connect_button(self.alt_button, emit(self, signals.reset_mode))
407 connect_button(self.fetch_button, remote.fetch)
408 connect_button(self.push_button, remote.push)
409 connect_button(self.pull_button, remote.pull)
410 connect_button(self.stash_button, stash.stash)
412 connect_button(self.stage_button, self.stage)
413 connect_button(self.unstage_button, self.unstage)
415 self.connect(self.commitmsgeditor, SIGNAL('cursorPosition(int,int)'),
416 self.show_cursor_position)
417 self.connect(self, SIGNAL('update'), self._update_callback)
418 self.connect(self, SIGNAL('apply_state'), self.apply_state)
419 self.connect(self, SIGNAL('install_config_actions'),
420 self._install_config_actions)
422 # Install .git-config-defined actions
423 self._config_task = None
424 self.install_config_actions()
426 # Restore saved settings
427 self._gui_state_task = None
428 self._load_gui_state()
430 log(0, version.git_version_str() + '\ncola version ' + version.version())
432 # Qt overrides
433 def closeEvent(self, event):
434 """Save state in the settings manager."""
435 qtutils.save_state(self)
436 standard.MainWindow.closeEvent(self, event)
438 # Accessors
439 mode = property(lambda self: self.model.mode)
441 def _mode_changed(self, mode):
442 """React to mode changes; hide/show the "Exit Diff Mode" button."""
443 if mode in (self.model.mode_review,
444 self.model.mode_diff,
445 self.model.mode_diff_expr):
446 height = self.stage_button.minimumHeight()
447 self.alt_button.setMinimumHeight(height)
448 self.alt_button.show()
449 else:
450 self.alt_button.setMinimumHeight(1)
451 self.alt_button.hide()
453 def _config_updated(self, source, config, value):
454 if config == 'cola.fontdiff':
455 font = QtGui.QFont()
456 if not font.fromString(value):
457 return
458 qtutils.logger().setFont(font)
459 self.diff_editor.setFont(font)
460 self.commitmsgeditor.setFont(font)
462 elif config == 'cola.tabwidth':
463 # variable-tab-width setting
464 self.diff_editor.set_tab_width(value)
466 def install_config_actions(self):
467 """Install .gitconfig-defined actions"""
468 self._config_task = self._start_config_actions_task()
470 def _start_config_actions_task(self):
471 """Do the expensive "get_config_actions()" call in the background"""
472 class ConfigActionsTask(QtCore.QRunnable):
473 def __init__(self, sender):
474 QtCore.QRunnable.__init__(self)
475 self._sender = sender
476 def run(self):
477 names = cfgactions.get_config_actions()
478 self._sender.emit(SIGNAL('install_config_actions'), names)
480 task = ConfigActionsTask(self)
481 QtCore.QThreadPool.globalInstance().start(task)
482 return task
484 def _install_config_actions(self, names):
485 """Install .gitconfig-defined actions"""
486 if not names:
487 return
488 menu = self.actions_menu
489 menu.addSeparator()
490 for name in names:
491 menu.addAction(name, emit(self, signals.run_config_action, name))
493 def _update_view(self):
494 self.emit(SIGNAL('update'))
496 def _update_callback(self):
497 """Update the title with the current branch and directory name."""
498 branch = self.model.currentbranch
499 curdir = core.decode(os.getcwd())
500 msg = 'Repository: %s\nBranch: %s' % (curdir, branch)
501 self.commitdockwidget.setToolTip(msg)
503 title = '%s: %s' % (self.model.project, branch)
504 if self.mode in (self.model.mode_diff, self.model.mode_diff_expr):
505 title += ' *** diff mode***'
506 elif self.mode == self.model.mode_review:
507 title += ' *** review mode***'
508 elif self.mode == self.model.mode_amend:
509 title += ' *** amending ***'
510 self.setWindowTitle(title)
512 self.commitmsgeditor.set_mode(self.mode)
514 if not self.model.read_only() and self.mode != self.model.mode_amend:
515 # Check if there's a message file in .git/
516 merge_msg_path = gitcmds.merge_message_path()
517 if merge_msg_path is None:
518 return
519 merge_msg_hash = utils.checksum(core.decode(merge_msg_path))
520 if merge_msg_hash == self.merge_message_hash:
521 return
522 self.merge_message_hash = merge_msg_hash
523 cola.notifier().broadcast(signals.load_commit_message,
524 core.decode(merge_msg_path))
526 def apply_state(self, state):
527 """Imports data for save/restore"""
528 # 1 is the widget version; change when widgets are added/removed
529 standard.MainWindow.apply_state(self, state)
530 qtutils.apply_window_state(self, state, 1)
532 def export_state(self):
533 """Exports data for save/restore"""
534 state = standard.MainWindow.export_state(self)
535 return qtutils.export_window_state(self, state, self.widget_version)
537 def _load_gui_state(self):
538 """Restores the gui from the preferences file."""
539 self._gui_state_task = self._start_gui_state_loading_thread()
541 def _start_gui_state_loading_thread(self):
542 """Do expensive file reading and json decoding in the background"""
543 class LoadGUIStateTask(QtCore.QRunnable):
544 def __init__(self, sender):
545 QtCore.QRunnable.__init__(self)
546 self._sender = sender
547 def run(self):
548 state = settings.Settings().get_gui_state(self._sender)
549 self._sender.emit(SIGNAL('apply_state'), state)
551 task = LoadGUIStateTask(self)
552 QtCore.QThreadPool.globalInstance().start(task)
553 return task
555 def setup_dockwidget_tools_menu(self):
556 # Hotkeys for toggling the dock widgets
557 dockwidgets = (
558 (self.logdockwidget, 'Alt+0'),
559 (self.commitdockwidget, 'Alt+1'),
560 (self.statusdockwidget, 'Alt+2'),
561 (self.diffdockwidget, 'Alt+3'),
562 (self.actionsdockwidget, 'Alt+4'),
564 for dockwidget, shortcut in dockwidgets:
565 # Associate the action with the shortcut
566 action = dockwidget.toggleViewAction()
567 action.setShortcut(shortcut)
568 self.tools_menu.addAction(action)
569 def showdock(show, dockwidget=dockwidget):
570 if show:
571 dockwidget.raise_()
572 dockwidget.widget().setFocus(True)
573 else:
574 self.setFocus(True)
575 self.addAction(action)
576 connect_action_bool(action, showdock)
578 # Create a new shortcut Shift+<shortcut> that gives focus
579 action = QtGui.QAction(self)
580 action.setShortcut('Shift+' + shortcut)
581 def focusdock(dockwidget=dockwidget, showdock=showdock):
582 if dockwidget.toggleViewAction().isChecked():
583 showdock(True)
584 else:
585 dockwidget.toggleViewAction().trigger()
586 self.addAction(action)
587 connect_action(action, focusdock)
589 def save_archive(self):
590 ref = git.rev_parse('HEAD')
591 shortref = ref[:7]
592 GitArchiveDialog.save(ref, shortref, self)
594 def stage(self):
595 """Stage selected files, or all files if no selection exists."""
596 paths = cola.selection_model().unstaged
597 if not paths:
598 cola.notifier().broadcast(signals.stage_modified)
599 else:
600 cola.notifier().broadcast(signals.stage, paths)
602 def unstage(self):
603 """Unstage selected files, or all files if no selection exists."""
604 paths = cola.selection_model().staged
605 if not paths:
606 cola.notifier().broadcast(signals.unstage_all)
607 else:
608 cola.notifier().broadcast(signals.unstage, paths)
610 def dragEnterEvent(self, event):
611 """Accepts drops"""
612 standard.MainWindow.dragEnterEvent(self, event)
613 event.acceptProposedAction()
615 def dropEvent(self, event):
616 """Apply dropped patches with git-am"""
617 event.accept()
618 urls = event.mimeData().urls()
619 if not urls:
620 return
621 paths = map(lambda x: unicode(x.path()), urls)
622 patches = [p for p in paths if p.endswith('.patch')]
623 dirs = [p for p in paths if os.path.isdir(p)]
624 dirs.sort()
625 for d in dirs:
626 patches.extend(self._gather_patches(d))
627 # Broadcast the patches to apply
628 cola.notifier().broadcast(signals.apply_patches, patches)
630 def _gather_patches(self, path):
631 """Find patches in a subdirectory"""
632 patches = []
633 for root, subdirs, files in os.walk(path):
634 for name in [f for f in files if f.endswith('.patch')]:
635 patches.append(os.path.join(root, name))
636 return patches
638 def show_cursor_position(self, rows, cols):
639 display = '&nbsp;%02d:%02d&nbsp;' % (rows, cols)
640 if cols > 78:
641 display = ('<span style="color: white; '
642 ' background-color: red;"'
643 '>%s</span>' % display)
644 elif cols > 72:
645 display = ('<span style="color: black; '
646 ' background-color: orange;"'
647 '>%s</span>' % display)
648 elif cols > 64:
649 display = ('<span style="color: black; '
650 ' background-color: yellow;"'
651 '>%s</span>' % display)
652 else:
653 display = ('<span style="color: grey;">%s</span>' % display)
655 self.position_label.setText(display)