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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2462 - (show annotations)
Wed Dec 15 16:42:56 2004 UTC (20 years, 2 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/classgen.py
File MIME type: text/x-python
File size: 32359 byte(s)
(GenQuantilesPanel.__init__): Set the
minimum number of classes to 2.  The calculate_quantiles needs at
least two and raises an exception otherwise.
Fixes RT#2549

1 # Copyright (c) 2003, 2004 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 """The Classification Generator Dialog"""
9
10 __version__ = "$Revision$"
11 # $Source$
12 # $Id$
13
14
15 import sys
16
17 from wxPython.wx import *
18
19 from Thuban import _
20
21 from Thuban.Model.classification import ClassGroupProperties
22
23 from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
24 FIELDTYPE_STRING
25
26 from Thuban.Model.layer import SHAPETYPE_ARC
27 from Thuban.Model.range import Range
28 from Thuban.UI.common import ThubanBeginBusyCursor, ThubanEndBusyCursor
29
30 import classifier, resource
31
32 from Thuban.Model.classgen import \
33 generate_uniform_distribution, generate_singletons, generate_quantiles, \
34 CustomRamp, grey_ramp, red_ramp, green_ramp, blue_ramp, green_to_red_ramp, \
35 HotToColdRamp, FixedRamp
36
37
38 USEALL_BMP = "group_use_all"
39 USE_BMP = "group_use"
40 USENOT_BMP = "group_use_not"
41 USENONE_BMP = "group_use_none"
42
43 GENCOMBOSTR_UNIFORM = _("Uniform Distribution")
44 GENCOMBOSTR_UNIQUE = _("Unique Values")
45 GENCOMBOSTR_QUANTILES = _("Quantiles from Table")
46
47 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 PROPCOMBOSTR_GREEN2RED = _("Green-to-Red Ramp")
53 PROPCOMBOSTR_HOT2COLD = _("Hot-to-Cold Ramp")
54
55 ID_CLASSGEN_GENCOMBO = 4007
56 ID_CLASSGEN_PROPCOMBO = 4008
57
58 ID_BORDER_COLOR = 4009
59 ID_BORDER_COLOR_CHANGE = 4010
60
61 class ClassGenDialog(wxDialog):
62
63 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 wxDialog.__init__(self, parent, -1, _("Generate Classification"),
70 style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
71
72 self.parent = parent
73 self.layer = layer
74 self.clazz = None
75
76 col = layer.ShapeStore().Table().Column(fieldName)
77 self.type = col.type
78
79 self.fieldName = fieldName
80 self.fieldType = self.type
81
82 self.curGenPanel = None
83
84 self.genpanels = []
85
86 #############
87 # we need to create genButton first because when we create the
88 # panels they will call AllowGenerate() which uses genButton.
89 #
90 self.genButton = wxButton(self, wxID_OK, _("Generate"))
91 self.cancelButton = wxButton(self, wxID_CANCEL, _("Close"))
92 self.genButton.SetDefault()
93
94 self.genChoice = wxChoice(self, ID_CLASSGEN_GENCOMBO)
95
96 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
101 for name, clazz in self.genpanels:
102 self.genChoice.Append(name, [clazz, None])
103
104 self.genChoice.SetSelection(0)
105
106 for i in range(self.genChoice.GetCount()):
107 clazz, obj = self.genChoice.GetClientData(i)
108
109 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
114
115 #############
116
117 sizer = wxBoxSizer(wxVERTICAL)
118
119 sizer.Add(wxStaticText(self, -1, _("Field: %s") % fieldName),
120 0, wxALL, 4)
121 sizer.Add(wxStaticText(
122 self, -1,
123 _("Data Type: %s") % classifier.Classifier.type2string[self.type]),
124 0, wxALL, 4)
125
126 psizer = wxBoxSizer(wxHORIZONTAL)
127 psizer.Add(wxStaticText(self, -1, _("Generate:")),
128 0, wxALIGN_CENTER_VERTICAL, 0)
129 psizer.Add(self.genChoice, 1, wxALL | wxGROW, 4)
130
131 sizer.Add(psizer, 0, wxALL | wxGROW, 4)
132
133 self.sizer_genPanel = wxBoxSizer(wxVERTICAL)
134 sizer.Add(self.sizer_genPanel, 1, wxGROW | wxALL, 4)
135
136 psizer = wxBoxSizer(wxHORIZONTAL)
137 psizer.Add(wxStaticText(self, -1, _("Color Scheme:")),
138 0, wxALIGN_CENTER_VERTICAL, 0)
139
140 # Properties (Ramp) ComboBox
141 self.propCombo = wxChoice(self, ID_CLASSGEN_PROPCOMBO)
142
143 self.propPanel = None
144 custom_ramp_panel = CustomRampPanel(self, layer.ShapeType())
145
146 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 self.propCombo.Append(PROPCOMBOSTR_HOT2COLD, HotToColdRamp())
152 self.propCombo.Append(PROPCOMBOSTR_CUSTOM, custom_ramp_panel)
153
154 self.propCombo.SetSelection(0)
155
156 psizer.Add(self.propCombo, 1, wxALL | wxGROW, 4)
157 sizer.Add(psizer, 0, wxALL | wxGROW, 4)
158
159 if layer.ShapeType() != SHAPETYPE_ARC:
160 psizer = wxBoxSizer(wxHORIZONTAL)
161 self.fix_border_check = wxCheckBox(self, -1, _("Fix Border Color"))
162 psizer.Add(self.fix_border_check, 0, wxALL | wxGROW, 4)
163 self.border_color = classifier.ClassGroupPropertiesCtrl(
164 self, ID_BORDER_COLOR,
165 ClassGroupProperties(), SHAPETYPE_ARC,
166 style=wxSIMPLE_BORDER, size=(40, 20))
167 psizer.Add(self.border_color, 0, wxALL | wxGROW, 4)
168 psizer.Add(wxButton(self, ID_BORDER_COLOR_CHANGE, _("Change")),
169 0, wxALL, 4)
170 sizer.Add(psizer, 0, wxALL | wxGROW, 4)
171 EVT_BUTTON(self, ID_BORDER_COLOR_CHANGE, self.OnBorderColorChange)
172 else:
173 self.border_color = None
174
175 sizer.Add(custom_ramp_panel, 1, wxGROW | wxALL, 4)
176 sizer.Show(custom_ramp_panel, False)
177
178 # Finally place the main buttons
179 buttonSizer = wxBoxSizer(wxHORIZONTAL)
180 buttonSizer.Add(self.genButton, 0, wxRIGHT|wxEXPAND, 10)
181 buttonSizer.Add(self.cancelButton, 0, wxRIGHT|wxEXPAND, 10)
182 sizer.Add(buttonSizer, 0, wxALIGN_RIGHT|wxBOTTOM|wxTOP, 10)
183
184 self.SetSizer(sizer)
185 self.SetAutoLayout(True)
186 sizer.SetSizeHints(self)
187
188 self.topBox = sizer
189
190 self.__DoOnGenTypeSelect()
191
192 EVT_CHOICE(self, ID_CLASSGEN_GENCOMBO, self._OnGenTypeSelect)
193 EVT_CHOICE(self, ID_CLASSGEN_PROPCOMBO, self._OnPropTypeSelect)
194 EVT_BUTTON(self, wxID_OK, self.OnOK)
195 EVT_BUTTON(self, wxID_CANCEL, self.OnCancel)
196
197 self.__DoOnGenTypeSelect()
198
199 self.genChoice.SetFocus()
200
201 def GetClassification(self):
202 return self.clazz
203
204 def AllowGenerate(self, on):
205 pass #self.genButton.Enable(on)
206
207 def OnOK(self, event):
208 """This is really the generate button, but we want to override
209 the wxDialog class.
210 """
211
212 index = self.genChoice.GetSelection()
213
214 assert index != -1, "button should be disabled!"
215
216 genSel = self.genChoice.GetString(index)
217 clazz, genPanel = self.genChoice.GetClientData(index)
218
219 propPanel = self.propPanel
220
221 if genSel in (GENCOMBOSTR_UNIFORM, \
222 GENCOMBOSTR_UNIQUE, \
223 GENCOMBOSTR_QUANTILES):
224
225 numGroups = genPanel.GetNumGroups()
226
227 index = self.propCombo.GetSelection()
228
229 propSel = self.propCombo.GetString(index)
230 propPanel = self.propCombo.GetClientData(index)
231
232 ramp = propPanel.GetRamp()
233 if self.border_color and self.fix_border_check.IsChecked():
234 props = self.border_color.GetProperties()
235 ramp = FixedRamp(ramp,
236 (props.GetLineColor(), props.GetLineWidth(), None))
237
238 if genSel == GENCOMBOSTR_UNIFORM:
239
240 min = genPanel.GetMin()
241 max = genPanel.GetMax()
242
243 if min is not None \
244 and max is not None \
245 and numGroups is not None:
246
247 self.clazz = generate_uniform_distribution(
248 min, max, numGroups, ramp,
249 self.type == FIELDTYPE_INT)
250
251 self.parent._SetClassification(self.clazz)
252
253 elif genSel == GENCOMBOSTR_UNIQUE:
254
255 list = genPanel.GetValueList()
256
257 if len(list) > 0:
258 self.clazz = generate_singletons(list, ramp)
259 self.parent._SetClassification(self.clazz)
260
261 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 generate_quantiles(_list, percents, ramp, _range)
271
272 if adjusted:
273 dlg = wxMessageDialog(self,
274 _("Based on the data from the table and the input\n"
275 "values, the exact quantiles could not be generated.\n\n"
276 "Accept a close estimate?"),
277 _("Problem with Quantiles"),
278
279 wxYES_NO|wxYES_DEFAULT|wxICON_QUESTION)
280 if dlg.ShowModal() == wxID_YES:
281 self.parent._SetClassification(self.clazz)
282 else:
283 self.parent._SetClassification(self.clazz)
284
285 def OnCancel(self, event):
286 self.Close()
287
288 def OnBorderColorChange(self, event):
289 self.border_color.DoEdit()
290
291 def _OnGenTypeSelect(self, event):
292 self.__DoOnGenTypeSelect()
293 return
294
295 combo = event.GetEventObject()
296
297 selIndex = combo.GetSelection()
298
299 if self.genPanel is not None:
300 self.topBox.Show(self.genPanel, False)
301
302 self.genPanel = combo.GetClientData(selIndex)
303 if self.genPanel is not None:
304 self.topBox.Show(self.genPanel, True)
305
306 self.topBox.SetSizeHints(self)
307 self.topBox.Layout()
308
309 def _OnPropTypeSelect(self, event):
310 combo = event.GetEventObject()
311
312 selIndex = combo.GetSelection()
313 sel = combo.GetString(selIndex)
314
315 if isinstance(self.propPanel, wxPanel):
316 self.topBox.Show(self.propPanel, False)
317
318 self.propPanel = combo.GetClientData(selIndex)
319
320 if isinstance(self.propPanel, wxPanel):
321 self.topBox.Show(self.propPanel, True)
322
323 self.topBox.SetSizeHints(self)
324 self.topBox.Layout()
325
326 def __DoOnGenTypeSelect(self):
327 choice = self.genChoice
328
329 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 wxALL|wxEXPAND|wxADJUST_MINSIZE, 3)
343 self.sizer_genPanel.Layout()
344 self.Layout()
345 self.topBox.SetSizeHints(self)
346
347 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 class GenUniformPanel(wxPanel):
354
355 def __init__(self, parent, layer, fieldName, fieldType):
356 wxPanel.__init__(self, parent, -1)
357
358 self.parent = parent
359 self.layer = layer
360 self.fieldName = fieldName
361 self.fieldType = fieldType
362
363 topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""),
364 wxVERTICAL)
365
366 #############
367
368 sizer = wxBoxSizer(wxHORIZONTAL)
369
370 sizer.Add(wxStaticText(self, -1, _("Min:")), 0, wxALL, 4)
371 self.minCtrl = wxTextCtrl(self, ID_UNIFORM_MIN, style=wxTE_RIGHT)
372 sizer.Add(self.minCtrl, 1, wxALL, 4)
373 EVT_TEXT(self, ID_UNIFORM_MIN, self._OnRangeChanged)
374
375 sizer.Add(wxStaticText(self, -1, _("Max:")), 0, wxALL, 4)
376 self.maxCtrl = wxTextCtrl(self, ID_UNIFORM_MAX, style=wxTE_RIGHT)
377 sizer.Add(self.maxCtrl, 1, wxALL, 4)
378 EVT_TEXT(self, ID_UNIFORM_MAX, self._OnRangeChanged)
379
380 sizer.Add(wxButton(self, ID_UNIFORM_RETRIEVE, _("Retrieve From Table")),
381 0, wxALL, 4)
382 EVT_BUTTON(self, ID_UNIFORM_RETRIEVE, self._OnRetrieve)
383
384 topSizer.Add(sizer, 1, wxGROW, 0)
385
386 #############
387
388 sizer = wxBoxSizer(wxHORIZONTAL)
389
390 sizer.Add(wxStaticText(self, -1, _("Number of Groups:")), 0, wxALL, 4)
391 self.numGroupsCtrl = wxSpinCtrl(self, ID_UNIFORM_NGROUPS,
392 style=wxTE_RIGHT)
393 EVT_TEXT(self, ID_UNIFORM_NGROUPS, self._OnNumGroupsChanged)
394 EVT_SPINCTRL(self, ID_UNIFORM_NGROUPS, self._OnNumGroupsChanged)
395 sizer.Add(self.numGroupsCtrl, 1, wxALL, 4)
396
397 sizer.Add(wxStaticText(self, -1, _("Stepping:")), 0, wxALL, 4)
398 self.stepCtrl = wxTextCtrl(self, ID_UNIFORM_STEP, style=wxTE_RIGHT)
399 EVT_TEXT(self, ID_UNIFORM_STEP, self._OnSteppingChanged)
400 sizer.Add(self.stepCtrl , 1, wxALL, 4)
401
402 topSizer.Add(sizer, 1, wxGROW, 0)
403
404 #############
405
406 self.SetSizer(topSizer)
407 self.SetAutoLayout(True)
408 topSizer.SetSizeHints(self)
409
410 self.numGroupsChanging = False
411 self.steppingChanging = False
412
413 self.numGroupsCtrl.SetRange(1, sys.maxint)
414
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 return self.__GetValidatedTypeEntry(self.numGroupsCtrl,
424 value,
425 FIELDTYPE_INT,
426 None)
427
428 def GetStepping(self):
429 step = self.stepCtrl.GetValue()
430 return self.__GetValidatedTypeEntry(self.stepCtrl,
431 step,
432 self.fieldType,
433 0)
434
435 def GetMin(self):
436 min = self.minCtrl.GetValue()
437 max = self.maxCtrl.GetValue()
438 return self.__GetValidatedTypeEntry(self.minCtrl,
439 min,
440 self.fieldType,
441 max)
442
443 def GetMax(self):
444 min = self.minCtrl.GetValue()
445 max = self.maxCtrl.GetValue()
446 return self.__GetValidatedTypeEntry(self.maxCtrl,
447 max,
448 self.fieldType,
449 min)
450
451 def _OnRangeChanged(self, event):
452
453 hasFocus = wxWindow_FindFocus() == event.GetEventObject()
454 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 #self.stepCtrl.SetValue(str((max - min) / ngroups))
471 self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
472 #self.numGroupsCtrl.SetValue(ngroups)
473
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 self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
508
509 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 self.numGroupsCtrl.SetValue(self.__CalcNumGroups(min, max, step))
533
534 self.parent.AllowGenerate(self.GetNumGroups() is not None)
535 else:
536 self.parent.AllowGenerate(False)
537
538 def _OnRetrieve(self, event):
539 table = self.layer.ShapeStore().Table()
540 if table is not None:
541 ThubanBeginBusyCursor()
542 try:
543 min, max = table.ValueRange(self.fieldName)
544 self.minCtrl.SetValue(str(min))
545 self.maxCtrl.SetValue(str(max))
546 finally:
547 ThubanEndBusyCursor()
548
549 def __GetValidatedTypeEntry(self, win, value, type, badValue = None):
550
551 if type == FIELDTYPE_INT:
552 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 win.SetForegroundColour(wxBLACK)
581 else:
582 win.SetForegroundColour(wxRED)
583
584 win.Refresh()
585
586 return valid
587
588 def __CalcStepping(self, min, max, ngroups):
589 if self.fieldType == FIELDTYPE_INT:
590 step = int((max - min + 1) / float(ngroups))
591 else:
592 step = (max - min) / float(ngroups)
593
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 ID_UNIQUE_REVAVAIL = 4008
615 ID_UNIQUE_REVUSE = 4009
616
617 class GenUniquePanel(wxPanel):
618
619 def __init__(self, parent, layer, fieldName, fieldType):
620 wxPanel.__init__(self, parent, -1)
621
622 self.parent = parent
623 self.layer = layer
624 self.fieldName = fieldName
625 self.fieldType = fieldType
626
627 topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""),
628 wxVERTICAL)
629
630
631 #bsizer = wxBoxSizer(wxVERTICAL)
632 topSizer.Add(wxButton(self, ID_UNIQUE_RETRIEVE,
633 _("Retrieve From Table")),
634 0, wxALL | wxALIGN_RIGHT, 4)
635
636 EVT_BUTTON(self, ID_UNIQUE_RETRIEVE, self._OnRetrieve)
637
638 #topSizer.Add(bsizer, 0, wxALL, 4)
639
640 sizer = wxBoxSizer(wxHORIZONTAL)
641
642 self.dataList = []
643
644 psizer = wxBoxSizer(wxVERTICAL)
645 self.list_avail = wxListCtrl(self, -1,
646 style=wxLC_REPORT | wxLC_SINGLE_SEL)
647 self.list_avail.InsertColumn(0, _("Available"))
648 self.list_avail_data = []
649 psizer.Add(self.list_avail, 1, wxGROW, 0)
650
651 bsizer = wxBoxSizer(wxHORIZONTAL)
652 bsizer.Add(wxButton(self, ID_UNIQUE_SORTAVAIL, _("Sort")))
653 EVT_BUTTON(self, ID_UNIQUE_SORTAVAIL, self._OnSortList)
654
655 bsizer.Add(wxButton(self, ID_UNIQUE_REVAVAIL, _("Reverse")))
656 EVT_BUTTON(self, ID_UNIQUE_REVAVAIL, self._OnReverseList)
657
658 psizer.Add(bsizer, 0, wxGROW, 0)
659 sizer.Add(psizer, 1, wxGROW, 0)
660
661
662 bsizer = wxBoxSizer(wxVERTICAL)
663
664 bmp = resource.GetBitmapResource(USEALL_BMP, wxBITMAP_TYPE_XPM)
665 bsizer.Add(wxBitmapButton(self, ID_UNIQUE_USEALL, bmp),
666 0, wxGROW | wxALL, 4)
667 bmp = resource.GetBitmapResource(USE_BMP, wxBITMAP_TYPE_XPM)
668 bsizer.Add(wxBitmapButton(self, ID_UNIQUE_USE, bmp),
669 0, wxGROW | wxALL, 4)
670 bmp = resource.GetBitmapResource(USENOT_BMP, wxBITMAP_TYPE_XPM)
671 bsizer.Add(wxBitmapButton(self, ID_UNIQUE_DONTUSE, bmp),
672 0, wxGROW | wxALL, 4)
673 bmp = resource.GetBitmapResource(USENONE_BMP, wxBITMAP_TYPE_XPM)
674 bsizer.Add(wxBitmapButton(self, ID_UNIQUE_USENONE, bmp),
675 0, wxGROW | wxALL, 4)
676
677 EVT_BUTTON(self, ID_UNIQUE_USEALL, self._OnUseAll)
678 EVT_BUTTON(self, ID_UNIQUE_USE, self._OnUse)
679 EVT_BUTTON(self, ID_UNIQUE_DONTUSE, self._OnDontUse)
680 EVT_BUTTON(self, ID_UNIQUE_USENONE, self._OnUseNone)
681
682 sizer.Add(bsizer, 0, wxALL | wxALIGN_CENTER_VERTICAL, 4)
683
684 psizer = wxBoxSizer(wxVERTICAL)
685 self.list_use = wxListCtrl(self, -1,
686 style=wxLC_REPORT | wxLC_SINGLE_SEL)
687 self.list_use.InsertColumn(0, _("Use"))
688 self.list_use_data = []
689 psizer.Add(self.list_use, 1, wxGROW, 0)
690
691 bsizer = wxBoxSizer(wxHORIZONTAL)
692 bsizer.Add(wxButton(self, ID_UNIQUE_SORTUSE, _("Sort")))
693 EVT_BUTTON(self, ID_UNIQUE_SORTUSE, self._OnSortList)
694
695 bsizer.Add(wxButton(self, ID_UNIQUE_REVUSE, _("Reverse")))
696 EVT_BUTTON(self, ID_UNIQUE_REVUSE, self._OnReverseList)
697
698 psizer.Add(bsizer, 0, wxGROW, 0)
699
700 sizer.Add(psizer, 1, wxGROW, 0)
701
702
703 topSizer.Add(sizer, 1, wxGROW, 0)
704
705 self.SetSizer(topSizer)
706 self.SetAutoLayout(True)
707 topSizer.SetSizeHints(self)
708
709 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 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 def _OnSortList(self, event):
726 id = event.GetId()
727
728 if id == ID_UNIQUE_SORTUSE:
729 list = self.list_use
730 else:
731 list = self.list_avail
732
733 list.SortItems(lambda i1, i2: cmp(self.dataList[i1],
734 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 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 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
764 self.list_avail_data.append(v)
765 index += 1
766 finally:
767 ThubanEndBusyCursor()
768
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 wxLIST_NEXT_ALL,
788 wxLIST_STATE_SELECTED)
789
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 list_dest.GetItemCount(),
802 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 ID_QUANTILES_RANGE = 4001
815 ID_QUANTILES_RETRIEVE = 4002
816
817 class GenQuantilesPanel(wxPanel):
818
819 def __init__(self, parent, layer, fieldName, fieldType):
820 wxPanel.__init__(self, parent, -1)
821
822 self.parent = parent
823 self.layer = layer
824 self.fieldName = fieldName
825 self.fieldType = fieldType
826
827 topBox = wxStaticBoxSizer(wxStaticBox(self, -1, ""),
828 wxVERTICAL)
829
830 self.text_range = wxTextCtrl(self, ID_QUANTILES_RANGE, "")
831 self.button_retrieve = wxButton(self, ID_QUANTILES_RETRIEVE,
832 _("Retrieve from Table"))
833
834 self.spin_numClasses = wxSpinCtrl(self, -1, style=wxTE_RIGHT)
835 self.spin_numClasses.SetRange(2, sys.maxint)
836 self.spin_numClasses.SetValue(2)
837
838
839 sizer = wxBoxSizer(wxHORIZONTAL)
840 sizer.Add(wxStaticText(self, -1, _("Apply to Range")), 0, wxALL, 4)
841 sizer.Add(self.text_range, 1, wxALL, 4)
842 sizer.Add(self.button_retrieve, 0, wxALL, 4)
843
844 topBox.Add(sizer, 0, wxEXPAND, 0)
845
846 sizer = wxBoxSizer(wxHORIZONTAL)
847 sizer.Add(wxStaticText(self, -1, _("Number of Classes:")), 0, wxALL, 4)
848 sizer.Add(self.spin_numClasses, 1, wxALL, 4)
849
850 topBox.Add(sizer, 0, wxEXPAND, 0)
851
852 self.SetSizer(topBox)
853 self.SetAutoLayout(True)
854 topBox.Fit(self)
855 topBox.SetSizeHints(self)
856
857 EVT_TEXT(self, ID_QUANTILES_RANGE, self.OnRangeText)
858 EVT_BUTTON(self, ID_QUANTILES_RETRIEVE, self.OnRetrieve)
859
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 _list = []
872 table = self.layer.ShapeStore().Table()
873 if table is not None:
874 ThubanBeginBusyCursor()
875 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 _list.append(table.ReadValue(i, self.fieldName,
882 row_is_ordinal = True))
883 finally:
884 ThubanEndBusyCursor()
885
886 return _list
887
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 self.text_range.SetForegroundColour(wxBLACK)
897 else:
898 self.text_range.SetForegroundColour(wxRED)
899
900 def OnRetrieve(self, event):
901 table = self.layer.ShapeStore().Table()
902 if table is not None:
903 ThubanBeginBusyCursor()
904 try:
905 min, max = table.ValueRange(self.fieldName)
906 self.text_range.SetValue("[" + str(min) + ";" + str(max) + "]")
907 finally:
908 ThubanEndBusyCursor()
909
910 ID_CUSTOMRAMP_COPYSTART = 4001
911 ID_CUSTOMRAMP_COPYEND = 4002
912 ID_CUSTOMRAMP_EDITSTART = 4003
913 ID_CUSTOMRAMP_EDITEND = 4004
914 ID_CUSTOMRAMP_SPROP = 4005
915 ID_CUSTOMRAMP_EPROP = 4006
916
917 class CustomRampPanel(wxPanel):
918
919 def __init__(self, parent, shapeType):
920 wxPanel.__init__(self, parent, -1)
921
922 topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""), wxHORIZONTAL)
923
924 bsizer = wxBoxSizer(wxVERTICAL)
925 bsizer.Add(wxStaticText(self, -1, _("Start:")), 0, wxALL | wxCENTER, 4)
926 self.startPropCtrl = classifier.ClassGroupPropertiesCtrl(
927 self, ID_CUSTOMRAMP_SPROP,
928 ClassGroupProperties(), shapeType,
929 style=wxSIMPLE_BORDER, size=(40, 20))
930 bsizer.Add(self.startPropCtrl, 1, wxGROW | wxALL | wxCENTER, 4)
931 bsizer.Add(wxButton(self, ID_CUSTOMRAMP_EDITSTART, _("Change")),
932 0, wxGROW | wxALL | wxCENTER, 4)
933
934 topSizer.Add(bsizer,
935 1, wxALL \
936 | wxSHAPED \
937 | wxALIGN_CENTER_HORIZONTAL \
938 | wxALIGN_CENTER_VERTICAL, \
939 4)
940
941 bmp = resource.GetBitmapResource(USE_BMP, wxBITMAP_TYPE_XPM)
942 bsizer = wxBoxSizer(wxVERTICAL)
943 bsizer.Add(wxBitmapButton(self, ID_CUSTOMRAMP_COPYSTART, bmp),
944 0, wxGROW | wxALL, 4)
945 bmp = resource.GetBitmapResource(USENOT_BMP, wxBITMAP_TYPE_XPM)
946 bsizer.Add(wxBitmapButton(self, ID_CUSTOMRAMP_COPYEND, bmp),
947 0, wxGROW | wxALL, 4)
948
949 topSizer.Add(bsizer,
950 0, wxALL \
951 | wxALIGN_CENTER_HORIZONTAL \
952 | wxALIGN_CENTER_VERTICAL,
953 4)
954
955 bsizer = wxBoxSizer(wxVERTICAL)
956 bsizer.Add(wxStaticText(self, -1, _("End:")), 0, wxALL | wxCENTER, 4)
957 self.endPropCtrl = classifier.ClassGroupPropertiesCtrl(
958 self, ID_CUSTOMRAMP_EPROP,
959 ClassGroupProperties(), shapeType,
960 style=wxSIMPLE_BORDER, size=(40, 20))
961 bsizer.Add(self.endPropCtrl, 1, wxGROW | wxALL | wxCENTER, 4)
962 bsizer.Add(wxButton(self, ID_CUSTOMRAMP_EDITEND, _("Change")),
963 0, wxGROW | wxALL | wxCENTER, 4)
964
965 topSizer.Add(bsizer,
966 1, wxALL \
967 | wxSHAPED \
968 | wxALIGN_RIGHT \
969 | wxALIGN_CENTER_HORIZONTAL \
970 | wxALIGN_CENTER_VERTICAL,
971 4)
972
973 EVT_BUTTON(self, ID_CUSTOMRAMP_COPYSTART, self._OnCopyStart)
974 EVT_BUTTON(self, ID_CUSTOMRAMP_COPYEND, self._OnCopyEnd)
975 EVT_BUTTON(self, ID_CUSTOMRAMP_EDITSTART, self._OnEditStart)
976 EVT_BUTTON(self, ID_CUSTOMRAMP_EDITEND, self._OnEditEnd)
977
978 self.SetSizer(topSizer)
979 self.SetAutoLayout(True)
980 topSizer.SetSizeHints(self)
981
982 def GetRamp(self):
983 return CustomRamp(self.startPropCtrl.GetProperties(),
984 self.endPropCtrl.GetProperties())
985
986 def _OnCopyStart(self, event):
987 self.endPropCtrl.SetProperties(self.startPropCtrl.GetProperties())
988
989 def _OnCopyEnd(self, event):
990 self.startPropCtrl.SetProperties(self.endPropCtrl.GetProperties())
991
992 def _OnEditStart(self, event):
993 self.startPropCtrl.DoEdit()
994
995 def _OnEditEnd(self, event):
996 self.endPropCtrl.DoEdit()
997
998

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26