/[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 1526 - (show annotations)
Wed Jul 30 15:43:06 2003 UTC (21 years, 7 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/classgen.py
File MIME type: text/x-python
File size: 32196 byte(s)
 Use renamed Ramp instances.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26