/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/classgen.py
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/Thuban/UI/classgen.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 620 - (hide annotations)
Mon Apr 7 10:14:25 2003 UTC (21 years, 11 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/classgen.py
File MIME type: text/x-python
File size: 13774 byte(s)
Fix Windows problem.

1 jonathan 607 # Copyright (c) 2003 by Intevation GmbH
2     # Authors:
3     # Jonathan Coles <[email protected]>
4     #
5     # This program is free software under the GPL (>=v2)
6     # Read the file COPYING coming with Thuban for details.
7    
8     from Thuban import _
9    
10     from wxPython.wx import *
11    
12     from Thuban.Model.classification import Classification, ClassGroupRange, \
13     ClassGroupSingleton, ClassGroupProperties
14    
15     from Thuban.Model.table import Table, FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
16     FIELDTYPE_STRING
17    
18     from Thuban.Model.color import Color
19    
20     ID_CLASSGEN_GEN = 4001
21     ID_CLASSGEN_CANCEL = 4002
22    
23     class ClassGenDialog(wxDialog):
24    
25     def __init__(self, parent, table, fieldName):
26     wxDialog.__init__(self, parent, -1, _("Generate Classification"),
27     style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
28    
29     self.clazz = None
30    
31     type, name, width, prec = table.field_info_by_name(fieldName)
32    
33     sizer = wxBoxSizer(wxVERTICAL)
34    
35     buttonSizer = wxBoxSizer(wxHORIZONTAL)
36     self.genButton = wxButton(self, ID_CLASSGEN_GEN, _("Generate"))
37     buttonSizer.Add(self.genButton, 0, wxALL, 4)
38     buttonSizer.Add(60, 20, 0, wxALL, 4)
39     buttonSizer.Add(wxButton(self, ID_CLASSGEN_CANCEL, _("Cancel")),
40     0, wxALL, 4)
41    
42     if type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):
43     self.panel = GenRangePanel(self, table, fieldName, type)
44     elif type == FIELDTYPE_STRING:
45     print "Select a field that is an int/decimal"
46     #panel = GenSingletonPanel(self, table, fieldName)
47     else:
48     assert False, "Shouldn't be here."
49     pass
50    
51     sizer.Add(self.panel, 1, wxGROW | wxALL, 4)
52     sizer.Add(buttonSizer, 0,
53     wxALL | wxALIGN_BOTTOM | wxALIGN_CENTER_HORIZONTAL, 4)
54    
55     self.SetSizer(sizer)
56     self.SetAutoLayout(True)
57     sizer.SetSizeHints(self)
58    
59     EVT_BUTTON(self, ID_CLASSGEN_GEN, self._OnGenerate)
60     EVT_BUTTON(self, ID_CLASSGEN_CANCEL, self._OnCancel)
61    
62     def GetClassification(self):
63     return self.clazz
64    
65     def AllowGenerate(self, on):
66     self.genButton.Enable(on)
67    
68     def _OnGenerate(self, event):
69     min = self.panel.GetMin()
70     max = self.panel.GetMax()
71     numGroups = self.panel.GetNumGroups()
72     cgp = ClassGroupProperties()
73     cgp2 = ClassGroupProperties()
74    
75     cgp.SetLineColor(Color(.5, 0, 0))
76     cgp2.SetLineColor(Color(1, 0, 1))
77     cgp2.SetLineWidth(10)
78    
79     if min is not None \
80     and max is not None \
81     and numGroups is not None:
82     self.clazz = ClassGenerator().GenerateRanges(min, max,
83     numGroups, cgp, cgp2)
84     else:
85     self.clazz = None # for now
86    
87     self.EndModal(wxID_OK)
88    
89     def _OnCancel(self, event):
90     self.EndModal(wxID_CANCEL)
91    
92     ID_RANGE_MIN = 4001
93     ID_RANGE_MAX = 4002
94     ID_RANGE_NGROUPS = 4003
95     ID_RANGE_STEP = 4004
96    
97     class GenRangePanel(wxPanel):
98    
99     def __init__(self, parent, table, fieldName, fieldType):
100     wxPanel.__init__(self, parent, -1)
101    
102     self.parent = parent
103    
104     self.fieldType = fieldType
105    
106     topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, "Ranges"),
107     wxVERTICAL)
108    
109     sizer = wxBoxSizer(wxHORIZONTAL)
110    
111     sizer.Add(wxStaticText(self, -1, _("Min:")), 0, wxALL, 4)
112     self.minCtrl = wxTextCtrl(self, ID_RANGE_MIN, style=wxTE_RIGHT)
113     sizer.Add(self.minCtrl, 0, wxALL, 4)
114     EVT_TEXT(self, ID_RANGE_MIN, self._OnRangeChanged)
115     self.goodTextColour = self.minCtrl.GetForegroundColour()
116     self.badTextColour = wxRED
117    
118     sizer.Add(wxStaticText(self, -1, _("Max:")), 0, wxALL, 4)
119     self.maxCtrl = wxTextCtrl(self, ID_RANGE_MAX, style=wxTE_RIGHT)
120     sizer.Add(self.maxCtrl, 0, wxALL, 4)
121     EVT_TEXT(self, ID_RANGE_MAX, self._OnRangeChanged)
122     topSizer.Add(sizer, 0, wxALL, 4)
123    
124     sizer = wxBoxSizer(wxHORIZONTAL)
125     sizer.Add(wxStaticText(self, -1, _("Number of Groups:")), 0, wxALL, 4)
126     self.numGroupsCtrl = wxSpinCtrl(self, ID_RANGE_NGROUPS, style=wxTE_RIGHT)
127     EVT_TEXT(self, ID_RANGE_NGROUPS, self._OnNumGroupsChanged)
128     EVT_SPINCTRL(self, ID_RANGE_NGROUPS, self._OnNumGroupsChanged)
129     sizer.Add(self.numGroupsCtrl, 0, wxALL, 4)
130    
131     sizer.Add(wxStaticText(self, -1, _("Stepping:")), 0, wxALL, 4)
132     self.stepCtrl = wxTextCtrl(self, ID_RANGE_STEP, style=wxTE_RIGHT)
133     EVT_TEXT(self, ID_RANGE_STEP, self._OnSteppingChanged)
134     sizer.Add(self.stepCtrl , 0, wxALL, 4)
135     topSizer.Add(sizer, 0, wxALL, 4)
136    
137     self.SetSizer(topSizer)
138     self.SetAutoLayout(True)
139     topSizer.SetSizeHints(self)
140    
141     self.numGroupsChanging = False
142     self.steppingChanging = False
143    
144     self.numGroupsCtrl.SetRange(1, 100)
145    
146     self.numGroupsCtrl.SetValue(1)
147     self.stepCtrl.SetValue("1")
148     self.maxCtrl.SetValue("0")
149     self.minCtrl.SetValue("0")
150     self.minCtrl.SetFocus()
151    
152     def GetNumGroups(self):
153     value = self.numGroupsCtrl.GetValue()
154     return self.__GetValidatedTypeEntry(self.numGroupsCtrl,
155     value,
156     FIELDTYPE_INT,
157     None)
158    
159     ##if self.__ValidateEntry(self.numGroupsCtrl, value, int):
160     #return value
161    
162     #return None
163    
164     def GetStepping(self):
165     step = self.stepCtrl.GetValue()
166     return self.__GetValidatedTypeEntry(self.stepCtrl,
167     step,
168     self.fieldType,
169     0)
170    
171     def GetMin(self):
172     min = self.minCtrl.GetValue()
173     max = self.maxCtrl.GetValue()
174     return self.__GetValidatedTypeEntry(self.minCtrl,
175     min,
176     self.fieldType,
177     max)
178    
179     def GetMax(self):
180     min = self.minCtrl.GetValue()
181     max = self.maxCtrl.GetValue()
182     return self.__GetValidatedTypeEntry(self.maxCtrl,
183     max,
184     self.fieldType,
185     min)
186    
187     def _OnRangeChanged(self, event):
188    
189     hasFocus = wxWindow_FindFocus() == event.GetEventObject()
190     min = self.GetMin()
191     max = self.GetMax()
192    
193     on = min is not None \
194     and max is not None
195    
196     self.numGroupsCtrl.Enable(on)
197     self.stepCtrl.Enable(on)
198    
199     if on:
200     self.numGroupsCtrl.SetRange(1, abs(max - min) / 0.001)
201    
202     ngroups = self.GetNumGroups()
203    
204     if ngroups is not None \
205     and min is not None \
206     and max is not None \
207     and ngroups != 0:
208    
209     self.stepCtrl.SetValue(str((max - min) / ngroups))
210    
211     self.parent.AllowGenerate(self.GetStepping() is not None)
212     else:
213     self.parent.AllowGenerate(False)
214    
215    
216     if hasFocus:
217     event.GetEventObject().SetFocus()
218    
219     def _OnNumGroupsChanged(self, event):
220     if self.steppingChanging:
221     self.steppingChanging = False
222     return
223    
224    
225     obj = event.GetEventObject()
226     ngroups = self.GetNumGroups()
227     min = self.GetMin()
228     max = self.GetMax()
229    
230     if ngroups >= self.numGroupsCtrl.GetMax():
231     self.numGroupsCtrl.SetRange(1, ngroups + 1)
232    
233     if ngroups is not None \
234     and min is not None \
235     and max is not None \
236     and ngroups != 0:
237    
238     #
239     # changing the value in the stepCtrl sends an event
240     # that the control is changing, at which point
241     # we try to update the numGroupsCtrl. This causes
242     # an infinite recursion. This flag and the one
243     # called steppingChanging tries to prevent the recursion.
244     #
245     self.numGroupsChanging = True
246     self.stepCtrl.SetValue(str((max - min) / ngroups))
247    
248     self.parent.AllowGenerate(self.GetStepping() is not None)
249     else:
250     self.parent.AllowGenerate(False)
251    
252    
253     def _OnSteppingChanged(self, event):
254     if self.numGroupsChanging:
255     self.numGroupsChanging = False
256     return
257    
258     step = self.GetStepping()
259     min = self.GetMin()
260     max = self.GetMax()
261    
262     if step is not None \
263     and min is not None \
264     and max is not None \
265     and step != 0:
266    
267     #
268     # see note in _OnNumGroupsChanged
269     #
270     self.steppingChanging = True
271     n = int((max - min) / step)
272     if n == 0:
273     n = 1
274    
275     self.numGroupsCtrl.SetValue(n)
276    
277     self.parent.AllowGenerate(self.GetNumGroups() is not None)
278     else:
279     self.parent.AllowGenerate(False)
280    
281     def __GetValidatedTypeEntry(self, win, value, type, badValue = None):
282    
283     if type == FIELDTYPE_INT:
284     func = int
285     elif type == FIELDTYPE_DOUBLE:
286     func = float
287     elif type == FIELDTYPE_STRING:
288     func = str
289     else:
290     assert False, "Unsupported FIELDTYPE"
291     pass
292    
293     if self.__ValidateEntry(win, value, func, badValue):
294     return func(value)
295    
296     return None
297    
298     def __ValidateEntry(self, win, value, test, badValue = None):
299    
300     valid = value != ""
301    
302     try:
303     if valid:
304     value = test(value)
305    
306     if badValue is not None:
307     valid = value != test(badValue)
308     except ValueError:
309     valid = False
310    
311     if valid:
312     win.SetForegroundColour(wxBLACK)
313     else:
314     win.SetForegroundColour(wxRED)
315    
316 jonathan 620 win.Refresh()
317    
318 jonathan 607 return valid
319    
320    
321     class GenSingletonPanel(wxPanel):
322    
323     def __init__(self, parent, table, fieldName, fieldType):
324     wxPanel.__init__(self, parent, -1)
325    
326    
327     class ClassGenerator:
328    
329     def GenerateSingletons(self, list, numGroups, prop1, prop2):
330     """Generate a new classification consisting solely of singletons.
331    
332     The resulting classification will consist of at most 'numGroups'
333     groups whose group properties ramp between 'prop1' and 'prop2'. There
334     could be fewer groups if 'list' contains fewer that 'numGroups' items.
335    
336     list -- any object that implements the iterator interface
337    
338     numGroups -- how many groups to generate. This can not be
339     determined while the classification is being
340     generated because the stepping values must
341     be precalculated to ramp between prop1 and prop2.
342    
343     prop1 -- initial group property values
344    
345     prop2 -- final group property values
346     """
347    
348     clazz = Classification()
349     if numGroups == 0: return clazz
350    
351     for value, prop in zip(list, PropertyRamp(numGroups, prop1, prop2)):
352 jonathan 614 clazz.AppendGroup(ClassGroupSingleton(value, prop))
353 jonathan 607
354     return clazz
355    
356     def GenerateRanges(self, min, max, numGroups, prop1, prop2):
357    
358     clazz = Classification()
359     if numGroups == 0: return clazz
360    
361     step = (max - min) / float(numGroups)
362    
363     cur_min = min
364     cur_max = cur_min + step
365    
366     i = 0
367     for prop in PropertyRamp(numGroups, prop1, prop2):
368    
369     if i == (numGroups - 1):
370     cur_max = max
371    
372     # this check guards against rounding issues
373     if cur_min != cur_max:
374 jonathan 614 clazz.AppendGroup(ClassGroupRange(cur_min, cur_max, prop))
375 jonathan 607
376     cur_min = cur_max
377     cur_max += step
378     i += 1
379    
380     return clazz
381    
382     class PropertyRamp:
383    
384     def __init__(self, num, prop1, prop2):
385    
386     self.count = int(num)
387     num = float(num)
388    
389    
390     self.lineColor = prop1.GetLineColor()
391     self.fillColor = prop1.GetFill()
392     self.lineWidth = prop1.GetLineWidth()
393    
394     lineColor2 = prop2.GetLineColor()
395     fillColor2 = prop2.GetFill()
396     lineWidth2 = prop2.GetLineWidth()
397    
398     self.line_redStep = (lineColor2.red - self.lineColor.red) / num
399     self.line_greenStep = (lineColor2.green - self.lineColor.green) / num
400     self.line_blueStep = (lineColor2.blue - self.lineColor.blue) / num
401    
402     self.line_widthStep = (lineWidth2 - self.lineWidth) / num
403    
404     self.fill_redStep = (fillColor2.red - self.fillColor.red) / num
405     self.fill_greenStep = (fillColor2.green - self.fillColor.green) / num
406     self.fill_blueStep = (fillColor2.blue - self.fillColor.blue) / num
407    
408     def __iter__(self):
409     return self
410    
411     def next(self):
412     if self.count == 0:
413     raise StopIteration
414    
415     prop = ClassGroupProperties()
416     prop.SetFill(self.fillColor)
417     prop.SetLineColor(self.lineColor)
418     prop.SetLineWidth(int(self.lineWidth))
419    
420     self.lineColor.red += self.line_redStep
421     self.lineColor.green += self.line_greenStep
422     self.lineColor.blue += self.line_blueStep
423    
424     self.fillColor.red += self.fill_redStep
425     self.fillColor.green += self.fill_greenStep
426     self.fillColor.blue += self.fill_blueStep
427    
428     self.lineWidth += self.line_widthStep
429    
430     self.count -= 1
431    
432     return prop
433    

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26