Add jump to change

Add a dialog that prompts for a change number and syncs that change
if needed then immediately opens the change.

Change-Id: Ic2d4f41ad9bd944c2540e8d71bdd3e730bb96117
This commit is contained in:
James E. Blair 2014-05-17 20:00:26 -04:00
parent e63c26f2ed
commit 3252d29400
4 changed files with 107 additions and 3 deletions

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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 '<SyncChangeByNumberTask %s>' % (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)