Subversion Repositories HelenOS

Rev

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

Rev 3805 Rev 3843
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):
-
 
171
            width = 35
-
 
172
       
170
        args = []
173
        args = []
171
        cnt = 0
174
        cnt = 0
172
        for option in options:
175
        for option in options:
173
            args.append(str(cnt + 1))
176
            args.append(str(cnt + 1))
174
            args.append(option)
177
            args.append(option)
175
           
178
           
176
            cnt += 1
179
            cnt += 1
177
       
180
       
178
        kw = {}
181
        kw = {}
179
        if (position != None):
182
        if (position != None):
180
            kw['default-item'] = str(position + 1)
183
            kw['default-item'] = str(position + 1)
181
       
184
       
182
        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)
183
       
186
       
184
        if (status == 1):
187
        if (status == 1):
185
            return ('cancel', None)
188
            return ('cancel', None)
186
       
189
       
187
        try:
190
        try:
188
            choice = int(data) - 1
191
            choice = int(data) - 1
189
        except ValueError:
192
        except ValueError:
190
            return ('cancel', None)
193
            return ('cancel', None)
191
       
194
       
192
        if (status == 0):
195
        if (status == 0):
193
            return (None, choice)
196
            return (None, choice)
194
       
197
       
195
        return ('done', choice)
198
        return ('done', choice)
196
   
199
   
197
    sys.stdout.write("\n *** %s *** \n%s\n\n" % (title, text))
200
    sys.stdout.write("\n *** %s *** \n%s\n\n" % (title, text))
198
   
201
   
199
    maxcnt = len(str(len(options)))
202
    maxcnt = len(str(len(options)))
200
    cnt = 0
203
    cnt = 0
201
    for option in options:
204
    for option in options:
202
        sys.stdout.write("%*s. %s\n" % (maxcnt, cnt + 1, option))
205
        sys.stdout.write("%*s. %s\n" % (maxcnt, cnt + 1, option))
203
        cnt += 1
206
        cnt += 1
204
   
207
   
205
    sys.stdout.write("\n%*s. Done\n" % (maxcnt, '0'))
208
    sys.stdout.write("\n%*s. Done\n" % (maxcnt, '0'))
206
    sys.stdout.write("%*s. Quit\n\n" % (maxcnt, 'q'))
209
    sys.stdout.write("%*s. Quit\n\n" % (maxcnt, 'q'))
207
   
210
   
208
    while True:
211
    while True:
209
        if (position != None):
212
        if (position != None):
210
            sys.stdout.write("Selection[%s]: " % str(position + 1))
213
            sys.stdout.write("Selection[%s]: " % str(position + 1))
211
        else:
214
        else:
212
            sys.stdout.write("Selection: ")
215
            sys.stdout.write("Selection: ")
213
        inp = sys.stdin.readline()
216
        inp = sys.stdin.readline()
214
       
217
       
215
        if (not inp):
218
        if (not inp):
216
            raise EOFError
219
            raise EOFError
217
       
220
       
218
        if (not inp.strip()):
221
        if (not inp.strip()):
219
            if (position != None):
222
            if (position != None):
220
                return (None, position)
223
                return (None, position)
221
            continue
224
            continue
222
       
225
       
223
        if (inp.strip() == 'q'):
226
        if (inp.strip() == 'q'):
224
            return ('cancel', None)
227
            return ('cancel', None)
225
       
228
       
226
        try:
229
        try:
227
            choice = int(inp.strip())
230
            choice = int(inp.strip())
228
        except ValueError:
231
        except ValueError:
229
            continue
232
            continue
230
       
233
       
231
        if (choice == 0):
234
        if (choice == 0):
232
            return ('done', 0)
235
            return ('done', 0)
233
       
236
       
234
        if (choice < 1) or (choice > len(options)):
237
        if (choice < 1) or (choice > len(options)):
235
            continue
238
            continue
236
       
239
       
237
        return (None, choice - 1)
240
        return (None, choice - 1)
238
 
241
 
239
def error_dialog(screen, title, msg):
242
def error_dialog(screen, title, msg):
240
    "Print error dialog"
243
    "Print error dialog"
241
   
244
   
242
    width = len(msg)
245
    width = len(msg)
243
   
246
   
244
    if (newt):
247
    if (newt):
245
        width = width_fix(screen, width)
248
        width = width_fix(screen, width)
246
       
249
       
247
        buttonbar = snack.ButtonBar(screen, ['Ok'])
250
        buttonbar = snack.ButtonBar(screen, ['Ok'])
248
        textbox = snack.TextboxReflowed(width, msg)
251
        textbox = snack.TextboxReflowed(width, msg)
249
       
252
       
250
        grid = snack.GridForm(screen, title, 1, 2)
253
        grid = snack.GridForm(screen, title, 1, 2)
251
        grid.add(textbox, 0, 0, padding = (0, 0, 0, 1))
254
        grid.add(textbox, 0, 0, padding = (0, 0, 0, 1))
252
        grid.add(buttonbar, 0, 1, growx = 1)
255
        grid.add(buttonbar, 0, 1, growx = 1)
253
        grid.runOnce()
256
        grid.runOnce()
254
    elif (dialog):
257
    elif (dialog):
255
        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))
256
   
259
   
257
    sys.stdout.write("\n%s: %s\n" % (title, msg))
260
    sys.stdout.write("\n%s: %s\n" % (title, msg))
258
 
261