Subversion Repositories HelenOS

Rev

Rev 3843 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3843 Rev 4054
1
#
1
#
2
# Copyright (c) 2009 Martin Decky
2
# Copyright (c) 2009 Martin Decky
3
# All rights reserved.
3
# All rights reserved.
4
#
4
#
5
# Redistribution and use in source and binary forms, with or without
5
# Redistribution and use in source and binary forms, with or without
6
# modification, are permitted provided that the following conditions
6
# modification, are permitted provided that the following conditions
7
# are met:
7
# are met:
8
#
8
#
9
# - Redistributions of source code must retain the above copyright
9
# - Redistributions of source code must retain the above copyright
10
#   notice, this list of conditions and the following disclaimer.
10
#   notice, this list of conditions and the following disclaimer.
11
# - Redistributions in binary form must reproduce the above copyright
11
# - Redistributions in binary form must reproduce the above copyright
12
#   notice, this list of conditions and the following disclaimer in the
12
#   notice, this list of conditions and the following disclaimer in the
13
#   documentation and/or other materials provided with the distribution.
13
#   documentation and/or other materials provided with the distribution.
14
# - The name of the author may not be used to endorse or promote products
14
# - The name of the author may not be used to endorse or promote products
15
#   derived from this software without specific prior written permission.
15
#   derived from this software without specific prior written permission.
16
#
16
#
17
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
#
27
#
28
"""
28
"""
29
Text User Interface wrapper
29
Text User Interface wrapper
30
"""
30
"""
31
 
31
 
32
import sys
32
import sys
33
import os
33
import os
34
 
34
 
35
def call_dlg(dlgcmd, *args, **kw):
35
def call_dlg(dlgcmd, *args, **kw):
36
    "Wrapper for calling 'dialog' program"
36
    "Wrapper for calling 'dialog' program"
37
   
37
   
38
    indesc, outdesc = os.pipe()
38
    indesc, outdesc = os.pipe()
39
    pid = os.fork()
39
    pid = os.fork()
40
    if (not pid):
40
    if (not pid):
41
        os.close(2)
41
        os.close(2)
42
        os.dup(outdesc)
42
        os.dup(outdesc)
43
        os.close(indesc)
43
        os.close(indesc)
44
       
44
       
45
        dlgargs = [dlgcmd]
45
        dlgargs = [dlgcmd]
46
        for key, val in kw.items():
46
        for key, val in kw.items():
47
            dlgargs.append('--' + key)
47
            dlgargs.append('--' + key)
48
            dlgargs.append(val)
48
            dlgargs.append(val)
49
       
49
       
50
        dlgargs += args
50
        dlgargs += args
51
        os.execlp(dlgcmd, *dlgargs)
51
        os.execlp(dlgcmd, *dlgargs)
52
   
52
   
53
    os.close(outdesc)
53
    os.close(outdesc)
54
   
54
   
55
    try:
55
    try:
56
        errout = os.fdopen(indesc, 'r')
56
        errout = os.fdopen(indesc, 'r')
57
        data = errout.read()
57
        data = errout.read()
58
        errout.close()
58
        errout.close()
59
        pid, status = os.wait()
59
        pid, status = os.wait()
60
    except:
60
    except:
61
        # Reset terminal
61
        # Reset terminal
62
        os.system('reset')
62
        os.system('reset')
63
        raise
63
        raise
64
   
64
   
65
    if (not os.WIFEXITED(status)):
65
    if (not os.WIFEXITED(status)):
66
        # Reset terminal
66
        # Reset terminal
67
        os.system('reset')
67
        os.system('reset')
68
        raise EOFError
68
        raise EOFError
69
   
69
   
70
    status = os.WEXITSTATUS(status)
70
    status = os.WEXITSTATUS(status)
71
    if (status == 255):
71
    if (status == 255):
72
        raise EOFError
72
        raise EOFError
73
   
73
   
74
    return (status, data)
74
    return (status, data)
75
 
75
 
76
try:
76
try:
77
    import snack
77
    import snack
78
    newt = True
78
    newt = True
79
    dialog = False
79
    dialog = False
80
except ImportError:
80
except ImportError:
81
    newt = False
81
    newt = False
82
   
82
   
83
    dlgcmd = os.environ.get('DIALOG', 'dialog')
83
    dlgcmd = os.environ.get('DIALOG', 'dialog')
84
    if (call_dlg(dlgcmd, '--print-maxsize')[0] != 0):
84
    if (call_dlg(dlgcmd, '--print-maxsize')[0] != 0):
85
        dialog = False
85
        dialog = False
86
    else:
86
    else:
87
        dialog = True
87
        dialog = True
88
 
88
 
89
width_extra = 13
89
width_extra = 13
90
height_extra = 11
90
height_extra = 11
91
 
91
 
92
def width_fix(screen, width):
92
def width_fix(screen, width):
93
    "Correct width to screen size"
93
    "Correct width to screen size"
94
   
94
   
95
    if (width + width_extra > screen.width):
95
    if (width + width_extra > screen.width):
96
        width = screen.width - width_extra
