• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Add bindings for custom menu items' isHidden to (an attribute of) a custom object?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Add bindings for custom menu items' isHidden to (an attribute of) a custom object?


  • Subject: Re: Add bindings for custom menu items' isHidden to (an attribute of) a custom object?
  • From: Daryle Walker <email@hidden>
  • Date: Mon, 08 Sep 2014 04:21:47 -0400

On Sep 8, 2014, at 3:10 AM, Daryle Walker <email@hidden> wrote:

> On Sep 8, 2014, at 1:12 AM, Daryle Walker <email@hidden> wrote:
[SNIP]
>>> @interface MyOverflowMenuController : NSObject
>>>
>>> //! Starts as nil; when set, this instance stores copies of the menu’s
>>> //! items and tracks the menu for item insertions, removals, and renames.
>>> @property (nonatomic) NSMenu *            sourceMenu;
>>> //! Starts as zero; if the menu has more menu items that this value,
>>> //! the copies of the menu's latter items are stored in the overflow
>>> //! array instead of the direct array.
>>> @property (nonatomic, assign) NSUInteger  maxDirectCount;
>>>
>>> //! Starts as empty; updated to mirror the source menu's menu-items.
>>> //! Keeps at most 'maxDirectCount' items. KVO-compliant.
>>> @property (nonatomic, readonly) NSArray *    directMenuItems;
>>> //! Starts as empty; updated to mirror the source menu's menu-items.
>>> //! Keeps the overflow from 'directMenuItems'. KVO-compliant.
>>> @property (nonatomic, readonly) NSArray *  overflowMenuItems;
>>>
>>> //! Transforms a NSMenu to a NSNumber with a BOOL value that's YES
>>> //! when the given menu is self.sourceMenu.
>>> @property (nonatomic, readonly) NSValueTransformer *  isSourceMenuTransformer;
>>>
>>> @end
>>
>>
>> That last property is of a custom NSValueTransformer subclass. (Is not using a new .h/.m file pair for the subclass OK?) The subclass holds a pointer to the source menu, and gets updated when the outer class changes that property in the setter. The custom object should out-live the per-day history menu items. So how would connect each menu item’s Hidden attribute to the custom object and the value transformer? Am I using the right kind of transformer? The source-menu attribute should be KVO-compliant since I use the automatic getter and a custom setter (that mutate the two arrays).
>
> I tried:
>
>> static inline
>> NSMenuItem *  CreateMenuItemForDay(NSCalendarDate *day, NSDateFormatter *format) {
>>     NSString * const   dayTitle = [format stringFromDate:day];
>>     NSMenu * const   daySubmenu = [[NSMenu alloc] initWithTitle:dayTitle];
>>     NSMenuItem * const  dayItem = [[NSMenuItem alloc] initWithTitle:dayTitle action:NULL keyEquivalent:@""];
>>
>>     dayItem.representedObject = day;
>>     dayItem.submenu = daySubmenu;
>>
>>     // Attach a binding to let the menu item auto-hide when used as the Today menu item.
>>     MyAppDelegate * const  appDelegate = [NSApp delegate];
>>
>>     [dayItem bind:NSHiddenBinding toObject:appDelegate.myOverflowMenuController.sourceMenu withKeyPath:@"sourceMenu" options:@{NSValueTransformerBindingOption: appDelegate.myOverflowMenuController.isSourceMenuTransformer}];
>>     return dayItem;
>> }
>
> (Good thing I already #imported my application delegate header to get access to the load-URL-from-menu-item action.) I crashed with:
>
>> 2014-09-08 02:43:31.216 MyApp[28296:303] Controller cannot be nil
>> 2014-09-08 02:43:31.279 MyApp[28296:303] (
>> 	0   CoreFoundation                      0x00007fff8557625c __exceptionPreprocess + 172
>> 	1   libobjc.A.dylib                     0x00007fff8d741e75 objc_exception_throw + 43
>> 	2   CoreFoundation                      0x00007fff8557610c +[NSException raise:format:] + 204
>> 	3   AppKit                              0x00007fff8cc37499 -[NSBinder addBinding:toController:withKeyPath:valueTransformer:options:] + 337
>> 	4   AppKit                              0x00007fff8cc41c38 -[NSEditableBinder addBinding:toController:withKeyPath:valueTransformer:options:] + 51
>> 	5   AppKit                              0x00007fff8cc32efb -[NSObject(NSKeyValueBindingCreation) bind:toObject:withKeyPath:options:] + 639
>> 	6   Prairie                             0x0000000100006246 CreateMenuItemForDay + 678
>> 	7   Prairie                             0x0000000100005a44 -[MyHistoryMenus notifyOnHistoryLoad:] + 708
>> 	8   CoreFoundation                      0x00007fff85544e0c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
>
> (Trimming out the reset of the stack.) The “sourceMenu” starts off as NIL and gets set by -prepareTodayHistoryMenu, which gets called when the array of WebHistory per-day menu items (and sub-menus) gets updated.
>
> …
>
> In the definition, instead of ‘@“sourceMenu”’, I used a constant. Looking at that in this e-mail, I realized I specified that property twice. I changed the second argument to “appDelegate.myOverflowMenuController” and it doesn’t crash. Now, none of the per-day web-history menus show up, not just the one for Today. (The one page I visited today does show up directly in the History, proving that the just-today web-history menu item mirroring system still works. All of the per-day menu items return YES through the custom value-transformer, or I screwed up the binding.
>
>> @interface MyCustomTargettingTransformer : NSValueTransformer
>>
>> //! Starts as nil; the menu instance to be compared.
>> @property (nonatomic) NSMenu *  targetMenu;
>>
>> @end
>>
>> @implementation MyCustomTargettingTransformer
>>
>> + (Class)transformedValueClass {
>>     return [NSNumber class];
>> }
>>
>> + (BOOL)allowsReverseTransformation {
>>     return NO;
>> }
>>
>> - (id)transformedValue:(id)value {
>>     return [NSNumber numberWithBool:(self.targetMenu == value)];
>> }
>>
>> @end
>
>
> (This is within the *.m file for MyOverflowMenuController.) In the setter for the “sourceMenu” property of MyOverflowMenuController, I set the “targetMenu” property of the “isSourceMenuTransformer” property of MyOverflowMenuController. When a using a custom setter for a property, are KVO notifications sent?

I tried some log-debugging:

> - (id)transformedValue:(id)value {
>     NSLog(@"Calling -transformedValue with (%@) and self.targetMenu = %@.", value, self.targetMenu);
>     return [NSNumber numberWithBool:(self.targetMenu == value)];
> }

> static inline
> NSMenuItem *  CreateMenuItemForDay(NSCalendarDate *day, NSDateFormatter *format) {
>     NSString * const   dayTitle = [format stringFromDate:day];
>     NSMenu * const   daySubmenu = [[NSMenu alloc] initWithTitle:dayTitle];
>     NSMenuItem * const  dayItem = [[NSMenuItem alloc] initWithTitle:dayTitle action:NULL keyEquivalent:@""];
>
>     dayItem.representedObject = day;
>     dayItem.submenu = daySubmenu;
>     NSLog(@"Creating menu item (%@) for day (%@).", dayItem, day);
>
>     // Attach a binding to let the menu item auto-hide when used as the Today menu item.
>     MyAppDelegate * const  appDelegate = [NSApp delegate];
>
>     [dayItem bind:NSHiddenBinding toObject:appDelegate.myOverflowMenuController withKeyPath:MyKeyPathSourceMenu options:@{NSValueTransformerBindingOption: appDelegate.myOverflowMenuController.isSourceMenuTransformer}];
>     return dayItem;
> }


and got:

> 2014-09-08 03:54:10.776 MyApp[28618:303] Creating menu item (<NSMenuItem: 0x6080000aa500 Monday, September 8, 2014, submenu: 0x608000263800 (Monday, September 8, 2014)>) for day (2014-09-08 00:00:00 -0400).
> 2014-09-08 03:54:10.777 MyApp[28618:303] Calling -transformedValue with ((null)) and self.targetMenu = (null).
> 2014-09-08 03:54:10.777 MyApp[28618:303] Creating menu item (<NSMenuItem: 0x6080000aa6e0 Sunday, September 7, 2014, submenu: 0x608000269480 (Sunday, September 7, 2014)>) for day (2014-09-07 00:00:00 -0400).
> 2014-09-08 03:54:10.778 MyApp[28618:303] Calling -transformedValue with ((null)) and self.targetMenu = (null).
> 2014-09-08 03:54:10.778 MyApp[28618:303] Creating menu item (<NSMenuItem: 0x6080000aa8c0 Saturday, September 6, 2014, submenu: 0x608000268ac0 (Saturday, September 6, 2014)>) for day (2014-09-06 00:00:00 -0400).
> 2014-09-08 03:54:10.779 MyApp[28618:303] Calling -transformedValue with ((null)) and self.targetMenu = (null).
> 2014-09-08 03:54:10.779 MyApp[28618:303] Creating menu item (<NSMenuItem: 0x6080000aab00 Thursday, September 4, 2014, submenu: 0x608000268dc0 (Thursday, September 4, 2014)>) for day (2014-09-04 00:00:00 -0400).
> 2014-09-08 03:54:10.779 MyApp[28618:303] Calling -transformedValue with ((null)) and self.targetMenu = (null).
> 2014-09-08 03:54:10.782 MyApp[28618:303] Calling -transformedValue with (<NSMenu: 0x608000263800> SKIP) and self.targetMenu = <NSMenu: 0x608000263800> SKIP.
> 2014-09-08 03:54:10.796 MyApp[28618:303] Calling -transformedValue with (<NSMenu: 0x608000263800> SKIP) and self.targetMenu = <NSMenu: 0x608000263800> SKIP.
> 2014-09-08 03:54:10.796 MyApp[28618:303] Calling -transformedValue with (<NSMenu: 0x608000263800> SKIP) and self.targetMenu = <NSMenu: 0x608000263800> SKIP.
> 2014-09-08 03:54:10.797 MyApp[28618:303] Calling -transformedValue with (<NSMenu: 0x608000263800> SKIP) and self.targetMenu = <NSMenu: 0x608000263800> SKIP.

The test value and the target menu were always the same. Four runs of double NULL then four more with Today’s sub-menu (Sep. 8). So the transformer always returns YES and every per-day history menu item (and sub-menu) is hidden. How do I get “dayItem.submenu” to be the operand for the transformer? Did I mess up the binding? Or the transformer’s very design? Where did those 4 NULL runs come from?

…

Oh, for that last question, it’s because the “sourceMenu” property starts as NIL and I don’t change it until I create the per-day menus. It would have to be that way since I set the property to the sub-menu of the newest day (unless it’s before Today).

—
Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden


  • Follow-Ups:
    • Re: Add bindings for custom menu items' isHidden to (an attribute of) a custom object?
      • From: Daryle Walker <email@hidden>
    • Re: Add bindings for custom menu items' isHidden to (an attribute of) a custom object?
      • From: Jerry Krinock <email@hidden>
References: 
 >Add bindings for custom menu items' isHidden to (an attribute of) a custom object? (From: Daryle Walker <email@hidden>)
 >Re: Add bindings for custom menu items' isHidden to (an attribute of) a custom object? (From: Daryle Walker <email@hidden>)

  • Prev by Date: Re: Add bindings for custom menu items' isHidden to (an attribute of) a custom object?
  • Next by Date: Re: My services in my own app
  • Previous by thread: Re: Add bindings for custom menu items' isHidden to (an attribute of) a custom object?
  • Next by thread: Re: Add bindings for custom menu items' isHidden to (an attribute of) a custom object?
  • Index(es):
    • Date
    • Thread