validateMenuItem to disable specific menu items - objective-c

I an new to macOS XCode Obj-C so bear with me. I am trying to use validateMenuItem to disable and enable specific menu items.
I currently have this working to disable and enable *all menu items:
BOOL g_bEnableAllMenus = YES;
and then I am using the validateMenuItem
- (BOOL)validateMenuItem:(NSMenuItem *)item
{
if( !g_bEnableAllMenus )
return NO;
return YES;
}
To test, I am calling g_bEnableAllMenus in awakeFromNib and it is disabling all my menu items correctly.
- (void)awakeFromNib {
g_bEnableAllMenus = NO;
}
What I am trying to do now is this scenario:
Instead of g_bEnableAllMenus disabling and enabling ALL menu items when g_bEnableAllMenus = YES/NO; is called, I want it to disable all menu items EXCEPT a list of several other menuItems under a menu called TestMenu.
Then I want this list of other menu items under TestMenu separately controlled with a different BOOL: so I can enable and disable this menu item separately and not have it changed by g_bEnableAllMenus - only by g_bEnableTestMenu.
BOOL g_bEnableTestMenu = YES;
There is where I am stuck. I think I have to use some combination of [item action] == #selector(TestMenuItem:) in validateMenuItem so when g_bEnableTestMenu == NO it disables all menu items under my TestMenu (but doesn't touch other menu items).
Then when g_bEnableAllMenus == NO it still disables all my menus (as it correctly does now) but excludes my TestMenu.

Here's a more concrete answer based on my comment above.
You can set a tag value on a menu item to avoid having to match by action/selector. If you're creating the menu items in code just set the .tag property directly; in an .xib layout set it on the main properties tab of the menu item:
Then in your validation handler you can just check the range of the tag:
func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool {
if item.tag >= 1000 && item.tag <= 1100 {
// return your test validation logic result
} else {
// return your normal validation result
}
}
Of course you could improve this sample by defining constants for your test-menu-item tag range min and max, or with other data structures (e.g. a CaseIterable enum of test-item tag values). You might want to use tags for other groups of commands that share validation logic that isn't readily determined by selectors/responder-chain.

Related

replacement for tabbar selected index

