File: InspectableViews.py

package info (click to toggle)
boa-constructor 0.3.0-3
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 8,188 kB
  • ctags: 8,857
  • sloc: python: 54,163; sh: 66; makefile: 36
file content (851 lines) | stat: -rw-r--r-- 33,739 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
#-----------------------------------------------------------------------------
# Name:        InspectableViews.py
# Purpose:     View base class for GUI builder designer classes than can be
#              inspected and edited in the object inspector.
#              Currently: frame designer, data view and collection editors
#
# Author:      Riaan Booysen
#
# Created:     2001
# RCS-ID:      $Id: InspectableViews.py,v 1.17 2004/08/21 19:02:14 riaan Exp $
# Copyright:   (c) 2001 - 2004 Riaan Booysen
# Licence:     GPL
#-----------------------------------------------------------------------------
print 'importing Views.InspectableViews'

import copy, os, pprint

from wxPython.wx import *

import Preferences, Utils

import PaletteMapping, EditorViews
from ObjCollection import ObjectCollection, getCollName

import methodparse, sourceconst

class DesignerError(Exception): pass

class InspectorSessionMix:
    def doPost(self, inspector):
        pass

    def doCancel(self, inspector):
        pass

    def promptPostOrCancel(self, inspector):
        pass

    # Up is included because it can exit a session
    def doUp(self, inspector):
        pass

class InspectableObjectView(EditorViews.EditorView, InspectorSessionMix):
    """ Base class for Designers

    A designer visually maintains one _init_* method in the source.
    """
    viewName = 'InspectableObject'
    collectionMethod = 'init_'
    collectionParams = 'self'
##    handledProps = []
    supportsParentView = false

    def setupArgs(self, ctrlName, params, dontEval, evalDct):
        """ Create a dictionary of parameters for the constructor of the
            control from a dictionary of string/source parameters.
            Catches design time parameter overrides.
        """

        args = {}
        # Build dictionary of params
        for paramKey in params.keys():
            value = params[paramKey]
            ## function references in the constructor
            #if len(value) >= 11 and value[:11] == 'self._init_':
            #    continue
            #    collItem = methodparse.CollectionInitParse(value)
            #    self.addCollView(paramKey, collItem.method, false)
            if paramKey in dontEval:
                args[paramKey] = params[paramKey]
            else:
                try:
                    args[paramKey] = PaletteMapping.evalCtrl(params[paramKey], 
                          evalDct)
                except AttributeError:
                    args[paramKey] = PaletteMapping.evalCtrl(params[paramKey], 
                          {'self': self.controllerView.objectNamespace})

        return args

    def __init__(self, inspector, model, compPal, actions=(), dclickActionIdx=-1, 
          editorIsWindow=true):
        self.compPal = compPal
        EditorViews.EditorView.__init__(self, model, actions, dclickActionIdx, editorIsWindow)
        self.selection = None
        self.inspector = inspector
        self.controllerView = None
        self.objects = {}
        self.objectOrder = []
        self.collEditors = {}
        self.opened = false

    def destroy(self):
        del self.controllerView
        del self.inspector
        for objval in self.objects.values():
            objval[0].destroy()
        for coll in self.collEditors.values():
            coll.destroy()
        del self.collEditors
        del self.objects
        EditorViews.EditorView.destroy(self)

    def doUp(self, inspector):
        self.controllerView.OnSelectParent()

