From 68c51ffdb7dfaa3745b641d77ace799c0899b4c4 Mon Sep 17 00:00:00 2001 From: "James E. Blair" Date: Fri, 2 May 2014 19:38:00 -0700 Subject: [PATCH] Add a Quit dialog Remove the contextlib pipe close feature -- file descriptors are closed on program exit anyway. Letting that happen normally actually makes exiting with CTRL-C nicer (fewer race conditions). Map "CTRL-Q" to the quit command, but pop up a yes/no dialog. Refactor the MessageDialog into a ButtonDialog base class that can serve MessageDialog and YesNoDialog. Add global help text that is prepended to each screen's help text to deal with the growing number of global commands. Change-Id: I455344cb20fb19032a3964d602fc886e19f256e5 --- gertty/gertty.py | 25 ++++++++++++-------- gertty/mywid.py | 46 +++++++++++++++++++++++++++++-------- gertty/view/change.py | 5 ++-- gertty/view/change_list.py | 6 +++-- gertty/view/diff.py | 7 ++++-- gertty/view/project_list.py | 5 +++- 6 files changed, 68 insertions(+), 26 deletions(-) diff --git a/gertty/gertty.py b/gertty/gertty.py index 407efdc..f05de3d 100644 --- a/gertty/gertty.py +++ b/gertty/gertty.py @@ -13,7 +13,6 @@ # under the License. import argparse -import contextlib import logging import os import sys @@ -123,6 +122,7 @@ class App(object): self.loop = urwid.MainLoop(screen, palette=palette, unhandled_input=self.unhandledInput) self.sync_pipe = self.loop.watch_pipe(self.refresh) + self.loop.screen.tty_signal_keys(start='undefined', stop='undefined') #self.loop.screen.set_terminal_properties(colors=88) if not disable_sync: self.sync_thread = threading.Thread(target=self.sync.run, args=(self.sync_pipe,)) @@ -134,15 +134,23 @@ class App(object): def run(self): self.loop.run() - def close(self): - os.close(self.sync_pipe) + def _quit(self, widget=None): + raise urwid.ExitMainLoop() + + def quit(self): + dialog = mywid.YesNoDialog(u'Quit', + u'Are you sure you want to quit?') + urwid.connect_signal(dialog, 'no', self.backScreen) + urwid.connect_signal(dialog, 'yes', self._quit) + + self.popup(dialog) def changeScreen(self, widget): self.status.update(title=widget.title) self.screens.append(self.loop.widget) self.loop.widget = widget - def backScreen(self): + def backScreen(self, widget=None): if not self.screens: return widget = self.screens.pop() @@ -173,15 +181,15 @@ class App(object): lines = self.loop.widget.help.split('\n') urwid.connect_signal(dialog, 'close', lambda button: self.backScreen()) - self.popup(dialog, min_width=76, min_height=len(lines)+2) + self.popup(dialog, min_width=76, min_height=len(lines)+4) def unhandledInput(self, key): if key == 'esc': self.backScreen() elif key == 'f1': self.help() - elif key in ('q', 'Q'): - raise urwid.ExitMainLoop() + elif key == 'ctrl q': + self.quit() def getRepo(self, project_name): local_path = os.path.join(self.config.git_root, project_name) @@ -201,5 +209,4 @@ if __name__ == '__main__': help='the server to use (as specified in config file)') args = parser.parse_args() g = App(args.server, args.debug, args.no_sync) - with contextlib.closing(g): - g.run() + g.run() diff --git a/gertty/mywid.py b/gertty/mywid.py index e7370ea..a715b77 100644 --- a/gertty/mywid.py +++ b/gertty/mywid.py @@ -14,6 +14,14 @@ import urwid +GLOBAL_HELP = """\ +Global Keys +=========== + Help + Back to previous screen + Quit Gertty +""" + class TextButton(urwid.Button): def selectable(self): return True @@ -44,18 +52,36 @@ class Table(urwid.WidgetWrap): for i, widget in enumerate(cells): self._w.contents[i][0].contents.append((widget, ('pack', None))) -class MessageDialog(urwid.WidgetWrap): - signals = ['close'] - def __init__(self, title, message): - ok_button = FixedButton(u'OK') - urwid.connect_signal(ok_button, 'click', - lambda button:self._emit('close')) - buttons = urwid.Columns([('pack', ok_button)], - dividechars=2) +class ButtonDialog(urwid.WidgetWrap): + def __init__(self, title, message, 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)) rows.append(urwid.Divider()) - rows.append(buttons) + rows.append(button_columns) pile = urwid.Pile(rows) fill = urwid.Filler(pile, valign='top') - super(MessageDialog, self).__init__(urwid.LineBox(fill, title)) + super(ButtonDialog, self).__init__(urwid.LineBox(fill, title)) + +class MessageDialog(ButtonDialog): + signals = ['close'] + def __init__(self, title, message): + ok_button = FixedButton('OK') + urwid.connect_signal(ok_button, 'click', + lambda button:self._emit('close')) + super(MessageDialog, self).__init__(title, message, buttons=[ok_button]) + +class YesNoDialog(ButtonDialog): + signals = ['yes', 'no'] + def __init__(self, title, message): + yes_button = FixedButton('Yes') + no_button = FixedButton('No') + urwid.connect_signal(yes_button, 'click', + lambda button:self._emit('yes')) + urwid.connect_signal(no_button, 'click', + lambda button:self._emit('no')) + super(YesNoDialog, self).__init__(title, message, buttons=[yes_button, + no_button]) diff --git a/gertty/view/change.py b/gertty/view/change.py index 8d58488..500858c 100644 --- a/gertty/view/change.py +++ b/gertty/view/change.py @@ -238,9 +238,10 @@ class ChangeMessageBox(urwid.Text): self.set_text(text) class ChangeView(urwid.WidgetWrap): - help = """ + help = mywid.GLOBAL_HELP + """ +This Screen +=========== Toggle the reviewed flag for the current change. - Go back to the previous screen. """ def __init__(self, app, change_key): diff --git a/gertty/view/change_list.py b/gertty/view/change_list.py index 4d3b194..5805e81 100644 --- a/gertty/view/change_list.py +++ b/gertty/view/change_list.py @@ -14,6 +14,7 @@ import urwid +import mywid import view.change class ChangeRow(urwid.Button): @@ -64,10 +65,11 @@ class ChangeListHeader(urwid.WidgetWrap): self._w.contents.append((urwid.Text(' %s' % category[0]), self._w.options('given', 3))) class ChangeListView(urwid.WidgetWrap): - help = """ + help = mywid.GLOBAL_HELP + """ +This Screen +=========== Toggle whether only unreviewed or all changes are displayed. Toggle the reviewed flag for the currently selected change. - Go back to the previous screen. """ def __init__(self, app, project_key): diff --git a/gertty/view/diff.py b/gertty/view/diff.py index f89fe1d..b42ed2b 100644 --- a/gertty/view/diff.py +++ b/gertty/view/diff.py @@ -17,6 +17,8 @@ import logging import urwid +import mywid + class LineContext(object): def __init__(self, old_revision_key, new_revision_key, old_revision_num, new_revision_num, @@ -101,9 +103,10 @@ class DiffLine(urwid.Button): self._w = urwid.AttrMap(col, None, focus_map=map) class DiffView(urwid.WidgetWrap): - help = """ + help = mywid.GLOBAL_HELP + """ +This Screen +=========== Add an inline comment. - Go back to the previous screen. """ def __init__(self, app, new_revision_key): diff --git a/gertty/view/project_list.py b/gertty/view/project_list.py index efefffb..2a5cff3 100644 --- a/gertty/view/project_list.py +++ b/gertty/view/project_list.py @@ -14,6 +14,7 @@ import urwid +import mywid import sync import view.change_list @@ -56,7 +57,9 @@ class ProjectRow(urwid.Button): self.reviewed_changes.set_text(str(len(project.reviewed_changes))) class ProjectListView(urwid.WidgetWrap): - help = """ + help = mywid.GLOBAL_HELP + """ +This Screen +=========== Toggle whether only subscribed projects or all projects are listed. Toggle the subscription flag for the currently selected project. """