/[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 1341 - (show annotations)
Tue Jul 1 16:10:42 2003 UTC (21 years, 8 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/classgen.py
File MIME type: text/x-python
File size: 30937 byte(s)
Fixes RTbug #1972.
(ClassGenDialog.__init__): Color ramps are now instances
        already so we don't need to create any new objects.
(ClassGenDialog.OnOK): Check for numGroups is no longer
        necessary because we never use it.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26