# XXX Consider building subsets of the tree where possible
# XXX may become an issue on frames with many controls
##  decl buildParentRelationship(self) -> (dict, dict)
    def buildParentRelationship(self):
        """ Build a nested dictionary of key = name, value = dict pairs
            describing parental relationship.
            Assuming parents are created before children

            parRel : Nested relationship dictionary
            parRef : Flat reference dictionary
        """

        parRel = {}
        parRef = {}
        for ctrl in self.objectOrder:
            ce = self.objects[ctrl]
            if ce[2] is None:
                parRel[ctrl] = {}
                parRef[ctrl] = parRel[ctrl]
            else:
                parRef[ce[2]][ctrl] = {}
                parRef[ctrl] = parRef[ce[2]][ctrl]

        return  parRel, parRef

    def loadControl(self, ctrlClass, ctrlCompanion, ctrlName, params):
        pass

    def initObjectsAndCompanions(self, creators, objColl, dependents, depLinks):
        collDeps = {}
        for constr in creators:
            self.initObjCreator(constr)
            self.initObjProps(objColl.propertiesByName, constr.comp_name, constr, 
                  dependents, depLinks)
            self.initObjColls(objColl.collectionsByName, constr.comp_name, constr, 
                  collDeps)
            self.initObjEvts(objColl.eventsByName, constr.comp_name, constr)

            self.applyDepsForCtrl(constr.comp_name, depLinks)

        for ctrlName in collDeps.keys():
            for collInit in collDeps[ctrlName]:
                self.addCollView(ctrlName, collInit.method, false)

    def initObjCreator(self, constrPrs):
        # Assumes all design time ctrls are imported in global scope
        try:
            ctrlClass = PaletteMapping.evalCtrl(constrPrs.class_name, 
                  self.model.customClasses)
        except NameError:
            raise DesignerError, \
                  '%s is not defined on the Palette.'%constrPrs.class_name
        try:
            ctrlCompnClass = PaletteMapping.compInfo[ctrlClass][1]
        except KeyError:
            raise DesignerError, \
                  '%s is not defined on the Palette.'%ctrlClass.__name__
        else:
            ctrlName = self.loadControl(ctrlClass, ctrlCompnClass,
              constrPrs.comp_name, constrPrs.params)
            ctrlCompn = self.objects[ctrlName][0]
            ctrlCompn.setConstr(constrPrs)
    
    def initObjProps(self, props, name, creator, dependents, depLinks):
        """ Initialise property list by evaluating 1st parameter and calling
            prop's setter with it.
            Also associate companion name with prop parse objs               """
        # XXX creator not used
        if props.has_key(name):
            comp, ctrl = self.objects[name][0:2]
            # initialise live component's properies
            for prop in props[name]:
                prop.prop_name = comp.getPropNameFromSetter(prop.prop_setter)
                # Dependent properties
                if prop.prop_name in comp.dependentProps():
                    self.addDepLink(prop, name, dependents, depLinks)
                # Collection initialisers
                elif len(prop.params) and prop.params[0][:11] == 'self._init_':
                    collItem = methodparse.CollectionInitParse(prop.params[0])
                    self.addCollView(name, collItem.method, false)
                # Check for custom evaluator
                elif comp.customPropEvaluators.has_key(prop.prop_name):
                    args = comp.customPropEvaluators[prop.prop_name](prop.params, 
                          self.getAllObjects())
                    # XXX This is a hack !!!
                    # XXX argument list with more than one prop value are
                    # XXX initialised thru the companion instead of the control
                    if prop.prop_name in comp.initPropsThruCompanion:
                        apply(getattr(comp, prop.prop_setter), (args,))
                    else:
                        apply(getattr(ctrl, prop.prop_setter), args)
                # Check for pops which don't update the control
                elif prop.prop_name in comp.onlyPersistProps():
                    continue
                # Normal property, eval value and apply it
                else:
                    try:
                        value = PaletteMapping.evalCtrl(prop.params[0], 
                                                        self.model.specialAttrs)
                    except AttributeError, name:
                        value = PaletteMapping.evalCtrl(prop.params[0], 
                          {'self': self.controllerView.objectNamespace})
                    except:
                        print 'Problem with: %s' % prop.asText()
                        raise

                    if prop.prop_name in comp.initPropsThruCompanion:
                        getattr(comp, prop.prop_setter)(value)
                    else:
                        getattr(ctrl, prop.prop_setter)(value)

            # store default prop vals
            comp.setProps(props[name])

    def initObjColls(self, collInits, name, creator, dependents = None):
        """ Initialise collection properties by creating a collection view
            for it and applying it.
            Also associate companion name with prop parse objs               """

        if collInits.has_key(name):
            if dependents is None: dependents = {}
            comp = self.objects[name][0]
            for collInit in collInits[name]:
                if collInit.getPropName() in comp.dependentProps():
                    if not dependents.has_key(name):
                        dependents[name] = []
                    dependents[name].append(collInit)
                else:
                    self.addCollView(name, collInit.method, false)

            # store default collection initialisers
            comp.setCollInits(collInits[name])

    def initObjEvts(self, events, name, creator):
        if events.has_key(name):
            self.objects[name][0].setEvents(events[name])

    def initIdOnlyObjEvts(self, events, creators):
        for crt in creators:
            name = crt.comp_name
            if crt.params.has_key('id'):
                wId = crt.params['id']
                for evt in events:
                    if evt.windowid and evt.windowid == wId:
                        self.objects[name][0].setEvents([evt])

    def addCollView(self, name, collInitMethod, create):
        comp, ctrl = self.objects[name][:2]
        collName = getCollName(collInitMethod, name)
        collCompClass = comp.subCompanions[collName]
        # decl collComp -> CollectionDTC
        collComp = collCompClass(name, self, comp, ctrl)
        if create:
            collComp.persistCollInit(collInitMethod, name, collName)

        collInit = self.model.objectCollections[collInitMethod]
        collComp.setConstrs(collInit.creators, collInit.initialisers,
          collInit.finalisers)

        # init DTCtrl
        for crt in collComp.textConstrLst:
            collComp.applyDesignTimeDefaults(crt.params, crt.method)
        collComp.initCollection()

        comp.collections[collName] = collComp

        collEditView = CollectionEdit.CollectionEditorView(self, self.inspector,
            self.model, collComp)
        collEditView.initialise()

        self.collEditors[(comp.name, collName)] = collEditView

    def getRefsFromProp(self, prop):
        refs = []
        # Build lst of ctrl references from property
        for param in prop.params:
            if len(param) >= 4 and param[:4] == 'self':
                refs.append(Utils.ctrlNameFromSrcRef(param))
        return refs

    def checkAndAddDepLink(self, ctrlName, prop, dependentProps, deps, depLinks, definedCtrls):
        if prop.prop_name in dependentProps:
            refs = self.getRefsFromProp(prop)
            # Postpone if target ctrls not yet defined
            allCtrlsDefined = true#len(refs) > 0
            for ref in refs:
                if ref not in definedCtrls:
                    allCtrlsDefined = false

            if not allCtrlsDefined:
                self.addDepLink(prop, ctrlName, deps, depLinks)
                return true

        return false

    def applyDepsForCtrl(self, ctrlName, depLinks):
        if depLinks.has_key(ctrlName):
            for prop, otherRefs in depLinks[ctrlName]:
                for oRf in otherRefs:
                    if not oRf in self.objectOrder:
                        break
                else:
                    # Dependent properties are usually one parameter name
                    # references
                    comp, ctrl = self.objects[prop.comp_name][:2]
                    if len(prop.params) == 1:
                        if ctrlName is None:
                            value = self.companion.eval(prop.params[0])
                        elif ctrlName == '':
                            value = self
                        else:
                            ord, objs = self.model.allObjects()

                            if objs.has_key(ctrlName):
                                value = objs[ctrlName][1]
                            else:
                                continue
                        if prop.prop_name in comp.initPropsThruCompanion:
                            getattr(comp, prop.prop_setter)(value)
                        else:
                            getattr(ctrl, prop.prop_setter)(value)
                    else:
                        refs = []
                        # Build lst of ctrl references from property
                        for param in prop.params:
                            ctrlSrcName = Utils.ctrlNameFromSrcRef(param)
                            if len(param) >= 4 and param[:4] == 'self' and \
                                  self.objects.has_key(ctrlSrcName):
                                refs.append(self.objects[ctrlSrcName][1])
                            else:
                                refs.append(self.companion.eval(param))

                        apply(getattr(ctrl, prop.prop_setter), refs)

            del depLinks[ctrlName]

    def addDepLink(self, prop, name, dependents, depLinks):
        refs = self.getRefsFromProp(prop)
        # Handle the case where ref is not a designer obj but a constant
        # all such constansts will be grouped under 'None'
        if not refs:
            if not depLinks.has_key(None):
                depLinks[None] = []
            depLinks[None].append( (prop, ()) )
        else:
            for link in refs:
                if not depLinks.has_key(link):
                    depLinks[link] = []
                otherRefs = refs[:]
                otherRefs.remove(link)
                depLinks[link].append( (prop, otherRefs) )

    def finaliseDepLinks(self, depLinks):
        for ctrlName in depLinks.keys():
            self.applyDepsForCtrl(ctrlName, depLinks)

    def renameEventMeth(self, oldName, newName):
        pass

    def renameCtrl(self, oldName, newName):
        """ Rename a control and update all its properties and events."""

        ctrl = self.objects[oldName]
        del self.objects[oldName]
        self.objects[newName] = ctrl

        idx = self.objectOrder.index(oldName)
        del self.objectOrder[idx]
        self.objectOrder.insert(idx, newName)
        # self.objectOrder[self.objectOrder.index(oldName)] = newName

        companion = self.objects[newName][0]
        companion.renameCtrl(oldName, newName)
        companion.renameCtrlRefs(oldName, newName)

        for name, prop in self.collEditors.keys():
            if name == oldName:
                collEditor = self.collEditors[(name, prop)]
                collEditor.renameCtrl(oldName, newName)
                del self.collEditors[(name, prop)]
                self.collEditors[(newName, prop)] = collEditor


    def renameFrame(self, oldName, newName):
        # update windowids & ctrls
        for comp, ctrl, dummy in self.objects.values():
            if not comp.suppressWindowId:
                comp.updateWindowIds()

    def saveCtrls(self, definedCtrls, module=None, collDeps=None):
        """ Replace current source of method in collectionMethod with values from
            constructors, properties and events.
        """

        newBody = []
        deps = {}
        depLinks = {}
        imports = []
        resourceImports = []

        if collDeps is None:
            extraLines = []
        else:
            extraLines = collDeps
        collDeps = []

        if not module:
            module = self.model.getModule()

        for collView in self.collEditors.values():
            collView.saveCtrls(module)

        # XXX Move toolbar up to the 1st position after the frame

        for ctrlName in self.objectOrder:
            definedCtrls.append(ctrlName)
            compn = self.objects[ctrlName][0]

            compn.writeConstructor(newBody, self.collectionMethod)
            compn.writeProperties(newBody, ctrlName, definedCtrls, deps, depLinks)
            compn.writeCollections(newBody, collDeps)
            compn.writeEvents(newBody, module=module)

            compn.writeDependencies(newBody, ctrlName, depLinks, definedCtrls)

            imp = compn.writeImports()
            if imp and imp not in imports:
                imports.append(imp)

            imp = compn.writeResourceImports()
            if imp and imp not in resourceImports:
                resourceImports.append(imp)

            if Preferences.cgEmptyLineBetweenObjects:
                newBody.append('')

        if not newBody or newBody[-1]:
            newBody.append('')

        if collDeps:
            newBody.extend(collDeps + [''])
            
        if extraLines:
            newBody.extend(extraLines + [''])

        for imp in imports:
            imps = imp.split('\n')
            for imp in imps:
                imp = imp.strip()
                if imp:
                    module.addImportStatement(imp)

        for imp in resourceImports:
            imps = imp.split('\n')
            for imp in imps:
                imp = imp.strip()
                if imp:
                    module.addImportStatement(imp, resourceImport=true)

        emptyCodeBlock = newBody == ['']

        if Preferences.cgAddInitMethodWarning:
            newBody.insert(0, '%s# %s'%(sourceconst.bodyIndent,
                                        sourceconst.code_gen_warning))

        if module.classes[self.model.main].methods.has_key(\
          self.collectionMethod):
            # Add doc string
            docs = module.getClassMethDoc(self.model.main,
              self.collectionMethod)
            if (len(docs) > 0) and docs[0]:
                newBody.insert(0, '%s""" %s """'%(sourceconst.bodyIndent, docs))
                emptyCodeBlock = false

            if emptyCodeBlock:
                module.removeMethod(self.model.main, self.collectionMethod)
                #newBody[-1:-1] = [sourceconst.bodyIndent+'pass']
            else:
                module.replaceMethodBody(self.model.main, self.collectionMethod, 
                      newBody)
        else:
            if not emptyCodeBlock:
                module.addMethod(self.model.main,
                  self.collectionMethod, self.collectionParams, newBody, 0)

    def copyCtrls(self, selCtrls, definedCtrls, output):
        """ Write out current source of selection to a text line list.
        """

        ctrlsAndContainedCtrls = self.expandNamesToContainers(selCtrls)
        deps = {}
        depLinks = {}
        collDeps = []

        collMeths = []
        for compName, collProp in self.collEditors.keys():
            if compName in ctrlsAndContainedCtrls:
                collView = self.collEditors[(compName, collProp)]
                collMeth = []
                collView.copyCtrls(collMeth)
                collMeths.append(collMeth)

        output.insert(0, '%sdef %s(%s):'% (sourceconst.methodIndent,
              self.collectionMethod, self.collectionParams))
        for ctrlName in ctrlsAndContainedCtrls:
            definedCtrls.append(ctrlName)
            compn = self.objects[ctrlName][0]

            compn.updatePosAndSize()

            frmName = self.model.main
            compn.writeConstructor(output, self.collectionMethod, stripFrmId=frmName)
            compn.writeProperties(output, ctrlName, definedCtrls, deps, depLinks, stripFrmId=frmName)
            compn.writeCollections(output, collDeps, stripFrmId=frmName)
            compn.writeEvents(output, stripFrmId=frmName)

            compn.writeDependencies(output, ctrlName, depLinks, definedCtrls, stripFrmId=frmName)

            output.append('')

        if collDeps:
            output.extend(collDeps + [''])

        collMeths.reverse()
        for methBody in collMeths:
            output[0:0] = methBody + ['']

    def cutCtrls(self, selCtrls, definedCtrls, output):
        # Copy to output
        self.copyCtrls(selCtrls, definedCtrls, output)
        self.selectNone()

        # Delete ctrls
        for ctrl in selCtrls:
            self.deleteCtrl(ctrl)

    def pasteCtrls(self, destCtrlName, input):
        # Split up into methods
        methList = []
        for line in input:
            splitLine = line.split()
            if len(splitLine) >= 2 and splitLine[0] == 'def':
                meth = splitLine[1][:splitLine[1].find('(')]
                currMeth = [meth]
                methList.append(currMeth)
            else:
                try:
                    currMeth.append(line)
                except NameError:
                    print 'PASTE ERROR', input
        if not methList:
            raise 'Nothing to paste'

        collObjColls = []
        pastedCtrls = []
        collMethod = ''
        # find main method
        idx = -1
        for meth in methList[:]:
            idx = idx + 1
            if meth[0] == self.collectionMethod:
                collMethod = meth[0]
                methBody = meth[1:]
            else:
                # XXX not good :(
                ctrlName = methodparse.ctrlNameFromMeth(meth[0])
                newObjColl = self.model.readDesignerMethod(meth[0], meth[1:])
                methodparse.decorateParseItems(
                      newObjColl.creators + newObjColl.events,
                      ctrlName, self.model.main)

                for plp in newObjColl.creators + newObjColl.events + \
                      newObjColl.properties + newObjColl.collections:
                    plp.prependFrameWinId(self.model.main)

                collObjColls.append( (meth[0], ctrlName, newObjColl) )

        if not collMethod:
            raise DesignerError, 'Method % not found' % self.collectionMethod

        # Parse input source
        objCol = self.model.readDesignerMethod(collMethod, methBody)

        if not len(objCol.creators):
            return []

        # Fixup window ids
        for plp in objCol.creators + objCol.events + objCol.properties + \
              objCol.collections:
            plp.prependFrameWinId(self.model.main)

        # Rename possible name clashes
        objCol.indexOnCtrlName()
        pasteNameClasses = objCol.getCtrlNames()
        
        for name, cls in pasteNameClasses:
            if objCol.eventsByName.has_key(name):
                methodparse.decorateParseItems(objCol.eventsByName[name], name, 
                      self.model.main)
        
        newNames = []
        oldNames = []
        # Preserve order, but determine all new names before creating objs
        for name, clss in pasteNameClasses:
            if name in self.objectOrder:
                newName = self.newObjName(clss, newNames)
                newNames.append(newName)
                oldNames.append(name)
            else:
                newNames.append(name)
                oldNames.append(name)

        for oldName, newName in map(None, oldNames, newNames):
            if newName != oldName:
                objCol.renameCtrl(oldName, newName)
                pastedCtrls.append(newName)
                for idx in range(len(collObjColls)):
                    meth, collCtrlName, collObjColl = collObjColls[idx]
                    collObjColl.renameCtrl(oldName, newName)
                    if collCtrlName == oldName:
                        itms = meth.split('_')
                        itms[3:-1] = [newName]
                        collObjColls[idx] = ('_'.join(itms), newName, collObjColl)
            else:
                pastedCtrls.append(oldName)

        # Update model's object collections' collections
        for meth, collCtrlName, collObjColl in collObjColls:
            self.model.objectCollections[meth] = collObjColl

        # Get previous parent, 1st item in the group's parent will always be
        # the root parent
        # Only reparent visual controls
        if objCol.creators[0].params.has_key('parent'):
            copySource = objCol.creators[0].params['parent']
            objCol.reparent(copySource, Utils.srcRefFromCtrlName(destCtrlName))

        # create controls
        deps = {}
        depLnks = {}
        self.inspector.vetoSelect = true
        try:
            self.initObjectsAndCompanions(objCol.creators, objCol, deps, depLnks)
        finally:
            self.inspector.vetoSelect = false

        # merge pasted controls with current controls
        self.model.objectCollections[collMethod].merge(objCol)

        return pastedCtrls

    def addObject(self, ctrlName, companion, designTimeCtrl, parentName = None):
        self.objects[ctrlName] = [companion, designTimeCtrl]
        if parentName is not None: self.objects[ctrlName].append(parentName)
        self.objectOrder.append(ctrlName)

    def newObjName(self, className, additionalNames = None):
        """ Return a name for a control unique in the scope of the model. """

        if additionalNames is None: additionalNames = []
        # XXX Now that there is multiple maintained methods is may fail because
        # XXX it's only unique in the method.
        num = 1
        if className[:2] == 'wx':
            newName = '%s%s'%(className[2:3].lower(), className[3:])
        else:
            newName = '%s%s'%(className[0].lower(), className[1:])

        return Utils.getValidName(self.objects.keys() + additionalNames, newName)

    def newObject(self, ObjClass, ObjCompanionClass):
        """ At design time, when adding a new ctrl from the palette, create and
            register given control and companion.
        """
        self.checkHost(ObjCompanionClass)

        # XXX Only DataView uses this, refc
        objName = self.newObjName(ObjClass.__name__)

        companion = ObjCompanionClass(objName, self, ObjClass)
        params = companion.designTimeSource()
        self.addObject(objName, companion, companion.designTimeObject(), '')
        companion.persistConstr(ObjClass.__name__, params)
        return objName


    def addCtrlToObjectCollection(self, textConstr):
        colMeth = self.collectionMethod
        if not self.model.objectCollections.has_key(colMeth):
            self.model.objectCollections[colMeth] = ObjectCollection()

        self.model.objectCollections[colMeth].creators.append(textConstr)

    def addCollToObjectCollection(self, collInitParse):
        colMeth = self.collectionMethod
        self.model.objectCollections[colMeth].collections.append(collInitParse)
        # Add a new method to maintained methods
        newObjColl = ObjectCollection()
        self.model.objectCollections[collInitParse.method] = newObjColl
        return newObjColl

    def selectObject(self):
        pass

    def selectNone(self):
        pass

    def deleteCtrl(self, name, parentRef = None):
        self.model.objectCollections[self.collectionMethod].deleteCtrl(name)
        del self.objectOrder[self.objectOrder.index(name)]
        del self.objects[name]

        for ctrlName, propName in self.collEditors.keys()[:]:
            if ctrlName == name:
#                self.collEditors[(ctrlName, propName)].close()
                if self.collEditors[(ctrlName, propName)].frame:
                    self.collEditors[(ctrlName, propName)].frame.Close()
                del self.collEditors[(ctrlName, propName)]

    def cleanup(self):
        if self == self.inspector.prevDesigner[0]:
            self.inspector.prevDesigner = (None, None)

    def close(self):
        if self.controllerView and self.controllerView != self:
            self.controllerView.close()

    def refreshContainment(self, selectName = None):
        """ Rebuild parent tree and optionally select given control """
        parRelations, parReference = self.buildParentRelationship()
        self.inspector.containment.refreshCtrl(self.model.main, parRelations, self)
        if selectName is not None:
            self.inspector.containment.selectName(selectName)
        return parRelations, parReference

##  decl getObjectsOfClass(self, theClass: class) -> dict
    def getObjectsOfClass(self, theClass):
        results = {}
        for objName in self.objects.keys():
            if issubclass(self.objects[objName][1].__class__, theClass):
                if objName:
                    results['self.'+objName] = self.objects[objName][1]
                else:
                    results['self'] = self.objects[objName][1]
        return results

    def getObjectsOfClassWithParent(self, theClass, theParentName):
        results = {}
        for objName in self.objects.keys():
            if self.objects[objName][2] == theParentName and \
                  isinstance(self.objects[objName][1], theClass):
                if objName:
                    results['self.'+objName] = self.objects[objName][1]
                else:
                    results['self'] = self.objects[objName][1]
        return results

    def getAllObjects(self):
        results = {}
        for objName in self.objects.keys():
            if objName:
                results['self.'+objName] = self.objects[objName][1]
            else:
                results['self'] = self.objects[objName][1]
        return results

    def getObjectsOfClassOwnedBy(self, theClass, theOwner):#XXX
        results = {}
        for objName in self.objects.keys():
            if self.objects[objName][1].__class__ is theClass:
                results['self.'+objName] = self.objects[objName][1]
        return results

    def showCollectionEditor(self, ctrlName, propName, show=true):
        """ Show the Collection Editor frame for given name and prop """
        # XXX param ctrlName is actually wrong!
        if ctrlName == self.GetName():
            ctrlName = ''

        if not self.collEditors.has_key((ctrlName, propName)):
            self.addCollView(ctrlName, '_init_coll_%s_%s'%(ctrlName, propName), true)

        collEditor = self.collEditors[(ctrlName, propName)]
        
        if show:
            collEditor.show()
        else:
            return collEditor

    def checkHost(self, CtrlCompanion):
        """ Checks that the companion may be hosted in this designer """
        if CtrlCompanion.host == 'Not Implemented':
            dlg = wxMessageDialog(self, 'This component is not yet implemented',
                              'Not Implemented', wxOK | wxICON_ERROR)
            try: dlg.ShowModal()
            finally: dlg.Destroy()
            raise DesignerError, 'Not Implemented'
        if CtrlCompanion.host != self.viewName:
            dlg = wxMessageDialog(self,
              'This component must be created in the '+CtrlCompanion.host+' view',
              'Wrong Designer', wxOK | wxICON_ERROR)
            try: dlg.ShowModal()
            finally: dlg.Destroy()
            raise DesignerError, 'Wrong Designer'

    def expandNamesToContainers(self, ctrlNames):
        """ Expand set of names to include the names of all their children """
        return ctrlNames

    def collapseNamesToContainers(self, ctrlNames):
        """ Collapse set of names to exclude the names of all their children """
        return ctrlNames

    def notifyAction(self, compn, action):
        # notify components
        for otherCompn, otherCtrl, otherPrnt in self.objects.values():
            otherCompn.notification(compn, action)

        # notify collections
        for collView in self.collEditors.values():
            collView.companion.notification(compn, action)

    def showCreationOrderDlg(self, selName):
        sibs = []
        allNames = []
        idx = -1
        for objName in self.objectOrder:
            idx = idx + 1
            ctrl, parent = self.objects[objName][1:3]
            if parent == selName:
                sibs.append( (idx, objName) )
                allNames.append(objName)

        allNames = self.expandNamesToContainers(allNames)
        allSibs = []
        for name in allNames:
            allSibs.append( (self.objectOrder.index(name), name) )

        from CreationOrdDlg import CreationOrderDlg
        dlg = CreationOrderDlg(self, sibs, allSibs)
        if dlg.ShowModal() == wxID_OK:
            for idx, name in map(None, dlg.allCtrlIdxs, dlg.allCtrlNames):
                self.objectOrder[idx] = name

import CollectionEdit