2 # Copyright (C) Tiny 2008
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License, or (at your option) any later version.
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 # Author(s): Johan Dahlin (Async Open Source)
31 from tools
import date_mapping
33 from mx
.DateTime
import DateTime
35 class DateEntry(gtk
.Entry
):
36 def __init__(self
, format
, callback
=None, callback_process
=None):
37 super(DateEntry
, self
).__init
__()
38 self
.modify_font(pango
.FontDescription("monospace"))
41 self
.regex
= self
.initial_value
= format
42 for key
,val
in date_mapping
.items():
43 self
.regex
= self
.regex
.replace(key
, val
[1])
44 self
.initial_value
= self
.initial_value
.replace(key
, val
[0])
46 self
.set_text(self
.initial_value
)
47 self
.regex
= re
.compile(self
.regex
)
49 assert self
.regex
.match(self
.initial_value
), 'Error, the initial value should be validated by regex'
50 self
.set_width_chars(len(self
.initial_value
))
51 self
.set_max_length(len(self
.initial_value
))
53 self
.connect('key-press-event', self
._on
_key
_press
)
54 self
.connect('insert-text', self
._on
_insert
_text
)
55 self
.connect('delete-text', self
._on
_delete
_text
)
57 self
.connect('focus-out-event', self
._focus
_out
)
58 self
.callback
= callback
59 self
.callback_process
= callback_process
61 self
._interactive
_input
= True
63 gobject
.idle_add(self
.set_position
, 0)
64 tooltips
= gtk
.Tooltips()
65 tooltips
.set_tip(self
, _('''You can use special operation by pressing +, - or =. Plus/minus adds/decrease the variable to the current selected date. Equals set part of selected date. Available variables: 12h = 12 hours, 8d = 8 days, 4w = 4 weeks, 1m = 1 month, 2y = 2 years. Some examples:
66 * +21d : adds 21 days to selected year
67 * =23w : set date to the 23th week of the year
68 * -4m : decrease 4 months to the current date
69 You can also use "=" to set the date to the current date/time and '-' to clear the field.'''))
72 def _on_insert_text(self
, editable
, value
, length
, position
):
73 if not self
._interactive
_input
:
77 if self
.callback
: self
.callback(value
)
78 self
.stop_emission('insert-text')
81 pos
= self
.get_position()
83 # TODO: Implement paste
84 self
.stop_emission('insert-text')
87 text
= self
.get_text()
89 text
= text
[:pos
] + value
+ text
[pos
+ 1:]
90 if self
.regex
.match(text
):
92 while (pos
<len(self
.initial_value
)) and (self
.initial_value
[pos
] not in ['_','0','X']):
95 gobject
.idle_add(self
.set_position
, pos
)
96 self
.stop_emission('insert-text')
100 def _on_delete_text(self
, editable
, start
, end
):
101 if not self
._interactive
_input
:
104 #if end - start != 1:
105 # #TODO: cut/delete several
106 # self.stop_emission('delete-text')
109 while (start
>0) and (self
.initial_value
[start
] not in ['_','0','X']):
111 text
= self
.get_text()
112 text
= text
[:start
] + self
.initial_value
[start
:end
] + text
[end
:]
114 gobject
.idle_add(self
.set_position
, start
)
115 self
.stop_emission('delete-text')
118 def _focus_out(self
, args
, args2
):
121 self
.mode_cmd
= False
122 if self
.callback_process
: self
.callback_process(False, self
, False)
124 def set_text(self
, text
):
125 self
._interactive
_input
= False
127 gtk
.Entry
.set_text(self
, text
)
129 self
._interactive
_input
= True
131 def date_set(self
, dt
):
133 self
.set_text( dt
.strftime(self
.format
) )
135 self
.set_text(self
.initial_value
)
138 tt
= time
.strftime(self
.format
, time
.localtime())
140 if tc
==self
.initial_value
:
142 for a
in range(len(self
.initial_value
)):
143 if self
.initial_value
[a
] == tc
[a
]:
144 tc
= tc
[:a
] + tt
[a
] + tc
[a
+1:]
147 return time
.strptime(tc
, self
.format
)
151 return time
.strptime(tc
, self
.format
)
153 def delete_text(self
, start
, end
):
155 self
._interactive
_input
= False
157 gtk
.Entry
.delete_text(self
, start
, end
)
159 self
._interactive
_input
= True
161 def insert_text(self
, text
, position
=0):
162 self
._interactive
_input
= False
164 gtk
.Entry
.insert_text(self
, text
, position
)
166 self
._interactive
_input
= True
169 self
.set_text(self
.initial_value
)
171 def _on_key_press(self
, editable
, event
):
172 if event
.keyval
in (gtk
.keysyms
.Tab
, gtk
.keysyms
.Escape
, gtk
.keysyms
.Return
):
174 self
.mode_cmd
= False
175 if self
.callback_process
: self
.callback_process(False, self
, event
)
176 self
.stop_emission("key-press-event")
178 elif event
.keyval
in (ord('+'),ord('-'),ord('=')):
181 if self
.callback_process
: self
.callback_process(True, self
, event
)
182 self
.stop_emission("key-press-event")
185 if self
.callback
: self
.callback(event
)
189 class CmdEntry(gtk
.Label
):
192 class ComplexEntry(gtk
.HBox
):
193 def __init__(self
, format
, *args
, **argv
):
194 super(ComplexEntry
, self
).__init
__(*args
, **argv
)
195 self
.widget
= DateEntry(
200 self
.widget
.set_position(0)
201 self
.widget
.select_region(0, 0)
202 self
.widget_cmd
= CmdEntry()
203 self
.widget_cmd
.hide()
204 self
.pack_start(self
.widget
, expand
=True, fill
=True)
205 self
.pack_start(self
.widget_cmd
, expand
=False, fill
=True)
207 def _date_cb(self
, event
):
208 if event
.keyval
in (gtk
.keysyms
.BackSpace
,):
209 text
= self
.widget_cmd
.get_text()[:-1]
210 self
.widget_cmd
.set_text(text
)
213 value
= chr(event
.keyval
)
214 text
= self
.widget_cmd
.get_text()
215 self
.widget_cmd
.set_text(text
+value
)
218 def _process_cb(self
, ok
, widget
, event
=None):
220 self
.widget_cmd
.show()
223 data
= self
.widget
.get_text()
224 if (not event
.keyval
== gtk
.keysyms
.Escape
) or not event
:
225 cmd
= self
.widget_cmd
.get_text()
226 for r
,f
in tools
.date_operation
.items():
227 groups
= re
.match(r
, cmd
)
229 dt
= self
.widget
.date_get()
231 dt
= time
.strftime(self
.widget
.format
, time
.localtime())
232 dt
= time
.strptime(dt
, self
.widget
.format
)
233 self
.widget
.date_set(f(dt
,groups
))
236 # Compute HERE using DATA and setting WIDGET
238 self
.widget_cmd
.set_text('')
239 self
.widget_cmd
.hide()
241 if __name__
== '__main__':
245 win
.set_title('gtk.Entry subclass')
246 def cb(window
, event
):
248 win
.connect('delete-event', cb
)
250 widget
= ComplexEntry('%d/%m/%Y %H:%M:%S')
256 sys
.exit(main(sys
.argv
))