/[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 649 - (show annotations)
Fri Apr 11 14:27:12 2003 UTC (21 years, 11 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/classgen.py
File MIME type: text/x-python
File size: 33748 byte(s)
(GenUniquePanel.__init__): Reordered buttons,
        added images to the move buttons, added 'reverse' button.
(CustomRampPanel.__init__): Added images to the move buttons.
(GreyRamp): New. Generates a ramp from white to black.
(HotToColdRamp): New. Generates a ramp from cold to hot colors.

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 from Thuban import _
9
10 from wxPython.wx import *
11
12 from Thuban.Model.classification import Classification, ClassGroupRange, \
13 ClassGroupSingleton, ClassGroupProperties
14
15 from Thuban.Model.table import Table, FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
16 FIELDTYPE_STRING
17
18 from Thuban.Model.color import Color
19
20 import classifier
21
22 import resource
23
24 from Thuban.common import Str2Num
25
26 ID_CLASSGEN_GEN = 4001
27 ID_CLASSGEN_CLOSE = 4002
28 ID_CLASSGEN_GENCOMBO = 4007
29 ID_CLASSGEN_PROPCOMBO = 4008
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
39 PROPCOMBOSTR_CUSTOM = _("Custom Ramp")
40 PROPCOMBOSTR_GREY = _("Grey Ramp")
41 PROPCOMBOSTR_RED = _("Red Ramp")
42 PROPCOMBOSTR_GREEN = _("Green Ramp")
43 PROPCOMBOSTR_BLUE = _("Blue Ramp")
44 PROPCOMBOSTR_HOT2COLD = _("Hot-to-Cold Ramp")
45
46 class ClassGenDialog(wxDialog):
47
48 def __init__(self, parent, layer, fieldName):
49 """Inialize the class generating dialog.
50
51 parent -- this must be an instance of the Classifier class
52 """
53
54 wxDialog.__init__(self, parent, -1, _("Generate Classification"),
55 style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
56
57 self.parent = parent
58 self.clazz = None
59
60 self.type, name, width, prec = layer.table.field_info_by_name(fieldName)
61
62 #############
63 # we need to create genButton first because when we create the
64 # panels they will call AllowGenerate() which uses genButton.
65 #
66 buttonSizer = wxBoxSizer(wxHORIZONTAL)
67 self.genButton = wxButton(self, ID_CLASSGEN_GEN, _("Generate"))
68
69 buttonSizer.Add(self.genButton, 0, wxALL, 4)
70 buttonSizer.Add(60, 20, 0, wxALL, 4)
71 buttonSizer.Add(wxButton(self, ID_CLASSGEN_CLOSE, _("Close")),
72 0, wxALL, 4)
73
74 #############
75
76 sizer = wxBoxSizer(wxVERTICAL)
77
78 sizer.Add(wxStaticText(self, -1, _("Field: %s") % fieldName),
79 0, wxALL, 4)
80 sizer.Add(wxStaticText(
81 self, -1,
82 _("Data Type: %s") % classifier.Classifier.type2string[self.type]),
83 0, wxALL, 4)
84
85 psizer = wxBoxSizer(wxHORIZONTAL)
86 psizer.Add(wxStaticText(self, -1, _("Generate:")),
87 0, wxALIGN_CENTER_VERTICAL, 0)
88
89 self.genCombo = wxComboBox(self,
90 ID_CLASSGEN_GENCOMBO,
91 "", style = wxCB_READONLY)
92 psizer.Add(self.genCombo, 1, wxALL | wxGROW, 4)
93 EVT_COMBOBOX(self, ID_CLASSGEN_GENCOMBO, self._OnGenTypeSelect)
94
95 sizer.Add(psizer, 0, wxALL | wxGROW, 4)
96
97 #############
98
99 self.genPanel = None
100
101 panel = GenUniquePanel(self, layer, fieldName, self.type)
102 self.genCombo.Append(GENCOMBOSTR_UNIQUE, panel)
103 sizer.Add(panel, 1, wxGROW | wxALL, 4)
104
105 self.genPanel = panel
106
107 if self.type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):
108 panel = GenUniformPanel(self, layer, fieldName, self.type)
109 self.genCombo.Append(GENCOMBOSTR_UNIFORM, panel)
110 sizer.Add(panel, 0, wxGROW | wxALL, 4)
111 sizer.Show(panel, False)
112
113 #############
114
115 psizer = wxBoxSizer(wxHORIZONTAL)
116 psizer.Add(wxStaticText(self, -1, _("Color Schemes:")),
117 0, wxALIGN_CENTER_VERTICAL, 0)
118
119 self.propCombo = wxComboBox(self,
120 ID_CLASSGEN_PROPCOMBO,
121 "", style = wxCB_READONLY)
122 psizer.Add(self.propCombo, 1, wxALL | wxGROW, 4)
123 EVT_COMBOBOX(self, ID_CLASSGEN_PROPCOMBO, self._OnPropTypeSelect)
124 sizer.Add(psizer, 0, wxALL | wxGROW, 4)
125
126 #############
127
128 self.propPanel = None
129 panel = CustomRampPanel(self, layer.ShapeType())
130 sizer.Add(panel, 1, wxALL | wxGROW, 4)
131 sizer.Show(panel, False)
132
133 self.propCombo.Append(PROPCOMBOSTR_GREY, GreyRamp())
134 self.propCombo.Append(PROPCOMBOSTR_RED, RedRamp())
135 self.propCombo.Append(PROPCOMBOSTR_GREEN, GreenRamp())
136 self.propCombo.Append(PROPCOMBOSTR_BLUE, BlueRamp())
137 self.propCombo.Append(PROPCOMBOSTR_HOT2COLD, HotToColdRamp())
138 self.propCombo.Append(PROPCOMBOSTR_CUSTOM, panel)
139
140
141
142 #############
143
144 sizer.Add(buttonSizer, 0,
145 wxALL | wxALIGN_BOTTOM | wxALIGN_CENTER_HORIZONTAL, 4)
146
147
148 self.SetSizer(sizer)
149 self.SetAutoLayout(True)
150 sizer.SetSizeHints(self)
151
152 self.sizer = sizer
153
154 EVT_BUTTON(self, ID_CLASSGEN_GEN, self._OnGenerate)
155 EVT_BUTTON(self, ID_CLASSGEN_CLOSE, self._OnCloseBtn)
156
157 def GetClassification(self):
158 return self.clazz
159
160 def AllowGenerate(self, on):
161 pass #self.genButton.Enable(on)
162
163 def _OnGenerate(self, event):
164
165 index = self.genCombo.GetSelection()
166
167 genSel = self.genCombo.GetString(index)
168 genPanel = self.genCombo.GetClientData(index)
169
170 propPanel = self.propPanel
171
172 if genSel in (GENCOMBOSTR_UNIFORM, GENCOMBOSTR_UNIQUE):
173 numGroups = genPanel.GetNumGroups()
174
175 index = self.propCombo.GetSelection()
176
177 propSel = self.propCombo.GetString(index)
178 propPanel = self.propCombo.GetClientData(index)
179
180 ramp = propPanel.GetRamp()
181
182 if genSel == GENCOMBOSTR_UNIFORM:
183
184 min = genPanel.GetMin()
185 max = genPanel.GetMax()
186
187 if min is not None \
188 and max is not None \
189 and numGroups is not None:
190
191 self.clazz = ClassGenerator().GenUnifromDistribution(
192 min, max, numGroups, ramp,
193 self.type == FIELDTYPE_INT)
194
195 self.parent._SetClassification(self.clazz)
196
197 elif genSel == GENCOMBOSTR_UNIQUE:
198
199 list = genPanel.GetValueList()
200
201 if len(list) > 0 \
202 and numGroups is not None:
203
204 self.clazz = ClassGenerator().GenSingletonsFromList(
205 list, numGroups, ramp)
206
207 self.parent._SetClassification(self.clazz)
208
209 def _OnCloseBtn(self, event):
210 self.Close()
211
212 def _OnGenTypeSelect(self, event):
213
214 combo = event.GetEventObject()
215
216 selIndex = combo.GetSelection()
217
218 if self.genPanel is not None:
219 self.sizer.Show(self.genPanel, False)
220
221 self.genPanel = combo.GetClientData(selIndex)
222 if self.genPanel is not None:
223 self.sizer.Show(self.genPanel, True)
224
225 self.sizer.SetSizeHints(self)
226 self.sizer.Layout()
227
228 def _OnPropTypeSelect(self, event):
229 combo = event.GetEventObject()
230
231 selIndex = combo.GetSelection()
232 sel = combo.GetString(selIndex)
233
234 if isinstance(self.propPanel, wxPanel):
235 self.sizer.Show(self.propPanel, False)
236
237 self.propPanel = combo.GetClientData(selIndex)
238
239 if isinstance(self.propPanel, wxPanel):
240 self.sizer.Show(self.propPanel, True)
241
242 self.sizer.SetSizeHints(self)
243 self.sizer.Layout()
244
245
246 ID_UNIFORM_MIN = 4001
247 ID_UNIFORM_MAX = 4002
248 ID_UNIFORM_NGROUPS = 4003
249 ID_UNIFORM_STEP = 4004
250 ID_UNIFORM_RETRIEVE = 4005
251
252 class GenUniformPanel(wxPanel):
253
254 def __init__(self, parent, layer, fieldName, fieldType):
255 wxPanel.__init__(self, parent, -1)
256
257 self.parent = parent
258 self.layer = layer
259 self.fieldName = fieldName
260 self.fieldType = fieldType
261
262 topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""),
263 wxVERTICAL)
264
265 #############
266
267 sizer = wxBoxSizer(wxHORIZONTAL)
268
269 sizer.Add(wxStaticText(self, -1, _("Min:")), 0, wxALL, 4)
270 self.minCtrl = wxTextCtrl(self, ID_UNIFORM_MIN, style=wxTE_RIGHT)
271 sizer.Add(self.minCtrl, 1, wxALL, 4)
272 EVT_TEXT(self, ID_UNIFORM_MIN, self._OnRangeChanged)
273
274 sizer.Add(wxStaticText(self, -1, _("Max:")), 0, wxALL, 4)
275 self.maxCtrl = wxTextCtrl(self, ID_UNIFORM_MAX, style=wxTE_RIGHT)
276 sizer.Add(self.maxCtrl, 1, wxALL, 4)
277 EVT_TEXT(self, ID_UNIFORM_MAX, self._OnRangeChanged)
278
279 sizer.Add(wxButton(self, ID_UNIFORM_RETRIEVE, _("Retrieve From Table")),
280 0, wxALL, 4)
281 EVT_BUTTON(self, ID_UNIFORM_RETRIEVE, self._OnRetrieve)
282
283 topSizer.Add(sizer, 1, wxGROW, 0)
284
285 #############
286
287 sizer = wxBoxSizer(wxHORIZONTAL)
288
289 sizer.Add(wxStaticText(self, -1, _("Number of Groups:")), 0, wxALL, 4)
290 self.numGroupsCtrl = wxSpinCtrl(self, ID_UNIFORM_NGROUPS, style=wxTE_RIGHT)
291 EVT_TEXT(self, ID_UNIFORM_NGROUPS, self._OnNumGroupsChanged)
292 EVT_SPINCTRL(self, ID_UNIFORM_NGROUPS, self._OnNumGroupsChanged)
293 sizer.Add(self.numGroupsCtrl, 1, wxALL, 4)
294
295 sizer.Add(wxStaticText(self, -1, _("Stepping:")), 0, wxALL, 4)
296 self.stepCtrl = wxTextCtrl(self, ID_UNIFORM_STEP, style=wxTE_RIGHT)
297 EVT_TEXT(self, ID_UNIFORM_STEP, self._OnSteppingChanged)
298 sizer.Add(self.stepCtrl , 1, wxALL, 4)
299
300 topSizer.Add(sizer, 1, wxGROW, 0)
301
302 #############
303
304 self.SetSizer(topSizer)
305 self.SetAutoLayout(True)
306 topSizer.SetSizeHints(self)
307
308 self.numGroupsChanging = False
309 self.steppingChanging = False
310
311 self.numGroupsCtrl.SetRange(1, 100)
312
313 self.numGroupsCtrl.SetValue(1)
314 self.stepCtrl.SetValue("1")
315 self.maxCtrl.SetValue("0")
316 self.minCtrl.SetValue("0")
317 self.minCtrl.SetFocus()
318
319 def GetNumGroups(self):
320 value = self.numGroupsCtrl.GetValue()
321 return self.__GetValidatedTypeEntry(self.numGroupsCtrl,
322 value,
323 FIELDTYPE_INT,
324 None)
325
326 def GetStepping(self):
327 step = self.stepCtrl.GetValue()
328 return self.__GetValidatedTypeEntry(self.stepCtrl,
329 step,
330 self.fieldType,
331 0)
332
333 def GetMin(self):
334 min = self.minCtrl.GetValue()
335 max = self.maxCtrl.GetValue()
336 return self.__GetValidatedTypeEntry(self.minCtrl,
337 min,
338 self.fieldType,
339 max)
340
341 def GetMax(self):
342 min = self.minCtrl.GetValue()
343 max = self.maxCtrl.GetValue()
344 return self.__GetValidatedTypeEntry(self.maxCtrl,
345 max,
346 self.fieldType,
347 min)
348
349 def _OnRangeChanged(self, event):
350
351 hasFocus = wxWindow_FindFocus() == event.GetEventObject()
352 min = self.GetMin()
353 max = self.GetMax()
354
355 on = min is not None \
356 and max is not None
357
358 self.numGroupsCtrl.Enable(on)
359 self.stepCtrl.Enable(on)
360
361 if on:
362 self.numGroupsCtrl.SetRange(1, abs(max - min) / 0.001)
363
364 ngroups = self.GetNumGroups()
365
366 if ngroups is not None \
367 and min is not None \
368 and max is not None \
369 and ngroups != 0:
370
371 #self.stepCtrl.SetValue(str((max - min) / ngroups))
372 self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
373 #self.numGroupsCtrl.SetValue(ngroups)
374
375 self.parent.AllowGenerate(self.GetStepping() is not None)
376 else:
377 self.parent.AllowGenerate(False)
378
379
380 if hasFocus:
381 event.GetEventObject().SetFocus()
382
383 def _OnNumGroupsChanged(self, event):
384 if self.steppingChanging:
385 self.steppingChanging = False
386 return
387
388
389 obj = event.GetEventObject()
390 ngroups = self.GetNumGroups()
391 min = self.GetMin()
392 max = self.GetMax()
393
394 if ngroups >= self.numGroupsCtrl.GetMax():
395 self.numGroupsCtrl.SetRange(1, ngroups + 1)
396
397 if ngroups is not None \
398 and min is not None \
399 and max is not None \
400 and ngroups != 0:
401
402 #
403 # changing the value in the stepCtrl sends an event
404 # that the control is changing, at which point
405 # we try to update the numGroupsCtrl. This causes
406 # an infinite recursion. This flag and the one
407 # called steppingChanging tries to prevent the recursion.
408 #
409 self.numGroupsChanging = True
410
411 self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
412
413 self.parent.AllowGenerate(self.GetStepping() is not None)
414 else:
415 self.parent.AllowGenerate(False)
416
417
418 def _OnSteppingChanged(self, event):
419 if self.numGroupsChanging:
420 self.numGroupsChanging = False
421 return
422
423 step = self.GetStepping()
424 min = self.GetMin()
425 max = self.GetMax()
426
427 if step is not None \
428 and min is not None \
429 and max is not None \
430 and step != 0:
431
432 #
433 # see note in _OnNumGroupsChanged
434 #
435 self.steppingChanging = True
436 self.numGroupsCtrl.SetValue(self.__CalcNumGroups(min, max, step))
437
438 self.parent.AllowGenerate(self.GetNumGroups() is not None)
439 else:
440 self.parent.AllowGenerate(False)
441
442 def _OnRetrieve(self, event):
443
444 if self.layer.table is not None:
445 range = self.layer.table.field_range(self.fieldName)
446 self.minCtrl.SetValue(str(range[0][0]))
447 self.maxCtrl.SetValue(str(range[1][0]))
448
449 def __GetValidatedTypeEntry(self, win, value, type, badValue = None):
450
451 if type == FIELDTYPE_INT:
452 func = int
453 elif type == FIELDTYPE_DOUBLE:
454 func = float
455 elif type == FIELDTYPE_STRING:
456 func = str
457 else:
458 assert False, "Unsupported FIELDTYPE"
459 pass
460
461 if self.__ValidateEntry(win, value, func, badValue):
462 return func(value)
463
464 return None
465
466 def __ValidateEntry(self, win, value, test, badValue = None):
467
468 valid = value != ""
469
470 try:
471 if valid:
472 value = test(value)
473
474 if badValue is not None:
475 valid = value != test(badValue)
476 except ValueError:
477 valid = False
478
479 if valid:
480 win.SetForegroundColour(wxBLACK)
481 else:
482 win.SetForegroundColour(wxRED)
483
484 win.Refresh()
485
486 return valid
487
488 def __CalcStepping(self, min, max, ngroups):
489 step = Str2Num(str((max - min) / float(ngroups)))
490 if self.fieldType == FIELDTYPE_INT:
491 step = int(step)
492
493 return step
494
495 def __CalcNumGroups(self, min, max, step):
496 n = int((max - min) / step)
497 if n == 0:
498 n = 1
499
500 if self.fieldType == FIELDTYPE_INT and step == 1:
501 n += 1
502
503 return n
504
505
506 ID_UNIQUE_RETRIEVE = 4001
507 ID_UNIQUE_USEALL = 4002
508 ID_UNIQUE_USE = 4003
509 ID_UNIQUE_DONTUSE = 4004
510 ID_UNIQUE_USENONE = 4005
511 ID_UNIQUE_SORTAVAIL = 4006
512 ID_UNIQUE_SORTUSE = 4007
513 ID_UNIQUE_REVAVAIL = 4008
514 ID_UNIQUE_REVUSE = 4009
515
516 class GenUniquePanel(wxPanel):
517
518 def __init__(self, parent, layer, fieldName, fieldType):
519 wxPanel.__init__(self, parent, -1)
520
521 self.parent = parent
522 self.layer = layer
523 self.fieldName = fieldName
524 self.fieldType = fieldType
525
526 topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""),
527 wxVERTICAL)
528
529
530 #bsizer = wxBoxSizer(wxVERTICAL)
531 topSizer.Add(wxButton(self, ID_UNIQUE_RETRIEVE,
532 _("Retrieve From Table")),
533 0, wxALL | wxALIGN_RIGHT, 4)
534
535 EVT_BUTTON(self, ID_UNIQUE_RETRIEVE, self._OnRetrieve)
536
537 #topSizer.Add(bsizer, 0, wxALL, 4)
538
539 sizer = wxBoxSizer(wxHORIZONTAL)
540
541 self.dataList = []
542
543 psizer = wxBoxSizer(wxVERTICAL)
544 self.list_avail = wxListCtrl(self, -1,
545 style=wxLC_REPORT | wxLC_SINGLE_SEL)
546 self.list_avail.InsertColumn(0, "Available")
547 self.list_avail_data = []
548 psizer.Add(self.list_avail, 1, wxGROW, 0)
549
550 bsizer = wxBoxSizer(wxHORIZONTAL)
551 bsizer.Add(wxButton(self, ID_UNIQUE_SORTAVAIL, _("Sort")))
552 EVT_BUTTON(self, ID_UNIQUE_SORTAVAIL, self._OnSortList)
553
554 bsizer.Add(wxButton(self, ID_UNIQUE_REVAVAIL, _("Reverse")))
555 EVT_BUTTON(self, ID_UNIQUE_REVAVAIL, self._OnReverseList)
556
557 psizer.Add(bsizer, 0, wxGROW, 0)
558 sizer.Add(psizer, 1, wxGROW, 0)
559
560
561 bsizer = wxBoxSizer(wxVERTICAL)
562
563 bmp = resource.GetBitmapResource(USEALL_BMP, wxBITMAP_TYPE_XPM)
564 bsizer.Add(wxBitmapButton(self, ID_UNIQUE_USEALL, bmp),
565 0, wxGROW | wxALL, 4)
566 bmp = resource.GetBitmapResource(USE_BMP, wxBITMAP_TYPE_XPM)
567 bsizer.Add(wxBitmapButton(self, ID_UNIQUE_USE, bmp),
568 0, wxGROW | wxALL, 4)
569 bmp = resource.GetBitmapResource(USENOT_BMP, wxBITMAP_TYPE_XPM)
570 bsizer.Add(wxBitmapButton(self, ID_UNIQUE_DONTUSE, bmp),
571 0, wxGROW | wxALL, 4)
572 bmp = resource.GetBitmapResource(USENONE_BMP, wxBITMAP_TYPE_XPM)
573 bsizer.Add(wxBitmapButton(self, ID_UNIQUE_USENONE, bmp),
574 0, wxGROW | wxALL, 4)
575
576 EVT_BUTTON(self, ID_UNIQUE_USEALL, self._OnUseAll)
577 EVT_BUTTON(self, ID_UNIQUE_USE, self._OnUse)
578 EVT_BUTTON(self, ID_UNIQUE_DONTUSE, self._OnDontUse)
579 EVT_BUTTON(self, ID_UNIQUE_USENONE, self._OnUseNone)
580
581 sizer.Add(bsizer, 0, wxALL | wxALIGN_CENTER_VERTICAL, 4)
582
583 psizer = wxBoxSizer(wxVERTICAL)
584 self.list_use = wxListCtrl(self, -1,
585 style=wxLC_REPORT | wxLC_SINGLE_SEL)
586 self.list_use.InsertColumn(0, "Use")
587 self.list_use_data = []
588 psizer.Add(self.list_use, 1, wxGROW, 0)
589
590 bsizer = wxBoxSizer(wxHORIZONTAL)
591 bsizer.Add(wxButton(self, ID_UNIQUE_SORTUSE, _("Sort")))
592 EVT_BUTTON(self, ID_UNIQUE_SORTUSE, self._OnSortList)
593
594 bsizer.Add(wxButton(self, ID_UNIQUE_REVUSE, _("Reverse")))
595 EVT_BUTTON(self, ID_UNIQUE_REVUSE, self._OnReverseList)
596
597 psizer.Add(bsizer, 0, wxGROW, 0)
598
599 sizer.Add(psizer, 1, wxGROW, 0)
600
601
602 topSizer.Add(sizer, 1, wxGROW, 0)
603
604 self.SetSizer(topSizer)
605 self.SetAutoLayout(True)
606 topSizer.SetSizeHints(self)
607
608 self.parent.AllowGenerate(False)
609
610 self.mylist = ["Hallo", "Welt!", "Wie", "geht", "es", "dir", "?"]
611
612 def GetNumGroups(self):
613 return self.list_use.GetItemCount()
614
615 def GetValueList(self):
616 list = []
617 for i in range(self.list_use.GetItemCount()):
618 list.append(self.dataList[self.list_use.GetItemData(i)])
619 return list
620
621 def _OnSortList(self, event):
622 id = event.GetId()
623
624 if id == ID_UNIQUE_SORTUSE:
625 list = self.list_use
626 else:
627 list = self.list_avail
628
629 list.SortItems(lambda i1, i2: cmp(self.dataList[i1],
630 self.dataList[i2]))
631
632 def _OnReverseList(self, event):
633 id = event.GetId()
634
635 if id == ID_UNIQUE_REVUSE:
636 list = self.list_use
637 else:
638 list = self.list_avail
639
640 #
641 # always returning 1 reverses the list
642 #
643 list.SortItems(lambda i1, i2: 1)
644
645 def _OnRetrieve(self, event):
646 self.list_use.DeleteAllItems()
647 self.list_use_data = []
648 self.list_avail.DeleteAllItems()
649 self.list_avail_data = []
650
651 list = self.layer.table.GetUniqueValues(self.fieldName)
652 index = 0
653 for v in list:
654 self.dataList.append(v)
655 i = self.list_avail.InsertStringItem(index, str(v))
656 self.list_avail.SetItemData(index, i)
657
658 self.list_avail_data.append(v)
659 index += 1
660
661 def _OnUseAll(self, event):
662 for i in range(self.list_avail.GetItemCount()):
663 self.__MoveListItem(0, self.list_avail, self.list_use)
664
665 def _OnUse(self, event):
666 self.__MoveSelectedItems(self.list_avail, self.list_use)
667
668 def _OnDontUse(self, event):
669 self.__MoveSelectedItems(self.list_use, self.list_avail)
670
671 def _OnUseNone(self, event):
672
673 for i in range(self.list_use.GetItemCount()):
674 self.__MoveListItem(0, self.list_use, self.list_avail)
675
676 def __MoveSelectedItems(self, list_src, list_dest):
677 while True:
678 index = list_src.GetNextItem(-1,
679 wxLIST_NEXT_ALL,
680 wxLIST_STATE_SELECTED)
681
682 if index == -1:
683 break
684
685 self.__MoveListItem(index, list_src, list_dest)
686
687
688 def __MoveListItem(self, index, list_src, list_dest):
689
690 item = list_src.GetItem(index)
691
692 x = list_dest.InsertStringItem(
693 list_dest.GetItemCount(),
694 str(self.dataList[item.GetData()]))
695
696 list_dest.SetItemData(x, item.GetData())
697
698 list_src.DeleteItem(index)
699
700 # def _OnListSize(self, event):
701 # list = event.GetEventObject()
702
703 # list.SetColumnWidth(0, event.GetSize().GetWidth())
704 #
705
706 ID_CUSTOMRAMP_COPYSTART = 4001
707 ID_CUSTOMRAMP_COPYEND = 4002
708 ID_CUSTOMRAMP_EDITSTART = 4003
709 ID_CUSTOMRAMP_EDITEND = 4004
710 ID_CUSTOMRAMP_SPROP = 4005
711 ID_CUSTOMRAMP_EPROP = 4006
712
713 class CustomRampPanel(wxPanel):
714
715 def __init__(self, parent, shapeType):
716 wxPanel.__init__(self, parent, -1)
717
718 topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""), wxHORIZONTAL)
719
720 bsizer = wxBoxSizer(wxVERTICAL)
721 bsizer.Add(wxStaticText(self, -1, _("Start:")), 0, wxALL | wxCENTER, 4)
722 self.startPropCtrl = classifier.ClassGroupPropertiesCtrl(
723 self, ID_CUSTOMRAMP_SPROP,
724 ClassGroupProperties(), shapeType,
725 style=wxSIMPLE_BORDER, size=(40, 20))
726 bsizer.Add(self.startPropCtrl, 1, wxGROW | wxALL | wxCENTER, 4)
727 bsizer.Add(wxButton(self, ID_CUSTOMRAMP_EDITSTART, _("Change")),
728 0, wxGROW | wxALL | wxCENTER, 4)
729
730 topSizer.Add(bsizer,
731 1, wxALL \
732 | wxSHAPED \
733 | wxALIGN_CENTER_HORIZONTAL \
734 | wxALIGN_CENTER_VERTICAL, \
735 4)
736
737 bmp = resource.GetBitmapResource(USE_BMP, wxBITMAP_TYPE_XPM)
738 bsizer = wxBoxSizer(wxVERTICAL)
739 bsizer.Add(wxBitmapButton(self, ID_CUSTOMRAMP_COPYSTART, bmp),
740 0, wxGROW | wxALL, 4)
741 bmp = resource.GetBitmapResource(USENOT_BMP, wxBITMAP_TYPE_XPM)
742 bsizer.Add(wxBitmapButton(self, ID_CUSTOMRAMP_COPYEND, bmp),
743 0, wxGROW | wxALL, 4)
744
745 topSizer.Add(bsizer,
746 0, wxALL \
747 | wxALIGN_CENTER_HORIZONTAL \
748 | wxALIGN_CENTER_VERTICAL,
749 4)
750
751 bsizer = wxBoxSizer(wxVERTICAL)
752 bsizer.Add(wxStaticText(self, -1, _("End:")), 0, wxALL | wxCENTER, 4)
753 self.endPropCtrl = classifier.ClassGroupPropertiesCtrl(
754 self, ID_CUSTOMRAMP_EPROP,
755 ClassGroupProperties(), shapeType,
756 style=wxSIMPLE_BORDER, size=(40, 20))
757 bsizer.Add(self.endPropCtrl, 1, wxGROW | wxALL | wxCENTER, 4)
758 bsizer.Add(wxButton(self, ID_CUSTOMRAMP_EDITEND, _("Change")),
759 0, wxGROW | wxALL | wxCENTER, 4)
760
761 topSizer.Add(bsizer,
762 1, wxALL \
763 | wxSHAPED \
764 | wxALIGN_RIGHT \
765 | wxALIGN_CENTER_HORIZONTAL \
766 | wxALIGN_CENTER_VERTICAL,
767 4)
768
769 EVT_BUTTON(self, ID_CUSTOMRAMP_COPYSTART, self._OnCopyStart)
770 EVT_BUTTON(self, ID_CUSTOMRAMP_COPYEND, self._OnCopyEnd)
771 EVT_BUTTON(self, ID_CUSTOMRAMP_EDITSTART, self._OnEditStart)
772 EVT_BUTTON(self, ID_CUSTOMRAMP_EDITEND, self._OnEditEnd)
773
774 self.SetSizer(topSizer)
775 self.SetAutoLayout(True)
776 topSizer.SetSizeHints(self)
777
778 def GetRamp(self):
779 return CustomRamp(self.startPropCtrl.GetProperties(),
780 self.endPropCtrl.GetProperties())
781
782 def _OnCopyStart(self, event):
783 self.endPropCtrl.SetProperties(self.startPropCtrl.GetProperties())
784
785 def _OnCopyEnd(self, event):
786 self.startPropCtrl.SetProperties(self.endPropCtrl.GetProperties())
787
788 def _OnEditStart(self, event):
789 self.startPropCtrl.DoEdit()
790
791 def _OnEditEnd(self, event):
792 self.endPropCtrl.DoEdit()
793
794 class ClassGenerator:
795
796 def GenSingletonsFromList(self, list, numGroups, ramp):
797 """Generate a new classification consisting solely of singletons.
798
799 The resulting classification will consist of at most 'numGroups'
800 groups whose group properties ramp between 'prop1' and 'prop2'. There
801 could be fewer groups if 'list' contains fewer that 'numGroups' items.
802
803 list -- any object that implements the iterator interface
804
805 numGroups -- how many groups to generate. This can not be
806 determined while the classification is being
807 generated because the stepping values must
808 be precalculated to ramp between prop1 and prop2.
809
810 prop1 -- initial group property values
811
812 prop2 -- final group property values
813 """
814
815 clazz = Classification()
816 if numGroups == 0: return clazz
817
818 ramp.SetNumGroups(numGroups)
819
820 for value, prop in zip(list, ramp):
821 clazz.AppendGroup(ClassGroupSingleton(value, prop))
822
823 return clazz
824
825 def GenSingletons(self, min, max, numGroups, ramp):
826
827 clazz = Classification()
828
829 #step = int((max - min) / float(numGroups))
830 step = int(Str2Num(str((max - min + 1) / float(numGroups))))
831
832 if numGroups > 0:
833 cur_value = min
834
835 ramp.SetNumGroups(numGroups)
836
837 for prop in ramp:
838 clazz.AppendGroup(
839 ClassGroupSingleton(
840 Str2Num(str(cur_value)),
841 prop))
842 cur_value += step
843
844 return clazz
845
846 def GenUnifromDistribution(self, min, max, numGroups,
847 ramp, intStep = False):
848 """Generate a classification with numGroups range groups
849 each with the same interval.
850
851 intStep -- force the calculated stepping to an integer.
852 Useful if the values are integers but the
853 number of groups specified doesn't evenly
854 divide (max - min).
855 """
856
857 clazz = Classification()
858 if numGroups == 0: return clazz
859
860 ramp.SetNumGroups(numGroups)
861
862 step = Str2Num(str((max - min) / float(numGroups)))
863
864 if intStep:
865 step = int(step)
866
867 cur_min = min
868 cur_max = cur_min + step
869
870 i = 0
871 for prop in ramp:
872
873 if i == (numGroups - 1):
874 cur_max = max
875
876 # this check guards against rounding issues
877 if cur_min != cur_max:
878 clazz.AppendGroup(
879 ClassGroupRange(
880 Str2Num(str(cur_min)),
881 Str2Num(str(cur_max)),
882 prop))
883
884 cur_min = cur_max
885 cur_max += step
886 i += 1
887
888 return clazz
889
890 CLR = 0
891 STEP = 1
892 class CustomRamp:
893
894 def __init__(self, prop1, prop2):
895 self.prop1 = prop1
896 self.prop2 = prop2
897
898 self.count = 0
899
900 def __iter__(self):
901 return self
902
903 def GetRamp(self):
904 return self
905
906 def SetNumGroups(self, num):
907
908 if num <= 0:
909 return False
910
911 self.count = int(num)
912 num = float(num)
913
914 prop1 = self.prop1
915 prop2 = self.prop2
916
917 clr = prop1.GetLineColor()
918 lineColor2 = prop2.GetLineColor()
919
920 self.noLine = clr is not Color.Transparent \
921 and lineColor2 is not Color.Transparent
922
923
924 self.lineInfo = self.__GetColorInfo(prop1.GetLineColor(),
925 prop2.GetLineColor(),
926 num)
927
928 self.fillInfo = self.__GetColorInfo(prop1.GetFill(),
929 prop2.GetFill(),
930 num)
931
932 self.lineWidth = prop1.GetLineWidth()
933 self.lineWidthStep = (prop2.GetLineWidth() - self.lineWidth) / num
934
935 return True
936
937 def next(self):
938 if self.count == 0:
939 raise StopIteration
940
941 prop = ClassGroupProperties()
942
943 if self.lineInfo is None:
944 prop.SetLineColor(Color.Transparent)
945 else:
946 prop.SetLineColor(Color(self.lineInfo[CLR][0] / 255,
947 self.lineInfo[CLR][1] / 255,
948 self.lineInfo[CLR][2] / 255))
949
950 self.lineInfo[CLR][0] += self.lineInfo[STEP][0]
951 self.lineInfo[CLR][1] += self.lineInfo[STEP][1]
952 self.lineInfo[CLR][2] += self.lineInfo[STEP][2]
953
954 if self.fillInfo is None:
955 prop.SetFill(Color.Transparent)
956 else:
957 prop.SetFill(Color(self.fillInfo[CLR][0] / 255,
958 self.fillInfo[CLR][1] / 255,
959 self.fillInfo[CLR][2] / 255))
960
961 self.fillInfo[CLR][0] += self.fillInfo[STEP][0]
962 self.fillInfo[CLR][1] += self.fillInfo[STEP][1]
963 self.fillInfo[CLR][2] += self.fillInfo[STEP][2]
964
965
966 prop.SetLineWidth(int(self.lineWidth))
967 self.lineWidth += self.lineWidthStep
968
969 self.count -= 1
970
971 return prop
972
973 def __GetColorInfo(self, color1, color2, numGroups):
974
975 if color1 is Color.Transparent and color2 is Color.Transparent:
976 #
977 # returning early
978 #
979 return None
980 elif color1 is not Color.Transparent and color2 is Color.Transparent:
981 color = [color1.red * 255,
982 color1.green * 255,
983 color1.blue * 255]
984 step = (0, 0, 0)
985 elif color1 is Color.Transparent and color2 is not Color.Transparent:
986 color = [color2.red * 255,
987 color2.green * 255,
988 color2.blue * 255]
989 step = (0, 0, 0)
990 else:
991 color = [color1.red * 255,
992 color1.green * 255,
993 color1.blue * 255]
994 step = ((color2.red * 255 - color1.red * 255) / numGroups,
995 (color2.green * 255 - color1.green * 255) / numGroups,
996 (color2.blue * 255 - color1.blue * 255) / numGroups)
997
998
999 return (color, step)
1000
1001 class MonochromaticRamp(CustomRamp):
1002 def __init__(self, start, end):
1003 sp = ClassGroupProperties()
1004 sp.SetLineColor(start)
1005 sp.SetFill(start)
1006
1007 ep = ClassGroupProperties()
1008 ep.SetLineColor(end)
1009 ep.SetFill(end)
1010
1011 CustomRamp.__init__(self, sp, ep)
1012
1013 class GreyRamp(MonochromaticRamp):
1014 def __init__(self):
1015 MonochromaticRamp.__init__(self, Color(0, 0, 0), Color(1, 1, 1))
1016
1017 class RedRamp(MonochromaticRamp):
1018 def __init__(self):
1019 MonochromaticRamp.__init__(self, Color(.2, 0, 0), Color(1, 0, 0))
1020
1021 class GreenRamp(MonochromaticRamp):
1022 def __init__(self):
1023 MonochromaticRamp.__init__(self, Color(0, .2, 0), Color(0, 1, 0))
1024
1025 class BlueRamp(MonochromaticRamp):
1026 def __init__(self):
1027 MonochromaticRamp.__init__(self, Color(0, 0, .2), Color(0, 0, 1))
1028
1029 class HotToColdRamp:
1030
1031 def __iter__(self):
1032 return self
1033
1034 def GetRamp(self):
1035 return self
1036
1037 def SetNumGroups(self, num):
1038 if num < 0:
1039 return False
1040
1041 self.num = float(num)
1042 self.index = 0
1043
1044 return True
1045
1046 def next(self):
1047 if self.index == self.num:
1048 raise StopIteration
1049
1050 clr = [1.0, 1.0, 1.0]
1051
1052 if self.index < (.25 * self.num):
1053 clr[0] = 0
1054 clr[1] = 4 * self.index / self.num
1055 elif self.index < (.5 * self.num):
1056 clr[0] = 0
1057 clr[2] = 1 + 4 * (.25 * self.num - self.index) / self.num
1058 elif self.index < (.75 * self.num):
1059 clr[0] = 4 * (self.index - .5 * self.num) / self.num
1060 clr[2] = 0
1061 else:
1062 clr[1] = 1 + 4 * (.75 * self.num - self.index) / self.num
1063 clr[2] = 0
1064
1065 self.index += 1
1066
1067 prop = ClassGroupProperties()
1068 prop.SetLineColor(Color(clr[0], clr[1], clr[2]))
1069 prop.SetFill(Color(clr[0], clr[1], clr[2]))
1070
1071 return prop
1072
1073 #class Colors16Ramp:
1074 #
1075 #def __iter__(self):
1076 #return self
1077 #
1078 #def GetRamp(self):
1079 #return self
1080 #
1081 #def SetNumGroups(self, num):
1082 #if num < 0:
1083 #return False
1084 #
1085 #self.index = 0
1086 #
1087 #return True
1088
1089

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26