Cocoa text menu and modifying fonts in NSOutlineView - objective-c

The system supplied text menu works by sending a number of messages like changeFont: modifyFont: and addFontTrait: up the first responder chain until it reaches an NSTextView for example.
I'd like to extend this to control row styles in my NSOutlineView but I have only been able to override changeFont: in my window controller and intercept the message (maybe a better place to do this but it works for now). This works for changing fonts but the other menu items like Bold, Bigger, Smaller which use modifyFont: and addFontTrait: aren't ever getting called in the window controller so I can't modify their behavior to work on the outline view. Interestingly they appear selectable in the menu but only changeFont: is called and as I understand it I need to get a tag value from the NSMenuItem which is the sender of the methods modifyFont: and addFontTrait:.
Does anyone know how to implement this functionality by getting those other methods to be called anywhere? Thanks!

This is documented in the Cocoa Text Architecture Guide: Font Handling – Handling Font Changes. The -addFontTrait: and -modifyFont: messages are not sent up the responder chain. They are sent directly to the font manager. The font manager makes a note of the requested modifications and sends -changeFont: up the responder chain.
You should only need to implement -changeFont: as you have.
You do not get the tag from the menu item. The font manager does that. That's the source of the information that the font manager records internally.
Your -changeFont: method should call -convertFont: on the font manager, passing the current font. That method will return a new font modified as per the recorded change request. You would do that for all the fonts which should be affected. (For example, you might have a selection with multiple fonts in it.)
You do not normally have direct access to the requested modifications, such as "add the Bold trait" or "make the font bigger".
You can customize the font manager by subclassing NSFontManager and passing your subclass to +[NSFontManager setFontManagerFactory:] very early in app start-up. In your custom font manager, you can separately track the changes requested by the various action messages like -addFontTrait:. Here is where you would check the tag of the sender. Then, in your outline view you could query the properties of your the sender of -changeFont:, after verifying that it's an instance of your subclass, to determine what change(s) were requested.
Remember, though, that your custom subclass will be used throughout your app, not just for your outline view. So, your customizations should be in addition to the normal behavior of NSFontManager, not instead of, so it doesn't break stuff.

Related

Mac application About menu customisation

I am doing my first mac application. I have added my menus and customized. What is my problem is that I need some customizations in the about view. While the about menu clicked, automatically a view will pops up with details Name, Icon, copyright string, version etc. fetched from application plist. About menu in XCode application, which has buttons for Acknowledgment and Licensee Agreement. In chrome About Chrome will create a new tab in the webpage and details are shown. How this possible? Any help is appreciated.
It seems that you can do it in your MainMenu.xib, change to the target-action of the menu item About myApp to your custom action.
See the doc:
Connecting Menu Items Across Nib Files
The items in an OS X application’s menu bar often need to interact
with many different objects, including your application’s documents
and windows. The problem is that many of these objects cannot (or
should not) be accessed directly from the main nib file. The File’s
Owner of the main nib file is always set to an instance of the
NSApplication class. And although you might be able to instantiate a
number of custom objects in your main nib file, doing so is hardly
practical or necessary. In the case of document objects, connecting
directly to a specific document object is not even possible because
the number of document objects can change dynamically and can even be
zero.
Most menu items send action messages to one of the following:
A fixed object that always handles the command
A dynamic object, such as a document or window
Messaging fixed objects is a relatively straightforward process that
is usually best handled through the application delegate. The
application delegate object assists the NSApplication object in
running the application and is one of the few objects that rightfully
belongs in the main nib file. If the menu item refers to an
application-level command, you can implement that command directly in
the application delegate or just have the delegate forward the message
to the appropriate object elsewhere in your application.
If you have a menu item that acts on the contents of the frontmost
window, you need to link the menu item to the First Responder
placeholder object. If the action method associated with the menu item
is specific to one of your objects (and not defined by Cocoa), you
must add that action to the First Responder before creating the
connection.
After creating the connection, you need to implement the action method
in your custom class. That object should also implement the
validateMenuItem: method to enable the menu item at appropriate times.
For more information about how the responder chain handles commands,
see Cocoa Event Handling Guide.

iOS text popup with clickable links

