1 """This view provides the main git-cola user interface.
5 from PyQt4
import QtCore
6 from PyQt4
import QtGui
7 from PyQt4
.QtCore
import Qt
8 from PyQt4
.QtCore
import SIGNAL
12 from cola
import gitcmds
13 from cola
import guicmds
14 from cola
import merge
15 from cola
import gitcfg
16 from cola
import prefs
17 from cola
import qtutils
18 from cola
import resources
19 from cola
import settings
20 from cola
import stash
21 from cola
import utils
22 from cola
import version
23 from cola
.bookmarks
import manage_bookmarks
24 from cola
.classic
import cola_classic
25 from cola
.classic
import classic_widget
26 from cola
.dag
import git_dag
27 from cola
.git
import git
28 from cola
.git
import STDOUT
29 from cola
.i18n
import N_
30 from cola
.interaction
import Interaction
31 from cola
.qt
import create_dock
32 from cola
.qt
import create_menu
33 from cola
.qt
import create_toolbutton
34 from cola
.qtutils
import add_action
35 from cola
.qtutils
import add_action_bool
36 from cola
.qtutils
import connect_action
37 from cola
.qtutils
import connect_action_bool
38 from cola
.qtutils
import options_icon
39 from cola
.widgets
import action
40 from cola
.widgets
import cfgactions
41 from cola
.widgets
import editremotes
42 from cola
.widgets
import remote
43 from cola
.widgets
.about
import launch_about_dialog
44 from cola
.widgets
.about
import show_shortcuts
45 from cola
.widgets
.archive
import GitArchiveDialog
46 from cola
.widgets
.commitmsg
import CommitMessageEditor
47 from cola
.widgets
.compare
import compare_branches
48 from cola
.widgets
.createtag
import create_tag
49 from cola
.widgets
.createbranch
import create_new_branch
50 from cola
.widgets
.diff
import DiffEditor
51 from cola
.widgets
.log
import LogWidget
52 from cola
.widgets
.recent
import browse_recent
53 from cola
.widgets
.status
import StatusWidget
54 from cola
.widgets
.search
import search
55 from cola
.widgets
.standard
import MainWindow
58 class MainView(MainWindow
):
60 def __init__(self
, model
, parent
=None):
61 MainWindow
.__init
__(self
, parent
)
62 # Default size; this is thrown out when save/restore is used
65 self
.prefs_model
= prefs_model
= prefs
.PreferencesModel()
67 # The widget version is used by import/export_state().
68 # Change this whenever dockwidgets are removed.
69 self
.widget_version
= 2
71 # Keeps track of merge messages we've seen
72 self
.merge_message_hash
= ''
74 self
.setAcceptDrops(True)
75 self
.setAttribute(Qt
.WA_MacMetalStyle
)
77 cfg
= gitcfg
.instance()
78 self
.classic_dockable
= (cfg
.get('cola.browserdockable') or
79 cfg
.get('cola.classicdockable'))
80 if self
.classic_dockable
:
81 self
.classicdockwidget
= create_dock(N_('Browser'), self
)
82 self
.classicwidget
= classic_widget(self
)
83 self
.classicdockwidget
.setWidget(self
.classicwidget
)
86 self
.actionsdockwidget
= create_dock(N_('Action'), self
)
87 self
.actionsdockwidgetcontents
= action
.ActionButtons(self
)
88 self
.actionsdockwidget
.setWidget(self
.actionsdockwidgetcontents
)
89 self
.actionsdockwidget
.toggleViewAction().setChecked(False)
90 self
.actionsdockwidget
.hide()
92 # "Repository Status" widget
93 self
.statuswidget
= StatusWidget(self
)
94 self
.statusdockwidget
= create_dock(N_('Status'), self
)
95 self
.statusdockwidget
.setWidget(self
.statuswidget
)
97 # "Commit Message Editor" widget
98 self
.position_label
= QtGui
.QLabel()
99 font
= qtutils
.default_monospace_font()
100 font
.setPointSize(int(font
.pointSize() * 0.8))
101 self
.position_label
.setFont(font
)
102 self
.commitdockwidget
= create_dock(N_('Commit'), self
)
103 titlebar
= self
.commitdockwidget
.titleBarWidget()
104 titlebar
.add_corner_widget(self
.position_label
)
106 self
.commitmsgeditor
= CommitMessageEditor(model
, self
)
107 self
.commitdockwidget
.setWidget(self
.commitmsgeditor
)
110 self
.logwidget
= LogWidget()
111 self
.logdockwidget
= create_dock(N_('Console'), self
)
112 self
.logdockwidget
.setWidget(self
.logwidget
)
113 self
.logdockwidget
.toggleViewAction().setChecked(False)
114 self
.logdockwidget
.hide()
116 # "Diff Viewer" widget
117 self
.diffdockwidget
= create_dock(N_('Diff'), self
)
118 self
.diffeditor
= DiffEditor(self
.diffdockwidget
)
119 self
.diffdockwidget
.setWidget(self
.diffeditor
)
121 # "Diff Options" tool menu
122 self
.diff_ignore_space_at_eol_action
= add_action(self
,
123 N_('Ignore changes in whitespace at EOL'),
124 self
._update
_diff
_opts
)
125 self
.diff_ignore_space_at_eol_action
.setCheckable(True)
127 self
.diff_ignore_space_change_action
= add_action(self
,
128 N_('Ignore changes in amount of whitespace'),
129 self
._update
_diff
_opts
)
130 self
.diff_ignore_space_change_action
.setCheckable(True)
132 self
.diff_ignore_all_space_action
= add_action(self
,
133 N_('Ignore all whitespace'),
134 self
._update
_diff
_opts
)
135 self
.diff_ignore_all_space_action
.setCheckable(True)
137 self
.diff_function_context_action
= add_action(self
,
138 N_('Show whole surrounding functions of changes'),
139 self
._update
_diff
_opts
)
140 self
.diff_function_context_action
.setCheckable(True)
142 self
.diffopts_button
= create_toolbutton(text
=N_('Options'),
144 tooltip
=N_('Diff Options'))
145 self
.diffopts_menu
= create_menu(N_('Diff Options'),
146 self
.diffopts_button
)
148 self
.diffopts_menu
.addAction(self
.diff_ignore_space_at_eol_action
)
149 self
.diffopts_menu
.addAction(self
.diff_ignore_space_change_action
)
150 self
.diffopts_menu
.addAction(self
.diff_ignore_all_space_action
)
151 self
.diffopts_menu
.addAction(self
.diff_function_context_action
)
152 self
.diffopts_button
.setMenu(self
.diffopts_menu
)
153 self
.diffopts_button
.setPopupMode(QtGui
.QToolButton
.InstantPopup
)
155 titlebar
= self
.diffdockwidget
.titleBarWidget()
156 titlebar
.add_corner_widget(self
.diffopts_button
)
159 self
.menu_unstage_all
= add_action(self
,
160 N_('Unstage All'), cmds
.run(cmds
.UnstageAll
))
161 self
.menu_unstage_all
.setIcon(qtutils
.icon('remove.svg'))
163 self
.menu_unstage_selected
= add_action(self
,
164 N_('Unstage From Commit'), cmds
.run(cmds
.UnstageSelected
))
165 self
.menu_unstage_selected
.setIcon(qtutils
.icon('remove.svg'))
167 self
.menu_show_diffstat
= add_action(self
,
168 N_('Diffstat'), cmds
.run(cmds
.Diffstat
), 'Alt+D')
170 self
.menu_stage_modified
= add_action(self
,
171 N_('Stage Changed Files To Commit'),
172 cmds
.run(cmds
.StageModified
), 'Alt+A')
173 self
.menu_stage_modified
.setIcon(qtutils
.icon('add.svg'))
175 self
.menu_stage_untracked
= add_action(self
,
176 N_('Stage All Untracked'),
177 cmds
.run(cmds
.StageUntracked
), 'Alt+U')
178 self
.menu_stage_untracked
.setIcon(qtutils
.icon('add.svg'))
180 self
.menu_export_patches
= add_action(self
,
181 N_('Export Patches...'), guicmds
.export_patches
, 'Alt+E')
183 self
.new_repository
= add_action(self
,
184 N_('New Repository...'), guicmds
.open_new_repo
)
185 self
.new_repository
.setIcon(qtutils
.new_icon())
187 self
.menu_preferences
= add_action(self
,
188 N_('Preferences'), self
.preferences
,
189 QtGui
.QKeySequence
.Preferences
, 'Ctrl+O')
191 self
.menu_edit_remotes
= add_action(self
,
192 N_('Edit Remotes...'), lambda: editremotes
.edit().exec_())
193 self
.menu_rescan
= add_action(self
,
195 cmds
.run(cmds
.Refresh
),
196 cmds
.Refresh
.SHORTCUT
)
197 self
.menu_rescan
.setIcon(qtutils
.reload_icon())
199 self
.menu_browse_recent
= add_action(self
,
200 N_('Recently Modified Files...'),
201 browse_recent
, 'Shift+Ctrl+E')
203 self
.menu_cherry_pick
= add_action(self
,
204 N_('Cherry-Pick...'),
205 guicmds
.cherry_pick
, 'Ctrl+P')
207 self
.menu_load_commitmsg
= add_action(self
,
208 N_('Load Commit Message...'), guicmds
.load_commitmsg
)
210 self
.menu_save_tarball
= add_action(self
,
211 N_('Save As Tarball/Zip...'), self
.save_archive
)
213 self
.menu_quit
= add_action(self
,
214 N_('Quit'), self
.close
, 'Ctrl+Q')
215 self
.menu_manage_bookmarks
= add_action(self
,
216 N_('Bookmarks...'), manage_bookmarks
)
217 self
.menu_grep
= add_action(self
,
218 N_('Grep'), guicmds
.grep
, 'Ctrl+G')
219 self
.menu_merge_local
= add_action(self
,
220 N_('Merge...'), merge
.local_merge
)
222 self
.menu_merge_abort
= add_action(self
,
223 N_('Abort Merge...'), merge
.abort_merge
)
225 self
.menu_fetch
= add_action(self
,
226 N_('Fetch...'), remote
.fetch
)
227 self
.menu_push
= add_action(self
,
228 N_('Push...'), remote
.push
)
229 self
.menu_pull
= add_action(self
,
230 N_('Pull...'), remote
.pull
)
232 self
.menu_open_repo
= add_action(self
,
233 N_('Open...'), guicmds
.open_repo
)
234 self
.menu_open_repo
.setIcon(qtutils
.open_icon())
236 self
.menu_stash
= add_action(self
,
237 N_('Stash...'), stash
.stash
, 'Alt+Shift+S')
239 self
.menu_clone_repo
= add_action(self
,
240 N_('Clone...'), guicmds
.clone_repo
)
241 self
.menu_clone_repo
.setIcon(qtutils
.git_icon())
243 self
.menu_help_docs
= add_action(self
,
244 N_('Documentation'), resources
.show_html_docs
,
245 QtGui
.QKeySequence
.HelpContents
)
247 self
.menu_help_shortcuts
= add_action(self
,
248 N_('Keyboard Shortcuts'),
250 QtCore
.Qt
.Key_Question
)
252 self
.menu_visualize_current
= add_action(self
,
253 N_('Visualize Current Branch...'),
254 cmds
.run(cmds
.VisualizeCurrent
))
255 self
.menu_visualize_all
= add_action(self
,
256 N_('Visualize All Branches...'),
257 cmds
.run(cmds
.VisualizeAll
))
258 self
.menu_search_commits
= add_action(self
,
259 N_('Search...'), search
)
260 self
.menu_browse_branch
= add_action(self
,
261 N_('Browse Current Branch...'), guicmds
.browse_current
)
262 self
.menu_browse_other_branch
= add_action(self
,
263 N_('Browse Other Branch...'), guicmds
.browse_other
)
264 self
.menu_load_commitmsg_template
= add_action(self
,
265 N_('Get Commit Message Template'),
266 cmds
.run(cmds
.LoadCommitMessageFromTemplate
))
267 self
.menu_help_about
= add_action(self
,
268 N_('About'), launch_about_dialog
)
270 self
.menu_diff_expression
= add_action(self
,
271 N_('Expression...'), guicmds
.diff_expression
)
272 self
.menu_branch_compare
= add_action(self
,
273 N_('Branches...'), compare_branches
)
275 self
.menu_create_tag
= add_action(self
,
276 N_('Create Tag...'), create_tag
)
278 self
.menu_create_branch
= add_action(self
,
279 N_('Create...'), create_new_branch
, 'Ctrl+B')
281 self
.menu_delete_branch
= add_action(self
,
282 N_('Delete...'), guicmds
.delete_branch
)
284 self
.menu_delete_remote_branch
= add_action(self
,
285 N_('Delete Remote Branch...'), guicmds
.delete_remote_branch
)
287 self
.menu_checkout_branch
= add_action(self
,
288 N_('Checkout...'), guicmds
.checkout_branch
, 'Alt+B')
289 self
.menu_branch_review
= add_action(self
,
290 N_('Review...'), guicmds
.review_branch
)
292 self
.menu_classic
= add_action(self
,
293 N_('Browser...'), cola_classic
)
294 self
.menu_classic
.setIcon(qtutils
.git_icon())
296 self
.menu_dag
= add_action(self
,
297 N_('DAG...'), lambda: git_dag(self
.model
).show())
298 self
.menu_dag
.setIcon(qtutils
.git_icon())
300 self
.rebase_start_action
= add_action(self
,
301 N_('Start Interactive Rebase...'), self
.rebase_start
)
303 self
.rebase_edit_todo_action
= add_action(self
,
304 N_('Edit...'), self
.rebase_edit_todo
)
306 self
.rebase_continue_action
= add_action(self
,
307 N_('Continue'), self
.rebase_continue
)
309 self
.rebase_skip_action
= add_action(self
,
310 N_('Skip Current Patch'), self
.rebase_skip
)
312 self
.rebase_abort_action
= add_action(self
,
313 N_('Abort'), self
.rebase_abort
)
316 if not self
.classic_dockable
:
317 # These shortcuts conflict with those from the
318 # 'Browser' widget so don't register them when
319 # the browser is a dockable tool.
320 status_tree
= self
.statusdockwidget
.widget().tree
321 self
.addAction(status_tree
.up
)
322 self
.addAction(status_tree
.down
)
323 self
.addAction(status_tree
.process_selection
)
325 self
.lock_layout_action
= add_action_bool(self
,
326 N_('Lock Layout'), self
.set_lock_layout
, False)
328 # Create the application menu
329 self
.menubar
= QtGui
.QMenuBar(self
)
332 self
.file_menu
= create_menu(N_('File'), self
.menubar
)
333 self
.file_menu
.addAction(self
.new_repository
)
334 self
.file_menu
.addAction(self
.menu_open_repo
)
335 self
.menu_open_recent
= self
.file_menu
.addMenu(N_('Open Recent'))
336 self
.file_menu
.addSeparator()
337 self
.file_menu
.addAction(self
.menu_clone_repo
)
338 self
.file_menu
.addAction(self
.menu_manage_bookmarks
)
339 self
.file_menu
.addSeparator()
340 self
.file_menu
.addAction(self
.menu_edit_remotes
)
341 self
.file_menu
.addAction(self
.menu_rescan
)
342 self
.file_menu
.addSeparator()
343 self
.file_menu
.addAction(self
.menu_browse_recent
)
344 self
.file_menu
.addSeparator()
345 self
.file_menu
.addAction(self
.menu_load_commitmsg
)
346 self
.file_menu
.addAction(self
.menu_load_commitmsg_template
)
347 self
.file_menu
.addSeparator()
348 self
.file_menu
.addAction(self
.menu_save_tarball
)
349 self
.file_menu
.addAction(self
.menu_export_patches
)
350 self
.file_menu
.addSeparator()
351 self
.file_menu
.addAction(self
.menu_preferences
)
352 self
.file_menu
.addAction(self
.menu_quit
)
353 self
.menubar
.addAction(self
.file_menu
.menuAction())
356 self
.actions_menu
= create_menu(N_('Actions'), self
.menubar
)
357 self
.actions_menu
.addAction(self
.menu_fetch
)
358 self
.actions_menu
.addAction(self
.menu_push
)
359 self
.actions_menu
.addAction(self
.menu_pull
)
360 self
.actions_menu
.addAction(self
.menu_stash
)
361 self
.actions_menu
.addSeparator()
362 self
.actions_menu
.addAction(self
.menu_create_tag
)
363 self
.actions_menu
.addAction(self
.menu_cherry_pick
)
364 self
.actions_menu
.addAction(self
.menu_merge_local
)
365 self
.actions_menu
.addAction(self
.menu_merge_abort
)
366 self
.actions_menu
.addSeparator()
367 self
.actions_menu
.addAction(self
.menu_grep
)
368 self
.actions_menu
.addAction(self
.menu_search_commits
)
369 self
.menubar
.addAction(self
.actions_menu
.menuAction())
372 self
.commit_menu
= create_menu(N_('Index'), self
.menubar
)
373 self
.commit_menu
.setTitle(N_('Index'))
374 self
.commit_menu
.addAction(self
.menu_stage_modified
)
375 self
.commit_menu
.addAction(self
.menu_stage_untracked
)
376 self
.commit_menu
.addSeparator()
377 self
.commit_menu
.addAction(self
.menu_unstage_all
)
378 self
.commit_menu
.addAction(self
.menu_unstage_selected
)
379 self
.menubar
.addAction(self
.commit_menu
.menuAction())
382 self
.diff_menu
= create_menu(N_('Diff'), self
.menubar
)
383 self
.diff_menu
.addAction(self
.menu_diff_expression
)
384 self
.diff_menu
.addAction(self
.menu_branch_compare
)
385 self
.diff_menu
.addSeparator()
386 self
.diff_menu
.addAction(self
.menu_show_diffstat
)
387 self
.menubar
.addAction(self
.diff_menu
.menuAction())
390 self
.branch_menu
= create_menu(N_('Branch'), self
.menubar
)
391 self
.branch_menu
.addAction(self
.menu_branch_review
)
392 self
.branch_menu
.addSeparator()
393 self
.branch_menu
.addAction(self
.menu_create_branch
)
394 self
.branch_menu
.addAction(self
.menu_checkout_branch
)
395 self
.branch_menu
.addAction(self
.menu_delete_branch
)
396 self
.branch_menu
.addAction(self
.menu_delete_remote_branch
)
397 self
.branch_menu
.addSeparator()
398 self
.branch_menu
.addAction(self
.menu_browse_branch
)
399 self
.branch_menu
.addAction(self
.menu_browse_other_branch
)
400 self
.branch_menu
.addSeparator()
401 self
.branch_menu
.addAction(self
.menu_visualize_current
)
402 self
.branch_menu
.addAction(self
.menu_visualize_all
)
403 self
.menubar
.addAction(self
.branch_menu
.menuAction())
406 self
.rebase_menu
= create_menu(N_('Rebase'), self
.actions_menu
)
407 self
.rebase_menu
.addAction(self
.rebase_start_action
)
408 self
.rebase_menu
.addAction(self
.rebase_edit_todo_action
)
409 self
.rebase_menu
.addSeparator()
410 self
.rebase_menu
.addAction(self
.rebase_continue_action
)
411 self
.rebase_menu
.addAction(self
.rebase_skip_action
)
412 self
.rebase_menu
.addSeparator()
413 self
.rebase_menu
.addAction(self
.rebase_abort_action
)
414 self
.menubar
.addAction(self
.rebase_menu
.menuAction())
417 self
.view_menu
= create_menu(N_('View'), self
.menubar
)
418 self
.view_menu
.addAction(self
.menu_classic
)
419 self
.view_menu
.addAction(self
.menu_dag
)
420 self
.view_menu
.addSeparator()
421 if self
.classic_dockable
:
422 self
.view_menu
.addAction(self
.classicdockwidget
.toggleViewAction())
424 self
.setup_dockwidget_view_menu()
425 self
.view_menu
.addSeparator()
426 self
.view_menu
.addAction(self
.lock_layout_action
)
427 self
.menubar
.addAction(self
.view_menu
.menuAction())
430 self
.help_menu
= create_menu(N_('Help'), self
.menubar
)
431 self
.help_menu
.addAction(self
.menu_help_docs
)
432 self
.help_menu
.addAction(self
.menu_help_shortcuts
)
433 self
.help_menu
.addAction(self
.menu_help_about
)
434 self
.menubar
.addAction(self
.help_menu
.menuAction())
437 self
.setMenuBar(self
.menubar
)
439 # Arrange dock widgets
440 left
= Qt
.LeftDockWidgetArea
441 right
= Qt
.RightDockWidgetArea
442 bottom
= Qt
.BottomDockWidgetArea
444 self
.addDockWidget(left
, self
.commitdockwidget
)
445 if self
.classic_dockable
:
446 self
.addDockWidget(left
, self
.classicdockwidget
)
447 self
.tabifyDockWidget(self
.classicdockwidget
, self
.commitdockwidget
)
448 self
.addDockWidget(left
, self
.diffdockwidget
)
449 self
.addDockWidget(bottom
, self
.actionsdockwidget
)
450 self
.addDockWidget(bottom
, self
.logdockwidget
)
451 self
.tabifyDockWidget(self
.actionsdockwidget
, self
.logdockwidget
)
453 self
.addDockWidget(right
, self
.statusdockwidget
)
455 # Listen for model notifications
456 model
.add_observer(model
.message_updated
, self
._update
_view
)
458 prefs_model
.add_observer(prefs_model
.message_config_updated
,
459 self
._config
_updated
)
461 # Set a default value
462 self
.show_cursor_position(1, 0)
464 self
.connect(self
.menu_open_recent
, SIGNAL('aboutToShow()'),
465 self
.build_recent_menu
)
467 self
.connect(self
.commitmsgeditor
, SIGNAL('cursorPosition(int,int)'),
468 self
.show_cursor_position
)
469 self
.connect(self
, SIGNAL('update'), self
._update
_callback
)
470 self
.connect(self
, SIGNAL('install_config_actions'),
471 self
._install
_config
_actions
)
473 # Install .git-config-defined actions
474 self
._config
_task
= None
475 self
.install_config_actions()
477 # Restore saved settings
478 if not qtutils
.apply_state(self
):
479 self
.set_initial_size()
481 self
.statusdockwidget
.widget().setFocus()
483 # Route command output here
484 Interaction
.log_status
= self
.logwidget
.log_status
485 Interaction
.log
= self
.logwidget
.log
486 Interaction
.log(version
.git_version_str() + '\n' +
487 N_('git cola version %s') % version
.version())
489 def set_initial_size(self
):
490 self
.statuswidget
.set_initial_size()
491 self
.commitmsgeditor
.set_initial_size()
494 def closeEvent(self
, event
):
495 """Save state in the settings manager."""
496 commit_msg
= self
.commitmsgeditor
.commit_message(raw
=True)
497 self
.model
.save_commitmsg(commit_msg
)
498 MainWindow
.closeEvent(self
, event
)
500 def build_recent_menu(self
):
501 recent
= settings
.Settings().recent
502 menu
= self
.menu_open_recent
505 name
= os
.path
.basename(r
)
506 directory
= os
.path
.dirname(r
)
507 text
= '%s %s %s' % (name
, unichr(0x2192), directory
)
508 menu
.addAction(text
, cmds
.run(cmds
.OpenRepo
, r
))
511 mode
= property(lambda self
: self
.model
.mode
)
513 def _config_updated(self
, source
, config
, value
):
514 if config
== 'cola.fontdiff':
517 if not font
.fromString(value
):
519 self
.logwidget
.setFont(font
)
520 self
.diffeditor
.setFont(font
)
521 self
.commitmsgeditor
.setFont(font
)
523 elif config
== 'cola.tabwidth':
524 # variable-tab-width setting
525 self
.diffeditor
.set_tabwidth(value
)
526 self
.commitmsgeditor
.set_tabwidth(value
)
528 elif config
== 'cola.linebreak':
529 # enables automatic line breaks
530 self
.commitmsgeditor
.set_linebreak(value
)
532 elif config
== 'cola.textwidth':
533 # text width used for line wrapping
534 self
.commitmsgeditor
.set_textwidth(value
)
536 def install_config_actions(self
):
537 """Install .gitconfig-defined actions"""
538 self
._config
_task
= self
._start
_config
_actions
_task
()
540 def _start_config_actions_task(self
):
541 """Do the expensive "get_config_actions()" call in the background"""
542 class ConfigActionsTask(QtCore
.QRunnable
):
543 def __init__(self
, sender
):
544 QtCore
.QRunnable
.__init
__(self
)
545 self
._sender
= sender
547 names
= cfgactions
.get_config_actions()
548 self
._sender
.emit(SIGNAL('install_config_actions'), names
)
550 task
= ConfigActionsTask(self
)
551 QtCore
.QThreadPool
.globalInstance().start(task
)
554 def _install_config_actions(self
, names
):
555 """Install .gitconfig-defined actions"""
558 menu
= self
.actions_menu
561 menu
.addAction(name
, cmds
.run(cmds
.RunConfigAction
, name
))
563 def _update_view(self
):
564 self
.emit(SIGNAL('update'))
566 def _update_callback(self
):
567 """Update the title with the current branch and directory name."""
568 branch
= self
.model
.currentbranch
569 curdir
= core
.getcwd()
570 is_rebasing
= self
.model
.is_rebasing
572 msg
= N_('Repository: %s') % curdir
574 msg
+= N_('Branch: %s') % branch
577 msg
+= N_('This repository is currently being rebased.\n'
578 'Resolve conflicts, commit changes, and run:\n'
579 ' Rebase > Continue')
580 self
.commitdockwidget
.setToolTip(msg
)
584 alerts
.append(N_('Rebasing').upper())
585 if self
.mode
== self
.model
.mode_amend
:
586 alerts
.append(N_('Amending').upper())
590 title
= ('%s: %s %s%s' % (
593 alerts
and ((r
+' %s '+l
+' ') % ', '.join(alerts
)) or '',
594 self
.model
.git
.worktree()))
595 self
.setWindowTitle(title
)
596 self
.commitmsgeditor
.set_mode(self
.mode
)
597 self
.update_rebase_actions(is_rebasing
)
599 if not self
.model
.amending():
600 # Check if there's a message file in .git/
601 merge_msg_path
= gitcmds
.merge_message_path()
602 if merge_msg_path
is None:
604 merge_msg_hash
= utils
.checksum(merge_msg_path
)
605 if merge_msg_hash
== self
.merge_message_hash
:
607 self
.merge_message_hash
= merge_msg_hash
608 cmds
.do(cmds
.LoadCommitMessageFromFile
, merge_msg_path
)
610 def update_rebase_actions(self
, is_rebasing
):
611 can_rebase
= not is_rebasing
612 self
.rebase_start_action
.setEnabled(can_rebase
)
613 self
.rebase_edit_todo_action
.setEnabled(is_rebasing
)
614 self
.rebase_continue_action
.setEnabled(is_rebasing
)
615 self
.rebase_skip_action
.setEnabled(is_rebasing
)
616 self
.rebase_abort_action
.setEnabled(is_rebasing
)
618 def apply_state(self
, state
):
619 """Imports data for save/restore"""
620 result
= MainWindow
.apply_state(self
, state
)
621 self
.lock_layout_action
.setChecked(state
.get('lock_layout', False))
624 def setup_dockwidget_view_menu(self
):
625 # Hotkeys for toggling the dock widgets
626 if utils
.is_darwin():
631 (optkey
+ '+0', self
.logdockwidget
),
632 (optkey
+ '+1', self
.commitdockwidget
),
633 (optkey
+ '+2', self
.statusdockwidget
),
634 (optkey
+ '+3', self
.diffdockwidget
),
635 (optkey
+ '+4', self
.actionsdockwidget
),
637 for shortcut
, dockwidget
in dockwidgets
:
638 # Associate the action with the shortcut
639 toggleview
= dockwidget
.toggleViewAction()
640 toggleview
.setShortcut(shortcut
)
641 self
.view_menu
.addAction(toggleview
)
642 def showdock(show
, dockwidget
=dockwidget
):
645 dockwidget
.widget().setFocus()
648 self
.addAction(toggleview
)
649 connect_action_bool(toggleview
, showdock
)
651 # Create a new shortcut Shift+<shortcut> that gives focus
652 toggleview
= QtGui
.QAction(self
)
653 toggleview
.setShortcut('Shift+' + shortcut
)
654 def focusdock(dockwidget
=dockwidget
, showdock
=showdock
):
655 if dockwidget
.toggleViewAction().isChecked():
658 dockwidget
.toggleViewAction().trigger()
659 self
.addAction(toggleview
)
660 connect_action(toggleview
, focusdock
)
662 def _update_diff_opts(self
):
663 space_at_eol
= self
.diff_ignore_space_at_eol_action
.isChecked()
664 space_change
= self
.diff_ignore_space_change_action
.isChecked()
665 all_space
= self
.diff_ignore_all_space_action
.isChecked()
666 function_context
= self
.diff_function_context_action
.isChecked()
668 gitcmds
.update_diff_overrides(space_at_eol
,
672 self
.statuswidget
.refresh()
674 def preferences(self
):
675 return prefs
.preferences(model
=self
.prefs_model
, parent
=self
)
677 def save_archive(self
):
678 ref
= git
.rev_parse('HEAD')[STDOUT
]
680 GitArchiveDialog
.save(ref
, shortref
, self
)
682 def dragEnterEvent(self
, event
):
684 MainWindow
.dragEnterEvent(self
, event
)
685 event
.acceptProposedAction()
687 def dropEvent(self
, event
):
688 """Apply dropped patches with git-am"""
690 urls
= event
.mimeData().urls()
693 paths
= map(lambda x
: unicode(x
.path()), urls
)
694 patches
= [p
for p
in paths
if p
.endswith('.patch')]
695 dirs
= [p
for p
in paths
if os
.path
.isdir(p
)]
698 patches
.extend(self
._gather
_patches
(d
))
699 cmds
.do(cmds
.ApplyPatches
, patches
)
701 def _gather_patches(self
, path
):
702 """Find patches in a subdirectory"""
704 for root
, subdirs
, files
in os
.walk(path
):
705 for name
in [f
for f
in files
if f
.endswith('.patch')]:
706 patches
.append(os
.path
.join(root
, name
))
709 def show_cursor_position(self
, rows
, cols
):
710 display
= ' %02d:%02d ' % (rows
, cols
)
712 display
= ('<span style="color: white; '
713 ' background-color: red;"'
714 '>%s</span>' % display
)
716 display
= ('<span style="color: black; '
717 ' background-color: orange;"'
718 '>%s</span>' % display
)
720 display
= ('<span style="color: black; '
721 ' background-color: yellow;"'
722 '>%s</span>' % display
)
724 display
= ('<span style="color: grey;">%s</span>' % display
)
726 self
.position_label
.setText(display
)
728 def rebase_start(self
):
729 branch
= guicmds
.choose_ref(N_('Select New Upstream'),
730 N_('Interactive Rebase'))
733 self
.model
.is_rebasing
= True
734 self
._update
_callback
()
735 cmds
.do(cmds
.Rebase
, branch
)
737 def rebase_edit_todo(self
):
738 cmds
.do(cmds
.RebaseEditTodo
)
740 def rebase_continue(self
):
741 cmds
.do(cmds
.RebaseContinue
)
743 def rebase_skip(self
):
744 cmds
.do(cmds
.RebaseSkip
)
746 def rebase_abort(self
):
747 cmds
.do(cmds
.RebaseAbort
)