From f3903ef97bf20c002e0f00b3264b7d13d9be4330 Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Mon, 19 Dec 2011 00:06:42 -0800 Subject: [PATCH] main.model: Do not depend on ObservableModel Now that there's no QObserver we don't need all the magic. Simplify the model and factor out responsibility where possible. Signed-off-by: David Aguilar --- cola/main/model.py | 83 +++++++++++------------------- cola/main/view.py | 2 +- cola/version.py | 7 ++- cola/widgets/remote.py | 134 ++++++++++++++++++++++++------------------------- 4 files changed, 100 insertions(+), 126 deletions(-) diff --git a/cola/main/model.py b/cola/main/model.py index 92accd5b..5c882881 100644 --- a/cola/main/model.py +++ b/cola/main/model.py @@ -11,7 +11,7 @@ from cola import git from cola import gitcfg from cola import gitcmds from cola.compat import set -from cola.obsmodel import ObservableModel +from cola.observable import Observable from cola.decorators import memoize @@ -25,13 +25,14 @@ def model(): return MainModel() -class MainModel(ObservableModel): +class MainModel(Observable): """Provides a friendly wrapper for doing common git operations.""" # Observable messages message_about_to_update = 'about_to_update' message_commit_message_changed = 'commit_message_changed' message_diff_text_changed = 'diff_text_changed' + message_directory_changed = 'directory_changed' message_filename_changed = 'filename_changed' message_head_changed = 'head_changed' message_mode_changed = 'mode_changed' @@ -60,24 +61,20 @@ class MainModel(ObservableModel): """Reads git repository settings and sets several methods so that they refer to the git module. This object encapsulates cola's interaction with git.""" - ObservableModel.__init__(self) + super(MainModel, self).__init__() # Initialize the git command object self.git = git.instance() - ##################################################### self.head = 'HEAD' self.diff_text = '' self.mode = self.mode_none self.filename = None self.currentbranch = '' - self.trackedbranch = '' self.directory = '' - self.git_version = self.git.version() + self.project = '' self.remotes = [] - ##################################################### - # Status info self.commitmsg = '' self.modified = [] self.staged = [] @@ -86,24 +83,12 @@ class MainModel(ObservableModel): self.upstream_changed = [] self.submodules = set() - ##################################################### - # Refs - self.revision = '' self.local_branches = [] self.remote_branches = [] self.tags = [] - - self.fetch_helper = None - self.push_helper = None - self.pull_helper = None - self.generate_remote_helpers() if cwd: self.set_worktree(cwd) - ##################################################### - # Dag - self._commits = [] - def read_only(self): return self.mode in self.modes_read_only @@ -115,12 +100,6 @@ class MainModel(ObservableModel): """Whether staging should be allowed.""" return self.mode in (self.mode_worktree, self.mode_untracked) - def generate_remote_helpers(self): - """Generates helper methods for fetch, push and pull""" - self.push_helper = self.gen_remote_helper(self.git.push, push=True) - self.fetch_helper = self.gen_remote_helper(self.git.fetch) - self.pull_helper = self.gen_remote_helper(self.git.pull) - def editor(self): app = _config.get('gui.editor', 'gvim') return {'vim': 'gvim'}.get(app, app) @@ -136,7 +115,7 @@ class MainModel(ObservableModel): is_valid = self.git.is_valid() if is_valid: basename = os.path.basename(self.git.worktree()) - self.set_project(core.decode(basename)) + self.project = core.decode(basename) return is_valid def set_commitmsg(self, msg): @@ -147,6 +126,10 @@ class MainModel(ObservableModel): self.diff_text = txt self.notify_message_observers(self.message_diff_text_changed, txt) + def set_directory(self, path): + self.directory = path + self.notify_message_observers(self.message_directory_changed, path) + def set_filename(self, filename): self.filename = filename self.notify_message_observers(self.message_filename_changed, filename) @@ -174,30 +157,16 @@ class MainModel(ObservableModel): def update_file_status(self, update_index=False): self.notify_message_observers(self.message_about_to_update) - self.notification_enabled = False self._update_files(update_index=update_index) - self.notification_enabled = True - self.notify_observers('staged', 'unstaged') - self.broadcast_updated() + self.notify_message_observers(self.message_updated) def update_status(self, update_index=False): # Give observers a chance to respond self.notify_message_observers(self.message_about_to_update) - # This allows us to defer notification until the - # we finish processing data - self.notification_enabled = False - self._update_files(update_index=update_index) self._update_refs() self._update_branches_and_tags() self._update_branch_heads() - - # Re-enable notifications and emit changes - self.notification_enabled = True - self.notify_observers('staged', 'unstaged') - self.broadcast_updated() - - def broadcast_updated(self): self.notify_message_observers(self.message_updated) def _update_files(self, update_index=False): @@ -213,18 +182,17 @@ class MainModel(ObservableModel): self.upstream_changed = state.get('upstream_changed', []) def _update_refs(self): - self.set_remotes(self.git.remote().splitlines()) + self.remotes = self.git.remote().splitlines() def _update_branch_heads(self): # Set these early since they are used to calculate 'upstream_changed'. - self.set_trackedbranch(gitcmds.tracked_branch()) - self.set_currentbranch(gitcmds.current_branch()) + self.currentbranch = gitcmds.current_branch() def _update_branches_and_tags(self): local_branches, remote_branches, tags = gitcmds.all_refs(split=True) - self.set_local_branches(local_branches) - self.set_remote_branches(remote_branches) - self.set_tags(tags) + self.local_branches = local_branches + self.remote_branches = remote_branches + self.tags = tags def delete_branch(self, branch): return self.git.branch(branch, @@ -399,13 +367,18 @@ class MainModel(ObservableModel): } return (args, kwargs) - def gen_remote_helper(self, gitaction, push=False): - """Generates a closure that calls git fetch, push or pull - """ - def remote_helper(remote, **kwargs): - args, kwargs = self.remote_args(remote, push=push, **kwargs) - return gitaction(*args, **kwargs) - return remote_helper + def run_remote_action(self, action, remote, push=False, **kwargs): + args, kwargs = self.remote_args(remote, push=push, **kwargs) + return action(*args, **kwargs) + + def fetch(self, remote, **opts): + return self.run_remote_action(self.git.fetch, remote, **opts) + + def push(self, remote, **opts): + return self.run_remote_action(self.git.fetch, remote, push=True, **opts) + + def pull(self, remote, **opts): + return self.run_remote_action(self.git.pull, remote, push=True, **opts) def create_branch(self, name, base, track=False): """Create a branch named 'name' from revision 'base' diff --git a/cola/main/view.py b/cola/main/view.py index 0ddd779d..469c9835 100644 --- a/cola/main/view.py +++ b/cola/main/view.py @@ -427,7 +427,7 @@ class MainView(standard.MainWindow): self._gui_state_task = None self._load_gui_state() - log(0, self.model.git_version + '\ncola version ' + version.version()) + log(0, version.git_version_str() + '\ncola version ' + version.version()) # Qt overrides def closeEvent(self, event): diff --git a/cola/version.py b/cola/version.py index a6a81732..1934b7fa 100644 --- a/cola/version.py +++ b/cola/version.py @@ -67,9 +67,14 @@ def version_to_list(version): @memoize +def git_version_str(): + """Returns the current GIT version""" + return git.version() + +@memoize def git_version(): """Returns the current GIT version""" - return git.version().split()[-1] + return git_version_str().split()[-1] if __name__ == '__main__': diff --git a/cola/widgets/remote.py b/cola/widgets/remote.py index b5827600..06a885f8 100644 --- a/cola/widgets/remote.py +++ b/cola/widgets/remote.py @@ -66,20 +66,13 @@ class RemoteActionDialog(standard.Dialog): """Customizes the dialog based on the remote action """ standard.Dialog.__init__(self, parent=parent) - self.setWindowTitle(self.tr(action)) - self.setWindowModality(QtCore.Qt.WindowModal) - self.model = model - - #: The current mode; one of fetch/push/pull self.action = action - self.action_method = { - FETCH: self.gen_remote_callback(self.model.fetch_helper), - PUSH: self.gen_remote_callback(self.model.push_helper), - PULL: self.gen_remote_callback(self.model.pull_helper), - } [action] - self.tasks = [] + + self.setWindowTitle(self.tr(action)) + self.setWindowModality(QtCore.Qt.WindowModal) + self.progress = QtGui.QProgressDialog(self) self.progress.setRange(0, 0) self.progress.setCancelButton(None) @@ -187,7 +180,7 @@ class RemoteActionDialog(standard.Dialog): self.connect(self.remote_branches, SIGNAL('itemSelectionChanged()'), self.update_remote_branches) - connect_button(self.action_button, self.action_method) + connect_button(self.action_button, self.action_callback) connect_button(self.close_button, self.reject) self.connect(self, SIGNAL('action_completed'), self.action_completed) @@ -342,71 +335,74 @@ class RemoteActionDialog(standard.Dialog): #+------------------------------------------------------------- #+ Actions - def gen_remote_callback(self, model_action): - """Generates a Qt callback for fetch/push/pull. - """ - def remote_callback(): - 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() - action = self.action - - # 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 + 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() + action = self.action + # 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.discard_icon()): + icon=qtutils.git_icon()): return - # Disable the GUI by default - self.setEnabled(False) - self.progress.setEnabled(True) - QtGui.QApplication.setOverrideCursor(Qt.WaitCursor) + 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 - # Show a nice progress bar - self.progress.setLabelText('Updating...') - self.progress.show() + # Disable the GUI by default + self.setEnabled(False) + self.progress.setEnabled(True) + QtGui.QApplication.setOverrideCursor(Qt.WaitCursor) - # Use a thread to update in the background - task = ActionTask(self, model_action, remote, kwargs) - self.tasks.append(task) - QtCore.QThreadPool.globalInstance().start(task) + # Show a nice progress bar + self.progress.setLabelText('Updating...') + self.progress.show() - return remote_callback + # 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 action_completed(self, task, status, output): # Grab the results of the action and finish up -- 2.11.4.GIT