/[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 1391 - (show annotations)
Thu Jul 10 14:54:02 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: 32448 byte(s)
(ClassGenDialog.__init__): Add controls
        to allow the user to fix line color/width on generated groups.
(ClassGenDialog.OnOK): Use new 'fixes' parameter of the generate_*
        functions to optionally fix group properties.

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, GreyRamp, RedRamp, GreenRamp, BlueRamp, GreenToRedRamp, \
28 HotToColdRamp
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, GreyRamp)
140 self.propCombo.Append(PROPCOMBOSTR_RED, RedRamp)
141 self.propCombo.Append(PROPCOMBOSTR_GREEN, GreenRamp)
142 self.propCombo.Append(PROPCOMBOSTR_BLUE, BlueRamp)
143 self.propCombo.Append(PROPCOMBOSTR_GREEN2RED, GreenToRedRamp)
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 lineColor = props.GetLineColor()
229 lineWidth = props.GetLineWidth()
230 else:
231 lineColor = None
232 lineWidth = None
233
234 if genSel == GENCOMBOSTR_UNIFORM:
235
236 min = genPanel.GetMin()
237 max = genPanel.GetMax()
238
239 if min is not None \
240 and max is not None \
241 and numGroups is not None:
242
243 self.clazz = generate_uniform_distribution(
244 min, max, numGroups, ramp,
245 self.type == FIELDTYPE_INT,
246 fixes = (lineColor, lineWidth, None))
247
248 self.parent._SetClassification(self.clazz)
249
250 elif genSel == GENCOMBOSTR_UNIQUE:
251
252 list = genPanel.GetValueList()
253
254 if len(list) > 0:
255 self.clazz = generate_singletons(list, ramp,
256 (lineColor, lineWidth, None))
257 self.parent._SetClassification(self.clazz)
258
259 elif genSel == GENCOMBOSTR_QUANTILES:
260
261 _range = genPanel.GetRange()
262 _list = genPanel.GetList()
263 _list.sort()
264
265 delta = 1 / float(numGroups)
266 percents = [delta * i for i in range(1, numGroups + 1)]
267 adjusted, self.clazz = \
268 generate_quantiles(_list, percents, ramp, _range,
269 (lineColor, lineWidth, None))
270
271 if adjusted:
272 dlg = wxMessageDialog(self,
273 _("Based on the data from the table and the input\n" +
274 "values, the exact quantiles could not be generated.\n\n" +
275 "Accept a close estimate?"),
276 _("Problem with Quantiles"),
277
278 wxYES_NO|wxYES_DEFAULT|wxICON_QUESTION)
279 if dlg.ShowModal() == wxID_YES:
280 self.parent._SetClassification(self.clazz)
281 else:
282 self.parent._SetClassification(self.clazz)
283
284 def OnCancel(self, event):
285 self.Close()
286
287 def OnBorderColorChange(self, event):
288 self.border_color.DoEdit()
289
290 def _OnGenTypeSelect(self, event):
291 self.__DoOnGenTypeSelect()
292 return
293
294 combo = event.GetEventObject()
295
296 selIndex = combo.GetSelection()
297
298 if self.genPanel is not None:
299 self.topBox.Show(self.genPanel, False)
300
301 self.genPanel = combo.GetClientData(selIndex)
302 if self.genPanel is not None:
303 self.topBox.Show(self.genPanel, True)
304
305 self.topBox.SetSizeHints(self)
306 self.topBox.Layout()
307
308 def _OnPropTypeSelect(self, event):
309 combo = event.GetEventObject()
310
311 selIndex = combo.GetSelection()
312 sel = combo.GetString(selIndex)
313
314 if isinstance(self.propPanel, wxPanel):
315 self.topBox.Show(self.propPanel, False)
316
317 self.propPanel = combo.GetClientData(selIndex)
318
319 if isinstance(self.propPanel, wxPanel):
320 self.topBox.Show(self.propPanel, True)
321
322 self.topBox.SetSizeHints(self)
323 self.topBox.Layout()
324
325 def __DoOnGenTypeSelect(self):
326 choice = self.genChoice
327
328 sel = choice.GetSelection()
329 if sel == -1: return
330
331 clazz, obj = choice.GetClientData(sel)
332
333 if self.curGenPanel is not None:
334 self.curGenPanel.Hide()
335 self.sizer_genPanel.Remove(self.curGenPanel)
336
337 self.curGenPanel = obj
338 self.curGenPanel.Show()
339
340 self.sizer_genPanel.Add(self.curGenPanel, 1,
341 wxALL|wxEXPAND|wxADJUST_MINSIZE, 3)
342 self.sizer_genPanel.Layout()
343 self.Layout()
344 self.topBox.SetSizeHints(self)
345
346 ID_UNIFORM_MIN = 4001
347 ID_UNIFORM_MAX = 4002
348 ID_UNIFORM_NGROUPS = 4003
349 ID_UNIFORM_STEP = 4004
350 ID_UNIFORM_RETRIEVE = 4005
351
352 class GenUniformPanel(wxPanel):
353
354 def __init__(self, parent, layer, fieldName, fieldType):
355 wxPanel.__init__(self, parent, -1)
356
357 self.parent = parent
358 self.layer = layer
359 self.fieldName = fieldName
360 self.fieldType = fieldType
361
362 topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""),
363 wxVERTICAL)
364
365 #############
366
367 sizer = wxBoxSizer(wxHORIZONTAL)
368
369 sizer.Add(wxStaticText(self, -1, _("Min:")), 0, wxALL, 4)
370 self.minCtrl = wxTextCtrl(self, ID_UNIFORM_MIN, style=wxTE_RIGHT)
371 sizer.Add(self.minCtrl, 1, wxALL, 4)
372 EVT_TEXT(self, ID_UNIFORM_MIN, self._OnRangeChanged)
373
374 sizer.Add(wxStaticText(self, -1, _("Max:")), 0, wxALL, 4)
375 self.maxCtrl = wxTextCtrl(self, ID_UNIFORM_MAX, style=wxTE_RIGHT)
376 sizer.Add(self.maxCtrl, 1, wxALL, 4)
377 EVT_TEXT(self, ID_UNIFORM_MAX, self._OnRangeChanged)
378
379 sizer.Add(wxButton(self, ID_UNIFORM_RETRIEVE, _("Retrieve From Table")),
380 0, wxALL, 4)
381 EVT_BUTTON(self, ID_UNIFORM_RETRIEVE, self._OnRetrieve)
382
383 topSizer.Add(sizer, 1, wxGROW, 0)
384
385 #############
386
387 sizer = wxBoxSizer(wxHORIZONTAL)
388
389 sizer.Add(wxStaticText(self, -1, _("Number of Groups:")), 0, wxALL, 4)
390 self.numGroupsCtrl = wxSpinCtrl(self, ID_UNIFORM_NGROUPS,
391 style=wxTE_RIGHT)
392 EVT_TEXT(self, ID_UNIFORM_NGROUPS, self._OnNumGroupsChanged)
393 EVT_SPINCTRL(self, ID_UNIFORM_NGROUPS, self._OnNumGroupsChanged)
394 sizer.Add(self.numGroupsCtrl, 1, wxALL, 4)
395
396 sizer.Add(wxStaticText(self, -1, _("Stepping:")), 0, wxALL, 4)
397 self.stepCtrl = wxTextCtrl(self, ID_UNIFORM_STEP, style=wxTE_RIGHT)
398 EVT_TEXT(self, ID_UNIFORM_STEP, self._OnSteppingChanged)
399 sizer.Add(self.stepCtrl , 1, wxALL, 4)
400
401 topSizer.Add(sizer, 1, wxGROW, 0)
402
403 #############
404
405 self.SetSizer(topSizer)
406 self.SetAutoLayout(True)
407 topSizer.SetSizeHints(self)
408
409 self.numGroupsChanging = False
410 self.steppingChanging = False
411
412 self.numGroupsCtrl.SetRange(1, sys.maxint)
413
414 self.numGroupsCtrl.SetValue(1)
415 self.stepCtrl.SetValue("1")
416 self.maxCtrl.SetValue("0")
417 self.minCtrl.SetValue("0")
418 self.minCtrl.SetFocus()
419
420 def GetNumGroups(self):
421 value = self.numGroupsCtrl.GetValue()
422 return self.__GetValidatedTypeEntry(self.numGroupsCtrl,
423 value,
424 FIELDTYPE_INT,
425 None)
426
427 def GetStepping(self):
428 step = self.stepCtrl.GetValue()
429 return self.__GetValidatedTypeEntry(self.stepCtrl,
430 step,
431 self.fieldType,
432 0)
433
434 def GetMin(self):
435 min = self.minCtrl.GetValue()
436 max = self.maxCtrl.GetValue()
437 return self.__GetValidatedTypeEntry(self.minCtrl,
438 min,
439 self.fieldType,
440 max)
441
442 def GetMax(self):
443 min = self.minCtrl.GetValue()
444 max = self.maxCtrl.GetValue()
445 return self.__GetValidatedTypeEntry(self.maxCtrl,
446 max,
447 self.fieldType,
448 min)
449
450 def _OnRangeChanged(self, event):
451
452 hasFocus = wxWindow_FindFocus() == event.GetEventObject()
453 min = self.GetMin()
454 max = self.GetMax()
455
456 on = min is not None \
457 and max is not None
458
459 self.numGroupsCtrl.Enable(on)
460 self.stepCtrl.Enable(on)
461
462 ngroups = self.GetNumGroups()
463
464 if ngroups is not None \
465 and min is not None \
466 and max is not None \
467 and ngroups != 0:
468
469 #self.stepCtrl.SetValue(str((max - min) / ngroups))
470 self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
471 #self.numGroupsCtrl.SetValue(ngroups)
472
473 self.parent.AllowGenerate(self.GetStepping() is not None)
474 else:
475 self.parent.AllowGenerate(False)
476
477
478 if hasFocus:
479 event.GetEventObject().SetFocus()
480
481 def _OnNumGroupsChanged(self, event):
482 if self.steppingChanging:
483 self.steppingChanging = False
484 return
485
486
487 obj = event.GetEventObject()
488 ngroups = self.GetNumGroups()
489 min = self.GetMin()
490 max = self.GetMax()
491
492 if ngroups is not None \
493 and min is not None \
494 and max is not None \
495 and ngroups != 0:
496
497 #
498 # changing the value in the stepCtrl sends an event
499 # that the control is changing, at which point
500 # we try to update the numGroupsCtrl. This causes
501 # an infinite recursion. This flag and the one
502 # called steppingChanging tries to prevent the recursion.
503 #
504 self.numGroupsChanging = True
505
506 self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
507
508 self.parent.AllowGenerate(self.GetStepping() is not None)
509 else:
510 self.parent.AllowGenerate(False)
511
512
513 def _OnSteppingChanged(self, event):
514 if self.numGroupsChanging:
515 self.numGroupsChanging = False
516 return
517
518 step = self.GetStepping()
519 min = self.GetMin()
520 max = self.GetMax()
521
522 if step is not None \
523 and min is not None \
524 and max is not None \
525 and step != 0:
526
527 #
528 # see note in _OnNumGroupsChanged
529 #
530 self.steppingChanging = True
531 self.numGroupsCtrl.SetValue(self.__CalcNumGroups(min, max, step))
532
533 self.parent.AllowGenerate(self.GetNumGroups() is not None)
534 else:
535 self.parent.AllowGenerate(False)
536
537 def _OnRetrieve(self, event):
538 table = self.layer.ShapeStore().Table()
539 if table is not None:
540 ThubanBeginBusyCursor()
541 try:
542 min, max = table.ValueRange(self.fieldName)
543 self.minCtrl.SetValue(str(min))
544 self.maxCtrl.SetValue(str(max))
545 finally:
546 ThubanEndBusyCursor()
547
548 def __GetValidatedTypeEntry(self, win, value, type, badValue = None):
549
550 if type == FIELDTYPE_INT:
551 func = int
552 elif type == FIELDTYPE_DOUBLE:
553 func = float
554 elif type == FIELDTYPE_STRING:
555 func = str
556 else:
557 assert False, "Unsupported FIELDTYPE"
558 pass
559
560 if self.__ValidateEntry(win, value, func, badValue):
561 return func(value)
562
563 return None
564
565 def __ValidateEntry(self, win, value, test, badValue = None):
566
567 valid = value != ""
568
569 try:
570 if valid:
571 value = test(value)
572
573 if badValue is not None:
574 valid = value != test(badValue)
575 except ValueError:
576 valid = False
577
578 if valid:
579 win.SetForegroundColour(wxBLACK)
580 else:
581 win.SetForegroundColour(wxRED)
582
583 win.Refresh()
584
585 return valid
586
587 def __CalcStepping(self, min, max, ngroups):
588 if self.fieldType == FIELDTYPE_INT:
589 step = int((max - min + 1) / float(ngroups))
590 else:
591 step = (max - min) / float(ngroups)
592
593 return step
594
595 def __CalcNumGroups(self, min, max, step):
596 n = int((max - min) / step)
597 if n == 0:
598 n = 1
599
600 if self.fieldType == FIELDTYPE_INT and step == 1:
601 n += 1
602
603 return n
604
605
606 ID_UNIQUE_RETRIEVE = 4001
607 ID_UNIQUE_USEALL = 4002
608 ID_UNIQUE_USE = 4003
609 ID_UNIQUE_DONTUSE = 4004
610 ID_UNIQUE_USENONE = 4005
611 ID_UNIQUE_SORTAVAIL = 4006
612 ID_UNIQUE_SORTUSE = 4007
613 ID_UNIQUE_REVAVAIL = 4008
614 ID_UNIQUE_REVUSE = 4009
615
616 class GenUniquePanel(wxPanel):
617
618 def __init__(self, parent, layer, fieldName, fieldType):
619 wxPanel.__init__(self, parent, -1)
620
621 self.parent = parent
622 self.layer = layer
623 self.fieldName = fieldName
624 self.fieldType = fieldType
625
626 topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""),
627 wxVERTICAL)
628
629
630 #bsizer = wxBoxSizer(wxVERTICAL)
631 topSizer.Add(wxButton(self, ID_UNIQUE_RETRIEVE,
632 _("Retrieve From Table")),
633 0, wxALL | wxALIGN_RIGHT, 4)
634
635 EVT_BUTTON(self, ID_UNIQUE_RETRIEVE, self._OnRetrieve)
636
637 #topSizer.Add(bsizer, 0, wxALL, 4)
638
639 sizer = wxBoxSizer(wxHORIZONTAL)
640
641 self.dataList = []
642
643 psizer = wxBoxSizer(wxVERTICAL)
644 self.list_avail = wxListCtrl(self, -1,
645 style=wxLC_REPORT | wxLC_SINGLE_SEL)
646 self.list_avail.InsertColumn(0, "Available")
647 self.list_avail_data = []
648 psizer.Add(self.list_avail, 1, wxGROW, 0)
649
650 bsizer = wxBoxSizer(wxHORIZONTAL)
651 bsizer.Add(wxButton(self, ID_UNIQUE_SORTAVAIL, _("Sort")))
652 EVT_BUTTON(self, ID_UNIQUE_SORTAVAIL, self._OnSortList)
653
654 bsizer.Add(wxButton(self, ID_UNIQUE_REVAVAIL, _("Reverse")))
655 EVT_BUTTON(self, ID_UNIQUE_REVAVAIL, self._OnReverseList)
656
657 psizer.Add(bsizer, 0, wxGROW, 0)
658 sizer.Add(psizer, 1, wxGROW, 0)
659
660
661 bsizer = wxBoxSizer(wxVERTICAL)
662
663 bmp = resource.GetBitmapResource(USEALL_BMP, wxBITMAP_TYPE_XPM)
664 bsizer.Add(wxBitmapButton(self, ID_UNIQUE_USEALL, bmp),
665 0, wxGROW | wxALL, 4)
666 bmp = resource.GetBitmapResource(USE_BMP, wxBITMAP_TYPE_XPM)
667 bsizer.Add(wxBitmapButton(self, ID_UNIQUE_USE, bmp),
668 0, wxGROW | wxALL, 4)
669 bmp = resource.GetBitmapResource(USENOT_BMP, wxBITMAP_TYPE_XPM)
670 bsizer.Add(wxBitmapButton(self, ID_UNIQUE_DONTUSE, bmp),
671 0, wxGROW | wxALL, 4)
672 bmp = resource.GetBitmapResource(USENONE_BMP, wxBITMAP_TYPE_XPM)
673 bsizer.Add(wxBitmapButton(self, ID_UNIQUE_USENONE, bmp),
674 0, wxGROW | wxALL, 4)
675
676 EVT_BUTTON(self, ID_UNIQUE_USEALL, self._OnUseAll)
677 EVT_BUTTON(self, ID_UNIQUE_USE, self._OnUse)
678 EVT_BUTTON(self, ID_UNIQUE_DONTUSE, self._OnDontUse)
679 EVT_BUTTON(self, ID_UNIQUE_USENONE, self._OnUseNone)
680
681 sizer.Add(bsizer, 0, wxALL | wxALIGN_CENTER_VERTICAL, 4)
682
683 psizer = wxBoxSizer(wxVERTICAL)
684 self.list_use = wxListCtrl(self, -1,
685 style=wxLC_REPORT | wxLC_SINGLE_SEL)
686 self.list_use.InsertColumn(0, "Use")
687 self.list_use_data = []
688 psizer.Add(self.list_use, 1, wxGROW, 0)
689
690 bsizer = wxBoxSizer(wxHORIZONTAL)
691 bsizer.Add(wxButton(self, ID_UNIQUE_SORTUSE, _("Sort")))
692 EVT_BUTTON(self, ID_UNIQUE_SORTUSE, self._OnSortList)
693
694 bsizer.Add(wxButton(self, ID_UNIQUE_REVUSE, _("Reverse")))
695 EVT_BUTTON(self, ID_UNIQUE_REVUSE, self._OnReverseList)
696
697 psizer.Add(bsizer, 0, wxGROW, 0)
698
699 sizer.Add(psizer, 1, wxGROW, 0)
700
701
702 topSizer.Add(sizer, 1, wxGROW, 0)
703
704 self.SetSizer(topSizer)
705 self.SetAutoLayout(True)
706 topSizer.SetSizeHints(self)
707
708 width, height = self.list_avail.GetSizeTuple()
709 self.list_avail.SetColumnWidth(0,width)
710 width, height = self.list_use.GetSizeTuple()
711 self.list_use.SetColumnWidth(0,width)
712
713 self.parent.AllowGenerate(False)
714
715 def GetNumGroups(self):
716 return self.list_use.GetItemCount()
717
718 def GetValueList(self):
719 list = []
720 for i in range(self.list_use.GetItemCount()):
721 list.append(self.dataList[self.list_use.GetItemData(i)])
722 return list
723
724 def _OnSortList(self, event):
725 id = event.GetId()
726
727 if id == ID_UNIQUE_SORTUSE:
728 list = self.list_use
729 else:
730 list = self.list_avail
731
732 list.SortItems(lambda i1, i2: cmp(self.dataList[i1],
733 self.dataList[i2]))
734
735 def _OnReverseList(self, event):
736 id = event.GetId()
737
738 if id == ID_UNIQUE_REVUSE:
739 list = self.list_use
740 else:
741 list = self.list_avail
742
743 #
744 # always returning 1 reverses the list
745 #
746 list.SortItems(lambda i1, i2: 1)
747
748 def _OnRetrieve(self, event):
749 self.list_use.DeleteAllItems()
750 self.list_use_data = []
751 self.list_avail.DeleteAllItems()
752 self.list_avail_data = []
753
754 ThubanBeginBusyCursor()
755 try:
756 list = self.layer.ShapeStore().Table().UniqueValues(self.fieldName)
757 index = 0
758 for v in list:
759 self.dataList.append(v)
760 i = self.list_avail.InsertStringItem(index, str(v))
761 self.list_avail.SetItemData(index, i)
762
763 self.list_avail_data.append(v)
764 index += 1
765 finally:
766 ThubanEndBusyCursor()
767
768 def _OnUseAll(self, event):
769 for i in range(self.list_avail.GetItemCount()):
770 self.__MoveListItem(0, self.list_avail, self.list_use)
771
772 def _OnUse(self, event):
773 self.__MoveSelectedItems(self.list_avail, self.list_use)
774
775 def _OnDontUse(self, event):
776 self.__MoveSelectedItems(self.list_use, self.list_avail)
777
778 def _OnUseNone(self, event):
779
780 for i in range(self.list_use.GetItemCount()):
781 self.__MoveListItem(0, self.list_use, self.list_avail)
782
783 def __MoveSelectedItems(self, list_src, list_dest):
784 while True:
785 index = list_src.GetNextItem(-1,
786 wxLIST_NEXT_ALL,
787 wxLIST_STATE_SELECTED)
788
789 if index == -1:
790 break
791
792 self.__MoveListItem(index, list_src, list_dest)
793
794
795 def __MoveListItem(self, index, list_src, list_dest):
796
797 item = list_src.GetItem(index)
798
799 x = list_dest.InsertStringItem(
800 list_dest.GetItemCount(),
801 str(self.dataList[item.GetData()]))
802
803 list_dest.SetItemData(x, item.GetData())
804
805 list_src.DeleteItem(index)
806
807 # def _OnListSize(self, event):
808 # list = event.GetEventObject()
809
810 # list.SetColumnWidth(0, event.GetSize().GetWidth())
811 #
812
813 ID_QUANTILES_RANGE = 4001
814 ID_QUANTILES_RETRIEVE = 4002
815
816 class GenQuantilesPanel(wxPanel):
817
818 def __init__(self, parent, layer, fieldName, fieldType):
819 wxPanel.__init__(self, parent, -1)
820
821 self.parent = parent
822 self.layer = layer
823 self.fieldName = fieldName
824 self.fieldType = fieldType
825
826 topBox = wxStaticBoxSizer(wxStaticBox(self, -1, ""),
827 wxVERTICAL)
828
829 self.text_range = wxTextCtrl(self, ID_QUANTILES_RANGE, "")
830 self.button_retrieve = wxButton(self, ID_QUANTILES_RETRIEVE,
831 _("Retrieve from Table"))
832
833 self.spin_numClasses = wxSpinCtrl(self, -1, style=wxTE_RIGHT)
834 self.spin_numClasses.SetRange(1, sys.maxint)
835 self.spin_numClasses.SetValue(1)
836
837
838 sizer = wxBoxSizer(wxHORIZONTAL)
839 sizer.Add(wxStaticText(self, -1, _("Apply to Range")), 0, wxALL, 4)
840 sizer.Add(self.text_range, 1, wxALL, 4)
841 sizer.Add(self.button_retrieve, 0, wxALL, 4)
842
843 topBox.Add(sizer, 0, wxEXPAND, 0)
844
845 sizer = wxBoxSizer(wxHORIZONTAL)
846 sizer.Add(wxStaticText(self, -1, _("Number of Classes:")), 0, wxALL, 4)
847 sizer.Add(self.spin_numClasses, 1, wxALL, 4)
848
849 topBox.Add(sizer, 0, wxEXPAND, 0)
850
851 self.SetSizer(topBox)
852 self.SetAutoLayout(True)
853 topBox.Fit(self)
854 topBox.SetSizeHints(self)
855
856 EVT_TEXT(self, ID_QUANTILES_RANGE, self.OnRangeText)
857 EVT_BUTTON(self, ID_QUANTILES_RETRIEVE, self.OnRetrieve)
858
859 self.__range = None
860
861 def GetNumGroups(self):
862 return self.spin_numClasses.GetValue()
863
864 def GetRange(self):
865 assert self.__range is not None
866
867 return self.__range
868
869 def GetList(self):
870 _list = []
871 table = self.layer.ShapeStore().Table()
872 if table is not None:
873 ThubanBeginBusyCursor()
874 try:
875 #
876 # FIXME: Replace with a call to table when the method
877 # has been written to get all the values
878 #
879 for i in range(table.NumRows()):
880 _list.append(table.ReadValue(i, self.fieldName))
881 finally:
882 ThubanEndBusyCursor()
883
884 return _list
885
886 def OnRangeText(self, event):
887
888 try:
889 self.__range = Range(self.text_range.GetValue())
890 except ValueError:
891 self.__range = None
892
893 if self.__range is not None:
894 self.text_range.SetForegroundColour(wxBLACK)
895 else:
896 self.text_range.SetForegroundColour(wxRED)
897
898 def OnRetrieve(self, event):
899 table = self.layer.ShapeStore().Table()
900 if table is not None:
901 ThubanBeginBusyCursor()
902 try:
903 min, max = table.ValueRange(self.fieldName)
904 self.text_range.SetValue("[" + str(min) + ";" + str(max) + "]")
905 finally:
906 ThubanEndBusyCursor()
907
908 ID_CUSTOMRAMP_COPYSTART = 4001
909 ID_CUSTOMRAMP_COPYEND = 4002
910 ID_CUSTOMRAMP_EDITSTART = 4003
911 ID_CUSTOMRAMP_EDITEND = 4004
912 ID_CUSTOMRAMP_SPROP = 4005
913 ID_CUSTOMRAMP_EPROP = 4006
914
915 class CustomRampPanel(wxPanel):
916
917 def __init__(self, parent, shapeType):
918 wxPanel.__init__(self, parent, -1)
919
920 topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""), wxHORIZONTAL)
921
922 bsizer = wxBoxSizer(wxVERTICAL)
923 bsizer.Add(wxStaticText(self, -1, _("Start:")), 0, wxALL | wxCENTER, 4)
924 self.startPropCtrl = classifier.ClassGroupPropertiesCtrl(
925 self, ID_CUSTOMRAMP_SPROP,
926 ClassGroupProperties(), shapeType,
927 style=wxSIMPLE_BORDER, size=(40, 20))
928 bsizer.Add(self.startPropCtrl, 1, wxGROW | wxALL | wxCENTER, 4)
929 bsizer.Add(wxButton(self, ID_CUSTOMRAMP_EDITSTART, _("Change")),
930 0, wxGROW | wxALL | wxCENTER, 4)
931
932 topSizer.Add(bsizer,
933 1, wxALL \
934 | wxSHAPED \
935 | wxALIGN_CENTER_HORIZONTAL \
936 | wxALIGN_CENTER_VERTICAL, \
937 4)
938
939 bmp = resource.GetBitmapResource(USE_BMP, wxBITMAP_TYPE_XPM)
940 bsizer = wxBoxSizer(wxVERTICAL)
941 bsizer.Add(wxBitmapButton(self, ID_CUSTOMRAMP_COPYSTART, bmp),
942 0, wxGROW | wxALL, 4)
943 bmp = resource.GetBitmapResource(USENOT_BMP, wxBITMAP_TYPE_XPM)
944 bsizer.Add(wxBitmapButton(self, ID_CUSTOMRAMP_COPYEND, bmp),
945 0, wxGROW | wxALL, 4)
946
947 topSizer.Add(bsizer,
948 0, wxALL \
949 | wxALIGN_CENTER_HORIZONTAL \
950 | wxALIGN_CENTER_VERTICAL,
951 4)
952
953 bsizer = wxBoxSizer(wxVERTICAL)
954 bsizer.Add(wxStaticText(self, -1, _("End:")), 0, wxALL | wxCENTER, 4)
955 self.endPropCtrl = classifier.ClassGroupPropertiesCtrl(
956 self, ID_CUSTOMRAMP_EPROP,
957 ClassGroupProperties(), shapeType,
958 style=wxSIMPLE_BORDER, size=(40, 20))
959 bsizer.Add(self.endPropCtrl, 1, wxGROW | wxALL | wxCENTER, 4)
960 bsizer.Add(wxButton(self, ID_CUSTOMRAMP_EDITEND, _("Change")),
961 0, wxGROW | wxALL | wxCENTER, 4)
962
963 topSizer.Add(bsizer,
964 1, wxALL \
965 | wxSHAPED \
966 | wxALIGN_RIGHT \
967 | wxALIGN_CENTER_HORIZONTAL \
968 | wxALIGN_CENTER_VERTICAL,
969 4)
970
971 EVT_BUTTON(self, ID_CUSTOMRAMP_COPYSTART, self._OnCopyStart)
972 EVT_BUTTON(self, ID_CUSTOMRAMP_COPYEND, self._OnCopyEnd)
973 EVT_BUTTON(self, ID_CUSTOMRAMP_EDITSTART, self._OnEditStart)
974 EVT_BUTTON(self, ID_CUSTOMRAMP_EDITEND, self._OnEditEnd)
975
976 self.SetSizer(topSizer)
977 self.SetAutoLayout(True)
978 topSizer.SetSizeHints(self)
979
980 def GetRamp(self):
981 return CustomRamp(self.startPropCtrl.GetProperties(),
982 self.endPropCtrl.GetProperties())
983
984 def _OnCopyStart(self, event):
985 self.endPropCtrl.SetProperties(self.startPropCtrl.GetProperties())
986
987 def _OnCopyEnd(self, event):
988 self.startPropCtrl.SetProperties(self.endPropCtrl.GetProperties())
989
990 def _OnEditStart(self, event):
991 self.startPropCtrl.DoEdit()
992
993 def _OnEditEnd(self, event):
994 self.endPropCtrl.DoEdit()
995
996

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26