/[thuban]/trunk/thuban/Thuban/UI/classifier.py
ViewVC logotype

Diff of /trunk/thuban/Thuban/UI/classifier.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 376 by jonathan, Tue Jan 28 12:01:38 2003 UTC revision 630 by jonathan, Wed Apr 9 10:10:06 2003 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001 by Intevation GmbH  # Copyright (c) 2001, 2003 by Intevation GmbH
2  # Authors:  # Authors:
3  # Jonathan Coles <[email protected]>  # Jonathan Coles <[email protected]>
4  #  #
# Line 11  __version__ = "$Revision$" Line 11  __version__ = "$Revision$"
11    
12  import copy  import copy
13    
14    from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
15         FIELDTYPE_STRING
16    
17  from wxPython.wx import *  from wxPython.wx import *
18  from wxPython.grid import *  from wxPython.grid import *
19    
20  from Thuban import _  from Thuban import _
21    from Thuban.common import *
22    from Thuban.UI.common import *
23    
24    from Thuban.Model.classification import *
25    
26    from Thuban.Model.color import Color
27    
28    from Thuban.Model.layer import Layer, SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT
29    
30    from Thuban.UI.classgen import ClassGenDialog, ClassGenerator
31    
32    from dialogs import NonModalDialog
33    
34    # widget id's
35  ID_PROPERTY_SELECT = 4010  ID_PROPERTY_SELECT = 4010
36  ID_CLASS_TABLE = 40011  ID_CLASS_TABLE = 40011
37    
38  ID_CLASSIFY_OK = 4001  
39  ID_CLASSIFY_CANCEL = 4002  # table columns
40    COL_SYMBOL = 0
41    COL_VALUE  = 1
42    COL_LABEL  = 2
43    
44    # indices into the client data lists in Classifier.fields
45    FIELD_CLASS = 0
46    FIELD_TYPE = 1
47    FIELD_NAME = 2
48    
49    #
50    # this is a silly work around to ensure that the table that is
51    # passed into SetTable is the same that is returned by GetTable
52    #
53    import weakref
54    class ClassGrid(wxGrid):
55    
56    
57        def __init__(self, parent, classifier):
58            """Constructor.
59    
60            parent -- the parent window
61    
62            clazz -- the working classification that this grid should
63                     use for display.
64            """
65    
66            #wxGrid.__init__(self, parent, ID_CLASS_TABLE, size = (340, 160))
67            wxGrid.__init__(self, parent, ID_CLASS_TABLE)
68            #self.SetTable(ClassTable(fieldData, layer.ShapeType(), self), True)
69    
70            self.classifier = classifier
71    
72            self.currentSelection = []
73    
74            EVT_GRID_CELL_LEFT_DCLICK(self, self._OnCellDClick)
75            EVT_GRID_RANGE_SELECT(self, self._OnSelectedRange)
76            EVT_GRID_SELECT_CELL(self, self._OnSelectedCell)
77            EVT_GRID_COL_SIZE(self, self._OnCellResize)
78            EVT_GRID_ROW_SIZE(self, self._OnCellResize)
79    
80        def CreateTable(self, clazz, shapeType, group = None):
81    
82            assert isinstance(clazz, Classification)
83    
84            table = self.GetTable()
85            if table is None:
86                w = self.GetDefaultColSize() * 3 + self.GetDefaultRowLabelSize()
87                h = self.GetDefaultRowSize() * 4 + self.GetDefaultColLabelSize()
88                self.SetDimensions(-1, -1, w, h)
89                self.SetSizeHints(w, h, -1, -1)
90                table = ClassTable(self)
91                self.SetTable(table, True)
92    
93    
94            self.SetSelectionMode(wxGrid.wxGridSelectRows)
95            self.ClearSelection()
96    
97            table.Reset(clazz, shapeType, group)
98    
99        def GetCurrentSelection(self):
100            """Return the currently highlighted rows as an increasing list
101               of row numbers."""
102            sel = copy.copy(self.currentSelection)
103            sel.sort()
104            return sel
105    
106        def GetSelectedRows(self):
107            return self.GetCurrentSelection()
108    
109        def SetCellRenderer(self, row, col):
110            raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))
111    
112        #
113        # [Set|Get]Table is taken from http://wiki.wxpython.org
114        # they are needed as a work around to ensure that the table
115        # that is passed to SetTable is the one that is returned
116        # by GetTable.
117        #
118        def SetTable(self, object, *attributes):
119            self.tableRef = weakref.ref(object)
120            return wxGrid.SetTable(self, object, *attributes)
121    
122        def GetTable(self):
123            try:
124                return self.tableRef()
125            except:
126                return None
127    
128        def DeleteSelectedRows(self):
129            """Deletes all highlighted rows.
130      
131            If only one row is highlighted then after it is deleted the
132            row that was below the deleted row is highlighted."""
133    
134            sel = self.GetCurrentSelection()
135    
136            # nothing to do
137            if len(sel) == 0: return
138    
139            # if only one thing is selected check if it is the default
140            # data row, because we can't remove that
141            if len(sel) == 1:
142                #group = self.GetTable().GetValueAsCustom(sel[0], COL_SYMBOL, None)
143                group = self.GetTable().GetClassGroup(sel[0])
144                if isinstance(group, ClassGroupDefault):
145                    wxMessageDialog(self,
146                                    "The Default group cannot be removed.",
147                                    style = wxOK | wxICON_EXCLAMATION).ShowModal()
148                    return
149            
150    
151            self.ClearSelection()
152    
153            # we need to remove things from the bottom up so we don't
154            # change the indexes of rows that will be deleted next
155            sel.reverse()
156    
157            #
158            # actually remove the rows
159            #
160            table = self.GetTable()
161            for row in sel:
162                table.DeleteRows(row)
163    
164            #
165            # if there was only one row selected highlight the row
166            # that was directly below it, or move up one if the
167            # deleted row was the last row.
168            #
169            if len(sel) == 1:
170                r = sel[0]
171                if r > self.GetNumberRows() - 1:
172                    r = self.GetNumberRows() - 1
173                self.SelectRow(r)
174            
175    
176        def SelectGroup(self, group, makeVisible = True):
177            if group is None: return
178    
179            assert isinstance(group, ClassGroup)
180    
181            table = self.GetTable()
182    
183            assert table is not None
184    
185            for i in range(table.GetNumberRows()):
186                g = table.GetClassGroup(i)
187                if g is group:
188                    self.SelectRow(i)
189                    if makeVisible:
190                        self.MakeCellVisible(i, 0)
191                    break
192    
193    #
194    # XXX: This isn't working, and there is no way to deselect rows wxPython!
195    #
196    #   def DeselectRow(self, row):
197    #       self.ProcessEvent(
198    #           wxGridRangeSelectEvent(-1,
199    #                                  wxEVT_GRID_RANGE_SELECT,
200    #                                  self,
201    #                                  (row, row), (row, row),
202    #                                  sel = False))
203    
204        def _OnCellDClick(self, event):
205            """Handle a double on a cell."""
206    
207            r = event.GetRow()
208            c = event.GetCol()
209            if c == COL_SYMBOL:
210                self.classifier.EditGroupProperties(r)
211    
212    
213        #
214        # _OnSelectedRange() and _OnSelectedCell() were borrowed
215        # from http://wiki.wxpython.org to keep track of which
216        # cells are currently highlighted
217        #
218        def _OnSelectedRange(self, event):
219            """Internal update to the selection tracking list"""
220            if event.Selecting():
221                for index in range( event.GetTopRow(), event.GetBottomRow()+1):
222                    if index not in self.currentSelection:
223                        self.currentSelection.append( index )
224            else:
225                for index in range( event.GetTopRow(), event.GetBottomRow()+1):
226                    while index in self.currentSelection:
227                        self.currentSelection.remove( index )
228            #self.ConfigureForSelection()
229    
230            event.Skip()
231    
232        def _OnSelectedCell( self, event ):
233            """Internal update to the selection tracking list"""
234            self.currentSelection = [ event.GetRow() ]
235            #self.ConfigureForSelection()
236            event.Skip()
237    
238        def _OnCellResize(self, event):
239            self.FitInside()
240    
241  class ClassTable(wxPyGridTableBase):  class ClassTable(wxPyGridTableBase):
242        """Represents the underlying data structure for the grid."""
243    
244        NUM_COLS = 3
245    
246        __col_labels = [_("Symbol"), _("Value"), _("Label")]
247    
248    
249        def __init__(self, view = None):
250        #def __init__(self, clazz, shapeType, view = None):
251            """Constructor.
252    
253            shapeType -- the type of shape that the layer uses
254    
255            view -- a wxGrid object that uses this class for its table
256            """
257    
     def __init__(self, clinfo):  