I have an old app where I have 5 tabs. Each tab have list of ads & there is details. Also each tab have respective add ad. Design for all 5 tabs is same except some changes, so I decided to use 1 screen only for all 5 tabs.
Now what I am doing is while add ad, I am checking which tab I am and based on tab bar index, I am showing hiding fields. Same is applicable for details screen also. Sample code is as shown below.
if (self.tabBarController.selectedIndex==0) {
field1.hidden = NO;
} else if (self.tabBarController.selectedIndex==1) {
field1.hidden = NO;
} else if (self.tabBarController.selectedIndex==2) {
field1.hidden = NO;
} else if (self.tabBarController.selectedIndex==3) {
field1.hidden = NO;
} else if (self.tabBarController.selectedIndex==4) {
field1.hidden = YES;
}
Now I have around 15 fields for each form so I write this code for all fields.
What I noticed that client change the tab bar position continuously so I was looking for efficient way of doing it.
Right now what I do is at all places manually change index positions by doing Search-Replace, however I dont like this.
I was looking for a way where instead of selectedIndex, I was looking for someconstant value that I will assign to tab item of tab bar, so my code will change as below
if (self.tabBarController.selectedIndex==adType_News) {
field1.hidden = NO;
} else if (self.tabBarController.selectedIndex==adType_Occasions) {
.
.
And so on...
This way, I only need to change in the storyboard and code level will not have any changes.
Is there way where I can achieve this?
Main Issue
As client ask to change tab bar completely, I need to make changes of selectedIndex changes at all places which I don't like and feel more in-efficient way. So I was looking for a way where I will make change in storyboard only and coding level there won't be any change.
The main issue for me is changing selectedIndex in all files which make more error.
I think I understand the question to mean that the code is full of number literals, referring to the selected index of the tabbar, and the business requirements about the ordering of items are shifting. Fix by changing the literals to something symbolic that can be controlled centrally:
// in a new file, indexes.h
#define INDEXA (0)
#define INDEXB (1)
#define INDEXC (2)
// wherever existing code refers to the tab selection
#import "indexes.h"
// in the code, for example if selectedIndex == 2, change to
if (self.tabBarController.selectedIndex==INDEXC) {
// ...

How to Mimic Finder NSPredicateEditor leftExpression list

I would like to mimic the Finder's predicatesList. Especially the LeftExpressions popup with its "other" (in German: "Andere...") menu entry and like to popup a NSSheet with a user selectable list of search predicates.
My approach was to create some NSPredicateEditorRowTemplates and one last custom rowTemplate with a leftExpression named "other...".
Then I override the templateViews method and added a separatorItem:
-(NSArray *)templateViews{
NSMutableArray * views = [[super templateViews] mutableCopy];
// I tried already to add here my custom menu entry, but if I add more templates my custom entry (and the separator line) is not fixed at the last index.
if (!isCustomMenuItemAdded) {
NSPopUpButton *leftButton = views[0];
// Add a menu separator
[[leftButton menu]insertItem:[NSMenuItem separatorItem] atIndex:[leftButton menu].itemArray.count-1];
}
return views;
}
My custom predicateEditor is now shown correctly, But if I click on the last menu item 'Other.." the dummy NSPredicateRowTemplate shows up.
I tried to override the -(id)copy method in my rowTemplate class to suppress the new line but that feels strange to me.
-(id)copy{
return nil; // OK, now there is no new row, but this throws an internal exception
}
My question is:
Is there a better way to add a custom menu entry in the left expressions popupButton?
and
How can I suppress that a new predicateTemplateRow is shown in the PredicateEditor?

How to show a Safari Extension popover programmatically

I'm trying to write a Safari extension that consists of a button on the main toolbar with a popover tied to it, and a contextual menu item. The basic feel is modeled after the feel of the 1Password extension.
One of the jobs of the popover is to allow a person to log in. I'm also conditionally changing the action of the contextual menu item, and if a who person isn't logged in clicks the menu item I would like to show the popover allowing them to log in, but I can't find a way to do this in the developer guides.
How do I "show" a popover?
If you only have one toolbar item and one popover (and never plan to add more), then it's just one line. Assuming you've already assigned the popover to the toolbar item in Extension Builder, you can just use:
safari.extension.toolbarItems[0].showPopover();
But if you have more than one popover and (potentially) more than one toolbar item, here's a generalized function to open a popover, specified by its identifier, under the specified toolbar item in the active browser window:
function showPopover(popoverId, toolbarItemId) {
var toolbarItem = safari.extension.toolbarItems.filter(function (tbi) {
return tbi.identifier == toolbarItemId && tbi.browserWindow == safari.application.activeBrowserWindow;
})[0];
var popover = safari.extension.popovers.filter(function (po) {
return po.identifier == popoverId;
})[0];
toolbarItem.popover = popover;
toolbarItem.showPopover();
}

NSToolBar with two customize buttons

i am a beginner in mac development. i am developing an application with Toolbar. i just want to add Two customized Button in the tool bar.
The ToolBar will be looking like this. i have tried this using XIB, but i did not get this thing,.,.
any ideas about this,.
thanks in advance
Short answer: you need to validate each toolbar item that is not default.
Long answer:
First you need to connect actions of NSToolbarItem to a IBAction in your code.
Then you have two option:
Let the automatic validator do his job by simply checking if there is valid target/action pair.
Validate each toolbar item yourself. You can check here if there is anything to Copy/Paste
Exemple of validation:
- (BOOL)validateUserInterfaceItem:(id < NSValidatedUserInterfaceItem >)theMenuItem {
BOOL enable = NO;
if ([theMenuItem action] == #selector(myCopy:)) {
if (isThereSomethingToCopy)
enable = YES;
}
else if ([theMenuItem action] == #selector(myPaste:)) {
if ( (isThereSomethingToPaste) && (thereIsValidPasteTarget) )
enable = YES;
}
return enable;
}

How can I set the default state of a UISegmentedControl?

Is there a way to set the starting selected segment in a UISegmentedControl in Interface Builder, or do I have to do it in the code? If it's in the code, is viewDidLoad the best place to set it?
From code, you can do:
self.segmentedControl.selectedSegmentIndex = someDefaultIndex
Whether you should set it in viewDidLoad: or not depends entirely on the structure of your application. For example, if your app is starting up and loading the view for the first time and needs to set the control to whatever value it had during the previous run of the app, then it definitely makes sense to do it there.
In Interface Builder when you select UISegmentedControl object on your UI, then in attributes pane, in segment control there's segment drop down menu, select segment that you want selected (0,1 and so on) and tick the 'selected' option below it.
Select default value for your UISegmentedControl via storyBoard
Open ur storyboard and select the UISegmentedControl
Select atributes inspector of your UISegmentedControl (in the right corner)
Search the 'segment' atribute and open de dropdown.
Select the item you want to be selected by default.
Mark the selected checkbox to set selected by default.
If you don't use storyboards and want to set a default index after some setup/networking like me, this little snippet will select something if the user hasn't. I placed this in my subclass of UISegmentedControl, but you could place this anywhere. (Swift 3)
Decl: var UISegmentedControlNoSegment: Int { get }
Desc: A segment index value indicating that there is no selected segment. See selectedSegmentIndex for further information.
Short version:
if selectedSegmentIndex == UISegmentedControlNoSegment {
selectedSegmentIndex = initialIndex
}
Longer version
func reloadData() {
guard let numberOfItems = dataSource?.numberOfItems() else {
return
}
removeAllSegments()
for index in 0...numberOfItems {
insertSegment(with: $image, at: index, animated: false)
}
if selectedSegmentIndex == UISegmentedControlNoSegment {
selectedSegmentIndex = initialIndex
}
}
After clicking the Segmented Control go to where you created the segments and choose the one you want be default. Then below that there will be a Box with "Selected" by it. Select that and it will be default.