~toolpart/+junk/pythoncard

« back to all changes in this revision

Viewing changes to tools/experimentalResourceEditor/modules/propertyEditor.py

  • Committer: Bazaar Package Importer
  • Author(s): Sandro Tosi
  • Date: 2010-03-04 23:55:10 UTC
  • mfrom: (3.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20100304235510-3v6lbhzwrgm0pcca
Tags: 0.8.2-1
* QA upload.
* New upstream release
* debian/control
  - set maintainer to QA group
  - set Homepage field, removing the URL from packages description
  - bump versioned b-d-i on python-support, to properly support Python module
  - replace b-d on python-all-dev with python-all, since building only
    arch:all packages
  - replace Source-Version substvar with source:Version
  - add ${misc:Depends} to binary packages Depends
* debian/watch
  - updated to use the SourceForge redirector; thanks to Raphael Geissert for
    the report and to Dario Minnucci for the patch; Closes: #449904
* debian/{pythoncard-doc, python-pythoncard}.install
  - use wildcards instead of site-packages to fix build with python 2.6;
    thanks to Ilya Barygin for the report and patch; Closes: #572332
* debian/pythoncard-doc.doc-base
  - set section to Programmin/Python
* debian/pythoncard-tools.menu
  - set menu main section to Applications
* debian/pythoncard-tools.postinst
  - removed, needed only to update the menu, but it's now created by debhelper

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
 
 
3
"""
 
4
__version__ = "$Revision: 1.2 $"
 
5
__date__ = "$Date: 2004/12/31 20:44:29 $"
 
6
"""
 
7
 
 
8
from PythonCard import dialog, font, model, registry, util
 
9
from PythonCard.event import ChangeListener
 
10
import resourceOutput
 
11
import time
 
12
import os
 
13
import string
 
14
 
 
15
import wx
 
16
 
 
17
# KEA this is a load of dingos' kidneys and needs to be rewritten
 
18
# 2002-02-22
 
19
# now I'm compounding the problem by porting from the original
 
20
# Property Editor to a PythonCard background
 
21
class PropertyEditor(model.Background, ChangeListener):
 
22
 
 
23
    def on_initialize(self, event):
 
24
        self._parent = self.GetParent()
 
25
        self._comp = self._parent.components
 
26
        self._updatingComponent = 0
 
27
        self.autoAttributeUpdate = True
 
28
        ##self.components.addChangeEventListener(self)
 
29
        self._comp.addChangeEventListener(self)
 
30
        
 
31
        self.checkItems = ['enabled', 'visible', 'editable', 'checked', 'default', \
 
32
            'rules', 'labels', 'ticks', 'horizontalScrollbar']
 
33
        self.popItems = ['layout', 'border', 'style', 'alignment', 'stringSelection']
 
34
        self.cantModify = ['id', 'name', 'alignment', 'layout', 'style', 'border', \
 
35
            'horizontalScrollbar', 'min', 'max', 'columns', 'rules', 'labels', 'ticks']
 
36
 
 
37
        self.editItems = [self.components.wField, self.components.wColor,
 
38
                          self.components.wFont, self.components.wTextArea,
 
39
                          self.components.wChecked, self.components.wPop,
 
40
                          self.components.wFile,]        
 
41
 
 
42
        # KEA 2001-08-14
 
43
        # this was causing an assertion error with the hybrid wxPython
 
44
        #self.components.wComponentList.SetSelection(0)
 
45
        if self.components.wComponentList.stringSelection == "":
 
46
            wClass = ""
 
47
        else:
 
48
            wName, wClass = self.components.wComponentList.stringSelection.split("  :  ")
 
49
        self.setValidProps(wClass)
 
50
        
 
51
        #self.displayComponents(self.components)
 
52
        self.displayComponents(self._comp)
 
53
        self.visible = True
 
54
 
 
55
    # KEA 2004-08-23
 
56
    # support updating of attributes without the need
 
57
    # for clicking the Update button
 
58
    def on_wField_closeField(self, event):
 
59
        if self.autoAttributeUpdate:
 
60
            self.updateComponent()
 
61
 
 
62
    def on_wTextArea_closeField(self, event):
 
63
        if self.autoAttributeUpdate:
 
64
            self.updateComponent()
 
65
 
 
66
    def on_wChecked_mouseClick(self, event):
 
67
        if self.autoAttributeUpdate:
 
68
            self.updateComponent()
 
69
 
 
70
    def on_wPop_select(self, event):
 
71
        if self.autoAttributeUpdate:
 
72
            self.updateComponent()
 
73
 
 
74
    def on_wColor_mouseClick(self, event):
 
75
        result = dialog.colorDialog(self, color=util.colorFromString(self.components.wField.text))
 
76
        if result.accepted:
 
77
            self.components.wField.text = str(result.color)
 
78
            if self.autoAttributeUpdate:
 
79
                self.updateComponent()
 
80
 
 
81
    def on_wFont_mouseClick(self, event):
 
82
        wName, wClass = self.components.wComponentList.stringSelection.split("  :  ")
 
83
        ##widget = self.components[wName]
 
84
        widget = self._comp[wName]
 
85
        f = widget.font
 
86
        if f is None:
 
87
            desc = font.fontDescription(widget.GetFont())
 
88
            f = font.Font(desc)
 
89
        result = dialog.fontDialog(self, f)
 
90
        if result.accepted:
 
91
            #color = dlg.getColor()
 
92
            f = result.font
 
93
            #self.components.wField.SetValue("%s;%s" % (f, color))
 
94
            self.components.wField.text = "%s" % f
 
95
            if self.autoAttributeUpdate:
 
96
                self.updateComponent()
 
97
 
 
98
    def on_wFile_mouseClick(self, event):
 
99
        path, filename = os.path.split(self.components.wField.text)
 
100
        result = dialog.openFileDialog(self, directory=path, filename=filename)
 
101
        if result.accepted:
 
102
            self.components.wField.text = util.relativePath(self._parent.filename, result.paths[0])
 
103
            if self.autoAttributeUpdate:
 
104
                self.updateComponent()
 
105
 
 
106
 
 
107
    def addWidgetToComponentList(self, widget):
 
108
        wName = widget.name
 
109
        # KEA 2004-01-25
 
110
        # just use __name__, the other code must have been something from wxPython 2.3
 
111
        #wClass = str(widget.__class__).split('.')
 
112
        #self.components.wComponentList.Append(wName + "  :  " + wClass[len(wClass) - 1])
 
113
        wClass = widget.__class__.__name__
 
114
        self.components.wComponentList.Append(wName + "  :  " + wClass)
 
115
 
 
116
    # KEA 2002-02-23
 
117
    # need to redo the logic below to avoid asserts in hybrid
 
118
    # versions of wxPython, but also be cleaner
 
119
    def deleteWidgetFromComponentList(self, wName, wClass):
 
120
        i = self.components.wComponentList.GetSelection()
 
121
        j = self.components.wComponentList.FindString(wName + "  :  " + wClass)
 
122
        if i == -1 or i != j:
 
123
            if j != -1: 
 
124
                self.components.wComponentList.Delete(j)
 
125
        else:
 
126
            if j > 0:
 
127
                self.components.wComponentList.SetSelection(j - 1)
 
128
            if j != -1:
 
129
                self.components.wComponentList.Delete(j)
 
130
            if self.components.wComponentList.GetSelection() == -1:
 
131
                self.setValidProps("")
 
132
                self.hideAllBut(self.components.wField)
 
133
            else:
 
134
                wName, wClass = self.components.wComponentList.stringSelection.split("  :  ")
 
135
                # deselect the name from properties list
 
136
                self.setValidProps(wClass)
 
137
                propName = self.components.wPropertyList.stringSelection
 
138
                if propName == "":
 
139
                    propName = "name"
 
140
                    self.components.wPropertyList.stringSelection = "name"
 
141
                self.displayProperty(wName, wClass, propName)
 
142
 
 
143
    def selectComponentList(self, wName, wClass):
 
144
        self.components.wComponentList.stringSelection = wName + "  :  " + wClass
 
145
        self.setValidProps(wClass)
 
146
        propName = self.components.wPropertyList.stringSelection
 
147
        #print propName
 
148
        if propName == "":
 
149
            propName = "name"
 
150
            self.components.wPropertyList.stringSelection = "name"
 
151
        self.displayProperty(wName, wClass, propName)
 
152
        c = self._parent.components[wName]
 
153
        if hasattr(c, 'position'):
 
154
            # AB 2004-12-31
 
155
            # Don't set a tooltip pos for components that don't have a pos - they aren't displayed.
 
156
            self._parent.setToolTipDrag(wName, c.position, c.size)
 
157
 
 
158
    def changed(self, event):
 
159
        ##comp = self.components
 
160
        if self._updatingComponent:
 
161
            # KEA 2003-01-04
 
162
            # hack to speed up updates in place
 
163
            return
 
164
 
 
165
        comp = self._comp
 
166
        wName, wClass = event.getOldValue().split(",")
 
167
        if wName in comp:
 
168
            # new item added
 
169
            self.addWidgetToComponentList(comp[wName])
 
170
        else:
 
171
            # item deleted
 
172
            self.deleteWidgetFromComponentList(wName, wClass)
 
173
 
 
174
    """
 
175
    def on_wCopy_mouseClick(self, event):
 
176
        wName, wClass = self.components.wComponentList.stringSelection.split("  :  ")
 
177
        # what needs to happen here is to have a method for the Widget class that
 
178
        # will provide a valid resource description, each subclass of widget would
 
179
        # override the method to deal with their specific resource attributes
 
180
        # the Widget class should provide some ordering so that 'type',
 
181
        # 'position', 'size' comes before less commonly used items, the actual
 
182
        # ordering could just be defined in a list, so it is easy to change
 
183
        # also, if the current values match the defaults for a widget attribute
 
184
        # then that attribute should not be provided as part of the output
 
185
        print "this is just a placeholder method right now,"
 
186
        print "the resource is not actually copied to the clipboard yet"
 
187
        pprint.pprint(self._comp[wName])
 
188
    """
 
189
 
 
190
    def on_wUpdate_mouseClick(self, event):
 
191
        self.updateComponent()
 
192
 
 
193
    def updateComponent(self):
 
194
        wName, wClass = self.components.wComponentList.stringSelection.split("  :  ")
 
195
        propName = self.components.wPropertyList.stringSelection
 
196
        
 
197
        if propName in self.checkItems:
 
198
            value = self.components.wChecked.checked
 
199
        elif propName in self.popItems:
 
200
            value = self.components.wPop.stringSelection
 
201
        elif propName in ('items', 'userdata') or (wClass == 'TextArea' and propName == 'text'):
 
202
            value = self.components.wTextArea.text
 
203
        else:
 
204
            #value = self.components.wField.GetValue()
 
205
            value = self.components.wField.text
 
206
 
 
207
        if propName not in ['label', 'stringSelection', 'text', 'toolTip', 'userdata']:
 
208
            try:
 
209
                value = eval(value)
 
210
            except:
 
211
                pass
 
212
 
 
213
        # KEA 2004-05-10
 
214
        # need to figure out where to stick validation code
 
215
        # but for now just need to make sure that if we're changing the name
 
216
        # attribute that it is valid, but similar checks will be necessary for
 
217
        # integer fields, a list of items, etc.
 
218
        # also maybe each attribute should have a doc or help string displayed
 
219
        # saying what the attribute does, example values, etc.
 
220
        if propName == 'name':
 
221
            badValue = False
 
222
            # if it isn't valid then display an alert and exit
 
223
            # must start with a letter and only contain alphanumeric characters
 
224
            if value == "" or value[0] not in string.ascii_letters:
 
225
                badValue = True
 
226
            else:
 
227
                alphanumeric = string.ascii_letters + string.digits
 
228
                for c in value:
 
229
                    if c not in alphanumeric:
 
230
                        badValue = True
 
231
                        break
 
232
            if badValue:
 
233
                dialog.alertDialog(None, "Name must start with a letter and only contain letters and numbers.", 'Error: Name is invalid')
 
234
                self.components.wField.setFocus()
 
235
                self.components.wField.setSelection(-1, -1)
 
236
                return
 
237
            # check for duplicate names is done below
 
238
 
 
239
        ##widget = self.components[wName]
 
240
        widget = self._comp[wName]
 
241
 
 
242
        # KEA 2002-02-23
 
243
        # I can't remember why this is actually necessary
 
244
        if propName == 'size':
 
245
            width, height = value
 
246
            if wClass not in ['BitmapCanvas', 'HtmlWindow']:
 
247
                bestWidth, bestHeight = widget.GetBestSize()
 
248
                if width == -1:
 
249
                    width = bestWidth
 
250
                if height == -1:
 
251
                    height = bestHeight
 
252
            widget.size = (width, height)
 
253
            #setattr(widget, propName, (width, height))
 
254
            #print widget.size, propName, width, height
 
255
        else:
 
256
            if (propName in self.cantModify) or \
 
257
               (propName == 'items' and wClass == 'RadioGroup'):
 
258
                order = self._comp.order.index(wName)
 
259
                desc = resourceOutput.widgetAttributes(self._parent, widget)
 
260
                if desc.endswith(',\n'):
 
261
                    desc = eval(desc[:-2])
 
262
                else:
 
263
                    desc = eval(desc)
 
264
 
 
265
                if propName == 'name':
 
266
                    if value == wName:
 
267
                        # user didn't actually change the name
 
268
                        return
 
269
                    elif value in self._comp:
 
270
                        # we already have a component with that name
 
271
                        dialog.alertDialog(self, 'Another component already exists with the name ' + value,
 
272
                                           'Error: unable to rename component')
 
273
                        return
 
274
                if value is None:
 
275
                    desc[propName] = 'none'
 
276
                elif propName in ['min', 'max']:
 
277
                    desc[propName] = int(value)
 
278
                else:
 
279
                    desc[propName] = value
 
280
 
 
281
                # need to experiment with freeze and thaw to avoid
 
282
                # a lot of update events
 
283
                startTime = time.time()
 
284
 
 
285
                # this is going to trigger a changed event
 
286
                # as we delete the old component
 
287
                self._updatingComponent = True
 
288
                del self._comp[wName]
 
289
                if propName == 'name':
 
290
                    wName = value
 
291
                # this is going to trigger another changed event
 
292
                # as we create a new component with the changed attribute
 
293
                self._comp[wName] = desc
 
294
                c = self._comp[wName]
 
295
                wx.EVT_LEFT_DOWN(c, self._parent.on_mouseDown)
 
296
                wx.EVT_LEFT_UP(c, self._parent.on_mouseUp)
 
297
                wx.EVT_MOTION(c, self._parent.on_mouseDrag)
 
298
 
 
299
 
 
300
                # now restore the order of the component
 
301
                # have to update the startName in case the name was updated
 
302
                if propName == 'name':
 
303
                    self._parent.startName = wName
 
304
                self._comp.order.remove(wName)
 
305
                self._comp.order.insert(order, wName)
 
306
 
 
307
                self._parent.fixComponentOrder(wName)
 
308
 
 
309
                self._updatingComponent = False
 
310
                
 
311
                endTime = time.time()
 
312
                #print "attribute change took:", endTime - startTime
 
313
            else:
 
314
                if wClass in ['Image', 'ImageButton'] and propName == 'file':
 
315
                    cwd = os.getcwd()
 
316
                    try:
 
317
                        os.chdir(self._parent.filename)
 
318
                    except:
 
319
                        pass
 
320
                    setattr(widget, propName, value)
 
321
                    os.chdir(cwd)
 
322
                else:
 
323
                    setattr(widget, propName, value)
 
324
                    #print propName, value
 
325
        # KEA 2002-02-23
 
326
        self._parent.showSizingHandles(wName)
 
327
 
 
328
    def setValidProps(self, wClass):
 
329
        #print "setValidProps", wClass
 
330
        oldProp = self.components.wPropertyList.stringSelection
 
331
        if wClass == "":
 
332
            self.components.wPropertyList.Clear()
 
333
        else:
 
334
            ##props = self.propList + self.optionalProps[wClass]
 
335
            ##props.sort()
 
336
            ##print "props", props
 
337
            # get the property (attribute) list from the spec
 
338
            klass = registry.Registry.getInstance().getComponentClass(wClass)
 
339
            props = klass._spec.getAttributes().keys()
 
340
 
 
341
            # KEA 2002-03-24
 
342
            # only show the 'id' attribute for Button
 
343
            # and only when displaying dialog properties
 
344
            if not (self._parent.editingDialog and wClass == 'Button'):
 
345
                # AB 2004-12-31
 
346
                # The id attrib is optional, and may not be present. All widgets will have
 
347
                # IDs, but Components may not. If it is not present, then we don't need to remove it.
 
348
                if 'id' in props:
 
349
                    props.remove('id')
 
350
            
 
351
            # AB 2004-12-31
 
352
            # Don't show the action bindings at all. Edit them only via the action binding dialog.
 
353
            if 'actionBindings' in props:
 
354
                props.remove('actionBindings')
 
355
            props.sort()
 
356
            ##print "spec props", specProps
 
357
            
 
358
            self.components.wPropertyList.Clear()
 
359
            self.components.wPropertyList.InsertItems(props, 0)
 
360
            if oldProp in props:
 
361
                self.components.wPropertyList.stringSelection = oldProp
 
362
 
 
363
    def hideAllBut(self, widget):
 
364
        for w in self.editItems:
 
365
            if widget.id != w.id:
 
366
                w.visible = False
 
367
 
 
368
    def displayProperty(self, wName, wClass, propName):
 
369
        self.components.wName.text = propName + ":"
 
370
        ##widget = self.components[wName]
 
371
        widget = self._comp[wName]
 
372
        if propName in ['label', 'stringSelection', 'text', 'toolTip'] or propName in self.checkItems:
 
373
            value = getattr(widget, propName)
 
374
        else:
 
375
            value = str(getattr(widget, propName))
 
376
        
 
377
        if propName in self.checkItems:
 
378
            self.hideAllBut(self.components.wChecked)
 
379
            self.components.wChecked.visible = True
 
380
            self.components.wChecked.checked = value
 
381
        elif propName in self.popItems:
 
382
            self.hideAllBut(self.components.wPop)
 
383
            self.components.wPop.visible = True
 
384
            self.components.wPop.Clear()
 
385
            if propName == 'stringSelection':
 
386
                for v in widget.items:
 
387
                    self.components.wPop.Append(v)
 
388
            else:
 
389
                for v in widget._spec.getAttributes()[propName].values:
 
390
                    self.components.wPop.Append(v)
 
391
            try:
 
392
                self.components.wPop.stringSelection = value
 
393
            except:
 
394
                # if value is empty or doesn't already exist
 
395
                pass
 
396
        elif propName in ('items', 'userdata') or (wClass == 'TextArea' and propName == 'text'):
 
397
            #print 'displaying TextArea'
 
398
            self.hideAllBut(self.components.wTextArea)
 
399
            self.components.wTextArea.visible = True
 
400
            self.components.wTextArea.text = value
 
401
        else:
 
402
            self.hideAllBut(self.components.wField)
 
403
            self.components.wField.visible = True
 
404
            if propName == 'foregroundColor' or propName == 'backgroundColor':
 
405
                self.components.wColor.visible = True
 
406
            elif propName == 'font':
 
407
                self.components.wFont.visible = True
 
408
            elif propName == 'file':
 
409
                self.components.wFile.visible = True
 
410
            self.components.wName.text = propName + ":"
 
411
                    
 
412
            # KEA 2002-02-23
 
413
            # I can't remember why this is actually necessary
 
414
            if propName == 'size':
 
415
                width, height = getattr(widget, propName)
 
416
                if wClass not in ['BitmapCanvas', 'HtmlWindow']:
 
417
                    bestWidth, bestHeight = widget.GetBestSize()
 
418
                    if width == bestWidth:
 
419
                        width = -1
 
420
                    if height == bestHeight:
 
421
                        height = -1
 
422
                size = (width, height)
 
423
                value = str(size)
 
424
 
 
425
            self.components.wField.text = value
 
426
        # this should only display if the attribute is settable
 
427
        # so name, alignment, and others are read-only
 
428
        # KEA 2002-02-23
 
429
        # wUpdate is always visible now
 
430
        self.components.wUpdate.visible = True
 
431
 
 
432
    def on_wComponentList_select(self, event):
 
433
        #print 'selectComponentListEvent: %s\n' % event.GetString()
 
434
        wName, wClass = event.GetString().split("  :  ")
 
435
        # change the wPropertiesList to only show relevant properties
 
436
        # either display the name by default or try and preserve the
 
437
        # wPropertiesList selection and display that item, so for example
 
438
        # you could look at size for all widgets, simply by going up and down
 
439
        # the components list
 
440
        self.setValidProps(wClass)
 
441
        propName = self.components.wPropertyList.stringSelection
 
442
        #print propName
 
443
        if propName == "":
 
444
            propName = "name"
 
445
            self.components.wPropertyList.stringSelection = "name"
 
446
        self.displayProperty(wName, wClass, propName)
 
447
        c = self._parent.components[wName]
 
448
        if hasattr(c, 'position'):
 
449
            self._parent.showSizingHandles(wName)
 
450
            self._parent.setToolTipDrag(wName, c.position, c.size)
 
451
 
 
452
    def on_wPropertyList_select(self, event):
 
453
        propName = event.GetString()
 
454
        wName, wClass = self.components.wComponentList.stringSelection.split("  :  ")
 
455
        if wName != "":
 
456
            self.displayProperty(wName, wClass, propName)
 
457
 
 
458
    def clearComponentList(self):
 
459
        self.components.wComponentList.Clear()
 
460
        self.statusBar.text = ''
 
461
 
 
462
    def clearPropertyList(self):
 
463
        self.components.wPropertyList.Clear()
 
464
 
 
465
    def displayComponents(self, components):
 
466
        self.components.wComponentList.Freeze()
 
467
        self.components.wComponentList.Clear()
 
468
        self._comp = components
 
469
        for c in components.order:
 
470
            if c not in self._parent.sizingHandleNames:
 
471
                self.addWidgetToComponentList(components[c])
 
472
        self.components.wComponentList.Thaw()
 
473
        self.components.wComponentList.Refresh()
 
474
        self.components.wComponentList.Update()
 
475
 
 
476
    def on_close(self, event):
 
477
        self.visible = False
 
478
        parent = self.GetParent()
 
479
        parent.menuBar.setChecked('menuViewPropertyEditor', 0)