258          wxPyGridTableBase.__init__(self)          wxPyGridTableBase.__init__(self)
         self.clinfo = copy.deepcopy(clinfo)  
259    
260          self.tdata = []          self.SetView(view)
261            self.clazz = None
262    
263            #self.Reset(clazz, shapeType)
264    
265        def Reset(self, clazz, shapeType, group = None):
266            """Reset the table with the given data.
267    
268            This is necessary because wxWindows does not allow a grid's
269            table to change once it has been intially set and so we
270            need a way of modifying the data.
271    
272            clazz -- the working classification that this table should
273                     use for display. This may be different from the
274                     classification in the layer.
275    
276          for value, data in self.clinfo.points.items():          shapeType -- the type of shape that the layer uses
277              self.tdata.append([data, value])          """
278    
279          for range in self.clinfo.ranges:          assert isinstance(clazz, Classification)
             self.tdata.append([range[2], '%s-%s' % range[0], range[1]])  
280    
281          self.SetColLabelValue(1, "Data Values")          self.GetView().BeginBatch()
282    
283            self.fieldType = clazz.GetFieldType()
284            self.shapeType = shapeType
285    
286            self.SetClassification(clazz, group)
287            self.__Modified(-1)
288    
289            self.GetView().EndBatch()
290            self.GetView().FitInside()
291    
292        def GetClassification(self):
293            return self.clazz
294    
295        def SetClassification(self, clazz, group = None):
296    
297            self.GetView().BeginBatch()
298    
299            old_len = self.GetNumberRows()
300    
301            #
302            # copy the data out of the classification and into our
303            # array
304            #
305            row = -1
306    #       for g in clazz:
307    #           ng = copy.deepcopy(g)
308    #           self.__SetRow(None, ng)
309    #           if g is group:
310    #               row = self.GetNumberRows() - 1
311    #               #print "selecting row..."
312    
313    
314            #self.clazz = copy.deepcopy(clazz)
315            self.clazz = clazz
316    
317            self.__NotifyRowChanges(old_len, self.GetNumberRows())
318    
319            if row > -1:
320                self.GetView().ClearSelection()
321                self.GetView().SelectRow(row)
322                self.GetView().MakeCellVisible(row, 0)
323    
324            self.__Modified()
325    
326            self.GetView().EndBatch()
327            self.GetView().FitInside()
328    
329        def __NotifyRowChanges(self, curRows, newRows):
330            #
331            # silly message processing for updates to the number of
332            # rows and columns
333            #
334            if newRows > curRows:
335                msg = wxGridTableMessage(self,
336                            wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
337                            newRows - curRows)    # how many
338                self.GetView().ProcessTableMessage(msg)
339                self.GetView().FitInside()
340            elif newRows < curRows:
341                msg = wxGridTableMessage(self,
342                            wxGRIDTABLE_NOTIFY_ROWS_DELETED,
343                            curRows,              # position
344                            curRows - newRows)    # how many
345                self.GetView().ProcessTableMessage(msg)
346                self.GetView().FitInside()
347    
348    
349        def __SetRow(self, row, group):
350            """Set a row's data to that of the group.
351    
352            The table is considered modified after this operation.
353    
354            row -- if row is < 0 'group' is inserted at the top of the table
355                   if row is >= GetNumberRows() or None 'group' is append to
356                        the end of the table.
357                   otherwise 'group' replaces row 'row'
358            """
359    
360            # either append or replace
361            if row is None or row >= self.GetNumberRows():
362                self.clazz.AppendGroup(group)
363            elif row < 0:
364                self.clazz.InsertGroup(0, group)
365            else:
366                if row == 0:
367                    self.clazz.SetDefaultGroup(group)
368                else:
369                    self.clazz.ReplaceGroup(row - 1, group)
370    
371            self.__Modified()
372    
373        def GetColLabelValue(self, col):
374            """Return the label for the given column."""
375            return self.__col_labels[col]
376    
377        def GetRowLabelValue(self, row):
378            """Return the label for the given row."""
379    
380            if row == 0:
381                return _("Default")
382            else:
383                group = self.clazz.GetGroup(row - 1)
384                if isinstance(group, ClassGroupDefault):   return _("Default")
385                if isinstance(group, ClassGroupSingleton): return _("Singleton")
386                if isinstance(group, ClassGroupRange):     return _("Range")
387                if isinstance(group, ClassGroupMap):       return _("Map")
388    
389            assert False # shouldn't get here
390            return _("")
391    
392      def GetNumberRows(self):      def GetNumberRows(self):
393          return len(self.tdata)          """Return the number of rows."""
394            if self.clazz is None:
395                return 0
396    
397            return self.clazz.GetNumGroups() + 1 # +1 for default group
398    
399      def GetNumberCols(self):      def GetNumberCols(self):
400          return 2          """Return the number of columns."""
401            return self.NUM_COLS
402    
403      def IsEmptyCell(self, row, col):      def IsEmptyCell(self, row, col):
404          return false          """Determine if a cell is empty. This is always false."""
405            return False
406    
407      def GetValue(self, row, col):      def GetValue(self, row, col):
408          return self.tdata[row][col]          """Return the object that is used to represent the given
409               cell coordinates. This may not be a string."""
410            return self.GetValueAsCustom(row, col, None)
411    
412      def SetValue(self, row, col, value):      def SetValue(self, row, col, value):
413          pass          """Assign 'value' to the cell specified by 'row' and 'col'.
       
414    
415            The table is considered modified after this operation.
416            """
417    
418  class Classifier(wxDialog):          self.SetValueAsCustom(row, col, None, value)
419            self.__Modified()
420          
421        def GetValueAsCustom(self, row, col, typeName):
422            """Return the object that is used to represent the given
423               cell coordinates. This may not be a string.
424    
425            typeName -- unused, but needed to overload wxPyGridTableBase
426            """
427    
428            if row == 0:
429                group = self.clazz.GetDefaultGroup()
430            else:
431                group = self.clazz.GetGroup(row - 1)
432    
433    
434            if col == COL_SYMBOL:
435                return group.GetProperties()
436    
437            if col == COL_LABEL:
438                return group.GetLabel()
439    
440            # col must be COL_VALUE
441            assert col == COL_VALUE
442    
443            if isinstance(group, ClassGroupDefault):
444                return _("DEFAULT")
445            elif isinstance(group, ClassGroupSingleton):
446                return group.GetValue()
447            elif isinstance(group, ClassGroupRange):
448                return _("%s - %s") % (group.GetMin(), group.GetMax())
449    
450            assert(False) # shouldn't get here
451            return None
452    
453        def __ParseInput(self, value):
454            """Try to determine what kind of input value is
455               (string, number, or range)
456    
457            Returns a tuple of length one if there is a single
458            value, or of length two if it is a range.
459            """
460    
461            type = self.fieldType
462    
463            if type == FIELDTYPE_STRING:
464                return (value,)
465            elif type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):
466    
467                if type == FIELDTYPE_INT:
468                    conv = lambda p: int(float(p))
469                else:
470                    conv = lambda p: p
471    
472                #
473                # first try to take the input as a single number
474                # if there's an exception try to break it into
475                # a range seperated by a '-'. take care to ignore
476                # a leading '-' as that could be for a negative number.
477                # then try to parse the individual parts. if there
478                # is an exception here, let it pass up to the calling
479                # function.
480                #
481                try:
482                    return (conv(Str2Num(value)),)
483                except ValueError:
484                    i = value.find('-')
485                    if i == 0:
486                        i = value.find('-', 1)
487    
488                    return (conv(Str2Num(value[:i])), conv(Str2Num(value[i+1:])))
489    
490            assert False  # shouldn't get here
491            return (0,)
492                
493    
494        def SetValueAsCustom(self, row, col, typeName, value):
495            """Set the cell specified by 'row' and 'col' to 'value'.
496    
497            If column represents the value column, the input is parsed
498            to determine if a string, number, or range was entered.
499            A new ClassGroup may be created if the type of data changes.
500    
501            The table is considered modified after this operation.
502    
503            typeName -- unused, but needed to overload wxPyGridTableBase
504            """
505    
506            assert col >= 0 and col < self.GetNumberCols()
507            assert row >= 0 and row < self.GetNumberRows()
508    
509            if row == 0:
510                group = self.clazz.GetDefaultGroup()
511            else:
512                group = self.clazz.GetGroup(row - 1)
513    
514            mod = True # assume the data will change
515    
516            if col == COL_SYMBOL:
517                group.SetProperties(value)
518            elif col == COL_LABEL:
519                group.SetLabel(value)
520            elif col == COL_VALUE:
521                if isinstance(group, ClassGroupDefault):
522                    # not allowed to modify the default value
523                    pass
524                elif isinstance(group, ClassGroupMap):
525                    # something special
526                    pass
527                else: # SINGLETON, RANGE
528                    try:
529                        dataInfo = self.__ParseInput(value)
530                    except ValueError:
531                        # bad input, ignore the request
532                        mod = False
533                    else:
534    
535                        changed = False
536                        ngroup = group
537                        props = group.GetProperties()
538    
539                        #
540                        # try to update the values, which may include
541                        # changing the underlying group type if the
542                        # group was a singleton and a range was entered
543                        #
544                        if len(dataInfo) == 1:
545                            if not isinstance(group, ClassGroupSingleton):
546                                ngroup = ClassGroupSingleton(prop = props)
547                                changed = True
548                            ngroup.SetValue(dataInfo[0])
549                        elif len(dataInfo) == 2:
550                            if not isinstance(group, ClassGroupRange):
551                                ngroup = ClassGroupRange(prop = props)
552                                changed = True
553                            ngroup.SetRange(dataInfo[0], dataInfo[1])
554                        else:
555                            assert False
556                            pass
557    
558                        if changed:
559                            ngroup.SetLabel(group.GetLabel())
560                            self.SetClassGroup(row, ngroup)
561            else:
562                assert False # shouldn't be here
563                pass
564    
565            if mod:
566                self.__Modified()
567                self.GetView().Refresh()
568    
569        def GetAttr(self, row, col, someExtraParameter):
570            """Returns the cell attributes"""
571    
572            attr = wxGridCellAttr()
573            #attr = wxPyGridTableBase.GetAttr(self, row, col, someExtraParameter)
574    
575            if col == COL_SYMBOL:
576                # we need to create a new renderer each time, because
577                # SetRenderer takes control of the parameter
578                attr.SetRenderer(ClassRenderer(self.shapeType))
579                attr.SetReadOnly()
580    
581            return attr
582    
583        def GetClassGroup(self, row):
584            """Return the ClassGroup object representing row 'row'."""
585    
586            #return self.GetValueAsCustom(row, COL_SYMBOL, None)
587            if row == 0:
588                return self.clazz.GetDefaultGroup()
589            else:
590                return self.clazz.GetGroup(row - 1)
591    
592        def SetClassGroup(self, row, group):
593            self.__SetRow(row, group)
594            self.GetView().Refresh()
595    
596        def __Modified(self, mod = True):
597            """Adjust the modified flag.
598    
599            mod -- if -1 set the modified flag to False, otherwise perform
600                   an 'or' operation with the current value of the flag and
601                   'mod'
602            """
603    
604            if mod == -1:
605                self.modified = False
606            else:
607                self.modified = mod or self.modified
608    
609        def IsModified(self):
610            """True if this table is considered modified."""
611            return self.modified
612    
613        def DeleteRows(self, pos, numRows = 1):
614            """Deletes 'numRows' beginning at row 'pos'.
615    
616            The row representing the default group is not removed.
617    
618            The table is considered modified if any rows are removed.
619            """
620    
621            assert pos >= 0
622            old_len = self.GetNumberRows()
623            for row in range(pos, pos - numRows, -1):
624                group = self.GetClassGroup(row)
625                if row != 0:
626                    self.clazz.RemoveGroup(row - 1)
627                    self.__Modified()
628            
629      def __init__(self, parent, layer):          if self.IsModified():
630          wxDialog.__init__(self, parent, -1, _("Classify"),              self.__NotifyRowChanges(old_len, self.GetNumberRows())
631                            style = wxRESIZE_BORDER)  
632        def AppendRows(self, numRows = 1):
633            """Append 'numRows' empty rows to the end of the table.
634    
635            The table is considered modified if any rows are appended.
636            """
637    
638            old_len = self.GetNumberRows()
639            for i in range(numRows):
640                np = ClassGroupSingleton()
641                self.__SetRow(None, np)
642    
643            if self.IsModified():
644                self.__NotifyRowChanges(old_len, self.GetNumberRows())
645    
646    
647    ID_CLASSIFY_OK = 4001
648    ID_CLASSIFY_CANCEL = 4002
649    ID_CLASSIFY_ADD = 4003
650    ID_CLASSIFY_GENCLASS = 4004
651    ID_CLASSIFY_REMOVE = 4005
652    ID_CLASSIFY_MOVEUP = 4006
653    ID_CLASSIFY_MOVEDOWN = 4007
654    ID_CLASSIFY_APPLY = 4008
655    ID_CLASSIFY_EDITPROPS = 4009
656    ID_CLASSIFY_CLOSE = 4010
657    
658    BTN_ADD = 0
659    BTN_EDIT = 1
660    BTN_GEN = 2
661    BTN_UP = 3
662    BTN_DOWN = 4
663    BTN_RM = 5
664    
665    class Classifier(NonModalDialog):
666    
667        type2string = {None:             _("None"),
668                       FIELDTYPE_STRING: _("Text"),
669                       FIELDTYPE_INT:    _("Integer"),
670                       FIELDTYPE_DOUBLE: _("Decimal")}
671    
672        def __init__(self, parent, name, layer, group = None):
673            NonModalDialog.__init__(self, parent, name,
674                                    _("Classifier: %s") % layer.Title())
675    
676            panel = wxPanel(self, -1, size=(100, 100))
677    
678            self.layer = layer
679    
680            self.originalClass = self.layer.GetClassification()
681            field = self.originalClass.GetField()
682            fieldType = self.originalClass.GetFieldType()
683    
684            self.genDlg = None
685    
686          topBox = wxBoxSizer(wxVERTICAL)          topBox = wxBoxSizer(wxVERTICAL)
687            panelBox = wxBoxSizer(wxVERTICAL)
688    
689            #panelBox.Add(wxStaticText(panel, -1, _("Layer: %s") % layer.Title()),
690                #0, wxALIGN_LEFT | wxALL, 4)
691            panelBox.Add(wxStaticText(panel, -1,
692                                    _("Layer Type: %s") % layer.ShapeType()),
693                0, wxALIGN_LEFT | wxALL, 4)
694    
         propertyBox = wxBoxSizer(wxHORIZONTAL)  
         propertyBox.Add(wxStaticText(self, -1, _("Property")),  
             0, wxALIGN_CENTER | wxALL, 4)  
