def action_completed(self, task, status, output): # Grab the results of the action and finish up self.progress_thread.stop() self.progress_thread.wait() if task in self.tasks: self.tasks.remove(task) already_up_to_date = self.tr('Already up-to-date.') if not output: # git fetch --tags --verbose doesn't print anything... output = already_up_to_date self.setEnabled(True) self.progress.close() QtGui.QApplication.restoreOverrideCursor() result = 'returned exit status %d' % status message = '"git %s" %s' % (self.action.lower(), result) if output: message += '\n\n' + output # Force the status to 1 so that we always display the log qtutils.log(1, message) if status == 0: self.accept() return if self.action == PUSH: message += '\n\nHave you rebased/pulled lately?' qtutils.critical(self.windowTitle(), message=message, details=output)
def export_patch(self): widget = self.commit_list row, selected = qtutils.selected_row(widget) if not selected or len(self.results) < row: return revision = self.results[row][0] qtutils.log(*self.model.export_patchset(revision, revision))
def _revert_unstaged_edits(self, staged=False): if not self.m.undoable(): return if staged: items_to_undo = self.staged() else: items_to_undo = self.modified() if items_to_undo: if not qtutils.confirm('Revert Unstaged Changes?', 'This operation drops unstaged changes.' '\nThese changes cannot be recovered.', 'Revert the unstaged changes?', 'Revert Unstaged Changes', default=True, icon=qtutils.icon('undo.svg')): return args = [] if not staged and self.m.amending(): args.append(self.m.head) cola.notifier().broadcast(signals.checkout, args + ['--'] + items_to_undo) else: qtutils.log(1, self.tr('No files selected for ' 'checkout from HEAD.'))
def _action_completed(self, task, status, output): # Grab the results of the action and finish up if task in self._tasks: self._tasks.remove(task) if not output: # git fetch --tags --verbose doesn't print anything... output = self.tr('Already up-to-date.') # Force the status to 1 so that we always display the log qtutils.log(1, output) self.progress.close() QtGui.QApplication.restoreOverrideCursor() if status != 0 and self.action == 'push': message = 'Error pushing to "%s".\n\nPull first?' % self.model.remotename qtutils.critical('Push Error', message=message, details=output) else: title = self.view.windowTitle() if status == 0: result = 'succeeded' else: result = 'returned exit status %d' % status message = '"git %s" %s' % (self.action, result) qtutils.information(title, message=message, details=output) self.view.accept()
def stash_save(self): """Saves the worktree in a stash This prompts the user for a stash name and creates a git stash named accordingly. """ stash_name, ok = qtutils.prompt('Save Stash', 'Enter a name for the stash') if not ok or not stash_name: return # Sanitize the stash name stash_name = utils.sanitize(stash_name) if stash_name in self.model.stash_names: qtutils.critical('Oops!', 'A stash named "%s" already exists' % stash_name) return args = [] if self.view.keep_index.isChecked(): args.append('--keep-index') args.append(stash_name) qtutils.log(*self.model.git.stash('save', with_stderr=True, with_status=True, *args)) self.view.accept() cola.notifier().broadcast(signals.rescan)
def export_patch(self): widget = self.view.commit_list row, selected = qtutils.selected_row(widget) if not selected or len(self.results) < row: return revision = self.results[row][0] qtutils.log(*self.model.export_patchset(revision, revision))
def cherry_pick(self): widget = self.commit_list row, selected = qtutils.selected_row(widget) if not selected or len(self.results) < row: return revision = self.results[row][0] qtutils.log( *git.cherry_pick(revision, with_stderr=True, with_status=True))
def rebase(): """Rebase onto a branch.""" branch = choose_from_combo('Rebase Branch', cola.model().all_branches()) if not branch: return #TODO cmd status, output = git.rebase(branch, with_stderr=True, with_status=True) qtutils.log(status, output)
def cherry_pick(self): row, selected = qtutils.selected_row(self.view.commit_list) if not selected: return sha1 = self.model.revision_sha1(row) qtutils.log(*self.model.git.cherry_pick(sha1, with_stderr=True, with_status=True))
def cherry_pick(self): widget = self.view.commit_list row, selected = qtutils.selected_row(widget) if not selected or len(self.results) < row: return revision = self.results[row][0] qtutils.log(*self.model.git.cherry_pick(revision, with_stderr=True, with_status=True))
def clone_repo(spawn=True): """ Present GUI controls for cloning a repository A new cola session is invoked when 'spawn' is True. """ url, ok = qtutils.prompt('Path or URL to clone (Env. $VARS okay)') url = os.path.expandvars(core.encode(url)) if not ok or not url: return None try: # Pick a suitable basename by parsing the URL newurl = url.replace('\\', '/') default = newurl.rsplit('/', 1)[-1] if default == '.git': # The end of the URL is /.git, so assume it's a file path default = os.path.basename(os.path.dirname(newurl)) if default.endswith('.git'): # The URL points to a bare repo default = default[:-4] if url == '.': # The URL is the current repo default = os.path.basename(os.getcwd()) if not default: raise except: cola.notifier().broadcast(signals.information, 'Error Cloning', 'Could not parse: "%s"' % url) qtutils.log(1, 'Oops, could not parse git url: "%s"' % url) return None # Prompt the user for a directory to use as the parent directory parent = QtGui.QApplication.instance().activeWindow() msg = 'Select a parent directory for the new clone' dirname = qtutils.opendir_dialog(parent, msg, cola.model().getcwd()) if not dirname: return None count = 1 dirname = core.decode(dirname) destdir = os.path.join(dirname, core.decode(default)) olddestdir = destdir if os.path.exists(destdir): # An existing path can be specified msg = ('"%s" already exists, cola will create a new directory' % destdir) cola.notifier().broadcast(signals.information, 'Directory Exists', msg) # Make sure the new destdir doesn't exist while os.path.exists(destdir): destdir = olddestdir + str(count) count += 1 cola.notifier().broadcast(signals.clone, core.decode(url), destdir, spawn=spawn) return destdir
def remote_callback(): if not self.model.remotename: errmsg = self.tr('No repository selected.') qtutils.log(1, errmsg) return remote, kwargs = self.common_args() action = self.action # Check if we're about to create a new branch and warn. if action == 'push' and not self.model.remote_branch: branch = self.model.local_branch candidate = '%s/%s' % (remote, branch) if candidate not in self.model.remote_branches: title = 'Push' msg = 'Branch "%s" does not exist in %s.' % (branch, remote) msg += '\nA new remote branch will be published.' info_txt= 'Create a new remote branch?' ok_text = 'Create Remote Branch' if not qtutils.confirm(title, msg, info_txt, ok_text, default=False, icon=qtutils.git_icon()): return if not self.model.ffwd_only_checkbox: title = 'Force %s?' % action.title() ok_text = 'Force %s' % action.title() if action == 'fetch': msg = 'Non-fast-forward fetch overwrites local history!' info_txt = 'Force fetching from %s?' % remote elif action == 'push': msg = ('Non-fast-forward push overwrites published ' 'history!\n(Did you pull first?)') info_txt = 'Force push to %s?' % remote else: # pull: shouldn't happen since the controls are hidden msg = "You probably don't want to do this.\n\tContinue?" return if not qtutils.confirm(title, msg, info_txt, ok_text, default=False, icon=qtutils.discard_icon()): return # Disable the GUI by default self.view.setEnabled(False) self.progress.setEnabled(True) QtGui.QApplication.setOverrideCursor(Qt.WaitCursor) # Show a nice progress bar self.progress.setLabelText('Updating...') self.progress.show() # Use a thread to update in the background task = ActionTask(self.view, modelaction, remote, kwargs) self._tasks.append(task) QtCore.QThreadPool.globalInstance().start(task)
def clone_repo(spawn=True): """ Present GUI controls for cloning a repository A new cola session is invoked when 'spawn' is True. """ url, ok = qtutils.prompt('Path or URL to clone (Env. $VARS okay)') url = os.path.expandvars(core.encode(url)) if not ok or not url: return None try: # Pick a suitable basename by parsing the URL newurl = url.replace('\\', '/') default = newurl.rsplit('/', 1)[-1] if default == '.git': # The end of the URL is /.git, so assume it's a file path default = os.path.basename(os.path.dirname(newurl)) if default.endswith('.git'): # The URL points to a bare repo default = default[:-4] if url == '.': # The URL is the current repo default = os.path.basename(os.getcwd()) if not default: raise except: cola.notifier().broadcast(signals.information, 'Error Cloning', 'Could not parse: "%s"' % url) qtutils.log(1, 'Oops, could not parse git url: "%s"' % url) return None # Prompt the user for a directory to use as the parent directory msg = 'Select a parent directory for the new clone' dirname = qtutils.opendir_dialog(msg, cola.model().getcwd()) if not dirname: return None count = 1 dirname = core.decode(dirname) destdir = os.path.join(dirname, core.decode(default)) olddestdir = destdir if os.path.exists(destdir): # An existing path can be specified msg = ('"%s" already exists, cola will create a new directory' % destdir) cola.notifier().broadcast(signals.information, 'Directory Exists', msg) # Make sure the new destdir doesn't exist while os.path.exists(destdir): destdir = olddestdir + str(count) count += 1 cola.notifier().broadcast(signals.clone, core.decode(url), destdir, spawn=spawn) return destdir
def stash_apply(self): """Applies the currently selected stash """ selection = self.selected_stash() if not selection: return qtutils.log(*self.model.git.stash('apply', '--index', selection, with_stderr=True, with_status=True)) self.view.accept()
def select_commits(self): summaries = self.model.summaries if not summaries: msg = self.tr('No commits exist in this branch.') qtutils.log(1, msg) return [] qtutils.set_items(self.commit_list, summaries) self.show() if self.exec_() != QtGui.QDialog.Accepted: return [] revs = self.model.revisions return qtutils.selection_list(self.commit_list, revs)
def commit(self): """Attempt to create a commit from the index and commit message.""" if not bool(self.summary.value()): # Describe a good commit message error_msg = tr( '' 'Please supply a commit message.\n\n' 'A good commit message has the following format:\n\n' '- First line: Describe in one sentence what you did.\n' '- Second line: Blank\n' '- Remaining lines: Describe why this change is good.\n') log(1, error_msg) cola.notifier().broadcast(signals.information, 'Missing Commit Message', error_msg) return msg = self.commit_message(raw=False) if not self.model.staged: error_msg = tr( '' 'No changes to commit.\n\n' 'You must stage at least 1 file before you can commit.') if self.model.modified: informative_text = tr('Would you like to stage and ' 'commit all modified files?') if not confirm('Stage and commit?', error_msg, informative_text, 'Stage and Commit', default=False, icon=save_icon()): return else: cola.notifier().broadcast(signals.information, 'Nothing to commit', error_msg) return cola.notifier().broadcast(signals.stage_modified) # Warn that amending published commits is generally bad amend = self.amend_action.isChecked() if (amend and self.model.is_commit_published() and not confirm('Rewrite Published Commit?', 'This commit has already been published.\n' 'This operation will rewrite published history.\n' 'You probably don\'t want to do this.', 'Amend the published commit?', 'Amend Commit', default=False, icon=save_icon())): return # Perform the commit cola.notifier().broadcast(signals.commit, amend, msg)
def commit(self): """Attempt to create a commit from the index and commit message.""" if not bool(self.summary.value()): # Describe a good commit message error_msg = tr('' 'Please supply a commit message.\n\n' 'A good commit message has the following format:\n\n' '- First line: Describe in one sentence what you did.\n' '- Second line: Blank\n' '- Remaining lines: Describe why this change is good.\n') log(1, error_msg) cola.notifier().broadcast(signals.information, 'Missing Commit Message', error_msg) return msg = self.commit_message() if not self.model.staged: error_msg = tr('' 'No changes to commit.\n\n' 'You must stage at least 1 file before you can commit.') if self.model.modified: informative_text = tr('Would you like to stage and ' 'commit all modified files?') if not confirm('Stage and commit?', error_msg, informative_text, 'Stage and Commit', default=False, icon=save_icon()): return else: cola.notifier().broadcast(signals.information, 'Nothing to commit', error_msg) return cola.notifier().broadcast(signals.stage_modified) # Warn that amending published commits is generally bad amend = self.amend_action.isChecked() if (amend and self.model.is_commit_published() and not confirm('Rewrite Published Commit?', 'This commit has already been published.\n' 'This operation will rewrite published history.\n' 'You probably don\'t want to do this.', 'Amend the published commit?', 'Amend Commit', default=False, icon=save_icon())): return # Perform the commit cola.notifier().broadcast(signals.commit, amend, msg)
def clone_repo(parent, spawn=True): """ Present GUI controls for cloning a repository A new cola session is invoked when 'spawn' is True. """ url, ok = qtutils.prompt("Path or URL to clone (Env. $VARS okay)") url = os.path.expandvars(url) if not ok or not url: return None try: # Pick a suitable basename by parsing the URL newurl = url.replace("\\", "/") default = newurl.rsplit("/", 1)[-1] if default == ".git": # The end of the URL is /.git, so assume it's a file path default = os.path.basename(os.path.dirname(newurl)) if default.endswith(".git"): # The URL points to a bare repo default = default[:-4] if url == ".": # The URL is the current repo default = os.path.basename(os.getcwd()) if not default: raise except: cola.notifier().broadcast(signals.information, "Error Cloning", 'Could not parse: "%s"' % url) qtutils.log(1, 'Oops, could not parse git url: "%s"' % url) return None # Prompt the user for a directory to use as the parent directory msg = "Select a parent directory for the new clone" dirname = qtutils.opendir_dialog(parent, msg, cola.model().getcwd()) if not dirname: return None count = 1 destdir = os.path.join(dirname, default) olddestdir = destdir if os.path.exists(destdir): # An existing path can be specified msg = '"%s" already exists, cola will create a new directory' % destdir cola.notifier().broadcast(signals.information, "Directory Exists", msg) # Make sure the new destdir doesn't exist while os.path.exists(destdir): destdir = olddestdir + str(count) count += 1 cola.notifier().broadcast(signals.clone, url, destdir, spawn=spawn) return destdir
def commit(self): """Attempt to create a commit from the index and commit message.""" msg = unicode(self.commitmsg.toPlainText()) if not msg: # Describe a good commit message error_msg = self.tr('' 'Please supply a commit message.\n\n' 'A good commit message has the following format:\n\n' '- First line: Describe in one sentence what you did.\n' '- Second line: Blank\n' '- Remaining lines: Describe why this change is good.\n') qtutils.log(1, error_msg) cola.notifier().broadcast(signals.information, 'Missing Commit Message', error_msg) return if not self.model.staged: error_msg = self.tr('' 'No changes to commit.\n\n' 'You must stage at least 1 file before you can commit.') if self.model.modified: informative_text = self.tr('Would you like to stage ' 'and commit all modified files?') if not qtutils.confirm(self, 'Stage and commit?', error_msg, informative_text, ok_text='Stage and Commit'): return else: cola.notifier().broadcast(signals.information, 'Nothing to commit', error_msg) return cola.notifier().broadcast(signals.stage_modified) # Warn that amending published commits is generally bad amend = self.amend_checkbox.isChecked() if (amend and self.model.is_commit_published() and not qtutils.question(self, 'Rewrite Published Commit?', 'This commit has already been published.\n' 'You are rewriting published history.\n' 'You probably don\'t want to do this.\n\n' 'Continue?', default=False)): return # Perform the commit cola.notifier().broadcast(signals.commit, amend, msg)
def _remove_uncommitted_edits(self): if not self.model.undoable(): return items_to_undo = self.modified() if items_to_undo: if not qtutils.question( self, "Remove Uncommitted edits?", "This operation removes " "uncommitted edits.\n" "There's no going back. Continue?", default=False, ): return cola.notifier().broadcast(signals.checkout, ["HEAD", "--"] + items_to_undo) else: qtutils.log(1, self.tr("No files selected for " "checkout from HEAD."))
def _revert_uncommitted_edits(self): items_to_undo = self.modified() if items_to_undo: if not qtutils.confirm('Revert Uncommitted Changes?', 'This operation drops uncommitted changes.' '\nThese changes cannot be recovered.', 'Revert the uncommitted changes?', 'Revert Uncommitted Changes', default=True, icon=qtutils.icon('undo.svg')): return cola.notifier().broadcast(signals.checkout, [self.m.head, '--'] + items_to_undo) else: qtutils.log(1, self.tr('No files selected for ' 'checkout from HEAD.'))
def _revert_uncommitted_edits(self): if not self.model.undoable(): return items_to_undo = self.modified() if items_to_undo: if not qtutils.confirm( "Revert Uncommitted Changes?", "This operation drops uncommitted changes." "\nThese changes cannot be recovered.", "Revert the uncommitted changes?", "Revert Uncommitted Changes", default=False, icon=qtutils.icon("undo.svg"), ): return cola.notifier().broadcast(signals.checkout, ["HEAD", "--"] + items_to_undo) else: qtutils.log(1, self.tr("No files selected for " "checkout from HEAD."))
def _remove_uncommitted_edits(self): if not self.model.undoable(): return items_to_undo = self.modified() if items_to_undo: if not qtutils.question(self, 'Remove Uncommitted edits?', 'This operation removes ' 'uncommitted edits.\n' 'There\'s no going back. Continue?', default=False): return cola.notifier().broadcast(signals.checkout, ['HEAD', '--'] + items_to_undo) else: qtutils.log(1, self.tr('No files selected for ' 'checkout from HEAD.'))
def remote_callback(): if not self.model.remotename: errmsg = self.tr('No repository selected.') qtutils.log(1, errmsg) return remote, kwargs = self.common_args() action = self.action # Check if we're about to create a new branch and warn. if action == 'push' and not self.model.remote_branch: branch = self.model.local_branch candidate = '%s/%s' % (remote, branch) if candidate not in self.model.remote_branches: msg = ('Branch "' + branch + '" does not exist in ' + remote + '.\n\nCreate a new branch?') if not qtutils.question(self.view, 'Create New Branch?', msg, default=False): return if not self.model.ffwd_only_checkbox: if action == 'fetch': msg = ('Non-fast-forward fetch overwrites local ' 'history!\n\tContinue?') elif action == 'push': msg = ('Non-fast-forward push overwrites published ' 'history!\nAre you sure you want to do this? ' '(Did you pull first?)\n\tContinue?') else: # pull: shouldn't happen since the controls are hidden msg = "You probably don't want to do this.\n\tContinue?" if not qtutils.question(self.view, 'Force %s?' % action.title(), msg, default=False): return # Disable the GUI by default self.view.setEnabled(False) self.progress.setEnabled(True) QtGui.QApplication.setOverrideCursor(Qt.WaitCursor) # Show a nice progress bar self.progress.setLabelText('Updating...') self.progress.show() # Use a thread to update in the background task = ActionTask(self.view, modelaction, remote, kwargs) self._tasks.append(task) QtCore.QThreadPool.globalInstance().start(task)
def stash_remove(self): """Drops the currently selected stash """ selection = self.selected_stash() name = self.selected_name() if not selection: return if not qtutils.confirm(self.view, 'Remove Stash?', 'Remove "%s"?' % name, 'Recovering these changes may not be possible.', 'Remove', icon=qtutils.discard_icon()): return qtutils.log(*self.model.git.stash('drop', selection, with_stderr=True, with_status=True)) self.update_model()
def stash_drop(self): """Drops the currently selected stash """ selection = self.selected_stash() if not selection: return if not qtutils.question(self.view, 'Drop Stash?', 'This will permanently remove the ' 'selected stash.\n' 'Recovering these changes may not ' 'be possible.\n\n' 'Continue?'): return qtutils.log(*self.model.git.stash('drop', selection, with_stderr=True, with_status=True)) self.update_model()
def merge_revision(self): """Merge the selected revision/branch""" revision = self.model.revision if not revision: qtutils.information('No Revision Specified', 'You must specify a revision to merge') return no_commit = not(self.view.checkbox_commit.isChecked()) squash = self.view.checkbox_squash.isChecked() msg = gitcmds.merge_message() qtutils.log(*self.model.git.merge('-m'+msg, revision, strategy='recursive', no_commit=no_commit, squash=squash, with_stderr=True, with_status=True)) self.view.accept()
def stash_save(self): """Saves the worktree in a stash This prompts the user for a stash name and creates a git stash named accordingly. """ if not qtutils.question(self.view, 'Stash Changes?', 'This will stash your current ' 'changes away for later use.\n' 'Continue?'): return stash_name, ok = qtutils.prompt('Enter a name for this stash') if not ok: return while stash_name in self.model.stash_list: qtutils.information('Oops!', 'That name already exists. ' 'Please enter another name.') stash_name, ok = qtutils.prompt('Enter a name for this stash') if not ok: return if not stash_name: return # Sanitize the stash name stash_name = utils.sanitize(stash_name) args = [] if self.model.keep_index: args.append('--keep-index') args.append(stash_name) qtutils.log(*self.model.git.stash('save', with_stderr=True, with_status=True, *args)) self.view.accept()
def remote_callback(): if not self.model.remotename: errmsg = self.tr('No repository selected.') qtutils.log(1, errmsg) return remote, kwargs = self.common_args() action = self.action # Check if we're about to create a new branch and warn. if action == 'push' and not self.model.remote_branch: branch = self.model.local_branch candidate = '%s/%s' % (remote, branch) if candidate not in self.model.remote_branches: msg = ('Branch "' + branch + '" does not exist in ' + remote + '.\n\nCreate a new branch?') if not qtutils.question(self.view, 'Create New Branch?', msg, default=False): return if not self.model.ffwd_only_checkbox: if action == 'fetch': msg = ('Non-fast-forward fetch overwrites local ' 'history!\n\tContinue?') elif action == 'push': msg = ('Non-fast-forward push overwrites published ' 'history!\nAre you sure you want to do this? ' '(Did you pull first?)\n\tContinue?') else: # pull: shouldn't happen since the controls are hidden msg = "You probably don't want to do this.\n\tContinue?" if not qtutils.question(self.view, 'Force %s?' % action.title(), msg, default=False): return status, output = modelaction(remote, **kwargs) if not output: # git fetch --tags --verbose doesn't print anything... output = self.tr('Already up-to-date.') # Force the status to 1 so that we always display the log qtutils.log(1, output) self.view.accept()
def create_branch(self): """Creates a branch; called by the "Create Branch" button""" revision = self.model.revision branch = self.model.local_branch existing_branches = self.model.local_branches if not branch or not revision: qtutils.information('Missing Data', 'Please provide both a branch ' 'name and revision expression.') return check_branch = False if branch in existing_branches: if self.view.no_update_radio.isChecked(): msg = self.tr("Branch '%s' already exists.") msg = unicode(msg) % branch qtutils.information('warning', msg) return # Whether we should prompt the user for lost commits commits = gitcmds.rev_list_range(revision, branch) check_branch = bool(commits) if check_branch: msg = self.tr("Resetting '%s' to '%s' will " "lose the following commits:") lines = [ unicode(msg) % (branch, revision) ] for idx, commit in enumerate(commits): subject = commit[1][0:min(len(commit[1]),16)] if len(subject) < len(commit[1]): subject += '...' lines.append('\t' + commit[0][:8] +'\t' + subject) if idx >= 5: skip = len(commits) - 5 lines.append('\t(%d skipped)' % skip) break lines.extend([ unicode(self.tr('Recovering lost commits may not be easy.')), unicode(self.tr("Reset '%s'?")) % branch ]) result = qtutils.question(self.view, 'warning', '\n'.join(lines)) if not result: return # TODO handle fetch track = self.view.remote_radio.isChecked() fetch = self.view.fetch_checkbox.isChecked() ffwd = self.view.ffwd_only_radio.isChecked() reset = self.view.reset_radio.isChecked() chkout = self.view.checkout_checkbox.isChecked() status, output = self.model.create_branch(branch, revision, track=track) qtutils.log(status, output) if status == 0 and chkout: status, output = self.model.git.checkout(branch, with_status=True, with_stderr=True) qtutils.log(status, output) self.view.accept()
def _init_log_window(self): """Initialize the logging subwindow.""" branch = self.model.currentbranch qtutils.log(0, self.model.git_version + '\ncola version ' + version.version())
def thread_command(self, status, output): qtutils.log(status, output)
def __init__(self, model, parent): MainWindow.__init__(self, parent) # Default size; this is thrown out when save/restore is used self.resize(987, 610) self.model = model self.prefs_model = prefs_model = PreferencesModel() # Internal field used by import/export_state(). # Change this whenever dockwidgets are removed. self.widget_version = 1 # Keeps track of merge messages we've seen self.merge_message_hash = '' self.setAcceptDrops(True) self.setAttribute(Qt.WA_MacMetalStyle) # Dockwidget options qtcompat.set_common_dock_options(self) cfg = gitcfg.instance() self.classic_dockable = (cfg.get('cola.browserdockable') or cfg.get('cola.classicdockable')) if self.classic_dockable: self.classicdockwidget = create_dock('Browser', self) self.classicwidget = classic_widget(self) self.classicdockwidget.setWidget(self.classicwidget) # "Actions" widget self.actionsdockwidget = create_dock('Action', self) self.actionsdockwidgetcontents = qt.QFlowLayoutWidget(self) layout = self.actionsdockwidgetcontents.layout() self.stage_button = create_button(text='Stage', layout=layout) self.unstage_button = create_button(text='Unstage', layout=layout) self.rescan_button = create_button(text='Rescan', layout=layout) self.fetch_button = create_button(text='Fetch...', layout=layout) self.push_button = create_button(text='Push...', layout=layout) self.pull_button = create_button(text='Pull...', layout=layout) self.stash_button = create_button(text='Stash...', layout=layout) layout.addStretch() self.actionsdockwidget.setWidget(self.actionsdockwidgetcontents) # "Repository Status" widget self.statusdockwidget = create_dock('Status', self) self.statusdockwidget.setWidget(StatusWidget(self)) # "Commit Message Editor" widget self.position_label = QtGui.QLabel() font = qtutils.default_monospace_font() font.setPointSize(int(font.pointSize() * 0.8)) self.position_label.setFont(font) self.commitdockwidget = create_dock('Commit', self) titlebar = self.commitdockwidget.titleBarWidget() titlebar.add_corner_widget(self.position_label) self.commitmsgeditor = CommitMessageEditor(model, self) relay_signal(self, self.commitmsgeditor, SIGNAL(signals.amend_mode)) relay_signal(self, self.commitmsgeditor, SIGNAL(signals.signoff)) relay_signal(self, self.commitmsgeditor, SIGNAL(signals.load_previous_message)) self.commitdockwidget.setWidget(self.commitmsgeditor) # "Console" widget self.logwidget = LogWidget() self.logdockwidget = create_dock('Console', self) self.logdockwidget.setWidget(self.logwidget) cola.notifier().connect(signals.log_cmd, self.logwidget.log) # "Diff Viewer" widget self.diffdockwidget = create_dock('Diff', self) self.diffeditor = DiffEditor(self.diffdockwidget) self.diffdockwidget.setWidget(self.diffeditor) # All Actions self.menu_unstage_all = add_action(self, 'Unstage All', emit(self, signals.unstage_all)) self.menu_unstage_all.setIcon(qtutils.icon('remove.svg')) self.menu_unstage_selected = add_action(self, 'Unstage From Commit', emit(self, signals.unstage_selected)) self.menu_unstage_selected.setIcon(qtutils.icon('remove.svg')) self.menu_show_diffstat = add_action(self, 'Diffstat', emit(self, signals.diffstat), 'Alt+D') self.menu_stage_modified = add_action(self, 'Stage Changed Files To Commit', emit(self, signals.stage_modified), 'Alt+A') self.menu_stage_modified.setIcon(qtutils.icon('add.svg')) self.menu_stage_untracked = add_action(self, 'Stage All Untracked', emit(self, signals.stage_untracked), 'Alt+U') self.menu_stage_untracked.setIcon(qtutils.icon('add.svg')) self.menu_export_patches = add_action(self, 'Export Patches...', guicmds.export_patches, 'Alt+E') self.menu_preferences = add_action(self, 'Preferences', lambda: preferences(model=prefs_model), QtGui.QKeySequence.Preferences, 'Ctrl+O') self.menu_edit_remotes = add_action(self, 'Edit Remotes...', lambda: editremotes.edit().exec_()) self.menu_rescan = add_action(self, 'Rescan', emit(self, signals.rescan_and_refresh), 'Ctrl+R') self.menu_rescan.setIcon(qtutils.reload_icon()) self.menu_browse_recent = add_action(self, 'Recently Modified Files...', browse_recent, 'Shift+Ctrl+E') self.menu_cherry_pick = add_action(self, 'Cherry-Pick...', guicmds.cherry_pick, 'Ctrl+P') self.menu_load_commitmsg = add_action(self, 'Load Commit Message...', guicmds.load_commitmsg) self.menu_save_tarball = add_action(self, 'Save As Tarball/Zip...', self.save_archive) self.menu_quit = add_action(self, 'Quit', self.close, 'Ctrl+Q') self.menu_manage_bookmarks = add_action(self, 'Bookmarks...', manage_bookmarks) self.menu_grep = add_action(self, 'Grep', guicmds.grep) self.menu_merge_local = add_action(self, 'Merge...', merge.local_merge) self.menu_merge_abort = add_action(self, 'Abort Merge...', merge.abort_merge) self.menu_fetch = add_action(self, 'Fetch...', remote.fetch) self.menu_push = add_action(self, 'Push...', remote.push) self.menu_pull = add_action(self, 'Pull...', remote.pull) self.menu_open_repo = add_action(self, 'Open...', guicmds.open_repo) self.menu_open_repo.setIcon(qtutils.open_icon()) self.menu_stash = add_action(self, 'Stash...', stash.stash, 'Alt+Shift+S') self.menu_clone_repo = add_action(self, 'Clone...', guicmds.clone_repo) self.menu_clone_repo.setIcon(qtutils.git_icon()) self.menu_help_docs = add_action(self, 'Documentation', resources.show_html_docs, QtGui.QKeySequence.HelpContents) self.menu_help_shortcuts = add_action(self, 'Keyboard Shortcuts', show_shortcuts, QtCore.Qt.Key_Question) self.menu_visualize_current = add_action(self, 'Visualize Current Branch...', emit(self, signals.visualize_current)) self.menu_visualize_all = add_action(self, 'Visualize All Branches...', emit(self, signals.visualize_all)) self.menu_search_commits = add_action(self, 'Search...', search) self.menu_browse_branch = add_action(self, 'Browse Current Branch...', guicmds.browse_current) self.menu_browse_other_branch = add_action(self, 'Browse Other Branch...', guicmds.browse_other) self.menu_load_commitmsg_template = add_action(self, 'Get Commit Message Template', emit(self, signals.load_commit_template)) self.menu_help_about = add_action(self, 'About', launch_about_dialog) self.menu_branch_diff = add_action(self, 'SHA-1...', guicmds.diff_revision) self.menu_diff_expression = add_action(self, 'Expression...', guicmds.diff_expression) self.menu_branch_compare = add_action(self, 'Branches...', compare_branches) self.menu_create_tag = add_action(self, 'Create Tag...', create_tag) self.menu_create_branch = add_action(self, 'Create...', create_new_branch, 'Ctrl+B') self.menu_delete_branch = add_action(self, 'Delete...', guicmds.branch_delete) self.menu_checkout_branch = add_action(self, 'Checkout...', guicmds.checkout_branch, 'Alt+B') self.menu_rebase_branch = add_action(self, 'Rebase...', guicmds.rebase) self.menu_branch_review = add_action(self, 'Review...', guicmds.review_branch) self.menu_classic = add_action(self, 'Browser...', cola_classic) self.menu_classic.setIcon(qtutils.git_icon()) self.menu_dag = add_action(self, 'DAG...', lambda: git_dag(self.model)) self.menu_dag.setIcon(qtutils.git_icon()) # Relayed actions if not self.classic_dockable: # These shortcuts conflict with those from the # 'Browser' widget so don't register them when # the browser is a dockable tool. status_tree = self.statusdockwidget.widget().tree self.addAction(status_tree.up) self.addAction(status_tree.down) self.addAction(status_tree.process_selection) self.addAction(status_tree.launch_difftool) # Create the application menu self.menubar = QtGui.QMenuBar(self) # File Menu self.file_menu = create_menu('&File', self.menubar) self.file_menu.addAction(self.menu_preferences) self.file_menu.addSeparator() self.file_menu.addAction(self.menu_open_repo) self.menu_open_recent = self.file_menu.addMenu(tr('Open Recent')) self.file_menu.addSeparator() self.file_menu.addAction(self.menu_clone_repo) self.file_menu.addAction(self.menu_manage_bookmarks) self.file_menu.addSeparator() self.file_menu.addAction(self.menu_edit_remotes) self.file_menu.addAction(self.menu_rescan) self.file_menu.addSeparator() self.file_menu.addAction(self.menu_browse_recent) self.file_menu.addSeparator() self.file_menu.addAction(self.menu_load_commitmsg) self.file_menu.addAction(self.menu_load_commitmsg_template) self.file_menu.addSeparator() self.file_menu.addAction(self.menu_save_tarball) self.file_menu.addAction(self.menu_quit) # Add to menubar self.menubar.addAction(self.file_menu.menuAction()) # Commit Menu self.commit_menu = create_menu('Co&mmit', self.menubar) self.commit_menu.setTitle(tr('Commit@@verb')) self.commit_menu.addAction(self.menu_stage_modified) self.commit_menu.addAction(self.menu_stage_untracked) self.commit_menu.addSeparator() self.commit_menu.addAction(self.menu_unstage_all) self.commit_menu.addAction(self.menu_unstage_selected) self.commit_menu.addSeparator() self.commit_menu.addAction(self.menu_search_commits) # Add to menubar self.menubar.addAction(self.commit_menu.menuAction()) # Branch Menu self.branch_menu = create_menu('B&ranch', self.menubar) self.branch_menu.addAction(self.menu_branch_review) self.branch_menu.addSeparator() self.branch_menu.addAction(self.menu_create_branch) self.branch_menu.addAction(self.menu_checkout_branch) self.branch_menu.addAction(self.menu_rebase_branch) self.branch_menu.addAction(self.menu_delete_branch) self.branch_menu.addSeparator() self.branch_menu.addAction(self.menu_browse_branch) self.branch_menu.addAction(self.menu_browse_other_branch) self.branch_menu.addSeparator() self.branch_menu.addAction(self.menu_visualize_current) self.branch_menu.addAction(self.menu_visualize_all) # Add to menubar self.menubar.addAction(self.branch_menu.menuAction()) # Actions menu self.actions_menu = create_menu('Act&ions', self.menubar) self.actions_menu.addAction(self.menu_merge_local) self.actions_menu.addAction(self.menu_stash) self.actions_menu.addSeparator() self.actions_menu.addAction(self.menu_fetch) self.actions_menu.addAction(self.menu_push) self.actions_menu.addAction(self.menu_pull) self.actions_menu.addSeparator() self.actions_menu.addAction(self.menu_create_tag) self.actions_menu.addSeparator() self.actions_menu.addAction(self.menu_export_patches) self.actions_menu.addAction(self.menu_cherry_pick) self.actions_menu.addSeparator() self.actions_menu.addAction(self.menu_merge_abort) self.actions_menu.addAction(self.menu_grep) # Add to menubar self.menubar.addAction(self.actions_menu.menuAction()) # Diff Menu self.diff_menu = create_menu('&Diff', self.menubar) self.diff_menu.addAction(self.menu_branch_diff) self.diff_menu.addAction(self.menu_diff_expression) self.diff_menu.addAction(self.menu_branch_compare) self.diff_menu.addSeparator() self.diff_menu.addAction(self.menu_show_diffstat) # Add to menubar self.menubar.addAction(self.diff_menu.menuAction()) # Tools Menu self.tools_menu = create_menu('&Tools', self.menubar) self.tools_menu.addAction(self.menu_classic) self.tools_menu.addAction(self.menu_dag) self.tools_menu.addSeparator() if self.classic_dockable: self.tools_menu.addAction(self.classicdockwidget.toggleViewAction()) self.setup_dockwidget_tools_menu() self.menubar.addAction(self.tools_menu.menuAction()) # Help Menu self.help_menu = create_menu('&Help', self.menubar) self.help_menu.addAction(self.menu_help_docs) self.help_menu.addAction(self.menu_help_shortcuts) self.help_menu.addAction(self.menu_help_about) # Add to menubar self.menubar.addAction(self.help_menu.menuAction()) # Set main menu self.setMenuBar(self.menubar) # Arrange dock widgets top = Qt.TopDockWidgetArea bottom = Qt.BottomDockWidgetArea self.addDockWidget(top, self.commitdockwidget) if self.classic_dockable: self.addDockWidget(top, self.classicdockwidget) self.addDockWidget(top, self.statusdockwidget) self.addDockWidget(top, self.actionsdockwidget) self.addDockWidget(bottom, self.logdockwidget) if self.classic_dockable: self.tabifyDockWidget(self.classicdockwidget, self.commitdockwidget) self.tabifyDockWidget(self.logdockwidget, self.diffdockwidget) # Listen for model notifications model.add_observer(model.message_updated, self._update_view) prefs_model.add_observer(prefs_model.message_config_updated, self._config_updated) # Set a default value self.show_cursor_position(1, 0) # Add button callbacks connect_button(self.rescan_button, emit(self, signals.rescan_and_refresh)) connect_button(self.fetch_button, remote.fetch) connect_button(self.push_button, remote.push) connect_button(self.pull_button, remote.pull) connect_button(self.stash_button, stash.stash) connect_button(self.stage_button, self.stage) connect_button(self.unstage_button, self.unstage) self.connect(self.menu_open_recent, SIGNAL('aboutToShow()'), self.build_recent_menu) self.connect(self.commitmsgeditor, SIGNAL('cursorPosition(int,int)'), self.show_cursor_position) self.connect(self, SIGNAL('update'), self._update_callback) self.connect(self, SIGNAL('install_config_actions'), self._install_config_actions) # Install .git-config-defined actions self._config_task = None self.install_config_actions() # Restore saved settings qtutils.apply_state(self) self.statusdockwidget.widget().setFocus() log(0, version.git_version_str() + '\ncola version ' + version.version())
def action_callback(self): action = self.action if action == FETCH: model_action = self.model.fetch elif action == PUSH: model_action = self.model.push else: # if action == PULL: model_action = self.model.pull remote_name = unicode(self.remote_name.text()) if not remote_name: errmsg = self.tr('No repository selected.') qtutils.log(1, errmsg) return remote, kwargs = self.common_args() # Check if we're about to create a new branch and warn. remote_branch = unicode(self.remote_branch.text()) local_branch = unicode(self.local_branch.text()) if action == PUSH and not remote_branch: branch = local_branch candidate = '%s/%s' % (remote, branch) if candidate not in self.model.remote_branches: title = self.tr(PUSH) msg = 'Branch "%s" does not exist in %s.' % (branch, remote) msg += '\nA new remote branch will be published.' info_txt = 'Create a new remote branch?' ok_text = 'Create Remote Branch' if not qtutils.confirm(title, msg, info_txt, ok_text, default=False, icon=qtutils.git_icon()): return if not self.ffwd_only_checkbox.isChecked(): title = 'Force %s?' % action.title() ok_text = 'Force %s' % action.title() if action == FETCH: msg = 'Non-fast-forward fetch overwrites local history!' info_txt = 'Force fetching from %s?' % remote elif action == PUSH: msg = ('Non-fast-forward push overwrites published ' 'history!\n(Did you pull first?)') info_txt = 'Force push to %s?' % remote else: # pull: shouldn't happen since the controls are hidden msg = "You probably don't want to do this.\n\tContinue?" return if not qtutils.confirm(title, msg, info_txt, ok_text, default=False, icon=qtutils.discard_icon()): return # Disable the GUI by default self.setEnabled(False) self.progress.setEnabled(True) QtGui.QApplication.setOverrideCursor(Qt.WaitCursor) # Show a nice progress bar self.progress_thread.start() self.progress.show() # Use a thread to update in the background task = ActionTask(self, model_action, remote, kwargs) self.tasks.append(task) QtCore.QThreadPool.globalInstance().start(task)
def __init__(self, model, parent): standard.MainWindow.__init__(self, parent) # Default size; this is thrown out when save/restore is used self.resize(987, 610) self.model = model self.prefs_model = prefs_model = PreferencesModel() # Internal field used by import/export_state(). # Change this whenever dockwidgets are removed. self.widget_version = 1 # Keeps track of merge messages we've seen self.merge_message_hash = '' self.setAcceptDrops(True) # Dockwidget options qtcompat.set_common_dock_options(self) self.classic_dockable = gitcfg.instance().get('cola.classicdockable') if self.classic_dockable: self.classicdockwidget = create_dock('Cola Classic', self) self.classicwidget = classic_widget(self) self.classicdockwidget.setWidget(self.classicwidget) # "Actions" widget self.actiondockwidget = create_dock('Actions', self) self.actiondockwidgetcontents = qt.QFlowLayoutWidget(self) layout = self.actiondockwidgetcontents.layout() self.stage_button = create_button('Stage', layout) self.unstage_button = create_button('Unstage', layout) self.rescan_button = create_button('Rescan', layout) self.fetch_button = create_button('Fetch...', layout) self.push_button = create_button('Push...', layout) self.pull_button = create_button('Pull...', layout) self.stash_button = create_button('Stash...', layout) self.alt_button = create_button('Exit Diff Mode', layout) self.alt_button.hide() layout.addStretch() self.actiondockwidget.setWidget(self.actiondockwidgetcontents) # "Repository Status" widget self.statusdockwidget = create_dock('Repository Status', self) self.statusdockwidget.setWidget(StatusWidget(self)) # "Commit Message Editor" widget self.commitdockwidget = create_dock('Commit Message Editor', self) self.commitmsgeditor = CommitMessageEditor(model, self) relay_signal(self, self.commitmsgeditor, SIGNAL(signals.amend_mode)) relay_signal(self, self.commitmsgeditor, SIGNAL(signals.signoff)) relay_signal(self, self.commitmsgeditor, SIGNAL(signals.load_previous_message)) self.commitdockwidget.setWidget(self.commitmsgeditor) # "Command Output" widget logwidget = qtutils.logger() logwidget.setFont(diff_font()) self.logdockwidget = create_dock('Command Output', self) self.logdockwidget.setWidget(logwidget) # "Diff Viewer" widget self.diffdockwidget = create_dock('Diff Viewer', self) self.diff_viewer = DiffTextEdit(self.diffdockwidget) self.diffdockwidget.setWidget(self.diff_viewer) # All Actions self.menu_unstage_all = add_action(self, 'Unstage All', emit(self, signals.unstage_all)) self.menu_unstage_all.setIcon(qtutils.icon('remove.svg')) self.menu_unstage_selected = add_action(self, 'Unstage From Commit', emit(self, signals.unstage_selected)) self.menu_unstage_selected.setIcon(qtutils.icon('remove.svg')) self.menu_show_diffstat = add_action(self, 'Diffstat', emit(self, signals.diffstat), 'Ctrl+D') self.menu_stage_modified = add_action(self, 'Stage Changed Files To Commit', emit(self, signals.stage_modified), 'Alt+A') self.menu_stage_modified.setIcon(qtutils.icon('add.svg')) self.menu_stage_untracked = add_action(self, 'Stage All Untracked', emit(self, signals.stage_untracked), 'Alt+U') self.menu_stage_untracked.setIcon(qtutils.icon('add.svg')) self.menu_export_patches = add_action(self, 'Export Patches...', guicmds.export_patches, 'Ctrl+E') self.menu_preferences = add_action(self, 'Preferences', lambda: preferences(model=prefs_model), QtGui.QKeySequence.Preferences, 'Ctrl+O') self.menu_rescan = add_action(self, 'Rescan', emit(self, signals.rescan), 'Ctrl+R') self.menu_rescan.setIcon(qtutils.reload_icon()) self.menu_cherry_pick = add_action(self, 'Cherry-Pick...', guicmds.cherry_pick, 'Ctrl+P') self.menu_load_commitmsg = add_action(self, 'Load Commit Message...', guicmds.load_commitmsg) self.menu_quit = add_action(self, 'Quit', self.close, 'Ctrl+Q') self.menu_manage_bookmarks = add_action(self, 'Bookmarks...', manage_bookmarks) self.menu_grep = add_action(self, 'Grep', guicmds.grep) self.menu_merge_local = add_action(self, 'Merge...', merge.local_merge) self.menu_merge_abort = add_action(self, 'Abort Merge...', merge.abort_merge) self.menu_fetch = add_action(self, 'Fetch...', guicmds.fetch) self.menu_push = add_action(self, 'Push...', guicmds.push) self.menu_pull = add_action(self, 'Pull...', guicmds.pull) self.menu_open_repo = add_action(self, 'Open...', guicmds.open_repo) self.menu_open_repo.setIcon(qtutils.open_icon()) self.menu_stash = add_action(self, 'Stash...', stash.stash, 'Alt+Shift+S') self.menu_diff_branch = add_action(self, 'Apply Changes From Branch...', guicmds.diff_branch) self.menu_branch_compare = add_action(self, 'Branches...', compare.branch_compare) self.menu_clone_repo = add_action(self, 'Clone...', guicmds.clone_repo) self.menu_clone_repo.setIcon(qtutils.git_icon()) self.menu_help_docs = add_action(self, 'Documentation', lambda: self.model.git.web__browse(resources.html_docs()), QtGui.QKeySequence.HelpContents) self.menu_commit_compare = add_action(self, 'Commits...', compare.compare) self.menu_commit_compare_file = add_action(self, 'Commits Touching File...', compare.compare_file) self.menu_visualize_current = add_action(self, 'Visualize Current Branch...', emit(self, signals.visualize_current)) self.menu_visualize_all = add_action(self, 'Visualize All Branches...', emit(self, signals.visualize_all)) self.menu_search_commits = add_action(self, 'Search...', search.search) self.menu_browse_branch = add_action(self, 'Browse Current Branch...', guicmds.browse_current) self.menu_browse_other_branch = add_action(self, 'Browse Other Branch...', guicmds.browse_other) self.menu_load_commitmsg_template = add_action(self, 'Get Commit Message Template', emit(self, signals.load_commit_template)) self.menu_help_about = add_action(self, 'About', launch_about_dialog) self.menu_branch_diff = add_action(self, 'SHA-1...', guicmds.branch_diff) self.menu_diff_expression = add_action(self, 'Expression...', guicmds.diff_expression) self.menu_create_tag = add_action(self, 'Create Tag...', createtag.create_tag) self.menu_create_branch = add_action(self, 'Create...', create_new_branch, 'Ctrl+B') self.menu_delete_branch = add_action(self, 'Delete...', guicmds.branch_delete) self.menu_checkout_branch = add_action(self, 'Checkout...', guicmds.checkout_branch, 'Alt+B') self.menu_rebase_branch = add_action(self, 'Rebase...', guicmds.rebase) self.menu_branch_review = add_action(self, 'Review...', guicmds.review_branch) self.menu_classic = add_action(self, 'Cola Classic...', cola_classic) self.menu_classic.setIcon(qtutils.git_icon()) self.menu_dag = add_action(self, 'DAG...', lambda: git_dag(self.model)) self.menu_dag.setIcon(qtutils.git_icon()) # Create the application menu self.menubar = QtGui.QMenuBar(self) # File Menu self.file_menu = create_menu('&File', self.menubar) self.file_menu.addAction(self.menu_preferences) self.file_menu.addSeparator() self.file_menu.addAction(self.menu_open_repo) self.file_menu.addAction(self.menu_clone_repo) self.file_menu.addAction(self.menu_manage_bookmarks) self.file_menu.addSeparator() self.file_menu.addAction(self.menu_rescan) self.file_menu.addSeparator() self.file_menu.addSeparator() self.file_menu.addAction(self.menu_load_commitmsg) self.file_menu.addAction(self.menu_load_commitmsg_template) self.file_menu.addSeparator() self.file_menu.addAction(self.menu_quit) # Add to menubar self.menubar.addAction(self.file_menu.menuAction()) # Commit Menu self.commit_menu = create_menu('Co&mmit', self.menubar) self.commit_menu.setTitle(tr('Commit@@verb')) self.commit_menu.addAction(self.menu_stage_modified) self.commit_menu.addAction(self.menu_stage_untracked) self.commit_menu.addSeparator() self.commit_menu.addAction(self.menu_unstage_all) self.commit_menu.addAction(self.menu_unstage_selected) self.commit_menu.addSeparator() self.commit_menu.addAction(self.menu_search_commits) # Add to menubar self.menubar.addAction(self.commit_menu.menuAction()) # Branch Menu self.branch_menu = create_menu('B&ranch', self.menubar) self.branch_menu.addAction(self.menu_branch_review) self.branch_menu.addSeparator() self.branch_menu.addAction(self.menu_create_branch) self.branch_menu.addAction(self.menu_checkout_branch) self.branch_menu.addAction(self.menu_rebase_branch) self.branch_menu.addAction(self.menu_delete_branch) self.branch_menu.addSeparator() self.branch_menu.addAction(self.menu_browse_branch) self.branch_menu.addAction(self.menu_browse_other_branch) self.branch_menu.addSeparator() self.branch_menu.addAction(self.menu_visualize_current) self.branch_menu.addAction(self.menu_visualize_all) self.branch_menu.addSeparator() self.branch_menu.addAction(self.menu_diff_branch) # Add to menubar self.menubar.addAction(self.branch_menu.menuAction()) # Actions menu self.actions_menu = create_menu('Act&ions', self.menubar) self.actions_menu.addAction(self.menu_merge_local) self.actions_menu.addAction(self.menu_stash) self.actions_menu.addSeparator() self.actions_menu.addAction(self.menu_fetch) self.actions_menu.addAction(self.menu_push) self.actions_menu.addAction(self.menu_pull) self.actions_menu.addSeparator() self.actions_menu.addAction(self.menu_create_tag) self.actions_menu.addSeparator() self.actions_menu.addAction(self.menu_export_patches) self.actions_menu.addAction(self.menu_cherry_pick) self.actions_menu.addSeparator() self.actions_menu.addAction(self.menu_merge_abort) self.actions_menu.addAction(self.menu_grep) # Add to menubar self.menubar.addAction(self.actions_menu.menuAction()) # Diff Menu self.diff_menu = create_menu('&Diff', self.menubar) self.diff_menu.addAction(self.menu_branch_diff) self.diff_menu.addAction(self.menu_diff_expression) self.diff_menu.addSeparator() self.diff_menu.addAction(self.menu_branch_compare) self.diff_menu.addAction(self.menu_commit_compare) self.diff_menu.addAction(self.menu_commit_compare_file) self.diff_menu.addSeparator() self.diff_menu.addAction(self.menu_show_diffstat) # Add to menubar self.menubar.addAction(self.diff_menu.menuAction()) # Tools Menu self.tools_menu = create_menu('&Tools', self.menubar) self.tools_menu.addAction(self.menu_classic) self.tools_menu.addAction(self.menu_dag) self.tools_menu.addSeparator() if self.classic_dockable: self.tools_menu.addAction(self.classicdockwidget.toggleViewAction()) self.tools_menu.addAction(self.diffdockwidget.toggleViewAction()) self.tools_menu.addAction(self.actiondockwidget.toggleViewAction()) self.tools_menu.addAction(self.commitdockwidget.toggleViewAction()) self.tools_menu.addAction(self.statusdockwidget.toggleViewAction()) self.tools_menu.addAction(self.logdockwidget.toggleViewAction()) self.menubar.addAction(self.tools_menu.menuAction()) # Help Menu self.help_menu = create_menu('&Help', self.menubar) self.help_menu.addAction(self.menu_help_docs) self.help_menu.addAction(self.menu_help_about) # Add to menubar self.menubar.addAction(self.help_menu.menuAction()) # Set main menu self.setMenuBar(self.menubar) # Arrange dock widgets top = Qt.TopDockWidgetArea bottom = Qt.BottomDockWidgetArea self.addDockWidget(top, self.commitdockwidget) if self.classic_dockable: self.addDockWidget(top, self.classicdockwidget) self.addDockWidget(top, self.statusdockwidget) self.addDockWidget(top, self.actiondockwidget) self.addDockWidget(bottom, self.logdockwidget) if self.classic_dockable: self.tabifyDockWidget(self.classicdockwidget, self.commitdockwidget) self.tabifyDockWidget(self.logdockwidget, self.diffdockwidget) # Listen for model notifications model.add_message_observer(model.message_mode_changed, self._mode_changed) model.add_message_observer(model.message_updated, self._update_view) prefs_model.add_message_observer(prefs_model.message_config_updated, self._config_updated) # Add button callbacks connect_button(self.rescan_button, emit(self, signals.rescan)) connect_button(self.alt_button, emit(self, signals.reset_mode)) connect_button(self.fetch_button, guicmds.fetch) connect_button(self.push_button, guicmds.push) connect_button(self.pull_button, guicmds.pull) connect_button(self.stash_button, stash.stash) connect_button(self.stage_button, self.stage) connect_button(self.unstage_button, self.unstage) self.connect(self, SIGNAL('update'), self._update_callback) self.connect(self, SIGNAL('apply_state'), self.apply_state) self.connect(self, SIGNAL('install_config_actions'), self._install_config_actions) # Install .git-config-defined actions self._config_task = None self.install_config_actions() # Restore saved settings self._gui_state_task = None self._load_gui_state() log(0, self.model.git_version + '\ncola version ' + version.version())