Subversion Repositories HelenOS

Rev

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

Rev 3804 Rev 3805
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):
-
 
145
            large = True
-
 
146
        else:
-
 
147
            large = False
-
 
148
       
144
        buttonbar = snack.ButtonBar(screen, ('Done', 'Cancel'))
149
        buttonbar = snack.ButtonBar(screen, ('Done', 'Cancel'))
145
        textbox = snack.TextboxReflowed(width, text)
150
        textbox = snack.TextboxReflowed(width, text)
146
        listbox = snack.Listbox(height, scroll = True, returnExit = 1)
151
        listbox = snack.Listbox(height, scroll = large, returnExit = 1)
147
       
152
       
148
        cnt = 0
153
        cnt = 0
149
        for option in options:
154
        for option in options:
150
            listbox.append(option, cnt)
155
            listbox.append(option, cnt)
151
            cnt += 1
156
            cnt += 1
152
       
157
       
153
        if (position != None):
158
        if (position != None):
154
            listbox.setCurrent(position)
159
            listbox.setCurrent(position)
155
       
160
       
156
        grid = snack.GridForm(screen, title, 1, 3)
161
        grid = snack.GridForm(screen, title, 1, 3)
157
        grid.add(textbox, 0, 0)
162
        grid.add(textbox, 0, 0)
158
        grid.add(listbox, 0, 1, padding = (0, 1, 0, 1))
163
        grid.add(listbox, 0, 1, padding = (0, 1, 0, 1))
159
        grid.add(buttonbar, 0, 2, growx = 1)
164
        grid.add(buttonbar, 0, 2, growx = 1)
160
       
165
       
161
        retval = grid.runOnce()
166
        retval = grid.runOnce()
162
       
167
       
163
        return (buttonbar.buttonPressed(retval), listbox.current())
168
        return (buttonbar.buttonPressed(retval), listbox.current())
164
    elif (dialog):
169
    elif (dialog):
165
        args = []
170
        args = []
166
        cnt = 0
171
        cnt = 0
167
        for option in options:
172
        for option in options:
168
            args.append(str(cnt + 1))
173
            args.append(str(cnt + 1))
169
            args.append(option)
174
            args.append(option)
170
           
175
           
171
            cnt += 1
176
            cnt += 1
172
       
177
       
173
        kw = {}
178
        kw = {}
174
        if (position != None):
179
        if (position != None):
175
            kw['default-item'] = str(position + 1)
180
            kw['default-item'] = str(position + 1)
176
       
181
       
177
        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)
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)
178
       
183
       
179
        if (status == 1):
184
        if (status == 1):
180
            return ('cancel', None)
185
            return ('cancel', None)
181
       
186
       
182
        try:
187
        try:
183
            choice = int(data) - 1
188
            choice = int(data) - 1
184
        except ValueError:
189
        except ValueError:
185
            return ('cancel', None)
190
            return ('cancel', None)
186
       
191
       
187
        if (status == 0):
192
        if (status == 0):
188
            return (None, choice)
193
            return (None, choice)
189
       
194
       
190
        return ('done', choice)
195
        return ('done', choice)
191
   
196
   
192
    sys.stdout.write("\n *** %s *** \n%s\n\n" % (title, text))
197
    sys.stdout.write("\n *** %s *** \n%s\n\n" % (title, text))
193
   
198
   
194
    maxcnt = len(str(len(options)))
199
    maxcnt = len(str(len(options)))
195
    cnt = 0
200
    cnt = 0
196
    for option in options:
201
    for option in options:
197
        sys.stdout.write("%*s. %s\n" % (maxcnt, cnt + 1, option))
202
        sys.stdout.write("%*s. %s\n" % (maxcnt, cnt + 1, option))
198
        cnt += 1
203
        cnt += 1
199
   
204
   
200
    sys.stdout.write("\n%*s. Done\n" % (maxcnt, '0'))
205
    sys.stdout.write("\n%*s. Done\n" % (maxcnt, '0'))
201
    sys.stdout.write("%*s. Quit\n\n" % (maxcnt, 'q'))
206
    sys.stdout.write("%*s. Quit\n\n" % (maxcnt, 'q'))
202
   
207
   
203
    while True:
208
    while True:
204
        if (position != None):
209
        if (position != None):
205
            sys.stdout.write("Selection[%s]: " % str(position + 1))
210
            sys.stdout.write("Selection[%s]: " % str(position + 1))
206
        else:
211
        else:
207
            sys.stdout.write("Selection: ")
212
            sys.stdout.write("Selection: ")
208
        inp = sys.stdin.readline()
213
        inp = sys.stdin.readline()
209
       
214
       
210
        if (not inp):
215
        if (not inp):
211
            raise EOFError
216
            raise EOFError
212
       
217
       
213
        if (not inp.strip()):
218
        if (not inp.strip()):
214
            if (position != None):
219
            if (position != None):
215
                return (None, position)
220
                return (None, position)
216
            continue
221
            continue
217
       
222
       
218
        if (inp.strip() == 'q'):
223
        if (inp.strip() == 'q'):
219
            return ('cancel', None)
224
            return ('cancel', None)
220
       
225
       
221
        try:
226
        try:
222
            choice = int(inp.strip())
227
            choice = int(inp.strip())
223
        except ValueError:
228
        except ValueError:
224
            continue
229
            continue
225
       
230
       
226
        if (choice == 0):
231
        if (choice == 0):
227
            return ('done', 0)
232
            return ('done', 0)
228
       
233
       
229
        if (choice < 1) or (choice > len(options)):
234
        if (choice < 1) or (choice > len(options)):
230
            continue
235
            continue
231
       
236
       
232
        return (None, choice - 1)
237
        return (None, choice - 1)
233
 
238
 
234
def error_dialog(screen, title, msg):
239
def error_dialog(screen, title, msg):
235
    "Print error dialog"
240
    "Print error dialog"
236
   
241
   
237
    width = len(msg)
242
    width = len(msg)
238
   
243
   
239
    if (newt):
244
    if (newt):
240
        width = width_fix(screen, width)
245
        width = width_fix(screen, width)
241
       
246
       
242
        buttonbar = snack.ButtonBar(screen, ['Ok'])
247
        buttonbar = snack.ButtonBar(screen, ['Ok'])
243
        textbox = snack.TextboxReflowed(width, msg)
248
        textbox = snack.TextboxReflowed(width, msg)
244
       
249
       
245
        grid = snack.GridForm(screen, title, 1, 2)
250
        grid = snack.GridForm(screen, title, 1, 2)
246
        grid.add(textbox, 0, 0, padding = (0, 0, 0, 1))
251
        grid.add(textbox, 0, 0, padding = (0, 0, 0, 1))
247
        grid.add(buttonbar, 0, 1, growx = 1)
252
        grid.add(buttonbar, 0, 1, growx = 1)
248
        grid.runOnce()
253
        grid.runOnce()
249
    elif (dialog):
254
    elif (dialog):
250
        call_dlg(dlgcmd, '--title', title, '--msgbox', msg, '6', str(width + width_extra))
255
        call_dlg(dlgcmd, '--title', title, '--msgbox', msg, '6', str(width + width_extra))
251
   
256
   
252
    sys.stdout.write("\n%s: %s\n" % (title, msg))
257
    sys.stdout.write("\n%s: %s\n" % (title, msg))
253
 
258