695    
696          self.properties = wxComboBox(self, ID_PROPERTY_SELECT, "",          #
697            # make field combo box
698            #
699            self.fields = wxComboBox(panel, ID_PROPERTY_SELECT, "",
700                                       style = wxCB_READONLY)                                       style = wxCB_READONLY)
701    
702          self.num_cols = layer.table.field_count()          self.num_cols = layer.table.field_count()
703          cur_hilight = 0          # just assume the first field in case one hasn't been
704            # specified in the file.
705            self.__cur_field = 0
706    
707            self.fields.Append("<None>")
708            self.fields.SetClientData(0, None)
709    
710          for i in range(self.num_cols):          for i in range(self.num_cols):
711              type, name, len, decc = layer.table.field_info(i)              type, name, len, decc = layer.table.field_info(i)
712              if name == layer.classification.field:              self.fields.Append(name)
713                  cur_hilight = i  
714              self.properties.Append(name)              if name == field:
715                    self.__cur_field = i + 1
716          self.properties.SetSelection(cur_hilight)                  self.fields.SetClientData(i + 1,
717          propertyBox.Add(self.properties, 0, wxGROW, 4)                                            copy.deepcopy(self.originalClass))
718          EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self.OnPropertySelect)              else:
719                    self.fields.SetClientData(i + 1, None)
720    
721    
722            ###########
723    
724            self.fieldTypeText = wxStaticText(panel, -1, "")
725            panelBox.Add(self.fieldTypeText, 0,
726                         wxGROW | wxALIGN_LEFT | wxALL | wxADJUST_MINSIZE, 4)
727    
728            propertyBox = wxBoxSizer(wxHORIZONTAL)
729            propertyBox.Add(wxStaticText(panel, -1, _("Field: ")),
730                0, wxALIGN_LEFT | wxALL, 4)
731            propertyBox.Add(self.fields, 1, wxGROW|wxALL, 4)
732            EVT_COMBOBOX(self, ID_PROPERTY_SELECT, self._OnFieldSelect)
733    
734            panelBox.Add(propertyBox, 0, wxGROW, 4)
735    
         topBox.Add(propertyBox, 0, wxGROW, 4)  
