|
655.1.1
by mh21 at piware
First basic crude untested version. |
1 |
#!/usr/bin/python
|
2 |
||
|
1369.1.310
by Martin Pitt
Update all copyright and description headers and consistently format them. |
3 |
'''Command line Apport user interface.'''
|
4 |
||
5 |
# Copyright (C) 2007 - 2009 Canonical Ltd.
|
|
6 |
# Author: Michael Hofmann <mh21@piware.de>
|
|
7 |
#
|
|
8 |
# This program is free software; you can redistribute it and/or modify it
|
|
9 |
# under the terms of the GNU General Public License as published by the
|
|
10 |
# Free Software Foundation; either version 2 of the License, or (at your
|
|
11 |
# option) any later version. See http://www.gnu.org/copyleft/gpl.html for
|
|
12 |
# the full text of the license.
|
|
|
655.1.1
by mh21 at piware
First basic crude untested version. |
13 |
|
|
655.1.5
by mh21 at piware
CLI Fixes: |
14 |
# Web browser support:
|
15 |
# w3m, lynx: do not work
|
|
16 |
# elinks: works
|
|
17 |
||
|
1050
by Martin Pitt
* cli/apport-cli: Intercept SIGPIPE when calling sensible-pager, to avoid |
18 |
import os.path, os, sys, subprocess, re, errno |
|
1369.1.75
by Martin Pitt
apport-cli: Fix report saving in "bug report" mode. (LP: #353253) |
19 |
import tty, termios, tempfile |
|
655.1.10
by mh21 at piware
Control-C and wording fixes, shows date and time of crash. |
20 |
from datetime import datetime |
|
655.1.1
by mh21 at piware
First basic crude untested version. |
21 |
|
|
1369.1.215
by Martin Pitt
Update usage of gettext to work around Python bug of gettext() not returning unicodes, but str. Fixes UnicodeDecodeErrors on translated --help output. |
22 |
from apport import unicode_gettext as _ |
|
1369.18.1
by Marco Rodrigues
Add possibility of translation for some scripts |
23 |
import apport.ui |
|
655.1.1
by mh21 at piware
First basic crude untested version. |
24 |
|
25 |
class CLIDialog: |
|
26 |
'''Command line dialog wrapper.'''
|
|
27 |
||
28 |
def __init__(self, heading, text): |
|
|
655.1.5
by mh21 at piware
CLI Fixes: |
29 |
self.heading = '\n*** ' + heading + '\n' |
|
655.1.1
by mh21 at piware
First basic crude untested version. |
30 |
self.text = text |
31 |
self.keys = [] |
|
32 |
self.buttons = [] |
|
33 |
self.visible = False |
|
34 |
||
|
1369.1.245
by Martin Pitt
apport-cli: Fix crash with non-ASCII characters in prompts. |
35 |
def raw_input_char(self, prompt): |
|
1369.1.215
by Martin Pitt
Update usage of gettext to work around Python bug of gettext() not returning unicodes, but str. Fixes UnicodeDecodeErrors on translated --help output. |
36 |
'''raw_input, but read only one character'''
|
|
655.1.5
by mh21 at piware
CLI Fixes: |
37 |
|
|
1369.1.245
by Martin Pitt
apport-cli: Fix crash with non-ASCII characters in prompts. |
38 |
print >> sys.stdout, prompt, |
|
655.1.5
by mh21 at piware
CLI Fixes: |
39 |
|
40 |
file = sys.stdin.fileno() |
|
41 |
saved_attributes = termios.tcgetattr(file) |
|
42 |
attributes = termios.tcgetattr(file) |
|
43 |
attributes[3] = attributes[3] & ~(termios.ICANON) |
|
44 |
attributes[6][termios.VMIN] = 1 |
|
45 |
attributes[6][termios.VTIME] = 0 |
|
46 |
termios.tcsetattr(file, termios.TCSANOW, attributes) |
|
47 |
||
48 |
try: |
|
49 |
ch = str(sys.stdin.read(1)) |
|
50 |
finally: |
|
51 |
termios.tcsetattr(file, termios.TCSANOW, saved_attributes) |
|
52 |
||
53 |
print
|
|
54 |
return ch |
|
55 |
||
|
655.1.1
by mh21 at piware
First basic crude untested version. |
56 |
def show(self): |
57 |
self.visible = True |
|
58 |
print self.heading |
|
|
1369.4.12
by Martin Pitt
rename hook UI functions, drop titles |
59 |
if self.text: |
60 |
print self.text |
|
|
655.1.1
by mh21 at piware
First basic crude untested version. |
61 |
|
|
1369.4.9
by Martin Pitt
implement interactive hooks functions for CLI |
62 |
def run(self, prompt=None): |
|
655.1.1
by mh21 at piware
First basic crude untested version. |
63 |
if not self.visible: |
64 |
self.show() |
|
65 |
||
|
655.1.5
by mh21 at piware
CLI Fixes: |
66 |
print
|
|
655.1.10
by mh21 at piware
Control-C and wording fixes, shows date and time of crash. |
67 |
try: |
68 |
# Only one button
|
|
69 |
if len (self.keys) <= 1: |
|
70 |
self.raw_input_char(_('Press any key to continue...')) |
|
71 |
return 0 |
|
72 |
# Multiple choices
|
|
73 |
while True: |
|
|
1369.4.9
by Martin Pitt
implement interactive hooks functions for CLI |
74 |
if prompt is not None: |
75 |
print prompt |
|
76 |
else: |
|
77 |
print _('What would you like to do? Your options are:') |
|
|
655.1.10
by mh21 at piware
Control-C and wording fixes, shows date and time of crash. |
78 |
for index, button in enumerate(self.buttons): |
79 |
print ' %s: %s' % (self.keys[index], button) |
|
80 |
||
81 |
response = self.raw_input_char(_('Please choose (%s):') % ('/'.join(self.keys))) |
|
82 |
try: |
|
83 |
return self.keys.index(response[0].upper()) + 1 |
|
84 |
except ValueError: |
|
85 |
pass
|
|
86 |
except KeyboardInterrupt: |
|
87 |
print
|
|
88 |
sys.exit(1) |
|
|
655.1.1
by mh21 at piware
First basic crude untested version. |
89 |
|
|
1369.4.9
by Martin Pitt
implement interactive hooks functions for CLI |
90 |
def addbutton(self, button, hotkey=None): |
91 |
if hotkey: |
|
92 |
self.keys.append(hotkey) |
|
93 |
self.buttons.append(button) |
|
94 |
else: |
|
95 |
self.keys.append(re.search('&(.)', button).group(1).upper()) |
|
96 |
self.buttons.append(re.sub('&', '', button)) |
|
|
655.1.1
by mh21 at piware
First basic crude untested version. |
97 |
return len(self.keys) |
98 |
||
99 |
||
100 |
class CLIProgressDialog(CLIDialog): |
|
101 |
'''Command line progress dialog wrapper.'''
|
|
102 |
||
103 |
def __init__(self, heading, text): |
|
104 |
CLIDialog.__init__(self, heading, text) |
|
|
655.1.5
by mh21 at piware
CLI Fixes: |
105 |
self.progresscount = 0 |
106 |
||
107 |
def set(self, progress = None): |
|
108 |
self.progresscount = (self.progresscount + 1) % 5 |
|
109 |
if self.progresscount: |
|
110 |
return
|
|
111 |
||
112 |
if progress != None: |
|
113 |
sys.stdout.write('\r%u%%' % (progress * 100)) |
|
114 |
else: |
|
115 |
sys.stdout.write('.') |
|
|
655.1.1
by mh21 at piware
First basic crude untested version. |
116 |
sys.stdout.flush() |
117 |
||
118 |
class CLIUserInterface(apport.ui.UserInterface): |
|
119 |
'''Command line Apport user interface'''
|
|
120 |
||
121 |
def __init__(self): |
|
122 |
apport.ui.UserInterface.__init__(self) |
|
123 |
||
124 |
#
|
|
125 |
# ui_* implementation of abstract UserInterface classes
|
|
126 |
#
|
|
127 |
||
128 |
def ui_present_crash(self, desktop_entry): |
|
|
655.1.10
by mh21 at piware
Control-C and wording fixes, shows date and time of crash. |
129 |
date = datetime.strptime(self.report['Date'], '%a %b %d %H:%M:%S %Y') |
|
655.1.1
by mh21 at piware
First basic crude untested version. |
130 |
# adapt dialog heading and label appropriately
|
131 |
if desktop_entry: |
|
132 |
name = desktop_entry.getName() |
|
133 |
elif self.report.has_key('ExecutablePath'): |
|
134 |
name = os.path.basename(self.report['ExecutablePath']) |
|
135 |
else: |
|
136 |
name = self.cur_package |
|
|
1096.1.3
by Daniel Hahler
cli/apport-cli: Fix UnboundLocalError in ui_present_crash, which rendered |
137 |
# translators: first %s: application name, second %s: date, third %s: time
|
138 |
heading = _('%s closed unexpectedly on %s at %s.') % (name, date.date(), date.time()) |
|
|
655.1.1
by mh21 at piware
First basic crude untested version. |
139 |
|
|
655.1.5
by mh21 at piware
CLI Fixes: |
140 |
dialog = CLIDialog( |
|
655.1.1
by mh21 at piware
First basic crude untested version. |
141 |
heading, |
142 |
_('If you were not doing anything confidential (entering passwords or other\n' |
|
143 |
'private information), you can help to improve the application by reporting\n' |
|
144 |
'the problem.')) |
|
145 |
report = dialog.addbutton(_('&Report Problem...')) |
|
146 |
ignore = dialog.addbutton(_('Cancel and &ignore future crashes of this program version')) |
|
147 |
dialog.addbutton(_('&Cancel')) |
|
148 |
||
149 |
# show crash notification dialog
|
|
150 |
response = dialog.run() |
|
151 |
||
152 |
if response == report: |
|
153 |
return {'action': 'report', 'blacklist': False} |
|
154 |
if response == ignore: |
|
155 |
return {'action': 'cancel', 'blacklist': True} |
|
156 |
# Fallback
|
|
157 |
return {'action': 'cancel', 'blacklist': False} |
|
158 |
||
159 |
def ui_present_package_error(self): |
|
160 |
name = self.report['Package'] |
|
|
655.1.5
by mh21 at piware
CLI Fixes: |
161 |
dialog = CLIDialog( |
|
655.1.1
by mh21 at piware
First basic crude untested version. |
162 |
_('The package "%s" failed to install or upgrade.') % name, |
163 |
_('You can help the developers to fix the package by reporting the problem.')) |
|
164 |
report = dialog.addbutton(_('&Report Problem...')) |
|
165 |
dialog.addbutton(_('&Cancel')) |
|
166 |
||
|
1018
by martin at piware
* cli/apport-cli, ui_present_package_error(): Fix running of dialog, so that |
167 |
response = dialog.run() |
|
655.1.1
by mh21 at piware
First basic crude untested version. |
168 |
|
169 |
if response == report: |
|
170 |
return 'report' |
|
171 |
# Fallback
|
|
172 |
return 'cancel' |
|
173 |
||
174 |
def ui_present_kernel_error(self): |
|
|
1254
by Martin Pitt
cli/apport-cli, qt4/apport-qt: Unify string with apport-gtk. |
175 |
message = _('Your system encountered a serious kernel problem.') |
|
1251.1.1
by Andy Whitcroft
bin/apportcheckresume, bin/kernel_oops, cli/apport-cli, gtk/apport-gtk, |
176 |
annotation = '' |
177 |
if self.report.has_key('Annotation'): |
|
178 |
annotation += self.report['Annotation'] + '\n\n' |
|
179 |
annotation += _('You can help the developers to fix the problem by reporting it.') |
|
180 |
||
181 |
dialog = CLIDialog (message, annotation) |
|
|
655.1.1
by mh21 at piware
First basic crude untested version. |
182 |
report = dialog.addbutton(_('&Report Problem...')) |
183 |
dialog.addbutton(_('&Cancel')) |
|
184 |
||
185 |
response = dialog.run() |
|
186 |
||
187 |
if response == report: |
|
188 |
return 'report' |
|
189 |
# Fallback
|
|
190 |
return 'cancel' |
|
191 |
||
|
1369.1.365
by Martin Pitt
apport-cli: Create the details string only if user wants to view details, and do not show files larger than 1MB. Thanks Scott Moser! (LP: #486122) |
192 |
def _get_details(self): |
193 |
'''Build report string for display.'''
|
|
|
655.1.2
by mh21 at piware
Pager support to view the sent report. |
194 |
|
195 |
details = '' |
|
|
1369.1.365
by Martin Pitt
apport-cli: Create the details string only if user wants to view details, and do not show files larger than 1MB. Thanks Scott Moser! (LP: #486122) |
196 |
max_show = 1000000 |
|
1369.1.367
by Martin Pitt
Sort the report by key in the details view. (LP: #519416) |
197 |
for key in sorted(self.report): |
|
655.1.2
by mh21 at piware
Pager support to view the sent report. |
198 |
details += key + ':' |
|
979
by Martin Pitt
* apport/ui.py: Load crash report with keeping compressed binaries. This |
199 |
# string value
|
|
1369.1.365
by Martin Pitt
apport-cli: Create the details string only if user wants to view details, and do not show files larger than 1MB. Thanks Scott Moser! (LP: #486122) |
200 |
keylen = len(self.report[key]) |
|
1099
by Martin Pitt
* apport-{gtk,qt,cli}: Fix handling of file references added by package |
201 |
if not hasattr(self.report[key], 'gzipvalue') and \ |
202 |
hasattr(self.report[key], 'isspace') and \ |
|
|
1369.1.365
by Martin Pitt
apport-cli: Create the details string only if user wants to view details, and do not show files larger than 1MB. Thanks Scott Moser! (LP: #486122) |
203 |
not self.report._is_binary(self.report[key]) and \ |
204 |
keylen < max_show: |
|
|
979
by Martin Pitt
* apport/ui.py: Load crash report with keeping compressed binaries. This |
205 |
lines = self.report[key].splitlines() |
206 |
if len(lines) <= 1: |
|
207 |
details += ' ' + self.report[key] + '\n' |
|
|
655.1.2
by mh21 at piware
Pager support to view the sent report. |
208 |
else: |
|
979
by Martin Pitt
* apport/ui.py: Load crash report with keeping compressed binaries. This |
209 |
details += '\n' |
210 |
for line in lines: |
|
211 |
details += ' ' + line + '\n' |
|
|
1369.1.365
by Martin Pitt
apport-cli: Create the details string only if user wants to view details, and do not show files larger than 1MB. Thanks Scott Moser! (LP: #486122) |
212 |
elif keylen >= max_show: |
213 |
details += ' ' + (_('(%i bytes)') % keylen ) + '\n' |
|
|
655.1.2
by mh21 at piware
Pager support to view the sent report. |
214 |
else: |
|
979
by Martin Pitt
* apport/ui.py: Load crash report with keeping compressed binaries. This |
215 |
details += ' ' + _('(binary data)') + '\n' |
|
655.1.2
by mh21 at piware
Pager support to view the sent report. |
216 |
|
|
1369.1.365
by Martin Pitt
apport-cli: Create the details string only if user wants to view details, and do not show files larger than 1MB. Thanks Scott Moser! (LP: #486122) |
217 |
return details |
218 |
||
219 |
||
220 |
def ui_present_report_details(self, is_update): |
|
221 |
if is_update: |
|
222 |
dialog = CLIDialog (_('Send this data to the developers?'), None) |
|
223 |
else: |
|
224 |
dialog = CLIDialog (_('Send problem report to the developers?'), |
|
225 |
_('After the problem report has been sent, please fill out the form in the\n' |
|
226 |
'automatically opened web browser.')) |
|
227 |
||
|
655.1.2
by mh21 at piware
Pager support to view the sent report. |
228 |
# complete/reduced reports
|
|
764
by martin at piware
* gtk/apport-gtk, qt4/apport-qt, cli/apport-cli: Do not offer 'reduced |
229 |
if self.report.has_key('CoreDump') and self.report.has_useful_stacktrace(): |
|
655.1.2
by mh21 at piware
Pager support to view the sent report. |
230 |
complete = dialog.addbutton(_('&Send complete report (recommended; %s)') % |
|
655.1.1
by mh21 at piware
First basic crude untested version. |
231 |
self.format_filesize(self.get_complete_size())) |
|
655.1.2
by mh21 at piware
Pager support to view the sent report. |
232 |
reduced = dialog.addbutton(_('Send &reduced report (slow Internet connection; %s)') % |
|
655.1.1
by mh21 at piware
First basic crude untested version. |
233 |
self.format_filesize(self.get_reduced_size())) |
|
655.1.2
by mh21 at piware
Pager support to view the sent report. |
234 |
else: |
235 |
complete = dialog.addbutton(_('&Send report (%s)') % |
|
236 |
self.format_filesize(self.get_complete_size())) |
|
237 |
reduced = None |
|
238 |
||
|
655.1.1
by mh21 at piware
First basic crude untested version. |
239 |
view = dialog.addbutton(_('&View report')) |
|
910
by martin at piware
* cli/apport-cli: Add option for keeping the report file without sending it, |
240 |
save = dialog.addbutton(_('&Keep report file for sending later or copying to somewhere else')) |
241 |
||
|
655.1.1
by mh21 at piware
First basic crude untested version. |
242 |
dialog.addbutton(_('&Cancel')) |
243 |
||
244 |
while True: |
|
245 |
response = dialog.run() |
|
246 |
||
247 |
if response == complete: |
|
248 |
return 'full' |
|
249 |
if response == reduced: |
|
250 |
return 'reduced' |
|
251 |
if response == view: |
|
|
1050
by Martin Pitt
* cli/apport-cli: Intercept SIGPIPE when calling sensible-pager, to avoid |
252 |
try: |
253 |
subprocess.Popen(["/usr/bin/sensible-pager"], |
|
254 |
stdin=subprocess.PIPE, |
|
|
1369.1.365
by Martin Pitt
apport-cli: Create the details string only if user wants to view details, and do not show files larger than 1MB. Thanks Scott Moser! (LP: #486122) |
255 |
close_fds=True).communicate(self._get_details()) |
|
1050
by Martin Pitt
* cli/apport-cli: Intercept SIGPIPE when calling sensible-pager, to avoid |
256 |
except IOError, e: |
257 |
# ignore broken pipe (premature quit)
|
|
258 |
if e.errno == errno.EPIPE: |
|
259 |
pass
|
|
260 |
else: |
|
261 |
raise
|
|
|
655.1.1
by mh21 at piware
First basic crude untested version. |
262 |
continue
|
|
910
by martin at piware
* cli/apport-cli: Add option for keeping the report file without sending it, |
263 |
if response == save: |
|
1369.1.75
by Martin Pitt
apport-cli: Fix report saving in "bug report" mode. (LP: #353253) |
264 |
# we do not already have a report file if we report a bug
|
265 |
if not self.report_file: |
|
|
1369.1.186
by Martin Pitt
apport-cli: Save reports with .apport extension instead of .txt. Thanks to Steve Beattie! (LP: #401983) |
266 |
prefix = 'apport.' |
267 |
if self.report.has_key('Package'): |
|
268 |
prefix += self.report['Package'].split()[0] + '.' |
|
269 |
(fd, self.report_file) = tempfile.mkstemp(prefix=prefix, suffix='.apport') |
|
|
1369.1.75
by Martin Pitt
apport-cli: Fix report saving in "bug report" mode. (LP: #353253) |
270 |
self.report.write(os.fdopen(fd, 'w')) |
271 |
||
|
910
by martin at piware
* cli/apport-cli: Add option for keeping the report file without sending it, |
272 |
print _('Problem report file:'), self.report_file |
273 |
return 'cancel' |
|
274 |
||
|
655.1.1
by mh21 at piware
First basic crude untested version. |
275 |
# Fallback
|
276 |
return 'cancel' |
|
277 |
||
278 |
def ui_info_message(self, title, text): |
|
|
655.1.5
by mh21 at piware
CLI Fixes: |
279 |
dialog = CLIDialog(title, text) |
280 |
dialog.addbutton(_('&Confirm')) |
|
281 |
dialog.run() |
|
|
655.1.1
by mh21 at piware
First basic crude untested version. |
282 |
|
283 |
def ui_error_message(self, title, text): |
|
|
655.1.5
by mh21 at piware
CLI Fixes: |
284 |
dialog = CLIDialog(_('Error: %s') % title, text) |
285 |
dialog.addbutton(_('&Confirm')) |
|
286 |
dialog.run() |
|
|
655.1.1
by mh21 at piware
First basic crude untested version. |
287 |
|
288 |
def ui_start_info_collection_progress(self): |
|
289 |
self.progress = CLIProgressDialog ( |
|
290 |
_('Collecting problem information'), |
|
|
1008
by martin at piware
* cli/apport-cli, qt4/apport-qt: Fix typo 'send' -> 'sent'. |
291 |
_('The collected information can be sent to the developers to improve the\n' |
|
707
by Martin Pitt
* cli/apport-cli, qt4/apport-qt: Fix bad grammar 'some minutes'. |
292 |
'application. This might take a few minutes.')) |
|
655.1.1
by mh21 at piware
First basic crude untested version. |
293 |
self.progress.show() |
294 |
||
295 |
def ui_pulse_info_collection_progress(self): |
|
296 |
self.progress.set() |
|
297 |
||
298 |
def ui_stop_info_collection_progress(self): |
|
299 |
print
|
|
300 |
||
301 |
def ui_start_upload_progress(self): |
|
302 |
self.progress = CLIProgressDialog ( |
|
303 |
_('Uploading problem information'), |
|
|
329.1.42
by Kees Cook
english grammar fixup (thanks to Brian Murray) |
304 |
_('The collected information is being sent to the bug tracking system.\n' |
|
707
by Martin Pitt
* cli/apport-cli, qt4/apport-qt: Fix bad grammar 'some minutes'. |
305 |
'This might take a few minutes.')) |
|
655.1.1
by mh21 at piware
First basic crude untested version. |
306 |
self.progress.show() |
307 |
||
308 |
def ui_set_upload_progress(self, progress): |
|
|
655.1.5
by mh21 at piware
CLI Fixes: |
309 |
self.progress.set(progress) |
|
655.1.1
by mh21 at piware
First basic crude untested version. |
310 |
|
311 |
def ui_stop_upload_progress(self): |
|
|
655.1.5
by mh21 at piware
CLI Fixes: |
312 |
print
|
|
655.1.1
by mh21 at piware
First basic crude untested version. |
313 |
|
|
1369.4.13
by Martin Pitt
introduce apport.ui.HookUI |
314 |
def ui_question_yesno(self, text): |
|
1369.4.12
by Martin Pitt
rename hook UI functions, drop titles |
315 |
'''Show a yes/no question.
|
|
1369.4.4
by Martin Pitt
define new UI functions for interactive hooks |
316 |
|
|
1369.4.12
by Martin Pitt
rename hook UI functions, drop titles |
317 |
Return True if the user selected "Yes", False if selected "No" or
|
318 |
"None" on cancel/dialog closing.
|
|
|
1369.4.4
by Martin Pitt
define new UI functions for interactive hooks |
319 |
'''
|
|
1369.4.12
by Martin Pitt
rename hook UI functions, drop titles |
320 |
dialog = CLIDialog(text, None) |
|
1369.4.9
by Martin Pitt
implement interactive hooks functions for CLI |
321 |
r_yes = dialog.addbutton('&Yes') |
|
1369.4.16
by Martin Pitt
apport-cli: Fix totally broken yesno() implementation |
322 |
r_no = dialog.addbutton('&No') |
323 |
r_cancel = dialog.addbutton(_('&Cancel')) |
|
324 |
result = dialog.run() |
|
325 |
if result == r_yes: |
|
326 |
return True |
|
327 |
if result == r_no: |
|
328 |
return False |
|
329 |
assert result == r_cancel |
|
|
1369.4.12
by Martin Pitt
rename hook UI functions, drop titles |
330 |
return None |
|
1369.4.4
by Martin Pitt
define new UI functions for interactive hooks |
331 |
|
|
1369.4.13
by Martin Pitt
introduce apport.ui.HookUI |
332 |
def ui_question_choice(self, text, options, multiple): |
|
1369.4.12
by Martin Pitt
rename hook UI functions, drop titles |
333 |
'''Show an question with predefined choices.
|
|
1369.4.4
by Martin Pitt
define new UI functions for interactive hooks |
334 |
|
335 |
options is a list of strings to present. If multiple is True, they
|
|
336 |
should be check boxes, if multiple is False they should be radio
|
|
337 |
buttons.
|
|
338 |
||
339 |
Return list of selected option indexes, or None if the user cancelled.
|
|
340 |
If multiple == False, the list will always have one element.
|
|
341 |
'''
|
|
|
1369.4.9
by Martin Pitt
implement interactive hooks functions for CLI |
342 |
result = [] |
|
1369.4.12
by Martin Pitt
rename hook UI functions, drop titles |
343 |
dialog = CLIDialog(text, None) |
|
1369.4.9
by Martin Pitt
implement interactive hooks functions for CLI |
344 |
|
345 |
if multiple: |
|
346 |
while True: |
|
|
1369.4.12
by Martin Pitt
rename hook UI functions, drop titles |
347 |
dialog = CLIDialog(text, None) |
|
1369.4.9
by Martin Pitt
implement interactive hooks functions for CLI |
348 |
index = 0 |
349 |
choice_index_map = {} |
|
350 |
for option in options: |
|
351 |
if index not in result: |
|
352 |
choice_index_map[dialog.addbutton(option, str(index+1))] = index |
|
353 |
index += 1 |
|
354 |
done = dialog.addbutton(_('&Done')) |
|
355 |
cancel = dialog.addbutton(_('&Cancel')) |
|
356 |
||
357 |
if result: |
|
358 |
cur = ', '.join([str(r+1) for r in result]) |
|
359 |
else: |
|
360 |
cur = _('none') |
|
361 |
response = dialog.run(_('Selected: %s. Multiple choices:') % cur) |
|
362 |
if response == cancel: |
|
363 |
return None |
|
364 |
if response == done: |
|
365 |
break
|
|
366 |
result.append(choice_index_map[response]) |
|
367 |
||
368 |
else: |
|
369 |
# single choice (radio button)
|
|
|
1369.4.12
by Martin Pitt
rename hook UI functions, drop titles |
370 |
dialog = CLIDialog(text, None) |
|
1369.4.9
by Martin Pitt
implement interactive hooks functions for CLI |
371 |
index = 1 |
372 |
for option in options: |
|
373 |
dialog.addbutton(option, str(index)) |
|
374 |
index += 1 |
|
375 |
||
376 |
cancel = dialog.addbutton(_('&Cancel')) |
|
377 |
response = dialog.run(_('Choices:')) |
|
378 |
if response == cancel: |
|
379 |
return None |
|
380 |
result.append(response-1) |
|
381 |
||
382 |
return result |
|
|
1369.4.4
by Martin Pitt
define new UI functions for interactive hooks |
383 |
|
|
1369.4.13
by Martin Pitt
introduce apport.ui.HookUI |
384 |
def ui_question_file(self, text): |
|
1369.4.12
by Martin Pitt
rename hook UI functions, drop titles |
385 |
'''Show a file selector dialog.
|
|
1369.4.4
by Martin Pitt
define new UI functions for interactive hooks |
386 |
|
387 |
Return path if the user selected a file, or None if cancelled.
|
|
388 |
'''
|
|
|
1369.4.12
by Martin Pitt
rename hook UI functions, drop titles |
389 |
print '\n*** ', text |
|
1369.4.9
by Martin Pitt
implement interactive hooks functions for CLI |
390 |
while True: |
391 |
print _('Path to file (Enter to cancel):'), ' ', |
|
392 |
f = sys.stdin.readline().strip() |
|
393 |
if not f: |
|
394 |
return None |
|
395 |
if not os.path.exists(f): |
|
396 |
print _('File does not exist.') |
|
397 |
elif os.path.isdir(f): |
|
398 |
print _('This is a directory.') |
|
399 |
else: |
|
400 |
return f |
|
|
1369.4.4
by Martin Pitt
define new UI functions for interactive hooks |
401 |
|
|
1369.1.241
by Martin Pitt
apport-cli: Print the URL and ask whether to open a browser. (LP: #286415) |
402 |
def open_url(self, url): |
403 |
text = '%s\n\n %s\n\n%s' % ( |
|
404 |
_('To continue, you must visit the following URL:'), |
|
405 |
url, |
|
406 |
_('You can launch a browser now, or copy this URL into a browser on another computer.')) |
|
407 |
||
408 |
answer = self.ui_question_choice(text, [_('Launch a browser now')], False) |
|
|
1369.1.365
by Martin Pitt
apport-cli: Create the details string only if user wants to view details, and do not show files larger than 1MB. Thanks Scott Moser! (LP: #486122) |
409 |
if answer == [0]: |
|
1369.1.241
by Martin Pitt
apport-cli: Print the URL and ask whether to open a browser. (LP: #286415) |
410 |
apport.ui.UserInterface.open_url(self, url) |
411 |
||
|
655.1.1
by mh21 at piware
First basic crude untested version. |
412 |
if __name__ == '__main__': |
413 |
app = CLIUserInterface() |
|
|
1052
by Martin Pitt
* apport/ui.py, run_argv(): Add return code which indicates whether any |
414 |
if not app.run_argv(): |
415 |
print >> sys.stderr, _('No pending crash reports. Try --help for more information.') |