96
        width = screen.width - width_extra
97
   
97
   
98
    if (width <= 0):
98
    if (width <= 0):
99
        width = screen.width
99
        width = screen.width
100
   
100
   
101
    return width
101
    return width
102
 
102
 
103
def height_fix(screen, height):
103
def height_fix(screen, height):
104
    "Correct height to screen size"
104
    "Correct height to screen size"
105
   
105
   
106
    if (height + height_extra > screen.height):
106
    if (height + height_extra > screen.height):
107
        height = screen.height - height_extra
107
        height = screen.height - height_extra
108
   
108
   
109
    if (height <= 0):
109
    if (height <= 0):
110
        height = screen.height
110
        height = screen.height
111
   
111
   
112
    return height
112
    return height
113
 
113
 
114
def screen_init():
114
def screen_init():
115
    "Initialize the screen"
115
    "Initialize the screen"
116
   
116
   
117
    if (newt):
117
    if (newt):
118
        return snack.SnackScreen()
118
        return snack.SnackScreen()
119
   
119
   
120
    return None
120
    return None
121
 
121
 
122
def screen_done(screen):
122
def screen_done(screen):
123
    "Cleanup the screen"
123
    "Cleanup the screen"
124
   
124
   
125
    if (newt):
125
    if (newt):
126
        screen.finish()
126
        screen.finish()
127
 
127
 
128
def choice_window(screen, title, text, options, position):
128
def choice_window(screen, title, text, options, position):
129
    "Create options menu"
129
    "Create options menu"
130
   
130
   
131
    maxopt = 0
131
    maxopt = 0
132
    for option in options:
132
    for option in options:
133
        length = len(option)
133
        length = len(option)
134
        if (length > maxopt):
134
        if (length > maxopt):
135
            maxopt = length
135
            maxopt = length
136
   
136
   
137
    width = maxopt
137
    width = maxopt
138
    height = len(options)
138
    height = len(options)
139
   
139
   
140
    if (newt):
140
    if (newt):
141
        width = width_fix(screen, width + width_extra)
141
        width = width_fix(screen, width + width_extra)
142
        height = height_fix(screen, height)
142
        height = height_fix(screen, height)
143
       
143
       
144
        if (height > 3):
144
        if (height > 3):
145
            large = True
145
            large = True
146
        else:
146
        else:
147
            large = False
147
            large = False
148
       
148
       
149
        buttonbar = snack.ButtonBar(screen, ('Done', 'Cancel'))
149
        buttonbar = snack.ButtonBar(screen, ('Done', 'Cancel'))
150
        textbox = snack.TextboxReflowed(width, text)
150
        textbox = snack.TextboxReflowed(width, text)
151
        listbox = snack.Listbox(height, scroll = large, returnExit = 1)
151
        listbox = snack.Listbox(height, scroll = large, returnExit = 1)
152
       
152
       
153
        cnt = 0
153
        cnt = 0
154
        for option in options:
154
        for option in options:
155
            listbox.append(option, cnt)
155
            listbox.append(option, cnt)
156
            cnt += 1
156
            cnt += 1
157
       
157
       
158
        if (position != None):
158
        if (position != None):
159
            listbox.setCurrent(position)
159
            listbox.setCurrent(position)
160
       
160
       
161
        grid = snack.GridForm(screen, title, 1, 3)
161
        grid = snack.GridForm(screen, title, 1, 3)
162
        grid.add(textbox, 0, 0)
162
        grid.add(textbox, 0, 0)
163
        grid.add(listbox, 0, 1, padding = (0, 1, 0, 1))
163
        grid.add(listbox, 0, 1, padding = (0, 1, 0, 1))
164
        grid.add(buttonbar, 0, 2, growx = 1)
164
        grid.add(buttonbar, 0, 2, growx = 1)
165
       
165
       
166
        retval = grid.runOnce()
166
        retval = grid.runOnce()
167
       
167
       
168
        return (buttonbar.buttonPressed(retval), listbox.current())
168
        return (buttonbar.buttonPressed(retval), listbox.current())
169
    elif (dialog):
169
    elif (dialog):
170
        if (width < 35):
170
        if (width < 35):
171
            width = 35
171
            width = 35
172
       
172
       
173
        args = []
173
        args = []
174
        cnt = 0
174
        cnt = 0
175
        for option in options:
175
        for option in options:
176
            args.append(str(cnt + 1))
176
            args.append(str(cnt + 1))
177
            args.append(option)
177
            args.append(option)
178
           
178
           
179
            cnt += 1
179
            cnt += 1
180
       
180
       
181
        kw = {}
181
        kw = {}
182
        if (position != None):
182
        if (position != None):
183
            kw['default-item'] = str(position + 1)
183
            kw['default-item'] = str(position + 1)
184
       
184
       
185
        status, data = call_dlg(dlgcmd, '--title', title, '--extra-button', '--extra-label', 'Done', '--menu', text, str(height + height_extra), str(width + width_extra), str(cnt), *args, **kw)
