/[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 2734 - (hide annotations)
Thu Mar 1 12:42:59 2007 UTC (18 years ago) by bramz
File MIME type: text/x-python
File size: 33146 byte(s)
made a copy
1 bh 2099 # Copyright (c) 2003, 2004 by Intevation GmbH
2 jonathan 607 # 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 bh 1542 """The Classification Generator Dialog"""
9    
10     __version__ = "$Revision$"
11     # $Source$
12     # $Id$
13    
14    
15 jonathan 677 import sys
16    
17 dpinte 2700 import wx
18 bh 1542
19 jonathan 607 from Thuban import _
20    
21 bh 907 from Thuban.Model.classification import ClassGroupProperties
22 jonathan 607
23 bh 907 from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
24 jonathan 607 FIELDTYPE_STRING
25    
26 jonathan 1391 from Thuban.Model.layer import SHAPETYPE_ARC
27 jonathan 877 from Thuban.Model.range import Range
28 jonathan 1274 from Thuban.UI.common import ThubanBeginBusyCursor, ThubanEndBusyCursor
29 jonathan 607
30 jonathan 877 import classifier, resource
31 jonathan 629
32 jonathan 1100 from Thuban.Model.classgen import \
33 jonathan 1163 generate_uniform_distribution, generate_singletons, generate_quantiles, \
34 jonathan 1526 CustomRamp, grey_ramp, red_ramp, green_ramp, blue_ramp, green_to_red_ramp, \
35 jonathan 1432 HotToColdRamp, FixedRamp
36 jonathan 649
37 jonathan 1391
38 jonathan 649 USEALL_BMP = "group_use_all"
39     USE_BMP = "group_use"
40     USENOT_BMP = "group_use_not"
41     USENONE_BMP = "group_use_none"
42    
43 jonathan 635 GENCOMBOSTR_UNIFORM = _("Uniform Distribution")
44     GENCOMBOSTR_UNIQUE = _("Unique Values")
45 jonathan 877 GENCOMBOSTR_QUANTILES = _("Quantiles from Table")
46 jonathan 629
47 jonathan 649 PROPCOMBOSTR_CUSTOM = _("Custom Ramp")
48     PROPCOMBOSTR_GREY = _("Grey Ramp")
49     PROPCOMBOSTR_RED = _("Red Ramp")
50     PROPCOMBOSTR_GREEN = _("Green Ramp")
51     PROPCOMBOSTR_BLUE = _("Blue Ramp")
52 jonathan 877 PROPCOMBOSTR_GREEN2RED = _("Green-to-Red Ramp")
53 jonathan 649 PROPCOMBOSTR_HOT2COLD = _("Hot-to-Cold Ramp")
54 jonathan 635
55 jonathan 877 ID_CLASSGEN_GENCOMBO = 4007
56     ID_CLASSGEN_PROPCOMBO = 4008
57    
58 jonathan 1391 ID_BORDER_COLOR = 4009
59     ID_BORDER_COLOR_CHANGE = 4010
60    
61 dpinte 2700 class ClassGenDialog(wx.Dialog):
62 bh 834
63 jonathan 629 def __init__(self, parent, layer, fieldName):
64     """Inialize the class generating dialog.
65    
66     parent -- this must be an instance of the Classifier class
67     """
68    
69 dpinte 2700 wx.Dialog.__init__(self, parent, -1, _("Generate Classification"),
70     style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
71 bh 834
72 jonathan 629 self.parent = parent
73 jonathan 877 self.layer = layer
74 jonathan 607 self.clazz = None
75    
76 bh 1219 col = layer.ShapeStore().Table().Column(fieldName)
77 bh 834 self.type = col.type
78 jonathan 607
79 jonathan 877 self.fieldName = fieldName
80     self.fieldType = self.type
81    
82     self.curGenPanel = None
83    
84     self.genpanels = []
85    
86 jonathan 629 #############
87     # we need to create genButton first because when we create the
88     # panels they will call AllowGenerate() which uses genButton.
89     #
90 dpinte 2700 self.genButton = wx.Button(self, wx.ID_OK, _("Generate"))
91     self.cancelButton = wx.Button(self, wx.ID_CANCEL, _("Close"))
92 jonathan 812 self.genButton.SetDefault()
93 frank 978
94 dpinte 2700 self.genChoice = wx.Choice(self, ID_CLASSGEN_GENCOMBO)
95 jonathan 607
96 jonathan 877 self.genpanels.append((GENCOMBOSTR_UNIQUE, GenUniquePanel))
97     if self.type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):
98     self.genpanels.append((GENCOMBOSTR_UNIFORM, GenUniformPanel))
99     self.genpanels.append((GENCOMBOSTR_QUANTILES, GenQuantilesPanel))
100 jonathan 812
101 jonathan 877 for name, clazz in self.genpanels:
102     self.genChoice.Append(name, [clazz, None])
103 jonathan 812
104     self.genChoice.SetSelection(0)
105    
106 frank 978 for i in range(self.genChoice.GetCount()):
107     clazz, obj = self.genChoice.GetClientData(i)
108 jonathan 812
109 frank 978 if obj is None:
110     obj = clazz(self, self.layer, self.fieldName, self.fieldType)
111     obj.Hide()
112     self.genChoice.SetClientData(i, [clazz, obj])
113 jonathan 812
114    
115 jonathan 629 #############
116 jonathan 607
117 dpinte 2700 sizer = wx.BoxSizer(wx.VERTICAL)
118 jonathan 629
119 dpinte 2700 sizer.Add(wx.StaticText(self, -1, _("Field: %s") % fieldName),
120     0, wx.ALL, 4)
121     sizer.Add(wx.StaticText(
122     self, -1,
123 jonathan 649 _("Data Type: %s") % classifier.Classifier.type2string[self.type]),
124 dpinte 2700 0, wx.ALL, 4)
125 jonathan 629
126 dpinte 2700 psizer = wx.BoxSizer(wx.HORIZONTAL)
127     psizer.Add(wx.StaticText(self, -1, _("Generate:")),
128     0, wx.ALIGN_CENTER_VERTICAL, 0)
129     psizer.Add(self.genChoice, 1, wx.ALL | wx.GROW, 4)
130 jonathan 629
131 dpinte 2700 sizer.Add(psizer, 0, wx.ALL | wx.GROW, 4)
132 jonathan 629
133 dpinte 2700 self.sizer_genPanel = wx.BoxSizer(wx.VERTICAL)
134     sizer.Add(self.sizer_genPanel, 1, wx.GROW | wx.ALL, 4)
135 jonathan 629
136 dpinte 2700 psizer = wx.BoxSizer(wx.HORIZONTAL)
137     psizer.Add(wx.StaticText(self, -1, _("Color Scheme:")),
138     0, wx.ALIGN_CENTER_VERTICAL, 0)
139 frank 978
140     # Properties (Ramp) ComboBox
141 dpinte 2700 self.propCombo = wx.Choice(self, ID_CLASSGEN_PROPCOMBO)
142 frank 978
143     self.propPanel = None
144     custom_ramp_panel = CustomRampPanel(self, layer.ShapeType())
145    
146 jonathan 1526 self.propCombo.Append(PROPCOMBOSTR_GREY, grey_ramp)
147     self.propCombo.Append(PROPCOMBOSTR_RED, red_ramp)
148     self.propCombo.Append(PROPCOMBOSTR_GREEN, green_ramp)
149     self.propCombo.Append(PROPCOMBOSTR_BLUE, blue_ramp)
150     self.propCombo.Append(PROPCOMBOSTR_GREEN2RED, green_to_red_ramp)
151 frank 978 self.propCombo.Append(PROPCOMBOSTR_HOT2COLD, HotToColdRamp())
152     self.propCombo.Append(PROPCOMBOSTR_CUSTOM, custom_ramp_panel)
153    
154     self.propCombo.SetSelection(0)
155    
156 dpinte 2700 psizer.Add(self.propCombo, 1, wx.ALL | wx.GROW, 4)
157     sizer.Add(psizer, 0, wx.ALL | wx.GROW, 4)
158 jonathan 629
159 jonathan 1391 if layer.ShapeType() != SHAPETYPE_ARC:
160 dpinte 2700 psizer = wx.BoxSizer(wx.HORIZONTAL)
161     self.fix_border_check = wx.CheckBox(self, -1, _("Fix Border Color"))
162     psizer.Add(self.fix_border_check, 0, wx.ALL | wx.GROW, 4)
163 jonathan 1391 self.border_color = classifier.ClassGroupPropertiesCtrl(
164     self, ID_BORDER_COLOR,
165     ClassGroupProperties(), SHAPETYPE_ARC,
166 dpinte 2700 style=wx.SIMPLE_BORDER, size=(40, 20))
167     psizer.Add(self.border_color, 0, wx.ALL | wx.GROW, 4)
168     psizer.Add(wx.Button(self, ID_BORDER_COLOR_CHANGE, _("Change")),
169     0, wx.ALL, 4)
170     sizer.Add(psizer, 0, wx.ALL | wx.GROW, 4)
171     self.Bind(wx.EVT_BUTTON, self.OnBorderColorChange, id=ID_BORDER_COLOR_CHANGE)
172 jonathan 1391 else:
173     self.border_color = None
174    
175 dpinte 2700 sizer.Add(custom_ramp_panel, 1, wx.GROW | wx.ALL, 4)
176 jonathan 812 sizer.Show(custom_ramp_panel, False)
177 jonathan 629
178 frank 978 # Finally place the main buttons
179 dpinte 2700 buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
180     buttonSizer.Add(self.genButton, 0, wx.RIGHT|wx.EXPAND, 10)
181     buttonSizer.Add(self.cancelButton, 0, wx.RIGHT|wx.EXPAND, 10)
182     sizer.Add(buttonSizer, 0, wx.ALIGN_RIGHT|wx.BOTTOM|wx.TOP, 10)
183 jonathan 607
184     self.SetSizer(sizer)
185     self.SetAutoLayout(True)
186     sizer.SetSizeHints(self)
187    
188 jonathan 877 self.topBox = sizer
189 jonathan 629
190 jonathan 877 self.__DoOnGenTypeSelect()
191    
192 dpinte 2700 self.Bind(wx.EVT_CHOICE, self._OnGenTypeSelect, id=ID_CLASSGEN_GENCOMBO)
193     self.Bind(wx.EVT_CHOICE, self._OnPropTypeSelect, id=ID_CLASSGEN_PROPCOMBO)
194 dpinte 2709 self.Bind(wx.EVT_BUTTON, self.OnOK, self.genButton)
195     self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelButton)
196 jonathan 607
197 jonathan 877 self.__DoOnGenTypeSelect()
198 jonathan 812
199     self.genChoice.SetFocus()
200    
201 jonathan 607 def GetClassification(self):
202     return self.clazz
203    
204     def AllowGenerate(self, on):
205 jonathan 629 pass #self.genButton.Enable(on)
206 jonathan 607
207 jonathan 812 def OnOK(self, event):
208     """This is really the generate button, but we want to override
209     the wxDialog class.
210     """
211 jonathan 607
212 jonathan 728 index = self.genChoice.GetSelection()
213 jonathan 607
214 jonathan 877 assert index != -1, "button should be disabled!"
215    
216 jonathan 728 genSel = self.genChoice.GetString(index)
217 jonathan 877 clazz, genPanel = self.genChoice.GetClientData(index)
218 jonathan 635
219 jonathan 629 propPanel = self.propPanel
220 jonathan 607
221 jonathan 877 if genSel in (GENCOMBOSTR_UNIFORM, \
222     GENCOMBOSTR_UNIQUE, \
223     GENCOMBOSTR_QUANTILES):
224    
225 jonathan 629 numGroups = genPanel.GetNumGroups()
226 jonathan 607
227 jonathan 635 index = self.propCombo.GetSelection()
228 jonathan 629
229 jonathan 635 propSel = self.propCombo.GetString(index)
230     propPanel = self.propCombo.GetClientData(index)
231 jonathan 629
232 jonathan 635 ramp = propPanel.GetRamp()
233 jonathan 1391 if self.border_color and self.fix_border_check.IsChecked():
234     props = self.border_color.GetProperties()
235 dpinte 2700 ramp = FixedRamp(ramp,
236 jonathan 1432 (props.GetLineColor(), props.GetLineWidth(), None))
237 jonathan 629
238 jonathan 635 if genSel == GENCOMBOSTR_UNIFORM:
239 jonathan 629
240 jonathan 635 min = genPanel.GetMin()
241     max = genPanel.GetMax()
242 jonathan 629
243 jonathan 635 if min is not None \
244     and max is not None \
245     and numGroups is not None:
246 jonathan 629
247 jonathan 1163 self.clazz = generate_uniform_distribution(
248 jonathan 635 min, max, numGroups, ramp,
249 jonathan 1432 self.type == FIELDTYPE_INT)
250 jonathan 629
251 jonathan 635 self.parent._SetClassification(self.clazz)
252 jonathan 629
253 jonathan 635 elif genSel == GENCOMBOSTR_UNIQUE:
254 jonathan 629
255 jonathan 635 list = genPanel.GetValueList()
256    
257 jonathan 1341 if len(list) > 0:
258 jonathan 1432 self.clazz = generate_singletons(list, ramp)
259 jonathan 635 self.parent._SetClassification(self.clazz)
260    
261 jonathan 877 elif genSel == GENCOMBOSTR_QUANTILES:
262    
263     _range = genPanel.GetRange()
264     _list = genPanel.GetList()
265     _list.sort()
266    
267     delta = 1 / float(numGroups)
268     percents = [delta * i for i in range(1, numGroups + 1)]
269     adjusted, self.clazz = \
270 jonathan 1432 generate_quantiles(_list, percents, ramp, _range)
271 jonathan 877
272     if adjusted:
273 dpinte 2700 dlg = wx.MessageDialog(self,
274 bh 1566 _("Based on the data from the table and the input\n"
275     "values, the exact quantiles could not be generated.\n\n"
276 jonathan 877 "Accept a close estimate?"),
277     _("Problem with Quantiles"),
278    
279 dpinte 2700 wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
280     if dlg.ShowModal() == wx.ID_YES:
281 jonathan 877 self.parent._SetClassification(self.clazz)
282     else:
283     self.parent._SetClassification(self.clazz)
284    
285 jonathan 812 def OnCancel(self, event):
286 jonathan 629 self.Close()
287    
288 jonathan 1391 def OnBorderColorChange(self, event):
289     self.border_color.DoEdit()
290    
291 jonathan 629 def _OnGenTypeSelect(self, event):
292 jonathan 877 self.__DoOnGenTypeSelect()
293     return
294 jonathan 629
295     combo = event.GetEventObject()
296    
297     selIndex = combo.GetSelection()
298    
299     if self.genPanel is not None:
300 jonathan 877 self.topBox.Show(self.genPanel, False)
301 jonathan 629
302     self.genPanel = combo.GetClientData(selIndex)
303     if self.genPanel is not None:
304 jonathan 877 self.topBox.Show(self.genPanel, True)
305 jonathan 629
306 jonathan 877 self.topBox.SetSizeHints(self)
307     self.topBox.Layout()
308 jonathan 629
309 jonathan 635 def _OnPropTypeSelect(self, event):
310     combo = event.GetEventObject()
311 jonathan 629
312 jonathan 635 selIndex = combo.GetSelection()
313     sel = combo.GetString(selIndex)
314    
315 dpinte 2700 if isinstance(self.propPanel, wx.Panel):
316 jonathan 877 self.topBox.Show(self.propPanel, False)
317 jonathan 635
318     self.propPanel = combo.GetClientData(selIndex)
319    
320 dpinte 2700 if isinstance(self.propPanel, wx.Panel):
321 jonathan 877 self.topBox.Show(self.propPanel, True)
322 jonathan 635
323 jonathan 877 self.topBox.SetSizeHints(self)
324     self.topBox.Layout()
325 jonathan 635
326 jonathan 877 def __DoOnGenTypeSelect(self):
327     choice = self.genChoice
328 jonathan 635
329 jonathan 877 sel = choice.GetSelection()
330     if sel == -1: return
331    
332     clazz, obj = choice.GetClientData(sel)
333    
334     if self.curGenPanel is not None:
335     self.curGenPanel.Hide()
336     self.sizer_genPanel.Remove(self.curGenPanel)
337    
338     self.curGenPanel = obj
339     self.curGenPanel.Show()
340    
341     self.sizer_genPanel.Add(self.curGenPanel, 1,
342 dpinte 2700 wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 3)
343 jonathan 877 self.sizer_genPanel.Layout()
344     self.Layout()
345     self.topBox.SetSizeHints(self)
346    
347 jonathan 629 ID_UNIFORM_MIN = 4001
348     ID_UNIFORM_MAX = 4002
349     ID_UNIFORM_NGROUPS = 4003
350     ID_UNIFORM_STEP = 4004
351     ID_UNIFORM_RETRIEVE = 4005
352    
353 dpinte 2700 class GenUniformPanel(wx.Panel):
354 jonathan 629
355     def __init__(self, parent, layer, fieldName, fieldType):
356 dpinte 2700 wx.Panel.__init__(self, parent, -1)
357 jonathan 607
358     self.parent = parent
359 jonathan 629 self.layer = layer
360     self.fieldName = fieldName
361 jonathan 607 self.fieldType = fieldType
362    
363 dpinte 2700 topSizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""),
364     wx.VERTICAL)
365 jonathan 607
366 jonathan 629 #############
367    
368 dpinte 2700 sizer = wx.BoxSizer(wx.HORIZONTAL)
369 jonathan 607
370 dpinte 2700 sizer.Add(wx.StaticText(self, -1, _("Min:")), 0, wx.ALL, 4)
371     self.minCtrl = wx.TextCtrl(self, ID_UNIFORM_MIN, style=wx.TE_RIGHT)
372     sizer.Add(self.minCtrl, 1, wx.ALL, 4)
373     self.Bind(wx.EVT_TEXT, self._OnRangeChanged, id=ID_UNIFORM_MIN)
374 jonathan 607
375 dpinte 2700 sizer.Add(wx.StaticText(self, -1, _("Max:")), 0, wx.ALL, 4)
376     self.maxCtrl = wx.TextCtrl(self, ID_UNIFORM_MAX, style=wx.TE_RIGHT)
377     sizer.Add(self.maxCtrl, 1, wx.ALL, 4)
378     self.Bind(wx.EVT_TEXT, self._OnRangeChanged, id=ID_UNIFORM_MAX)
379 jonathan 607
380 dpinte 2700 sizer.Add(wx.Button(self, ID_UNIFORM_RETRIEVE, _("Retrieve From Table")),
381     0, wx.ALL, 4)
382     self.Bind(wx.EVT_BUTTON, self._OnRetrieve, id=ID_UNIFORM_RETRIEVE)
383 jonathan 629
384 dpinte 2700 topSizer.Add(sizer, 1, wx.GROW, 0)
385 jonathan 629
386     #############
387    
388 dpinte 2700 sizer = wx.BoxSizer(wx.HORIZONTAL)
389 jonathan 629
390 dpinte 2700 sizer.Add(wx.StaticText(self, -1, _("Number of Groups:")), 0, wx.ALL, 4)
391     self.numGroupsCtrl = wx.SpinCtrl(self, ID_UNIFORM_NGROUPS,
392     style=wx.TE_RIGHT)
393     self.Bind(wx.EVT_TEXT, self._OnNumGroupsChanged, id=ID_UNIFORM_NGROUPS)
394     self.Bind(wx.EVT_SPINCTRL, self._OnNumGroupsChanged, id=ID_UNIFORM_NGROUPS)
395     sizer.Add(self.numGroupsCtrl, 1, wx.ALL, 4)
396 jonathan 607
397 dpinte 2700 sizer.Add(wx.StaticText(self, -1, _("Stepping:")), 0, wx.ALL, 4)
398     self.stepCtrl = wx.TextCtrl(self, ID_UNIFORM_STEP, style=wx.TE_RIGHT)
399     self.Bind(wx.EVT_TEXT, self._OnSteppingChanged, id=ID_UNIFORM_STEP)
400     sizer.Add(self.stepCtrl , 1, wx.ALL, 4)
401 jonathan 607
402 dpinte 2700 topSizer.Add(sizer, 1, wx.GROW, 0)
403 jonathan 629
404     #############
405    
406 jonathan 607 self.SetSizer(topSizer)
407     self.SetAutoLayout(True)
408     topSizer.SetSizeHints(self)
409    
410     self.numGroupsChanging = False
411     self.steppingChanging = False
412    
413 jonathan 677 self.numGroupsCtrl.SetRange(1, sys.maxint)
414 jonathan 607
415     self.numGroupsCtrl.SetValue(1)
416     self.stepCtrl.SetValue("1")
417     self.maxCtrl.SetValue("0")
418     self.minCtrl.SetValue("0")
419     self.minCtrl.SetFocus()
420    
421     def GetNumGroups(self):
422     value = self.numGroupsCtrl.GetValue()
423 dpinte 2700 return self.__GetValidatedTypeEntry(self.numGroupsCtrl,
424 jonathan 607 value,
425     FIELDTYPE_INT,
426     None)
427    
428     def GetStepping(self):
429     step = self.stepCtrl.GetValue()
430 dpinte 2700 return self.__GetValidatedTypeEntry(self.stepCtrl,
431 jonathan 607 step,
432     self.fieldType,
433     0)
434    
435     def GetMin(self):
436     min = self.minCtrl.GetValue()
437     max = self.maxCtrl.GetValue()
438 dpinte 2700 return self.__GetValidatedTypeEntry(self.minCtrl,
439 jonathan 607 min,
440     self.fieldType,
441     max)
442    
443     def GetMax(self):
444     min = self.minCtrl.GetValue()
445     max = self.maxCtrl.GetValue()
446 dpinte 2700 return self.__GetValidatedTypeEntry(self.maxCtrl,
447 jonathan 607 max,
448     self.fieldType,
449     min)
450    
451     def _OnRangeChanged(self, event):
452    
453 dpinte 2700 hasFocus = wx.Window_FindFocus() == event.GetEventObject()
454 jonathan 607 min = self.GetMin()
455     max = self.GetMax()
456    
457     on = min is not None \
458     and max is not None
459    
460     self.numGroupsCtrl.Enable(on)
461     self.stepCtrl.Enable(on)
462    
463     ngroups = self.GetNumGroups()
464    
465     if ngroups is not None \
466     and min is not None \
467     and max is not None \
468     and ngroups != 0:
469    
470 jonathan 629 #self.stepCtrl.SetValue(str((max - min) / ngroups))
471     self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
472     #self.numGroupsCtrl.SetValue(ngroups)
473 jonathan 607
474     self.parent.AllowGenerate(self.GetStepping() is not None)
475     else:
476     self.parent.AllowGenerate(False)
477    
478    
479     if hasFocus:
480     event.GetEventObject().SetFocus()
481    
482     def _OnNumGroupsChanged(self, event):
483     if self.steppingChanging:
484     self.steppingChanging = False
485     return
486    
487    
488     obj = event.GetEventObject()
489     ngroups = self.GetNumGroups()
490     min = self.GetMin()
491     max = self.GetMax()
492    
493     if ngroups is not None \
494     and min is not None \
495     and max is not None \
496     and ngroups != 0:
497    
498     #
499     # changing the value in the stepCtrl sends an event
500     # that the control is changing, at which point
501     # we try to update the numGroupsCtrl. This causes
502     # an infinite recursion. This flag and the one
503     # called steppingChanging tries to prevent the recursion.
504     #
505     self.numGroupsChanging = True
506    
507 jonathan 629 self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
508    
509 jonathan 607 self.parent.AllowGenerate(self.GetStepping() is not None)
510     else:
511     self.parent.AllowGenerate(False)
512    
513    
514     def _OnSteppingChanged(self, event):
515     if self.numGroupsChanging:
516     self.numGroupsChanging = False
517     return
518    
519     step = self.GetStepping()
520     min = self.GetMin()
521     max = self.GetMax()
522    
523     if step is not None \
524     and min is not None \
525     and max is not None \
526     and step != 0:
527    
528     #
529     # see note in _OnNumGroupsChanged
530     #
531     self.steppingChanging = True
532 jonathan 629 self.numGroupsCtrl.SetValue(self.__CalcNumGroups(min, max, step))
533 jonathan 607
534     self.parent.AllowGenerate(self.GetNumGroups() is not None)
535     else:
536     self.parent.AllowGenerate(False)
537    
538 jonathan 629 def _OnRetrieve(self, event):
539 bh 1219 table = self.layer.ShapeStore().Table()
540     if table is not None:
541 jonathan 1274 ThubanBeginBusyCursor()
542 jonathan 1100 try:
543 bh 1219 min, max = table.ValueRange(self.fieldName)
544 jonathan 1100 self.minCtrl.SetValue(str(min))
545     self.maxCtrl.SetValue(str(max))
546     finally:
547 jonathan 1274 ThubanEndBusyCursor()
548 jonathan 629
549 jonathan 607 def __GetValidatedTypeEntry(self, win, value, type, badValue = None):
550    
551 dpinte 2700 if type == FIELDTYPE_INT:
552 jonathan 607 func = int
553     elif type == FIELDTYPE_DOUBLE:
554     func = float
555     elif type == FIELDTYPE_STRING:
556     func = str
557     else:
558     assert False, "Unsupported FIELDTYPE"
559     pass
560    
561     if self.__ValidateEntry(win, value, func, badValue):
562     return func(value)
563    
564     return None
565    
566     def __ValidateEntry(self, win, value, test, badValue = None):
567    
568     valid = value != ""
569    
570     try:
571     if valid:
572     value = test(value)
573    
574     if badValue is not None:
575     valid = value != test(badValue)
576     except ValueError:
577     valid = False
578    
579     if valid:
580 dpinte 2700 win.SetForegroundColour(wx.BLACK)
581 jonathan 607 else:
582 dpinte 2700 win.SetForegroundColour(wx.RED)
583 jonathan 607
584 jonathan 620 win.Refresh()
585    
586 jonathan 607 return valid
587 jonathan 629
588     def __CalcStepping(self, min, max, ngroups):
589     if self.fieldType == FIELDTYPE_INT:
590 jonathan 1163 step = int((max - min + 1) / float(ngroups))
591     else:
592     step = (max - min) / float(ngroups)
593 jonathan 629
594     return step
595    
596     def __CalcNumGroups(self, min, max, step):
597     n = int((max - min) / step)
598     if n == 0:
599     n = 1
600    
601     if self.fieldType == FIELDTYPE_INT and step == 1:
602     n += 1
603    
604     return n
605    
606    
607     ID_UNIQUE_RETRIEVE = 4001
608     ID_UNIQUE_USEALL = 4002
609     ID_UNIQUE_USE = 4003
610     ID_UNIQUE_DONTUSE = 4004
611     ID_UNIQUE_USENONE = 4005
612     ID_UNIQUE_SORTAVAIL = 4006
613     ID_UNIQUE_SORTUSE = 4007
614 jonathan 649 ID_UNIQUE_REVAVAIL = 4008
615     ID_UNIQUE_REVUSE = 4009
616 jonathan 629
617 dpinte 2700 class GenUniquePanel(wx.Panel):
618 jonathan 629
619     def __init__(self, parent, layer, fieldName, fieldType):
620 dpinte 2700 wx.Panel.__init__(self, parent, -1)
621 jonathan 629
622     self.parent = parent
623     self.layer = layer
624     self.fieldName = fieldName
625     self.fieldType = fieldType
626    
627 dpinte 2700 topSizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""),
628     wx.VERTICAL)
629 jonathan 629
630    
631 jonathan 649 #bsizer = wxBoxSizer(wxVERTICAL)
632 dpinte 2700 topSizer.Add(wx.Button(self, ID_UNIQUE_RETRIEVE,
633     _("Retrieve From Table")),
634     0, wx.ALL | wx.ALIGN_RIGHT, 4)
635 jonathan 649
636 dpinte 2700 self.Bind(wx.EVT_BUTTON, self._OnRetrieve, id=ID_UNIQUE_RETRIEVE)
637 jonathan 649
638 dpinte 2700 #topSizer.Add(bsizer, 0, wx.ALL, 4)
639 jonathan 649
640 dpinte 2700 sizer = wx.BoxSizer(wx.HORIZONTAL)
641 jonathan 629
642     self.dataList = []
643    
644 dpinte 2700 psizer = wx.BoxSizer(wx.VERTICAL)
645     self.list_avail = wx.ListCtrl(self, -1,
646     style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
647 jan 2191 self.list_avail.InsertColumn(0, _("Available"))
648 jonathan 629 self.list_avail_data = []
649 dpinte 2700 psizer.Add(self.list_avail, 1, wx.GROW, 0)
650 jonathan 629
651 dpinte 2700 bsizer = wx.BoxSizer(wx.HORIZONTAL)
652     bsizer.Add(wx.Button(self, ID_UNIQUE_SORTAVAIL, _("Sort")))
653     self.Bind(wx.EVT_BUTTON, self._OnSortList, id=ID_UNIQUE_SORTAVAIL)
654 jonathan 629
655 dpinte 2700 bsizer.Add(wx.Button(self, ID_UNIQUE_REVAVAIL, _("Reverse")))
656     self.Bind(wx.EVT_BUTTON, self._OnReverseList, id=ID_UNIQUE_REVAVAIL)
657 jonathan 629
658 dpinte 2700 psizer.Add(bsizer, 0, wx.GROW, 0)
659     sizer.Add(psizer, 1, wx.GROW, 0)
660 jonathan 629
661 jonathan 649
662 dpinte 2700 bsizer = wx.BoxSizer(wx.VERTICAL)
663 jonathan 607
664 dpinte 2700 bmp = resource.GetBitmapResource(USEALL_BMP, wx.BITMAP_TYPE_XPM)
665     bsizer.Add(wx.BitmapButton(self, ID_UNIQUE_USEALL, bmp),
666     0, wx.GROW | wx.ALL, 4)
667     bmp = resource.GetBitmapResource(USE_BMP, wx.BITMAP_TYPE_XPM)
668     bsizer.Add(wx.BitmapButton(self, ID_UNIQUE_USE, bmp),
669     0, wx.GROW | wx.ALL, 4)
670     bmp = resource.GetBitmapResource(USENOT_BMP, wx.BITMAP_TYPE_XPM)
671     bsizer.Add(wx.BitmapButton(self, ID_UNIQUE_DONTUSE, bmp),
672     0, wx.GROW | wx.ALL, 4)
673     bmp = resource.GetBitmapResource(USENONE_BMP, wx.BITMAP_TYPE_XPM)
674     bsizer.Add(wx.BitmapButton(self, ID_UNIQUE_USENONE, bmp),
675     0, wx.GROW | wx.ALL, 4)
676 jonathan 607
677 dpinte 2700 self.Bind(wx.EVT_BUTTON, self._OnUseAll, id=ID_UNIQUE_USEALL)
678     self.Bind(wx.EVT_BUTTON, self._OnUse, id=ID_UNIQUE_USE)
679     self.Bind(wx.EVT_BUTTON, self._OnDontUse, id=ID_UNIQUE_DONTUSE)
680     self.Bind(wx.EVT_BUTTON, self._OnUseNone, id=ID_UNIQUE_USENONE)
681 jonathan 629
682 dpinte 2700 sizer.Add(bsizer, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
683    
684     psizer = wx.BoxSizer(wx.VERTICAL)
685     self.list_use = wx.ListCtrl(self, -1,
686     style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
687 jan 2191 self.list_use.InsertColumn(0, _("Use"))
688 jonathan 629 self.list_use_data = []
689 dpinte 2700 psizer.Add(self.list_use, 1, wx.GROW, 0)
690 jonathan 629
691 dpinte 2700 bsizer = wx.BoxSizer(wx.HORIZONTAL)
692     bsizer.Add(wx.Button(self, ID_UNIQUE_SORTUSE, _("Sort")))
693     self.Bind(wx.EVT_BUTTON, self._OnSortList, id=ID_UNIQUE_SORTUSE)
694 jonathan 629
695 dpinte 2700 bsizer.Add(wx.Button(self, ID_UNIQUE_REVUSE, _("Reverse")))
696     self.Bind(wx.EVT_BUTTON, self._OnReverseList, id=ID_UNIQUE_REVUSE)
697 jonathan 629
698 dpinte 2700 psizer.Add(bsizer, 0, wx.GROW, 0)
699 jonathan 649
700 dpinte 2700 sizer.Add(psizer, 1, wx.GROW, 0)
701 jonathan 629
702    
703 dpinte 2700 topSizer.Add(sizer, 1, wx.GROW, 0)
704 jonathan 629
705     self.SetSizer(topSizer)
706     self.SetAutoLayout(True)
707     topSizer.SetSizeHints(self)
708    
709 frank 978 width, height = self.list_avail.GetSizeTuple()
710     self.list_avail.SetColumnWidth(0,width)
711     width, height = self.list_use.GetSizeTuple()
712     self.list_use.SetColumnWidth(0,width)
713    
714 jonathan 629 self.parent.AllowGenerate(False)
715    
716     def GetNumGroups(self):
717     return self.list_use.GetItemCount()
718    
719     def GetValueList(self):
720     list = []
721     for i in range(self.list_use.GetItemCount()):
722     list.append(self.dataList[self.list_use.GetItemData(i)])
723     return list
724    
725 jonathan 649 def _OnSortList(self, event):
726     id = event.GetId()
727 jonathan 629
728 jonathan 649 if id == ID_UNIQUE_SORTUSE:
729     list = self.list_use
730     else:
731     list = self.list_avail
732 jonathan 629
733 dpinte 2700 list.SortItems(lambda i1, i2: cmp(self.dataList[i1],
734 jonathan 649 self.dataList[i2]))
735    
736     def _OnReverseList(self, event):
737     id = event.GetId()
738    
739     if id == ID_UNIQUE_REVUSE:
740     list = self.list_use
741     else:
742     list = self.list_avail
743    
744     #
745     # always returning 1 reverses the list
746     #
747     list.SortItems(lambda i1, i2: 1)
748    
749 jonathan 629 def _OnRetrieve(self, event):
750     self.list_use.DeleteAllItems()
751     self.list_use_data = []
752     self.list_avail.DeleteAllItems()
753     self.list_avail_data = []
754    
755 jonathan 1274 ThubanBeginBusyCursor()
756     try:
757     list = self.layer.ShapeStore().Table().UniqueValues(self.fieldName)
758     index = 0
759     for v in list:
760     self.dataList.append(v)
761     i = self.list_avail.InsertStringItem(index, str(v))
762     self.list_avail.SetItemData(index, i)
763 dpinte 2700
764 jonathan 1274 self.list_avail_data.append(v)
765     index += 1
766     finally:
767     ThubanEndBusyCursor()
768 jonathan 629
769     def _OnUseAll(self, event):
770     for i in range(self.list_avail.GetItemCount()):
771     self.__MoveListItem(0, self.list_avail, self.list_use)
772    
773     def _OnUse(self, event):
774     self.__MoveSelectedItems(self.list_avail, self.list_use)
775    
776     def _OnDontUse(self, event):
777     self.__MoveSelectedItems(self.list_use, self.list_avail)
778    
779     def _OnUseNone(self, event):
780    
781     for i in range(self.list_use.GetItemCount()):
782     self.__MoveListItem(0, self.list_use, self.list_avail)
783    
784     def __MoveSelectedItems(self, list_src, list_dest):
785     while True:
786     index = list_src.GetNextItem(-1,
787 dpinte 2700 wx.LIST_NEXT_ALL,
788     wx.LIST_STATE_SELECTED)
789 jonathan 629
790     if index == -1:
791     break
792    
793     self.__MoveListItem(index, list_src, list_dest)
794    
795    
796     def __MoveListItem(self, index, list_src, list_dest):
797    
798     item = list_src.GetItem(index)
799    
800     x = list_dest.InsertStringItem(
801 dpinte 2700 list_dest.GetItemCount(),
802 jonathan 629 str(self.dataList[item.GetData()]))
803    
804     list_dest.SetItemData(x, item.GetData())
805    
806     list_src.DeleteItem(index)
807    
808     # def _OnListSize(self, event):
809     # list = event.GetEventObject()
810    
811     # list.SetColumnWidth(0, event.GetSize().GetWidth())
812     #
813    
814 jonathan 877 ID_QUANTILES_RANGE = 4001
815     ID_QUANTILES_RETRIEVE = 4002
816    
817 dpinte 2700 class GenQuantilesPanel(wx.Panel):
818 jonathan 877
819     def __init__(self, parent, layer, fieldName, fieldType):
820 dpinte 2700 wx.Panel.__init__(self, parent, -1)
821 jonathan 877
822     self.parent = parent
823     self.layer = layer
824     self.fieldName = fieldName
825     self.fieldType = fieldType
826    
827 dpinte 2700 topBox = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""),
828     wx.VERTICAL)
829 jonathan 877
830 dpinte 2700 self.text_range = wx.TextCtrl(self, ID_QUANTILES_RANGE, "")
831     self.button_retrieve = wx.Button(self, ID_QUANTILES_RETRIEVE,
832 jonathan 877 _("Retrieve from Table"))
833    
834 dpinte 2700 self.spin_numClasses = wx.SpinCtrl(self, -1, style=wx.TE_RIGHT)
835 bh 2462 self.spin_numClasses.SetRange(2, sys.maxint)
836     self.spin_numClasses.SetValue(2)
837 jonathan 877
838    
839 dpinte 2700 sizer = wx.BoxSizer(wx.HORIZONTAL)
840     sizer.Add(wx.StaticText(self, -1, _("Apply to Range")), 0, wx.ALL, 4)
841     sizer.Add(self.text_range, 1, wx.ALL, 4)
842     sizer.Add(self.button_retrieve, 0, wx.ALL, 4)
843 jonathan 877
844 dpinte 2700 topBox.Add(sizer, 0, wx.EXPAND, 0)
845 jonathan 877
846 dpinte 2700 sizer = wx.BoxSizer(wx.HORIZONTAL)
847     sizer.Add(wx.StaticText(self, -1, _("Number of Classes:")), 0, wx.ALL, 4)
848     sizer.Add(self.spin_numClasses, 1, wx.ALL, 4)
849 jonathan 877
850 dpinte 2700 topBox.Add(sizer, 0, wx.EXPAND, 0)
851 jonathan 877
852     self.SetSizer(topBox)
853     self.SetAutoLayout(True)
854     topBox.Fit(self)
855     topBox.SetSizeHints(self)
856    
857 dpinte 2700 self.Bind(wx.EVT_TEXT, self.OnRangeText, id=ID_QUANTILES_RANGE)
858     self.Bind(wx.EVT_BUTTON, self.OnRetrieve, id=ID_QUANTILES_RETRIEVE)
859 jonathan 877
860     self.__range = None
861    
862     def GetNumGroups(self):
863     return self.spin_numClasses.GetValue()
864    
865     def GetRange(self):
866     assert self.__range is not None
867    
868     return self.__range
869    
870     def GetList(self):
871 jonathan 898 _list = []
872 bh 1219 table = self.layer.ShapeStore().Table()
873     if table is not None:
874 jonathan 1274 ThubanBeginBusyCursor()
875 jonathan 1100 try:
876     #
877     # FIXME: Replace with a call to table when the method
878     # has been written to get all the values
879     #
880     for i in range(table.NumRows()):
881 bh 2099 _list.append(table.ReadValue(i, self.fieldName,
882 bh 2101 row_is_ordinal = True))
883 jonathan 1100 finally:
884 jonathan 1274 ThubanEndBusyCursor()
885 jonathan 898
886     return _list
887 jonathan 877
888     def OnRangeText(self, event):
889    
890     try:
891     self.__range = Range(self.text_range.GetValue())
892     except ValueError:
893     self.__range = None
894    
895     if self.__range is not None:
896 dpinte 2700 self.text_range.SetForegroundColour(wx.BLACK)
897 jonathan 877 else:
898 dpinte 2700 self.text_range.SetForegroundColour(wx.RED)
899 jonathan 877
900     def OnRetrieve(self, event):
901 bh 1219 table = self.layer.ShapeStore().Table()
902     if table is not None:
903 jonathan 1274 ThubanBeginBusyCursor()
904 jonathan 1100 try:
905 bh 1219 min, max = table.ValueRange(self.fieldName)
906 jonathan 1100 self.text_range.SetValue("[" + str(min) + ";" + str(max) + "]")
907 bernhard 2527 # This is a workaround, which will result in OnRangeText
908     # being called twice on some platforms.
909     # Testing showed this is needed with current wx 2.4. versions
910     # on MacOSX to guarantee that it is called at all.
911     self.OnRangeText(None)
912 jonathan 1100 finally:
913 jonathan 1274 ThubanEndBusyCursor()
914 jonathan 877
915 jonathan 629 ID_CUSTOMRAMP_COPYSTART = 4001
916     ID_CUSTOMRAMP_COPYEND = 4002
917     ID_CUSTOMRAMP_EDITSTART = 4003
918     ID_CUSTOMRAMP_EDITEND = 4004
919     ID_CUSTOMRAMP_SPROP = 4005
920     ID_CUSTOMRAMP_EPROP = 4006
921    
922 dpinte 2700 class CustomRampPanel(wx.Panel):
923 jonathan 629
924     def __init__(self, parent, shapeType):
925 dpinte 2700 wx.Panel.__init__(self, parent, -1)
926 jonathan 607
927 dpinte 2700 topSizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""), wx.HORIZONTAL)
928 jonathan 607
929 dpinte 2700 bsizer = wx.BoxSizer(wx.VERTICAL)
930     bsizer.Add(wx.StaticText(self, -1, _("Start:")), 0, wx.ALL | wx.CENTER, 4)
931 jonathan 629 self.startPropCtrl = classifier.ClassGroupPropertiesCtrl(
932 dpinte 2700 self, ID_CUSTOMRAMP_SPROP,
933 jonathan 629 ClassGroupProperties(), shapeType,
934 dpinte 2700 style=wx.SIMPLE_BORDER, size=(40, 20))
935     bsizer.Add(self.startPropCtrl, 1, wx.GROW | wx.ALL | wx.CENTER, 4)
936     bsizer.Add(wx.Button(self, ID_CUSTOMRAMP_EDITSTART, _("Change")),
937     0, wx.GROW | wx.ALL | wx.CENTER, 4)
938 jonathan 629
939     topSizer.Add(bsizer,
940 dpinte 2700 1, wx.ALL \
941     | wx.SHAPED \
942     | wx.ALIGN_CENTER_HORIZONTAL \
943     | wx.ALIGN_CENTER_VERTICAL, \
944 jonathan 629 4)
945    
946 dpinte 2700 bmp = resource.GetBitmapResource(USE_BMP, wx.BITMAP_TYPE_XPM)
947     bsizer = wx.BoxSizer(wx.VERTICAL)
948     bsizer.Add(wx.BitmapButton(self, ID_CUSTOMRAMP_COPYSTART, bmp),
949     0, wx.GROW | wx.ALL, 4)
950     bmp = resource.GetBitmapResource(USENOT_BMP, wx.BITMAP_TYPE_XPM)
951     bsizer.Add(wx.BitmapButton(self, ID_CUSTOMRAMP_COPYEND, bmp),
952     0, wx.GROW | wx.ALL, 4)
953 jonathan 629
954     topSizer.Add(bsizer,
955 dpinte 2700 0, wx.ALL \
956     | wx.ALIGN_CENTER_HORIZONTAL \
957     | wx.ALIGN_CENTER_VERTICAL,
958 jonathan 629 4)
959    
960 dpinte 2700 bsizer = wx.BoxSizer(wx.VERTICAL)
961     bsizer.Add(wx.StaticText(self, -1, _("End:")), 0, wx.ALL | wx.CENTER, 4)
962 jonathan 629 self.endPropCtrl = classifier.ClassGroupPropertiesCtrl(
963 dpinte 2700 self, ID_CUSTOMRAMP_EPROP,
964 jonathan 629 ClassGroupProperties(), shapeType,
965 dpinte 2700 style=wx.SIMPLE_BORDER, size=(40, 20))
966     bsizer.Add(self.endPropCtrl, 1, wx.GROW | wx.ALL | wx.CENTER, 4)
967     bsizer.Add(wx.Button(self, ID_CUSTOMRAMP_EDITEND, _("Change")),
968     0, wx.GROW | wx.ALL | wx.CENTER, 4)
969 jonathan 629
970     topSizer.Add(bsizer,
971 dpinte 2700 1, wx.ALL \
972     | wx.SHAPED \
973     | wx.ALIGN_RIGHT \
974     | wx.ALIGN_CENTER_HORIZONTAL \
975     | wx.ALIGN_CENTER_VERTICAL,
976 jonathan 629 4)
977    
978 dpinte 2700 self.Bind(wx.EVT_BUTTON, self._OnCopyStart, id=ID_CUSTOMRAMP_COPYSTART)
979     self.Bind(wx.EVT_BUTTON, self._OnCopyEnd, id=ID_CUSTOMRAMP_COPYEND)
980     self.Bind(wx.EVT_BUTTON, self._OnEditStart, id=ID_CUSTOMRAMP_EDITSTART)
981     self.Bind(wx.EVT_BUTTON, self._OnEditEnd, id=ID_CUSTOMRAMP_EDITEND)
982 jonathan 629
983     self.SetSizer(topSizer)
984     self.SetAutoLayout(True)
985     topSizer.SetSizeHints(self)
986    
987 jonathan 635 def GetRamp(self):
988     return CustomRamp(self.startPropCtrl.GetProperties(),
989     self.endPropCtrl.GetProperties())
990 jonathan 629
991     def _OnCopyStart(self, event):
992     self.endPropCtrl.SetProperties(self.startPropCtrl.GetProperties())
993    
994     def _OnCopyEnd(self, event):
995     self.startPropCtrl.SetProperties(self.endPropCtrl.GetProperties())
996    
997     def _OnEditStart(self, event):
998     self.startPropCtrl.DoEdit()
999    
1000     def _OnEditEnd(self, event):
1001     self.endPropCtrl.DoEdit()
1002    
1003 dpinte 2700

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26