736    
737          #          #
738            # Control Box
739            #
740            controlBox = wxBoxSizer(wxHORIZONTAL)
741    
742    
743            ###########
744            #
745            # Control buttons:
746            #
747            self.controlButtons = []
748    
749            controlButtonBox = wxBoxSizer(wxVERTICAL)
750    
751            button = wxButton(panel, ID_CLASSIFY_ADD, _("Add"))
752            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
753            self.controlButtons.append(button)
754    
755            button = wxButton(panel, ID_CLASSIFY_EDITPROPS, _("Edit Properties"))
756            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
757            self.controlButtons.append(button)
758    
759            button = wxButton(panel, ID_CLASSIFY_GENCLASS, _("Generate Class"))
760            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
761            self.controlButtons.append(button)
762    
763            button = wxButton(panel, ID_CLASSIFY_MOVEUP, _("Move Up"))
764            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
765            self.controlButtons.append(button)
766    
767            button = wxButton(panel, ID_CLASSIFY_MOVEDOWN, _("Move Down"))
768            controlButtonBox.Add(button, 0, wxGROW | wxALL, 4)
769            self.controlButtons.append(button)
770    
771            controlButtonBox.Add(60, 20, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
772    
773            button = wxButton(panel, ID_CLASSIFY_REMOVE, _("Remove"))
774            controlButtonBox.Add(button, 0, wxGROW | wxALL | wxALIGN_BOTTOM, 4)
775            self.controlButtons.append(button)
776    
777    
778            ###########
779            #
780          # Classification data table          # Classification data table
781          #          #
782    
783          self.classTable = wxGrid(self, ID_CLASS_TABLE, size=(300, 150))          self.classGrid = ClassGrid(panel, self)
784            #self.__SetGridTable(self.__cur_field, group)
785            #self.fields.SetSelection(self.__cur_field)
786    
787            # calling __SelectField after creating the classGrid fills in the
788            # grid with the correct information
789            self.fields.SetSelection(self.__cur_field)
790            self.__SelectField(self.__cur_field, group = group)
791    
792            #self.classGrid.SelectGroup(group)
793    
794            controlBox.Add(self.classGrid, 1, wxGROW, 0)
795    
796    
797    
798            controlBox.Add(controlButtonBox, 0, wxGROW, 10)
799            panelBox.Add(controlBox, 1, wxGROW, 10)
800    
801          table = ClassTable(layer.classification)          EVT_BUTTON(self, ID_CLASSIFY_ADD, self._OnAdd)
802          self.classTable.SetTable(table, true)          EVT_BUTTON(self, ID_CLASSIFY_EDITPROPS, self._OnEditGroupProperties)
803  <<<<<<< classifier.py          EVT_BUTTON(self, ID_CLASSIFY_REMOVE, self._OnRemove)
804            EVT_BUTTON(self, ID_CLASSIFY_GENCLASS, self._OnGenClass)
805          topBox.Add(self.classTable, 0, wxGROW, 0)          EVT_BUTTON(self, ID_CLASSIFY_MOVEUP, self._OnMoveUp)
806  =======          EVT_BUTTON(self, ID_CLASSIFY_MOVEDOWN, self._OnMoveDown)
         #table.SetNumberRows(10)  
         #table.SetNumberCols(2)  
         table.SetColLabelValue(0, _("Class"))  
         table.SetColLabelValue(1, _("Value"))  
         #self.classTable.SetColLabelValue(0, _("Class"))  
         #self.classTable.SetColLabelValue(1, _("Value"))  
         #self.classTable.SetCellValue(1, 1, _("Value"))  
807    
808          tableBox.Add(self.classTable, 0, wxALL, 4)          ###########
809    
810            buttonBox = wxBoxSizer(wxHORIZONTAL)
811            buttonBox.Add(wxButton(panel, ID_CLASSIFY_OK, _("OK")),
812                          0, wxALL, 4)
813            buttonBox.Add(60, 20, 0, wxALL, 4)
814            buttonBox.Add(wxButton(panel, ID_CLASSIFY_APPLY, _("Apply")),
815                          0, wxALL, 4)
816            buttonBox.Add(60, 20, 0, wxALL, 4)
817            buttonBox.Add(wxButton(panel, ID_CLASSIFY_CLOSE, _("Close")),
818                          0, wxALL, 4)
819            buttonBox.Add(60, 20, 0, wxALL, 4)
820            buttonBox.Add(wxButton(panel, ID_CLASSIFY_CANCEL, _("Cancel")),
821                          0, wxALL, 4)
822            panelBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 0)
823    
824            EVT_BUTTON(self, ID_CLASSIFY_OK, self._OnOK)
825            EVT_BUTTON(self, ID_CLASSIFY_APPLY, self._OnApply)
826            EVT_BUTTON(self, ID_CLASSIFY_CLOSE, self._OnCloseBtn)
827            EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self._OnCancel)
828    
829            ###########
830    
831    
832            panel.SetAutoLayout(True)
833            panel.SetSizer(panelBox)
834            panelBox.SetSizeHints(panel)
835    
836            topBox.Add(panel, 1, wxGROW, 0)
837            panelBox.SetSizeHints(self)
838            self.SetAutoLayout(True)
839            self.SetSizer(topBox)
840    
841            #self.Fit()
842            ######################
843    
844            self.haveApplied = False
845    
846        def EditGroupProperties(self, row):
847            table = self.classGrid.GetTable()
848            prop = table.GetValueAsCustom(row, COL_SYMBOL, None)
849    
850            # get a new ClassGroupProperties object and copy the
851            # values over to our current object
852            propDlg = SelectPropertiesDialog(NULL, prop, self.layer.ShapeType())
853    
854            self.Enable(False)
855            if propDlg.ShowModal() == wxID_OK:
856                new_prop = propDlg.GetClassGroupProperties()
857                table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)
858            self.Enable(True)
859            propDlg.Destroy()
860                    
861          topBox.Add(self.classTable, 0, 0)      def _SetClassification(self, clazz):
862  >>>>>>> 1.2          
863            self.fields.SetClientData(self.__cur_field, clazz)
864            self.classGrid.GetTable().SetClassification(clazz)
865    
866        def __BuildClassification(self, fieldIndex, copyClass = False):
867    
868    #       numRows = self.classGrid.GetNumberRows()
869    #       assert numRows > 0  # there should always be a default row
870    
871    #       clazz = Classification()
872            if fieldIndex == 0:
873                fieldName = None
874                fieldType = None
875            else:
876                fieldName = self.fields.GetString(fieldIndex)
877                fieldType = self.layer.GetFieldType(fieldName)
878    
879            clazz = self.classGrid.GetTable().GetClassification()
880    
881            if copyClass:
882                clazz = copy.deepcopy(clazz)
883    
884            clazz.SetField(fieldName)
885            clazz.SetFieldType(fieldType)
886    
887    
888    #       table = self.classGrid.GetTable()
889    #       clazz.SetDefaultGroup(table.GetClassGroup(0))
890    
891    #       for i in range(1, numRows):
892    #           clazz.AppendGroup(table.GetClassGroup(i))
893    
894            return clazz
895    
896        def __SetGridTable(self, fieldIndex, group = None):
897    
898            clazz = self.fields.GetClientData(fieldIndex)
899    
900            if clazz is None:
901                clazz = Classification()
902                clazz.SetDefaultGroup(
903                    ClassGroupDefault(
904                        self.layer.GetClassification().
905                                   GetDefaultGroup().GetProperties()))
906    
907                fieldName = self.fields.GetString(fieldIndex)
908                fieldType = self.layer.GetFieldType(fieldName)
909                clazz.SetFieldType(fieldType)
910                    
911            self.classGrid.CreateTable(clazz, self.layer.ShapeType(), group)
912    
913        def __SetFieldTypeText(self, fieldIndex):
914            fieldName = self.fields.GetString(fieldIndex)
915            fieldType = self.layer.GetFieldType(fieldName)
916    
917            assert Classifier.type2string.has_key(fieldType)
918    
919            text = Classifier.type2string[fieldType]
920    
921            self.fieldTypeText.SetLabel(_("Field Type: %s") % text)
922    
923        def __SelectField(self, newIndex, oldIndex = -1, group = None):
924            """This method assumes that the current selection for the
925            combo has already been set by a call to SetSelection().
926            """
927    
928            assert oldIndex >= -1
929    
930            if oldIndex != -1:
931                clazz = self.__BuildClassification(oldIndex)
932                self.fields.SetClientData(oldIndex, clazz)
933    
934            self.__SetGridTable(newIndex, group)
935    
936            enabled = newIndex != 0
937    
938            for b in self.controlButtons:
939                b.Enable(enabled)
940    
941            self.__SetFieldTypeText(newIndex)
942    
943    
944        def _OnEditGroupProperties(self, event):
945            sel = self.classGrid.GetCurrentSelection()
946    
947            if len(sel) == 1:
948                self.EditGroupProperties(sel[0])
949    
950        def _OnFieldSelect(self, event):
951            index = self.fields.GetSelection()
952            self.__SelectField(index, self.__cur_field)
953            self.__cur_field = index
954    
955        def _OnApply(self, event):
956            """Put the data from the table into a new Classification and hand
957               it to the layer.
958            """
959    
960            clazz = self.fields.GetClientData(self.__cur_field)
961    
962            #
963            # only build the classification if there wasn't one to
964            # to begin with or it has been modified
965            #
966            if clazz is None or self.classGrid.GetTable().IsModified():
967                clazz = self.__BuildClassification(self.__cur_field, True)
968    
969            self.layer.SetClassification(clazz)
970    
971            self.haveApplied = True
972    
973        def _OnOK(self, event):
974            self._OnApply(event)
975            self.Close()
976    
977        def _OnCloseBtn(self, event):
978            """Close is similar to Cancel except that any changes that were
979            made and applied remain applied, but the currently displayed
980            classification is discarded.
981            """
982    
983            self.Close()
984    
985        def _OnCancel(self, event):
986            """The layer's current classification stays the same."""
987            if self.haveApplied:
988                self.layer.SetClassification(self.originalClass)
989    
990            self.Close()
991    
992        def _OnAdd(self, event):
993            self.classGrid.AppendRows()
994    
995        def _OnRemove(self, event):
996            self.classGrid.DeleteSelectedRows()
997    
998        def _OnGenClass(self, event):
999    
1000            #if self.genDlg is None:
1001            self.genDlg = ClassGenDialog(self, self.layer,
1002                              self.fields.GetString(self.__cur_field))
1003    
1004            EVT_CLOSE(self.genDlg, self._OnGenDialogClose)
1005    
1006            self.fields.Enable(False)
1007            self.controlButtons[BTN_EDIT].Enable(False)
1008            self.controlButtons[BTN_GEN].Enable(False)
1009    
1010            self.genDlg.Show()
1011            #if self.genDlg.ShowModal() == wxID_OK:
1012            #    clazz = self.genDlg.GetClassification()
1013            #    self.fields.SetClientData(self.__cur_field, clazz)
1014            #    self.classGrid.GetTable().SetClassification(clazz)
1015            #self.Enable(True)
1016            #self.genDlg.Destroy()
1017    
1018        def _OnGenDialogClose(self, event):
1019            self.genDlg.Destroy()
1020    
1021            self.fields.Enable(True)
1022            self.controlButtons[BTN_EDIT].Enable(True)
1023            self.controlButtons[BTN_GEN].Enable(True)
1024    
1025        def _OnMoveUp(self, event):
1026            sel = self.classGrid.GetCurrentSelection()
1027    
1028            if len(sel) == 1:
1029                i = sel[0]
1030                if i > 1:
1031                    table = self.classGrid.GetTable()
1032                    x = table.GetClassGroup(i - 1)
1033                    y = table.GetClassGroup(i)
1034                    table.SetClassGroup(i - 1, y)
1035                    table.SetClassGroup(i, x)
1036                    self.classGrid.ClearSelection()
1037                    self.classGrid.SelectRow(i - 1)
1038                    self.classGrid.MakeCellVisible(i - 1, 0)
1039    
1040        def _OnMoveDown(self, event):
1041            sel = self.classGrid.GetCurrentSelection()
1042    
1043            if len(sel) == 1:
1044                i = sel[0]
1045                table = self.classGrid.GetTable()
1046                if 0 < i < table.GetNumberRows() - 1:
1047                    x = table.GetClassGroup(i)
1048                    y = table.GetClassGroup(i + 1)
1049                    table.SetClassGroup(i, y)
1050                    table.SetClassGroup(i + 1, x)
1051                    self.classGrid.ClearSelection()
1052                    self.classGrid.SelectRow(i + 1)
1053                    self.classGrid.MakeCellVisible(i + 1, 0)
1054    
1055    
1056    ID_SELPROP_OK = 4001
1057    ID_SELPROP_CANCEL = 4002
1058    ID_SELPROP_SPINCTRL = 4002
1059    ID_SELPROP_PREVIEW = 4003
1060    ID_SELPROP_STROKECLR = 4004
1061    ID_SELPROP_FILLCLR = 4005
1062    ID_SELPROP_STROKECLRTRANS = 4006
1063    ID_SELPROP_FILLCLRTRANS = 4007
1064    
1065    class SelectPropertiesDialog(wxDialog):
1066    
1067        def __init__(self, parent, prop, shapeType):
1068            wxDialog.__init__(self, parent, -1, _("Select Properties"),
1069                              style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
1070    
1071            self.prop = ClassGroupProperties(prop)
1072    
1073            topBox = wxBoxSizer(wxVERTICAL)
1074    
1075            itemBox = wxBoxSizer(wxHORIZONTAL)
1076    
1077            # preview box
1078            previewBox = wxBoxSizer(wxVERTICAL)
1079            previewBox.Add(wxStaticText(self, -1, _("Preview:")),
1080                0, wxALIGN_LEFT | wxALL, 4)
1081    
1082            self.previewWin = ClassGroupPropertiesCtrl(
1083                self, ID_SELPROP_PREVIEW, self.prop, shapeType,
1084                (40, 40), wxSIMPLE_BORDER)
1085    
1086            self.previewWin.AllowEdit(False)
1087    
1088            previewBox.Add(self.previewWin, 1, wxGROW | wxALL, 4)
1089    
1090            itemBox.Add(previewBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1091    
1092            # control box
1093            ctrlBox = wxBoxSizer(wxVERTICAL)
1094    
1095            lineColorBox = wxBoxSizer(wxHORIZONTAL)
1096            lineColorBox.Add(
1097                wxButton(self, ID_SELPROP_STROKECLR, _("Change Line Color")),
1098                1, wxALL | wxGROW, 4)
1099            EVT_BUTTON(self, ID_SELPROP_STROKECLR, self._OnChangeLineColor)
1100    
1101            lineColorBox.Add(
1102                wxButton(self, ID_SELPROP_STROKECLRTRANS, _("Transparent")),
1103                1, wxALL | wxGROW, 4)
1104            EVT_BUTTON(self, ID_SELPROP_STROKECLRTRANS,
1105                       self._OnChangeLineColorTrans)
1106    
1107            ctrlBox.Add(lineColorBox, 0,
1108                        wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
1109    
1110            if shapeType != SHAPETYPE_ARC:
1111                fillColorBox = wxBoxSizer(wxHORIZONTAL)
1112                fillColorBox.Add(
1113                    wxButton(self, ID_SELPROP_FILLCLR, _("Change Fill Color")),
1114                    1, wxALL | wxGROW, 4)
1115                EVT_BUTTON(self, ID_SELPROP_FILLCLR, self._OnChangeFillColor)
1116                fillColorBox.Add(
1117                    wxButton(self, ID_SELPROP_FILLCLRTRANS, _("Transparent")),
1118                    1, wxALL | wxGROW, 4)
1119                EVT_BUTTON(self, ID_SELPROP_FILLCLRTRANS,
1120                           self._OnChangeFillColorTrans)
1121                ctrlBox.Add(fillColorBox, 0,
1122                            wxALIGN_CENTER_HORIZONTAL | wxALL | wxGROW, 4)
1123    
1124            spinBox = wxBoxSizer(wxHORIZONTAL)
1125            spinBox.Add(wxStaticText(self, -1, _("Line Width: ")),
1126                    0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4)
1127            self.spinCtrl = wxSpinCtrl(self, ID_SELPROP_SPINCTRL,
1128                                       min=1, max=10,
1129                                       value=str(prop.GetLineWidth()),
1130                                       initial=prop.GetLineWidth())
1131    
1132            EVT_SPINCTRL(self, ID_SELPROP_SPINCTRL, self._OnSpin)
1133    
1134            spinBox.Add(self.spinCtrl, 0, wxALIGN_LEFT | wxALL, 4)
1135    
1136            ctrlBox.Add(spinBox, 0, wxALIGN_RIGHT | wxALL, 0)
1137            itemBox.Add(ctrlBox, 0, wxALIGN_RIGHT | wxALL | wxGROW, 0)
1138            topBox.Add(itemBox, 1, wxALIGN_LEFT | wxALL | wxGROW, 0)
1139    
1140          #          #
1141          # Control buttons:          # Control buttons:
1142          #          #
1143          buttonBox = wxBoxSizer(wxHORIZONTAL)          buttonBox = wxBoxSizer(wxHORIZONTAL)
1144          buttonBox.Add(wxButton(self, ID_CLASSIFY_OK, _("OK")),          buttonBox.Add(wxButton(self, ID_SELPROP_OK, _("OK")),
1145                        0, wxALL, 4)                        0, wxALL, 4)
1146          buttonBox.Add(wxButton(self, ID_CLASSIFY_CANCEL, _("Cancel")),          buttonBox.Add(wxButton(self, ID_SELPROP_CANCEL, _("Cancel")),
1147                        0, wxALL, 4)                        0, wxALL, 4)
1148          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)          topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 10)
1149                                                                                    
1150          EVT_BUTTON(self, ID_CLASSIFY_OK, self.OnOK)          EVT_BUTTON(self, ID_SELPROP_OK, self._OnOK)
1151          EVT_BUTTON(self, ID_CLASSIFY_CANCEL, self.OnCancel)          EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
1152                                                                                    
1153          self.SetAutoLayout(true)          self.SetAutoLayout(True)
1154          self.SetSizer(topBox)          self.SetSizer(topBox)
1155          topBox.Fit(self)          topBox.Fit(self)
1156          topBox.SetSizeHints(self)          topBox.SetSizeHints(self)
1157    
1158      def OnPropertySelect(self, event): pass      def _OnOK(self, event):
   
     def OnOK(self, event):  
1159          self.EndModal(wxID_OK)          self.EndModal(wxID_OK)
1160    
1161      def OnCancel(self, event):      def _OnCancel(self, event):
1162          self.EndModal(wxID_CANCEL)          self.EndModal(wxID_CANCEL)
1163    
1164        def _OnSpin(self, event):
1165            self.prop.SetLineWidth(self.spinCtrl.GetValue())
1166            self.previewWin.Refresh()
1167    
1168        def __GetColor(self, cur):
1169            dialog = wxColourDialog(self)
1170            if cur is not Color.Transparent:
1171                dialog.GetColourData().SetColour(Color2wxColour(cur))
1172    
1173            ret = None
1174            if dialog.ShowModal() == wxID_OK:
1175                ret = wxColour2Color(dialog.GetColourData().GetColour())
1176    
1177            dialog.Destroy()
1178    
1179            return ret
1180            
1181        def _OnChangeLineColor(self, event):
1182            clr = self.__GetColor(self.prop.GetLineColor())
1183            if clr is not None:
1184                self.prop.SetLineColor(clr)
1185            self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1186    
1187        def _OnChangeLineColorTrans(self, event):
1188            self.prop.SetLineColor(Color.Transparent)
1189            self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1190            
1191        def _OnChangeFillColor(self, event):
1192            clr = self.__GetColor(self.prop.GetFill())
1193            if clr is not None:
1194                self.prop.SetFill(clr)
1195            self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1196    
1197        def _OnChangeFillColorTrans(self, event):
1198            self.prop.SetFill(Color.Transparent)
1199            self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
1200    
1201        def GetClassGroupProperties(self):
1202            return self.prop
1203    
1204    
1205    class ClassDataPreviewWindow(wxWindow):
1206    
1207        def __init__(self, rect, prop, shapeType,
1208                           parent = None, id = -1, size = wxDefaultSize):
1209            if parent is not None:
1210                wxWindow.__init__(self, parent, id, (0, 0), size)
1211                EVT_PAINT(self, self._OnPaint)
1212    
1213            self.rect = rect
1214    
1215            self.prop = prop
1216            self.shapeType = shapeType
1217            self.previewer = ClassDataPreviewer()
1218    
1219        def GetProperties():
1220            return self.prop
1221    
1222        def _OnPaint(self, event):
1223            dc = wxPaintDC(self)
1224    
1225            # XXX: this doesn't seem to be having an effect:
1226            dc.DestroyClippingRegion()
1227    
1228            if self.rect is None:
1229                w, h = self.GetSize()
1230                rect = wxRect(0, 0, w, h)
1231            else:
1232                rect = self.rect
1233    
1234            self.previewer.Draw(dc, rect, self.prop, self.shapeType)
1235    
1236    class ClassDataPreviewer:
1237    
1238        def Draw(self, dc, rect, prop, shapeType):
1239    
1240            assert dc is not None
1241            assert isinstance(prop, ClassGroupProperties)
1242    
1243            if rect is None:
1244                x = 0
1245                y = 0
1246                w, h = dc.GetSize()
1247            else:
1248                x = rect.GetX()
1249                y = rect.GetY()
1250                w = rect.GetWidth()
1251                h = rect.GetHeight()
1252    
1253            stroke = prop.GetLineColor()
1254            if stroke is Color.Transparent:
1255                pen = wxTRANSPARENT_PEN
1256            else:
1257                pen = wxPen(Color2wxColour(stroke),
1258                            prop.GetLineWidth(),
1259                            wxSOLID)
1260    
1261            stroke = prop.GetFill()
1262            if stroke is Color.Transparent:
1263                brush = wxTRANSPARENT_BRUSH
1264            else:
1265                brush = wxBrush(Color2wxColour(stroke), wxSOLID)
1266    
1267            dc.SetPen(pen)
1268            dc.SetBrush(brush)
1269    
1270            if shapeType == SHAPETYPE_ARC:
1271                dc.DrawSpline([wxPoint(x, y + h),
1272                               wxPoint(x + w/2, y + h/4),
1273                               wxPoint(x + w/2, y + h/4*3),
1274                               wxPoint(x + w, y)])
1275    
1276            elif shapeType == SHAPETYPE_POINT:
1277    
1278                dc.DrawCircle(x + w/2, y + h/2,
1279                              (min(w, h) - prop.GetLineWidth())/2)
1280    
1281            elif shapeType == SHAPETYPE_POLYGON:
1282                dc.DrawRectangle(x, y, w, h)
1283    
1284    class ClassRenderer(wxPyGridCellRenderer):
1285    
1286        def __init__(self, shapeType):
1287            wxPyGridCellRenderer.__init__(self)
1288            self.shapeType = shapeType
1289            self.previewer = ClassDataPreviewer()
1290    
1291        def Draw(self, grid, attr, dc, rect, row, col, isSelected):
1292            data = grid.GetTable().GetClassGroup(row)
1293    
1294            dc.SetClippingRegion(rect.GetX(), rect.GetY(),
1295                                 rect.GetWidth(), rect.GetHeight())
1296            dc.SetPen(wxPen(wxLIGHT_GREY))
1297            dc.SetBrush(wxBrush(wxLIGHT_GREY, wxSOLID))
1298            dc.DrawRectangle(rect.GetX(), rect.GetY(),
1299                             rect.GetWidth(), rect.GetHeight())
1300    
1301            if not isinstance(data, ClassGroupMap):
1302                self.previewer.Draw(dc, rect, data.GetProperties(), self.shapeType)
1303    
1304            if isSelected:
1305                dc.SetPen(wxPen(wxBLACK, 1, wxSOLID))
1306                dc.SetBrush(wxTRANSPARENT_BRUSH)
1307    
1308                dc.DrawRectangle(rect.GetX(), rect.GetY(),
1309                                 rect.GetWidth(), rect.GetHeight())
1310    
1311            dc.DestroyClippingRegion()
1312    
1313    
1314    class ClassGroupPropertiesCtrl(wxWindow, wxControl):
1315    
1316        def __init__(self, parent, id, props, shapeType,
1317                     size = wxDefaultSize, style = 0):
1318    
1319            wxWindow.__init__(self, parent, id, size = size, style = style)
1320    
1321            self.SetProperties(props)
1322            self.SetShapeType(shapeType)
1323            self.AllowEdit(True)
1324    
1325            EVT_PAINT(self, self._OnPaint)
1326            EVT_LEFT_DCLICK(self, self._OnLeftDClick)
1327    
1328            self.previewer = ClassDataPreviewer()
1329    
1330        def _OnPaint(self, event):
1331            dc = wxPaintDC(self)
1332    
1333            # XXX: this doesn't seem to be having an effect:
1334            dc.DestroyClippingRegion()
1335    
1336            w, h = self.GetClientSize()
1337    
1338            self.previewer.Draw(dc,
1339                                wxRect(0, 0, w, h),
1340                                self.GetProperties(),
1341                                self.GetShapeType())
1342    
1343    
1344        def GetProperties(self):
1345            return self.props
1346    
1347        def SetProperties(self, props):
1348            self.props = props
1349            self.Refresh()
1350    
1351        def GetShapeType(self):
1352            return self.shapeType
1353    
1354        def SetShapeType(self, shapeType):
1355            self.shapeType = shapeType
1356            self.Refresh()
1357    
1358        def AllowEdit(self, allow):
1359            self.allowEdit = allow
1360    
1361        def DoEdit(self):
1362            if not self.allowEdit: return
1363    
1364            propDlg = SelectPropertiesDialog(NULL,
1365                                             self.GetProperties(),
1366                                             self.GetShapeType())
1367    
1368            if propDlg.ShowModal() == wxID_OK:
1369                new_prop = propDlg.GetClassGroupProperties()
1370                self.SetProperties(new_prop)
1371                self.Refresh()
1372    
1373            propDlg.Destroy()
1374    
1375        def _OnLeftDClick(self, event):
1376            self.DoEdit()

Legend:
Removed from v.376  
changed lines
  Added in v.630

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26