I'm looking for a simple solution to presenting popup text in an iOS app that contains text with hyperlinks.
At the moment, my text pops up as a UIAlertView. The user has a 'Close' button below which dismisses the box. However, this class (UIAlertView) doesn't allow the use of hyperlinks within the message text. I understand that creating a whole new custom UIAlertView is frowned upon (not to mention probably overkill for what I want to achieve).
Perhaps I'm barking up the wrong tree by using UIAlertViews. I'm new to iOS and don't know the scope of what's available. Essentially, I need a dialog (or window) to pop up, containing a string of text, a (close/back/dismiss) button, and possible hyperlinks within the text. Those hyperlinks in turn launch other popups/windows/dialogs of their own.
What I'm working on here is a simple dictionary application. It's a table view containing terms. The terms lead to definitions, and in most cases, the definitions themselves reference other terms. Fairly simple, and if possible I'd like to use standard API classes.
Any wisdom would be appreciated. If I truly have to go down the route of creating my own custom UIAlertView class, then sobeit! In this case, some pointers for lightweight class creation would be appreciated. I'm not looking to add fancy colours or anything, just the ability to click on bits of text.
I think you'll need to create your own UIView sub-class to do the trick, controlled by a UIViewController subclass. One trick I've used to make it look more like an alert view is to have your main popup view embedded in a fullscreen view with a clear background.
In general, Apple SDKs make it really easy to do standard things (UIAlertView), but if you want to tinker with it (embedded links), you need to do it yourself.

Removing the Proxy Icon in the bar of my mac app

I was wondering how to remove the proxy icon in the bar of my mac app. I've added an image so you can see what Icon I'm talking about
Thank you in advance!
The icon is included in the titlebar of the application automatically when you've created an NSDocument based application.
You can remove the proxy icon by returning nil from the -[NSWindow representedURL] method. This could be accomplished by using a custom NSWindow subclass with the method overridden; or simply setting the property to nil at the appropriate times.
Be aware, you might loose other functionality you normally get for free by changing this behavior, such as the dirty/clean indicator for the window, or some prompting to save when closing the window.
Alternatively, if you wanted a different image, you could use:
[[NSWindow standardWindowButton:NSWindowDocumentIconButton] setImage:customImage]
Then implement -[id<NSWindowDelegate> window:shouldPopUpDocumentPathMenu:] to return NO to prevent the popup menu from appearing.
If your application isn't actually document based, or the window doesn't represent a document, consider refactoring to present this window a different way, rather than being a document window.
There is some additional information in the Cocoa window documentation.

NSOutlineView elements remain hopelessly undraggable

I have a program with a NSOutlineView (that supports single selection only) from which I'd like to be able to drag elements. These elements should either be received as text or files: for instance, dropping the item on a TextEdit window should put text, but dropping the item on the Finder should create a file. I don't want anything to be dropped over my outline view, even it it comes from itself. This seems easy enough, but for some reason, I can't get it to work.
I checked the NSOutlineView drag and drop example from Apple, and I came to implement the following methods (plus a few definitely unrelated ones):
-(BOOL)outlineView:shouldSelectItem: // I don't expect to drag unselectable items
-(NSArray*)outlineView:namesOfPromisedFilesDroppedAtDestination:forDraggedItems:
-(BOOL)outlineView:writeItems:toPasteboard:
However, when I try to drag an item from my outline view, nothing happens. Instead, it just changes the selection following the cursor.
I've put breakpoints in the two last methods, and they never get called, so their implementation is not the immediate issue.
I must be missing something really obvious here.
Also, this is not (yet) a problem, but how am I supposed to provide contents to my promised files?
I was being stupid and I implemented the methods in the delegate instead of the data source (the two are distinct in my app). Problem solved!
Are you using a custom table view cell? The result of NSCell's hitTestForEvent:inRect:ofView: determines whether a dragging operation can be initiated. It also determines whether your outlineView:writeItems:toPasteboard: should be called.
This method should return NSCellHitContentArea to initiate a drag, or NSCellHitTrackableArea to extend or change the selection.
A standard text cell returns NSCellHitContentArea when you click on the actual text of the cell, and NSCellHitTrackableArea when you click outside of the text. This produces the drag behavior you see in Finder's table view.
You can override this method and always return NSCellHitContentArea if you want all areas of the cell to initiate a drag operation.
See Hit Testing for more information.

linking file menu items to buttons

I'm in need of linking some buttons in a 'document based' application to the file menu (bold text, italic text, make text bigger etc.). The issue is that since its a document based application, the MainMenu.xib is a completely different XIB file than the MyDocument.xib, so I can't drag the connections in Interface Builder like I usually would. Does anyone have a workaround? Is there a way to link button actions to a separate XIB files' built in menu functions?
Zach
Generally, you use the First Responder place-holder object.
About the First Responder
"In Interface Builder, the First Responder is a proxy object that represents the first object in your application’s dynamically determined responder chain. Because the responder chain of an application cannot be determined at design time, the First Responder proxy acts as a stand-in target for any action messages that need to be directed at the application’s responder chain. Menu items commonly target the First Responder proxy. For example, the Minimize menu item in the Window menu hides the frontmost window in an application, not just a specific window, and the Copy menu item should copy the current selection, not just the selection of a single control or view. Other objects in your application can target the First Responder as well."
Also see:
Connecting Menu Items Across Nib Files
Also, if you want to create buttons whose actions are basically the same as the Format > Bold, etc. commands, see: Connecting the Font Menu in Interface Builder 3