1__all__ = ('object_property', 'bool_property', 2 'array_property', 'set_property', 'dict_property') 3 4from objc import ivar, selector, _C_ID, _C_NSBOOL, _C_BOOL, NULL, _C_NSUInteger 5from objc import lookUpClass 6import collections 7from copy import copy as copy_func 8import sys 9 10NSSet = lookUpClass('NSSet') 11NSObject = lookUpClass('NSObject') 12 13 14def attrsetter(prop, name, copy): 15 if copy: 16 def func(self, value): 17 if isinstance(value, NSObject): 18 setattr(self, name, value.copy()) 19 else: 20 setattr(self, name, copy_func(value)) 21 else: 22 def func(self, value): 23 setattr(self, name, value) 24 return func 25 26def attrgetter(name): 27 def func(self): 28 return getattr(self, name) 29 return func 30 31def _return_value(value): 32 def func(self): 33 return value 34 35 return func 36 37def _dynamic_getter(name): 38 def getter(object): 39 m = getattr(object.pyobjc_instanceMethods, name) 40 return m() 41 getter.__name__ = name 42 return getter 43 44def _dynamic_setter(name): 45 def setter(object, value): 46 m = getattr(object.pyobjc_instanceMethods, name) 47 return m(value) 48 setter.__name__ = name 49 return setter 50 51class object_property (object): 52 def __init__(self, name=None, 53 read_only=False, copy=False, dynamic=False, 54 ivar=None, typestr=_C_ID, depends_on=None): 55 self.__created = False 56 self.__inherit = False 57 self._name = name 58 self._typestr = typestr 59 self._ro = read_only 60 self._copy = copy 61 self._dynamic = dynamic 62 self._ivar = ivar 63 self._getter = None 64 self._setter = None 65 self._validate = None 66 if depends_on is None: 67 self._depends_on = () 68 else: 69 self._depends_on = list(depends_on) 70 71 self.__getprop = None 72 self.__setprop = None 73 self.__parent = None 74 75 def _clone(self): 76 v = type(self)(name=self._name, 77 read_only=self._ro, copy=self._copy, dynamic=self._dynamic, 78 ivar=self._ivar, typestr=self._typestr, depends_on=None) 79 v.__inherit = True 80 81 v.__getprop = self.__getprop 82 v.__setprop = self.__setprop 83 v.__parent = self 84 85 return v 86 87 def __pyobjc_class_setup__(self, name, class_dict, instance_methods, class_methods): 88 self.__created = True 89 if self._name is None: 90 self._name = name 91 92 if self._ivar is not NULL: 93 if self._ivar is None: 94 ivname = '_' + self._name 95 else: 96 ivname = self._ivar 97 98 if self.__parent is None: 99 ivar_ref = ivar(name=ivname, type=self._typestr) 100 class_dict[ivname] = ivar_ref 101 102 if self._ro: 103 self._setter = None 104 105 else: 106 setterName = b'set' + name[0].upper().encode('latin1') + name[1:].encode('latin1') + b':' 107 signature = b'v@:' + self._typestr 108 if self._setter is None: 109 if self.__inherit: 110 pass 111 112 elif self._dynamic: 113 dynSetterName = 'set' + name[0].upper() + name[1:] + '_' 114 self.__setprop = _dynamic_setter(dynSetterName) 115 instance_methods.add(setterName) 116 117 else: 118 119 if self._ivar is NULL: 120 raise ValueError( 121 "Cannot create default setter for property " 122 "without ivar") 123 124 self.__setprop = selector( 125 attrsetter(self._name, ivname, self._copy), 126 selector=setterName, 127 signature=signature 128 ) 129 self.__setprop.isHidden = True 130 instance_methods.add(self.__setprop) 131 else: 132 self.__setprop = selector( 133 self._setter, 134 selector=setterName, 135 signature=signature 136 ) 137 self.__setprop.isHidden = True 138 instance_methods.add(self.__setprop) 139 140 if self._typestr in (_C_NSBOOL, _C_BOOL): 141 getterName = b'is' + name[0].upper().encode('latin1') + name[:1].encode('latin1') 142 else: 143 getterName = self._name.encode('latin1') 144 145 if self._getter is None: 146 if self.__inherit: 147 pass 148 149 elif self._dynamic: 150 if self._typestr in (_C_NSBOOL, _C_BOOL): 151 dynGetterName = 'is' + name[0].upper() + name[:1] 152 else: 153 dynGetterName = self._name 154 155 self.__getprop = _dynamic_getter(dynGetterName) 156 instance_methods.add(getterName) 157 158 else: 159 if self._ivar is NULL: 160 raise ValueError( 161 "Cannot create default getter for property without ivar") 162 163 self.__getprop = selector( 164 attrgetter(ivname), 165 selector=getterName, 166 signature=self._typestr + b'@:') 167 self.__getprop.isHidden=True 168 instance_methods.add(self.__getprop) 169 170 else: 171 self.__getprop = selector( 172 self._getter, 173 selector=getterName, 174 signature=self._typestr + b'@:') 175 self.__getprop.isHidden=True 176 instance_methods.add(self.__getprop) 177 178 if self._validate is not None: 179 selName = b'validate' + self._name[0].upper().encode('latin') + self._name[1:].encode('latin') + b':error:' 180 signature = _C_NSBOOL + b'@:N^@o^@' 181 validate = selector( 182 self._validate, 183 selector=selName, 184 signature=signature) 185 validate.isHidden = True 186 instance_methods.add(validate) 187 188 if self._depends_on: 189 if self.__parent is not None: 190 if self.__parent._depends_on: 191 self._depends_on.update(self.__parent._depends_on.copy()) 192 193 self._depends_on = self._depends_on 194 195 affecting = selector( 196 _return_value(NSSet.setWithArray_(list(self._depends_on))), 197 selector = b'keyPathsForValuesAffecting' + self._name[0].upper().encode('latin1') + self._name[1:].encode('latin1'), 198 signature = b'@@:', 199 isClassMethod=True) 200 affecting.isHidden = True 201 class_dict[affecting.selector] = affecting 202 class_methods.add(affecting) 203 204 205 def __get__(self, object, owner): 206 if object is None: 207 return self 208 return self.__getprop(object) 209 210 def __set__(self, object, value): 211 if self.__setprop is None: 212 raise ValueError("setting read-only property " + self._name) 213 214 return self.__setprop(object, value) 215 216 def __delete__(self, object): 217 raise TypeError("cannot delete property " + self._name) 218 219 def depends_on(self, keypath): 220 if self._depends_on is None: 221 self._depends_on = set() 222 self._depends_on.add(keypath) 223 224 def getter(self, function): 225 if self.__created: 226 v = self._clone() 227 v._getter = function 228 return v 229 230 self._getter = function 231 return self 232 233 def setter(self, function): 234 235 if self.__created: 236 v = self._clone() 237 v._ro = False 238 v._setter = function 239 return v 240 241 if self._ro: 242 raise ValueError("Defining settter for read-only property") 243 244 self._setter = function 245 return self 246 247 def validate(self, function): 248 if self._ro: 249 raise ValueError("Defining validator for read-only property") 250 251 if self.__created: 252 v = self._clone() 253 v._validate = function 254 return v 255 256 self._validate = function 257 return self 258 259class bool_property (object_property): 260 def __init__(self, name=None, 261 read_only=False, copy=False, dynamic=False, 262 ivar=None, typestr=_C_NSBOOL): 263 super(bool_property, self).__init__( 264 name, read_only, copy, dynamic, ivar, typestr) 265 266 267 268def _id(value): 269 return value 270 271NSIndexSet = lookUpClass('NSIndexSet') 272NSMutableIndexSet = lookUpClass('NSMutableIndexSet') 273NSKeyValueChangeSetting = 1 274NSKeyValueChangeInsertion = 2 275NSKeyValueChangeRemoval = 3 276NSKeyValueChangeReplacement = 4 277 278# FIXME: split into two: array_proxy and mutable_array_proxy 279class array_proxy (collections.MutableSequence): 280 # XXX: The implemenation should be complete, but is currently not 281 # tested. 282 __slots__ = ('_name', '_parent', '__wrapped', '_ro') 283 284 def __init__(self, name, parent, wrapped, read_only): 285 self._name = name 286 self._parent = parent 287 self._ro = read_only 288 self.__wrapped = wrapped 289 290 @property 291 def _wrapped(self): 292 return self.__wrapped.__getvalue__(self._parent) 293 294 @_wrapped.setter 295 def _wrapped(self, value): 296 setattr(self._parent, self._name, value) 297 298 def __indexSetForIndex(self, index): 299 if isinstance(index, slice): 300 result = NSMutableIndexSet.alloc().init() 301 start, stop, step = index.indices(len(self._wrapped)) 302 for i in xrange(start, stop, step): 303 result.addIndex_(i) 304 305 return result 306 307 else: 308 if index < 0: 309 v = len(self) + index 310 if v < 0: 311 raise IndexError(index) 312 return NSIndexSet.alloc().initWithIndex_(v) 313 314 else: 315 return NSIndexSet.alloc().initWithIndex_(index) 316 317 318 319 def __repr__(self): 320 return '<array proxy for property ' + self._name + ' ' + repr(self._wrapped) + '>' 321 322 def __reduce__(self): 323 # Ensure that the proxy itself doesn't get stored 324 # in pickles. 325 return _id, self._wrapped 326 327 def __getattr__(self, name): 328 # Default: just defer to wrapped list 329 return getattr(self._wrapped, name) 330 331 def __len__(self): 332 return self._wrapped.__len__() 333 334 def __getitem__(self, index): 335 return self._wrapped[index] 336 337 def __setitem__(self, index, value): 338 if self._ro: 339 raise ValueError("Property '%s' is read-only"%(self._name,)) 340 341 indexes = self.__indexSetForIndex(index) 342 self._parent.willChange_valuesAtIndexes_forKey_( 343 NSKeyValueChangeSetting, 344 indexes, self._name) 345 try: 346 self._wrapped[index] = value 347 finally: 348 self._parent.didChange_valuesAtIndexes_forKey_( 349 NSKeyValueChangeReplacement, 350 indexes, self._name) 351 352 def __delitem__(self, index): 353 if self._ro: 354 raise ValueError("Property '%s' is read-only"%(self._name,)) 355 356 indexes = self.__indexSetForIndex(index) 357 self._parent.willChange_valuesAtIndexes_forKey_( 358 NSKeyValueChangeRemoval, 359 indexes, self._name) 360 try: 361 del self._wrapped[index] 362 finally: 363 self._parent.didChange_valuesAtIndexes_forKey_( 364 NSKeyValueChangeRemoval, 365 indexes, self._name) 366 367 def append(self, value): 368 if self._ro: 369 raise ValueError("Property '%s' is read-only"%(self._name,)) 370 371 index = len(self) 372 indexes = NSIndexSet.alloc().initWithIndex_(index) 373 self._parent.willChange_valuesAtIndexes_forKey_( 374 NSKeyValueChangeInsertion, 375 indexes, self._name) 376 try: 377 self._wrapped.append(value) 378 finally: 379 self._parent.didChange_valuesAtIndexes_forKey_( 380 NSKeyValueChangeInsertion, 381 indexes, self._name) 382 383 def insert(self, index, value): 384 if self._ro: 385 raise ValueError("Property '%s' is read-only"%(self._name,)) 386 387 if isinstance(index, slice): 388 raise ValueError("insert argument 1 is a slice") 389 390 indexes = self.__indexSetForIndex(index) 391 self._parent.willChange_valuesAtIndexes_forKey_( 392 NSKeyValueChangeInsertion, 393 indexes, self._name) 394 try: 395 self._wrapped.insert(index, value) 396 finally: 397 self._parent.didChange_valuesAtIndexes_forKey_( 398 NSKeyValueChangeInsertion, 399 indexes, self._name) 400 401 def pop(self, index=-1): 402 if self._ro: 403 raise ValueError("Property '%s' is read-only"%(self._name,)) 404 405 if isinstance(index, slice): 406 raise ValueError("insert argument 1 is a slice") 407 408 indexes = self.__indexSetForIndex(index) 409 self._parent.willChange_valuesAtIndexes_forKey_( 410 NSKeyValueChangeRemoval, 411 indexes, self._name) 412 try: 413 return self._wrapped.pop(index) 414 finally: 415 self._parent.didChange_valuesAtIndexes_forKey_( 416 NSKeyValueChangeRemoval, 417 indexes, self._name) 418 419 def extend(self, values): 420 # XXX: This is suboptimal but correct 421 if self._ro: 422 raise ValueError("Property '%s' is read-only"%(self._name,)) 423 424 values = list(values) 425 426 indexes = NSIndexSet.alloc().initWithIndexesInRange_((len(self), len(values))) 427 428 self._parent.willChange_valuesAtIndexes_forKey_( 429 NSKeyValueChangeInsertion, 430 indexes, self._name) 431 try: 432 for item in values: 433 self._wrapped.append(item) 434 finally: 435 self._parent.didChange_valuesAtIndexes_forKey_( 436 NSKeyValueChangeInsertion, 437 indexes, self._name) 438 439 def __iadd__(self, value): 440 return self._wrapped + value 441 442# This causes a internal python error: 443# self._wrapped.extend(value) 444# return self 445 446 def __imul__(self, count): 447 return self._wrapped * count 448 449# This causes an error I don't quite get yet: 450# if self._ro: 451# raise ValueError("Property '%s' is read-only"%(self._name,)) 452# if not isinstance(count, (int, long)): 453# raise ValueError(count) 454# 455# indexes = NSIndexSet.alloc().initWithIndexesInRange_((len(self), len(self)*count)) 456# self._parent.willChange_valuesAtIndexes_forKey_( 457# NSKeyValueChangeInsertion, 458# indexes, self._name) 459# try: 460# self._wrapped *= count 461# finally: 462# self._parent.didChange_valuesAtIndexes_forKey_( 463# NSKeyValueChangeInsertion, 464# indexes, self._name) 465# 466# return self 467 468 469 def __eq__(self, other): 470 if isinstance(other, array_proxy): 471 return self._wrapped == other._wrapped 472 473 else: 474 return self._wrapped == other 475 476 def __ne__(self, other): 477 if isinstance(other, array_proxy): 478 return self._wrapped != other._wrapped 479 480 else: 481 return self._wrapped != other 482 483 def __lt__(self, other): 484 if isinstance(other, array_proxy): 485 return self._wrapped < other._wrapped 486 487 else: 488 return self._wrapped < other 489 490 def __le__(self, other): 491 if isinstance(other, array_proxy): 492 return self._wrapped <= other._wrapped 493 494 else: 495 return self._wrapped <= other 496 497 def __gt__(self, other): 498 if isinstance(other, array_proxy): 499 return self._wrapped > other._wrapped 500 501 else: 502 return self._wrapped > other 503 504 def __ge__(self, other): 505 if isinstance(other, array_proxy): 506 return self._wrapped >= other._wrapped 507 508 else: 509 return self._wrapped >= other 510 511 512 if sys.version_info[0] == 2: 513 def __cmp__(self, other): 514 if isinstance(other, array_proxy): 515 return cmp(self._wrapped, other._wrapped) 516 517 else: 518 return cmp(self._wrapped, other) 519 520 if sys.version_info[0] == 2: 521 def sort(self, cmp=None, key=None, reverse=False): 522 if self._ro: 523 raise ValueError("Property '%s' is read-only"%(self._name,)) 524 525 indexes = NSIndexSet.alloc().initWithIndexesInRange_( 526 (0, len(self._wrapped))) 527 self._parent.willChange_valuesAtIndexes_forKey_( 528 NSKeyValueChangeReplacement, 529 indexes, self._name) 530 try: 531 self._wrapped.sort(cmp=cmp, key=key, reverse=reverse) 532 finally: 533 self._parent.didChange_valuesAtIndexes_forKey_( 534 NSKeyValueChangeReplacement, 535 indexes, self._name) 536 537 else: 538 def sort(self, key=None, reverse=False): 539 if self._ro: 540 raise ValueError("Property '%s' is read-only"%(self._name,)) 541 542 indexes = NSIndexSet.alloc().initWithIndexesInRange_( 543 (0, len(self._wrapped))) 544 self._parent.willChange_valuesAtIndexes_forKey_( 545 NSKeyValueChangeReplacement, 546 indexes, self._name) 547 try: 548 self._wrapped.sort(key=key, reverse=reverse) 549 finally: 550 self._parent.didChange_valuesAtIndexes_forKey_( 551 NSKeyValueChangeReplacement, 552 indexes, self._name) 553 554 def reverse(self): 555 if self._ro: 556 raise ValueError("Property '%s' is read-only"%(self._name,)) 557 558 indexes = NSIndexSet.alloc().initWithIndexesInRange_( 559 (0, len(self._wrapped))) 560 self._parent.willChange_valuesAtIndexes_forKey_( 561 NSKeyValueChangeReplacement, 562 indexes, self._name) 563 try: 564 self._wrapped.reverse() 565 finally: 566 self._parent.didChange_valuesAtIndexes_forKey_( 567 NSKeyValueChangeReplacement, 568 indexes, self._name) 569 570def makeArrayAccessors(name): 571 572 def countOf(self): 573 return len(getattr(self, name)) 574 575 def objectIn(self, idx): 576 return getattr(self, name)[idx] 577 578 def insert(self, value, idx): 579 getattr(self, name).insert(idx, value) 580 581 def replace(self, idx, value): 582 getattr(self, name)[idx] = value 583 584 def remove(self, idx): 585 del getattr(self, name)[idx] 586 587 return countOf, objectIn, insert, remove, replace 588 589class array_property (object_property): 590 def __init__(self, name=None, 591 read_only=False, copy=True, dynamic=False, 592 ivar=None, depends_on=None): 593 super(array_property, self).__init__(name, 594 read_only=read_only, 595 copy=copy, dynamic=dynamic, 596 ivar=ivar, depends_on=depends_on) 597 598 def __pyobjc_class_setup__(self, name, class_dict, instance_methods, class_methods): 599 super(array_property, self).__pyobjc_class_setup__(name, class_dict, instance_methods, class_methods) 600 601 602 # Insert (Mutable) Indexed Accessors 603 # FIXME: should only do the mutable bits when we're actually a mutable property 604 605 name = self._name 606 Name = name[0].upper() + name[1:] 607 608 countOf, objectIn, insert, remove, replace = makeArrayAccessors(self._name) 609 610 countOf = selector(countOf, 611 selector = ('countOf%s'%(Name,)).encode('latin1'), 612 signature = _C_NSUInteger + b'@:', 613 ) 614 countOf.isHidden = True 615 instance_methods.add(countOf) 616 617 objectIn = selector(objectIn, 618 selector = ('objectIn%sAtIndex:'%(Name,)).encode('latin1'), 619 signature = b'@@:' + _C_NSUInteger, 620 ) 621 objectIn.isHidden = True 622 instance_methods.add(objectIn) 623 624 insert = selector(insert, 625 selector = ('insertObject:in%sAtIndex:'%(Name,)).encode('latin1'), 626 signature = b'v@:@' + _C_NSUInteger, 627 ) 628 insert.isHidden = True 629 instance_methods.add(insert) 630 631 remove = selector(remove, 632 selector = ('removeObjectFrom%sAtIndex:'%(Name,)).encode('latin1'), 633 signature = b'v@:' + _C_NSUInteger, 634 ) 635 remove.isHidden = True 636 instance_methods.add(remove) 637 638 replace = selector(replace, 639 selector = ('replaceObjectIn%sAtIndex:withObject:'%(Name,)).encode('latin1'), 640 signature = b'v@:' + _C_NSUInteger + b'@', 641 ) 642 replace.isHidden = True 643 instance_methods.add(replace) 644 645 646 def __set__(self, object, value): 647 if isinstance(value, array_property): 648 value = list(value) 649 650 super(array_property, self).__set__(object, value) 651 652 def __get__(self, object, owner): 653 v = object_property.__get__(self, object, owner) 654 if v is None: 655 v = list() 656 object_property.__set__(self, object, v) 657 return array_proxy(self._name, object, self, self._ro) 658 659 def __getvalue__(self, object): 660 v = object_property.__get__(self, object, None) 661 if v is None: 662 v = list() 663 object_property.__set__(self, object, v) 664 return v 665 666 667NSKeyValueUnionSetMutation = 1 668NSKeyValueMinusSetMutation = 2 669NSKeyValueIntersectSetMutation = 3 670NSKeyValueSetSetMutation = 4 671 672 673class set_proxy (collections.MutableSet): 674 __slots__ = ('_name', '__wrapped', '_parent', '_ro') 675 676 def __init__(self, name, parent, wrapped, read_only): 677 self._name = name 678 self._parent = parent 679 self._ro = read_only 680 self.__wrapped = wrapped 681 682 def __repr__(self): 683 return '<set proxy for property ' + self._name + ' ' + repr(self._wrapped) + '>' 684 685 @property 686 def _wrapped(self): 687 return self.__wrapped.__getvalue__(self._parent) 688 689 @_wrapped.setter 690 def _wrapped(self, value): 691 setattr(self._parent, self._name, value) 692 693 def __getattr__(self, attr): 694 return getattr(self._wrapped, attr) 695 696 697 def __contains__(self, value): 698 return self._wrapped.__contains__(value) 699 700 def __iter__(self): 701 return self._wrapped.__iter__() 702 703 def __len__(self): 704 return self._wrapped.__len__() 705 706 707 def __eq__(self, other): 708 if isinstance(other, set_proxy): 709 return self._wrapped == other._wrapped 710 711 else: 712 return self._wrapped == other 713 714 def __ne__(self, other): 715 if isinstance(other, set_proxy): 716 return self._wrapped != other._wrapped 717 718 else: 719 return self._wrapped != other 720 721 def __lt__(self, other): 722 if isinstance(other, set_proxy): 723 return self._wrapped < other._wrapped 724 725 else: 726 return self._wrapped < other 727 728 def __le__(self, other): 729 if isinstance(other, set_proxy): 730 return self._wrapped <= other._wrapped 731 732 else: 733 return self._wrapped <= other 734 735 def __gt__(self, other): 736 if isinstance(other, set_proxy): 737 return self._wrapped > other._wrapped 738 739 else: 740 return self._wrapped > other 741 742 def __ge__(self, other): 743 if isinstance(other, set_proxy): 744 return self._wrapped >= other._wrapped 745 746 else: 747 return self._wrapped >= other 748 749 750 if sys.version_info[0] == 2: 751 def __cmp__(self, other): 752 if isinstance(other, set_proxy): 753 return cmp(self._wrapped, other._wrapped) 754 755 else: 756 return cmp(self._wrapped, other) 757 758 def add(self, item): 759 if self._ro: 760 raise ValueError("Property '%s' is read-only"%(self._name,)) 761 762 self._parent.willChangeValueForKey_withSetMutation_usingObjects_( 763 self._name, 764 NSKeyValueUnionSetMutation, 765 set([item]), 766 ) 767 try: 768 self._wrapped.add(item) 769 finally: 770 self._parent.didChangeValueForKey_withSetMutation_usingObjects_( 771 self._name, 772 NSKeyValueUnionSetMutation, 773 set([item]), 774 ) 775 776 def clear(self): 777 if self._ro: 778 raise ValueError("Property '%s' is read-only"%(self._name,)) 779 780 object = set(self._wrapped) 781 self._parent.willChangeValueForKey_withSetMutation_usingObjects_( 782 self._name, 783 NSKeyValueMinusSetMutation, 784 object 785 ) 786 try: 787 self._wrapped.clear() 788 finally: 789 self._parent.didChangeValueForKey_withSetMutation_usingObjects_( 790 self._name, 791 NSKeyValueMinusSetMutation, 792 object 793 ) 794 795 def difference_update(self, *others): 796 if self._ro: 797 raise ValueError("Property '%s' is read-only"%(self._name,)) 798 799 s = set() 800 s.update(*others) 801 self._parent.willChangeValueForKey_withSetMutation_usingObjects_( 802 self._name, 803 NSKeyValueMinusSetMutation, 804 s 805 ) 806 try: 807 self._wrapped.difference_update(s) 808 809 finally: 810 self._parent.didChangeValueForKey_withSetMutation_usingObjects_( 811 self._name, 812 NSKeyValueMinusSetMutation, 813 s 814 ) 815 816 817 def discard(self, item): 818 if self._ro: 819 raise ValueError("Property '%s' is read-only"%(self._name,)) 820 821 self._parent.willChangeValueForKey_withSetMutation_usingObjects_( 822 self._name, 823 NSKeyValueMinusSetMutation, 824 set([item]) 825 ) 826 try: 827 self._wrapped.discard(item) 828 829 finally: 830 self._parent.didChangeValueForKey_withSetMutation_usingObjects_( 831 self._name, 832 NSKeyValueMinusSetMutation, 833 set([item]) 834 ) 835 836 def intersection_update(self, other): 837 if self._ro: 838 raise ValueError("Property '%s' is read-only"%(self._name,)) 839 840 self._parent.willChangeValueForKey_withSetMutation_usingObjects_( 841 self._name, 842 NSKeyValueIntersectSetMutation, 843 set([item]) 844 ) 845 try: 846 self._wrapped.intersection_update(s) 847 848 finally: 849 self._parent.didChangeValueForKey_withSetMutation_usingObjects_( 850 self._name, 851 NSKeyValueIntersectSetMutation, 852 set([item]) 853 ) 854 855 def pop(self): 856 if self._ro: 857 raise ValueError("Property '%s' is read-only"%(self._name,)) 858 859 try: 860 v = iter(self).next() 861 except KeyError: 862 raise KeyError("Empty set") 863 864 self.remove(v) 865 866 867 def remove(self, item): 868 if self._ro: 869 raise ValueError("Property '%s' is read-only"%(self._name,)) 870 871 self._parent.willChangeValueForKey_withSetMutation_usingObjects_( 872 self._name, 873 NSKeyValueMinusSetMutation, 874 set([item]) 875 ) 876 try: 877 self._wrapped.remove(item) 878 879 finally: 880 self._parent.didChangeValueForKey_withSetMutation_usingObjects_( 881 self._name, 882 NSKeyValueMinusSetMutation, 883 set([item]) 884 ) 885 886 def symmetric_difference_update(self, other): 887 # NOTE: This method does not call the corresponding method 888 # of the wrapped set to ensure that we generate the right 889 # notifications. 890 if self._ro: 891 raise ValueError("Property '%s' is read-only"%(self._name,)) 892 893 other = set(other) 894 895 to_add = set() 896 to_remove = set() 897 for o in other: 898 if o in self: 899 to_remove.add(o) 900 else: 901 to_add.add(o) 902 903 self._parent.willChangeValueForKey_withSetMutation_usingObjects_( 904 self._name, 905 NSKeyValueMinusSetMutation, 906 to_remove 907 ) 908 try: 909 self._wrapped.difference_update(to_remove) 910 911 finally: 912 self._parent.didChangeValueForKey_withSetMutation_usingObjects_( 913 self._name, 914 NSKeyValueMinusSetMutation, 915 to_remove 916 ) 917 918 self._parent.willChangeValueForKey_withSetMutation_usingObjects_( 919 self._name, 920 NSKeyValueUnionSetMutation, 921 to_add 922 ) 923 try: 924 self._wrapped.update(to_add) 925 926 finally: 927 self._parent.didChangeValueForKey_withSetMutation_usingObjects_( 928 self._name, 929 NSKeyValueUnionSetMutation, 930 to_add 931 ) 932 933 def update(self, *others): 934 if self._ro: 935 raise ValueError("Property '%s' is read-only"%(self._name,)) 936 937 s = set() 938 s.update(*others) 939 940 self._parent.willChangeValueForKey_withSetMutation_usingObjects_( 941 self._name, 942 NSKeyValueUnionSetMutation, 943 s 944 ) 945 try: 946 self._wrapped.update(s) 947 948 finally: 949 self._parent.didChangeValueForKey_withSetMutation_usingObjects_( 950 self._name, 951 NSKeyValueUnionSetMutation, 952 s 953 ) 954 955 def __or__(self, other): 956 return self._wrapped | other 957 958 def __and__(self, other): 959 return self._wrapped & other 960 961 def __xor__(self, other): 962 return self._wrapped ^ other 963 964 def __sub__(self, other): 965 return self._wrapped - other 966 967 def __ior__(self, other): 968 if self._ro: 969 raise ValueError("Property '%s' is read-only"%(self._name,)) 970 971 return self|other 972 973 def __isub__(self, other): 974 if self._ro: 975 raise ValueError("Property '%s' is read-only"%(self._name,)) 976 977 return self-other 978 979 def __ixor__(self, other): 980 if self._ro: 981 raise ValueError("Property '%s' is read-only"%(self._name,)) 982 983 return self^other 984 985 def __iand__(self, other): 986 if self._ro: 987 raise ValueError("Property '%s' is read-only"%(self._name,)) 988 989 return self&other 990 991def makeSetAccessors(name): 992 def countOf(self): 993 return len(getattr(self, name)) 994 995 def enumeratorOf(self): 996 return iter(getattr(self, name)) 997 998 def memberOf(self, value): 999 collection = getattr(self, name) 1000 if value not in collection: 1001 return None 1002 1003 for item in collection: 1004 if item == value: 1005 return item 1006 1007 def add(self, value): 1008 getattr(self, name).add(value) 1009 1010 def remove(self, value): 1011 getattr(self, name).discard(value) 1012 1013 return countOf, enumeratorOf, memberOf, add, remove 1014 1015 1016class set_property (object_property): 1017 def __init__(self, name=None, 1018 read_only=False, copy=True, dynamic=False, 1019 ivar=None, depends_on=None): 1020 super(set_property, self).__init__(name, 1021 read_only=read_only, 1022 copy=copy, dynamic=dynamic, 1023 ivar=ivar, depends_on=depends_on) 1024 1025 def __get__(self, object, owner): 1026 v = object_property.__get__(self, object, owner) 1027 if v is None: 1028 v = set() 1029 object_property.__set__(self, object, v) 1030 return set_proxy(self._name, object, self, self._ro) 1031 1032 def __getvalue__(self, object): 1033 v = object_property.__get__(self, object, None) 1034 if v is None: 1035 v = set() 1036 object_property.__set__(self, object, v) 1037 return v 1038 1039 def __pyobjc_class_setup__(self, name, class_dict, instance_methods, class_methods): 1040 super(set_property, self).__pyobjc_class_setup__(name, class_dict, instance_methods, class_methods) 1041 1042 # (Mutable) Unordered Accessors 1043 # FIXME: should only do the mutable bits when we're actually a mutable property 1044 1045 name = self._name 1046 Name = name[0].upper() + name[1:] 1047 1048 countOf, enumeratorOf, memberOf, add, remove = makeSetAccessors(self._name) 1049 1050 countOf = selector(countOf, 1051 selector = ('countOf%s'%(Name,)).encode('latin1'), 1052 signature = _C_NSUInteger + b'@:', 1053 ) 1054 countOf.isHidden = True 1055 instance_methods.add(countOf) 1056 1057 enumeratorOf = selector(enumeratorOf, 1058 selector = ('enumeratorOf%s'%(Name,)).encode('latin1'), 1059 signature = b'@@:', 1060 ) 1061 enumeratorOf.isHidden = True 1062 instance_methods.add(enumeratorOf) 1063 1064 memberOf = selector(memberOf, 1065 selector = ('memberOf%s:'%(Name,)).encode('latin'), 1066 signature = b'@@:@', 1067 ) 1068 memberOf.isHidden = True 1069 instance_methods.add(memberOf) 1070 1071 add1 = selector(add, 1072 selector = ('add%s:'%(Name,)).encode('latin'), 1073 signature = b'v@:@', 1074 ) 1075 add1.isHidden = True 1076 instance_methods.add(add1) 1077 1078 add2 = selector(add, 1079 selector = ('add%sObject:'%(Name,)).encode('latin1'), 1080 signature = b'v@:@', 1081 ) 1082 add2.isHidden = True 1083 instance_methods.add(add2) 1084 1085 remove1 = selector(remove, 1086 selector = ('remove%s:'%(Name,)).encode('latin1'), 1087 signature = b'v@:@', 1088 ) 1089 remove1.isHidden = True 1090 instance_methods.add(remove1) 1091 1092 remove2 = selector(remove, 1093 selector = ('remove%sObject:'%(Name,)).encode('latin'), 1094 signature = b'v@:@', 1095 ) 1096 remove2.isHidden = True 1097 instance_methods.add(remove2) 1098 1099 1100NSMutableDictionary = lookUpClass('NSMutableDictionary') 1101 1102class dict_property (object_property): 1103 def __get__(self, object, owner): 1104 v = object_property.__get__(self, object, owner) 1105 if v is None: 1106 v = NSMutableDictionary.alloc().init() 1107 object_property.__set__(self, object, v) 1108 return object_property.__get__(self, object, owner) 1109 1110