Tuesday, November 21, 2006

[Commentary] TextMate and [Tutorial] Printing the contents of WebViews

Well things are a little busy this week, but im also getting things done fortunitely. I can finally fully walk around in my closet now thanks to my cleaning session I decided to do on my day off... hey it had to get done sometime. One thing I decided to do is to continue going through my C Book and finally get through coding all the exercises which leads me to my quick commentary on TextMate. [Commentary] TextMate I must say im rather late to the party when it comes to TextMate. The videos I saw gave me the impression it was a good text editor for code and so I downloaded it, but I never really gave it a try till recently. Last night I am going through my C programming language book by Denise Ritche ( I am determined to go through and code all the exercises in the book and I left off in the middle of the thing ) and so I decided to see how TextMate could handle the code from scratch and I can say after experience it handled everything excellently. Heck I could even tell TextMate to compile the C exercises for me so all I had to do was have a terminal open to execute the finished programs. Im still learning and evaluating TextMate before the trial is up, but it looks good and I think it’s something i’ll probably get here soon. My only gripe with TextMate is that I wish it had code completion, but at the same time that might be venturing into the realm of starting to replace parts of Xcode which I don’t believe it’s meant to do. [Tutorial] Printing WebViews One thing you might think when printing a webview is that it should be as easy as something like simply going to File->Print when the WebView is visible or doing something like - (IBAction)printWebView:(id)sender { NSPrintOperation *printOperation; printOperation = [NSPrintOperation printOperationWithView:webView] [printOperation setShowPanels:YES]; [printOperation runOperation]; } However when this is run what happens? It only prints the visible bounds of the web view. At this point newbies and people unaccustomed to WebKit start to say things like WTF, etc. When you do this you are telling Mac OS X to print the WebView as it is visible. In order to print the whole contents of the WebView you must point it at it’s document view. So we end up with something like this: - (IBAction)printWebViewContents:(id)sender { NSPrintInfo *printInfo = [NSPrintInfo sharedPrintInfo]; NSPrintOperation *printOperation; NSView *webView = [[[myWebView mainFrame] frameView] documentView]; [printInfo setTopMargin:15.0]; [printInfo setLeftMargin:10.0]; [printInfo setHorizontallyCentered:NO]; [printInfo setVerticallyCentered:NO]; printOperation = [NSPrintOperation printOperationWithView:webView printInfo:printInfo]; [printOperation setShowPanels:YES]; [printOperation runOperation]; } Once that is is in place it will print all of the contents of the WebView. I set the margins myself in this case to try and make sure the specific document this method is printing fits the way I want. [What do you want covered?] One thing im starting to think about doing here soon is taking requests for covering various general cocoa topics. I used to be a n00b, but now Im sure I use a ton of things on a daily basis that I couldn’t figure out how to do when I was learning cocoa. If you think of something good post a comment about it here. I can’t guarantee i’ll cover everybody’s requests but if people want something explained in detail or elaborated on i’ll do my best to help you guys out. [Happy Thanksgiving!] Whatever you are doing this week I wish all of you safe travels or just a good time with friends and family regardless of what you are doing!

Saturday, November 11, 2006

[Tutorial] Lets get sorting

Well I am back people! This whole past couple weeks have just been crazy at work and in combination with hunting bugs in my first early Beta of AssignmentTracker X I haven't had much time for this blog lately, but now I am back and things have settled down and I am already full of stuff to post. Hey I'm just a student people, give me a break. Well for today I am gonna post 2 things that made my own LicenseKeeper app a little bit better. (1)I liked that I could easily store all my serial numbers, but I wanted them sorted by default (2)When I resized the columns I wanted the app to keep track of the length of them Let's get sorting! Like many things in life Core Data has a slight trade-off in that you now have automatic data persistence, but the data is not sorted. If you create a Core Data app right now, like creating a simple table that displays entities with 1 attribute (lets say a name) and create a few entities without telling the array controller to sort them and then quit and reopen the app a few times, the order of the entities will be almost random every time. So people new to Core Data then ask how do we keep this data sorted? Well Apples Documentations spells it out like so “ Objects in a persistent store are unordered. Typically you should impose order at the controller or view layer, based on an attribute such as creation date. If there is order inherent in your data, you need to explicitly model that.” In other words it's up to you to sort your data. So all I did was create a controller class I called LKAppController with an outlet to the NSArrayController. Here is LSAppController.h.

#import < cocoa/cocoa.h > @interface LKAppController : NSObject { IBOutlet NSArrayController *licensesController; } @end
Then I instantiated the class in Interface Builder and connected the outlet to the NSArrayController. And to sort the data I created a NSSortDescriptor and told the array controller to sort the objects it has with that sort descriptor in the awakeFromNib method. Here is LKAppController.m.
#import "LKAppController.h" @implementation LKAppController - (void)awakeFromNib { NSSortDescriptor * sd = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; [licensesController setSortDescriptors:[NSArray arrayWithObject:sd]]; [sd release]; } @end
I should state that this is not Core Data specific, in fact this method can be applied to any array controller in Cocoa. Now this is easy because in this instance we have a bunch of objects that we just want to sort by their name. I suggest that if you have to have objects in some specific order for something like a Source list (where we might want some static items at the top then user items at the bottom of the list) that you create an attribute and call it something like “position” that's an int sort it like that or use some other attribute or method you like, the point is you must create the means to sort the way you want. The only area where it may get difficult to auto sort items is in NSOutlineViews in which case you may find this ( http://allusions.sourceforge.net/articles/treeDragPart2.php ) to be of interest. Keeping track of column length So now we have our data sorted by default I wanted to do something nice for myself and make the app remember the length of all the columns when I resized them so I could at any time change them to my hearts content. Many people don't realize you can do this, but if you poke around in the Cocoa Bindings you can bind the length as well as the minimum length and max length of the columns to an entity or in this case (to make things simple) to the preferences. So all you need to do is select the table column and go to the Bindings option in the IB Inspector. Select the width attribute. For this we'll bind to Shared User Defaults (once you select this you should see the “Shared Defaults” controller appear in the instances tab), with the controller key “values” and model key path “nameColumnHeaderWidth” for the name column. Repeat the process for each additional column (giving a unique name for each model key path) and now your app will remember the length of each column as you drag them! It's the nice little stuff like this that you do that your users will really appreciate when you put out your app.