185
        status, data = call_dlg(dlgcmd, '--title', title, '--extra-button', '--extra-label', 'Done', '--menu', text, str(height + height_extra), str(width + width_extra), str(cnt), *args, **kw)
186
       
186
       
187
        if (status == 1):
187
        if (status == 1):
188
            return ('cancel', None)
188
            return ('cancel', None)
189
       
189
       
190
        try:
190
        try:
191
            choice = int(data) - 1
191
            choice = int(data) - 1
192
        except ValueError:
192
        except ValueError:
193
            return ('cancel', None)
193
            return ('cancel', None)
194
       
194
       
195
        if (status == 0):
195
        if (status == 0):
196
            return (None, choice)
196
            return (None, choice)
197
       
197
       
198
        return ('done', choice)
198
        return ('done', choice)
199
   
199
   
200
    sys.stdout.write("\n *** %s *** \n%s\n\n" % (title, text))
200
    sys.stdout.write("\n *** %s *** \n%s\n\n" % (title, text))
201
   
201
   
202
    maxcnt = len(str(len(options)))
202
    maxcnt = len(str(len(options)))
203
    cnt = 0
203
    cnt = 0
204
    for option in options:
204
    for option in options:
205
        sys.stdout.write("%*s. %s\n" % (maxcnt, cnt + 1, option))
205
        sys.stdout.write("%*s. %s\n" % (maxcnt, cnt + 1, option))
206
        cnt += 1
206
        cnt += 1
207
   
207
   
208
    sys.stdout.write("\n%*s. Done\n" % (maxcnt, '0'))
208
    sys.stdout.write("\n%*s. Done\n" % (maxcnt, '0'))
209
    sys.stdout.write("%*s. Quit\n\n" % (maxcnt, 'q'))
209
    sys.stdout.write("%*s. Quit\n\n" % (maxcnt, 'q'))
210
   
210
   
211
    while True:
211
    while True:
212
        if (position != None):
212
        if (position != None):
213
            sys.stdout.write("Selection[%s]: " % str(position + 1))
213
            sys.stdout.write("Selection[%s]: " % str(position + 1))
214
        else:
214
        else:
215
            sys.stdout.write("Selection: ")
215
            sys.stdout.write("Selection: ")
216
        inp = sys.stdin.readline()
216
        inp = sys.stdin.readline()
217
       
217
       
218
        if (not inp):
218
        if (not inp):
219
            raise EOFError
219
            raise EOFError
220
       
220
       
221
        if (not inp.strip()):
221
        if (not inp.strip()):
222
            if (position != None):
222
            if (position != None):
223
                return (None, position)
223
                return (None, position)
224
            continue
224
            continue
225
       
225
       
226
        if (inp.strip() == 'q'):
226
        if (inp.strip() == 'q'):
227
            return ('cancel', None)
227
            return ('cancel', None)
228
       
228
       
229
        try:
229
        try:
230
            choice = int(inp.strip())
230
            choice = int(inp.strip())
231
        except ValueError:
231
        except ValueError:
232
            continue
232
            continue
233
       
233
       
234
        if (choice == 0):
234
        if (choice == 0):
235
            return ('done', 0)
235
            return ('done', 0)
236
       
236
       
237
        if (choice < 1) or (choice > len(options)):
237
        if (choice < 1) or (choice > len(options)):
238
            continue
238
            continue
239
       
239
       
240
        return (None, choice - 1)
240
        return (None, choice - 1)
241
 
241
 
242
def error_dialog(screen, title, msg):
242
def error_dialog(screen, title, msg):
243
    "Print error dialog"
243
    "Print error dialog"
244
   
244
   
245
    width = len(msg)
245
    width = len(msg)
246
   
246
   
247
    if (newt):
247
    if (newt):
248
        width = width_fix(screen, width)
248
        width = width_fix(screen, width)
249
       
249
       
250
        buttonbar = snack.ButtonBar(screen, ['Ok'])
250
        buttonbar = snack.ButtonBar(screen, ['Ok'])
251
        textbox = snack.TextboxReflowed(width, msg)
251
        textbox = snack.TextboxReflowed(width, msg)
252
       
252
       
253
        grid = snack.GridForm(screen, title, 1, 2)
253
        grid = snack.GridForm(screen, title, 1, 2)
254
        grid.add(textbox, 0, 0, padding = (0, 0, 0, 1))
254
        grid.add(textbox, 0, 0, padding = (0, 0, 0, 1))
255
        grid.add(buttonbar, 0, 1, growx = 1)
255
        grid.add(buttonbar, 0, 1, growx = 1)
256
        grid.runOnce()
256
        grid.runOnce()
257
    elif (dialog):
257
    elif (dialog):
258
        call_dlg(dlgcmd, '--title', title, '--msgbox', msg, '6', str(width + width_extra))
258
        call_dlg(dlgcmd, '--title', title, '--msgbox', msg, '6', str(width + width_extra))
259
   
259
    else:
260
    sys.stdout.write("\n%s: %s\n" % (title, msg))
260
        sys.stdout.write("\n%s: %s\n" % (title, msg))
261
 
261