3 ### Utility module for xtoys Python programs
5 ### (c) 2007 Straylight/Edgeware
8 ###----- Licensing notice ---------------------------------------------------
10 ### This file is part of the Edgeware X tools collection.
12 ### X tools is free software; you can redistribute it and/or modify
13 ### it under the terms of the GNU General Public License as published by
14 ### the Free Software Foundation; either version 2 of the License, or
15 ### (at your option) any later version.
17 ### X tools is distributed in the hope that it will be useful,
18 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ### GNU General Public License for more details.
22 ### You should have received a copy of the GNU General Public License
23 ### along with X tools; if not, write to the Free Software Foundation,
24 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 ###--------------------------------------------------------------------------
27 ### External dependencies.
31 from sys
import stdin
, stdout
, exit
, argv
40 ###--------------------------------------------------------------------------
41 ### Reasons for living.
51 """Drop a reason. When reasons reach zero, the main loop stops."""
57 ###--------------------------------------------------------------------------
58 ### General utilities.
60 def make_optparse(options
, **kw
):
62 Construct an option parser object.
64 The KW are keyword arguments to be passed to OptionParser. The OPTIONS are
65 a list of (SHORT, LONG, KW) triples; the SHORT and LONG strings do /not/
68 op
= O
.OptionParser(**kw
)
69 for short
, long, kw
in options
:
70 names
= ['--%s' %
long]
72 names
.append('-%s' % short
)
73 op
.add_option(*names
, **kw
)
76 ###--------------------------------------------------------------------------
79 class MessageButton (object):
81 An object storing information about a button in a Message.
84 def __init__(me
, label
, value
= None, *options
):
86 Initialize a button definition.
88 If LABEL is a tuple, then it should have the form
89 (LABEL, VALUE, OPTIONS...); the initialization parser is applied to its
90 contents. This is not done recursively.
92 If LABEL is a string, and VALUE and OPTIONS are omitted, then it is
93 parsed as OPT:OPT:...:LABEL, where OPT is either an option (see below) or
94 `=VALUE'. Only one VALUE may be given.
96 The LABEL is the label to put on the button, or the GTK stock id. The
97 VALUE is the value to return from Message.ask if the button is chosen.
100 * 'default': this is the default button
101 * 'cancel': this is the cancel button
103 if value
is not None or len(options
) > 0:
104 me
._doinit(label
, value
, *options
)
105 elif isinstance(label
, tuple):
110 while 0 <= i
< len(label
):
114 j
= label
.find(':', i
)
118 if value
is not None:
119 raise ValueError, 'Duplicate value in button spec %s' % label
120 value
= label
[i
+ 1:j
]
122 options
.append(label
[i
:j
])
125 me
._doinit(label
, value
, *options
)
127 def _doinit(me
, label
, value
= None, *options
):
129 Does the work of processing the initialization parameters.
136 me
.defaultp
= me
.cancelp
= False
140 elif opt
== 'cancel':
143 raise ValueError, 'unknown button option %s' % opt
145 class Message (GTK
.MessageDialog
):
147 A simple message-box window: contains text and some buttons.
149 See __init__ for the usage instructions.
152 ## Mapping from Pythonic strings to GTK constants.
153 dboxtype
= {'info': GTK
.MESSAGE_INFO
,
154 'warning': GTK
.MESSAGE_WARNING
,
155 'question': GTK
.MESSAGE_QUESTION
,
156 'error': GTK
.MESSAGE_ERROR
}
166 Report a message to the user and get a response back.
168 The TITLE is placed in the window's title bar.
170 The TYPE controls what kind of icon is placed in the window; it should be
171 one of 'info', 'warning', 'question' or 'error'.
173 The MESSAGE is the string which should be displayed. It may have
174 multiple lines. There may also be a HEADLINE message. The messages are
175 parsed for Pango markup if MARKUPP is set.
177 The BUTTONS are a list of buttons to show, right to left. Each one
178 should be a string which may either be a GTK stock tag or a plain label
179 string. This may be prefixed, optionally, by `!' to ignore other prefix
180 characters, `+' to make this button the default, or `:' to make this the
181 `cancel' button, chosen by pressing escape. If no button is marked as
182 cancel, we just use the first.
185 ## Initialize superclasses.
186 GTK
.MessageDialog
.__init__(me
, type = me
.dboxtype
.get(type))
190 title
= OS
.path
.basename(argv
[0])
193 ## Add the message strings.
194 me
.set_property('use-markup', markupp
)
196 me
.set_property('text', message
)
198 me
.set_property('text', headline
)
199 me
.set_property('secondary-text', message
)
200 me
.set_property('secondary-use-markup', markupp
)
202 ## Include the buttons.
203 if len(buttons
) == 0:
204 buttons
= [MessageButton('gtk-ok', True, 'default', 'cancel')]
208 me
.buttons
= [isinstance(b
, MessageButton
) and b
or MessageButton(b
)
212 for i
in xrange(len(buttons
)):
213 button
= me
.buttons
[i
]
215 if GTK
.stock_lookup(label
) is None:
216 b
= GTK
.Button(label
= label
)
218 b
= GTK
.Button(stock
= label
)
223 b
.set_flags(b
.flags() | GTK
.CAN_DEFAULT
)
225 me
.add_action_widget(b
, i
)
227 ## Choose default buttons.
231 default
= len(me
.buttons
) - 1
235 ## Connect up the handlers and go.
236 me
.connect('key-press-event', me
.keypress
, me
.buttons
[cancel
])
237 me
.buttons
[default
].widget
.grab_default()
239 def keypress(me
, win
, event
, cancel
):
241 Handle key-press events.
243 If the EVENT was an escape-press, then activate the CANCEL button.
245 key
= GDK
.keyval_name(event
.keyval
)
248 cancel
.widget
.activate()
253 Display the message, and wait for a response.
255 The return value is the label of the button which was chosen.
262 return me
.buttons
[r
].value
264 ###----- That's all, folks --------------------------------------------------