diff --git a/gertty/app.py b/gertty/app.py index e4d0285..7666ee8 100644 --- a/gertty/app.py +++ b/gertty/app.py @@ -26,6 +26,7 @@ from gertty import gitrepo from gertty import mywid from gertty import sync from gertty.view import project_list as view_project_list +from gertty.view import change as view_change palette=[('focused', 'default,standout', ''), ('header', 'white,bold', 'dark blue'), @@ -125,6 +126,28 @@ class StatusHeader(urwid.WidgetWrap): self.error.set_text(u'') self.sync.set_text(u' Sync: %i' % self.app.sync.queue.qsize()) +class OpenChangeDialog(mywid.ButtonDialog): + signals = ['open', 'cancel'] + def __init__(self): + open_button = mywid.FixedButton('Open') + cancel_button = mywid.FixedButton('Cancel') + urwid.connect_signal(open_button, 'click', + lambda button:self._emit('open')) + urwid.connect_signal(cancel_button, 'click', + lambda button:self._emit('cancel')) + super(OpenChangeDialog, self).__init__("Open Change", + "Enter a change number to open that change.", + entry_prompt="Number: ", + buttons=[open_button, + cancel_button]) + + def keypress(self, size, key): + r = super(OpenChangeDialog, self).keypress(size, key) + if r == 'enter': + self._emit('open') + return None + return r + class App(object): def __init__(self, server=None, debug=False, disable_sync=False): self.server = server @@ -159,6 +182,8 @@ class App(object): self.sync_thread.start() else: self.sync_thread = None + self.sync.offline = True + self.status.update(offline=True) def run(self): self.loop.run() @@ -220,6 +245,50 @@ class App(object): lambda button: self.backScreen()) self.popup(dialog, min_width=76, min_height=len(lines)+4) + def openChange(self): + dialog = OpenChangeDialog() + urwid.connect_signal(dialog, 'cancel', + lambda button: self.backScreen()) + urwid.connect_signal(dialog, 'open', + lambda button: self._openChange(dialog)) + self.popup(dialog, min_width=76, min_height=8) + + def _openChange(self, open_change_dialog): + self.backScreen() + number = open_change_dialog.entry.edit_text + try: + number = int(number) + except Exception: + return self.error('Change number must be an integer.') + with self.db.getSession() as session: + change = session.getChangeByNumber(number) + change_key = change and change.key or None + if change_key is None: + if self.sync.offline: + return self.error('Can not sync change while offline.') + task = sync.SyncChangeByNumberTask(number, sync.HIGH_PRIORITY) + self.sync.submitTask(task) + succeeded = task.wait(300) + if not succeeded: + return self.error('Unable to find change.') + for subtask in task.tasks: + succeeded = task.wait(300) + if not succeeded: + return self.error('Unable to sync change.') + with self.db.getSession() as session: + change = session.getChangeByNumber(number) + change_key = change and change.key or None + if change_key is None: + return self.error('Change is not in local database.') + self.changeScreen(view_change.ChangeView(self, change_key)) + + def error(self, message): + dialog = mywid.MessageDialog('Error', message) + urwid.connect_signal(dialog, 'close', + lambda button: self.backScreen()) + self.popup(dialog, min_height=4) + return None + def unhandledInput(self, key): if key == 'esc': self.backScreen() @@ -227,6 +296,8 @@ class App(object): self.help() elif key == 'ctrl q': self.quit() + elif key == 'ctrl o': + self.openChange() def getRepo(self, project_name): local_path = os.path.join(self.config.git_root, project_name) diff --git a/gertty/db.py b/gertty/db.py index 6dcaf0d..cf81577 100644 --- a/gertty/db.py +++ b/gertty/db.py @@ -419,6 +419,12 @@ class DatabaseSession(object): except sqlalchemy.orm.exc.NoResultFound: return None + def getChangeByNumber(self, number): + try: + return self.session().query(Change).filter_by(number=number).one() + except sqlalchemy.orm.exc.NoResultFound: + return None + def getRevision(self, key): try: return self.session().query(Revision).filter_by(key=key).one() diff --git a/gertty/mywid.py b/gertty/mywid.py index ea6cf4d..2c68a75 100644 --- a/gertty/mywid.py +++ b/gertty/mywid.py @@ -57,13 +57,18 @@ class Table(urwid.WidgetWrap): self._w.contents[i][0].contents.append((widget, ('pack', None))) class ButtonDialog(urwid.WidgetWrap): - def __init__(self, title, message, buttons=[]): + def __init__(self, title, message, entry_prompt=None, entry_text='', buttons=[]): button_widgets = [] for button in buttons: button_widgets.append(('pack', button)) button_columns = urwid.Columns(button_widgets, dividechars=2) rows = [] rows.append(urwid.Text(message)) + if entry_prompt: + self.entry = urwid.Edit(entry_prompt, edit_text=entry_text) + rows.append(self.entry) + else: + self.entry = None rows.append(urwid.Divider()) rows.append(button_columns) pile = urwid.Pile(rows) diff --git a/gertty/sync.py b/gertty/sync.py index 966ce22..ddc888a 100644 --- a/gertty/sync.py +++ b/gertty/sync.py @@ -83,8 +83,9 @@ class Task(object): self.succeeded = success self.event.set() - def wait(self): - self.event.wait() + def wait(self, timeout=None): + self.event.wait(timeout) + return self.succeeded class SyncProjectListTask(Task): def __repr__(self): @@ -168,6 +169,27 @@ class SyncChangeByCommitTask(Task): sync.submitTask(SyncChangeTask(c['id'], self.priority)) self.log.debug("Sync change %s for its commit %s" % (c['id'], self.commit)) +class SyncChangeByNumberTask(Task): + def __init__(self, number, priority=NORMAL_PRIORITY): + super(SyncChangeByNumberTask, self).__init__(priority) + self.number = number + self.tasks = [] + + def __repr__(self): + return '' % (self.number,) + + def run(self, sync): + app = sync.app + with app.db.getSession() as session: + query = '%s' % self.number + changes = sync.get('changes/?q=%s' % query) + self.log.debug('Query: %s ' % (query,)) + for c in changes: + task = SyncChangeTask(c['id'], self.priority) + self.tasks.append(task) + sync.submitTask(task) + self.log.debug("Sync change %s because it is number %s" % (c['id'], self.number)) + class SyncChangeTask(Task): def __init__(self, change_id, priority=NORMAL_PRIORITY): super(SyncChangeTask, self).__init__(priority)