Brew up a Rich Web Application with Cappuccino

6,517 views

Published on

An overview of the Cappuccino rich client framework. Cappuccino extends the legacy of NeXTSTEP and Mac OS X desktop development to the web, creating cross-platform, cross-browser web applications that look and feel like modern Mac OS X desktop applications.

Published in: Technology, Education
1 Comment
14 Likes
Statistics
Notes
  • Thanks for a really great presentation. Any chance that you will make it available for download? Honestly, I just wanted to print it out and read over a cup of tea. (Not trying to be funny at all.)


    <b>[Comment posted from</b> http://tapestryjava.blogspot.com/2009/10/brew-up-rich-web-application-with.html]
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
6,517
On SlideShare
0
From Embeds
0
Number of Embeds
801
Actions
Shares
0
Downloads
0
Comments
1
Likes
14
Embeds 0
No embeds

No notes for slide

Brew up a Rich Web Application with Cappuccino

  1. 1. Brew up a Rich Web Application with Cappuccino Howard M. Lewis Ship TWD Consulting hlship@comcast.net 1 © 2009 Howard Lewis Ship
  2. 2. Three 'C's, Two 'P's, One 'N' 2 © 2009 Howard Lewis Ship
  3. 3. Agenda • Why Cappuccino? • Getting Started • Objective-J • Running as a Web App • Window Resizing & Remote Communication • Cappuccino Pitfalls 3 © 2009 Howard Lewis Ship
  4. 4. Why Cappuccino? 4 © 2009 Howard Lewis Ship
  5. 5. 5 © 2009 Howard Lewis Ship
  6. 6. 6 © 2009 Howard Lewis Ship
  7. 7. ❝If you need web applications that offer the same user experience as a desktop app would, then Cappuccino is for you. If you truly believe that the classic web development "components" - the usual HTML/CSS/Javascript horror shop - simply stinks, then you are going to be delighted about Cappuccino, too.❞ Holger Jahn 7 © 2009 Howard Lewis Ship
  8. 8. Getting Started 8 © 2009 Howard Lewis Ship
  9. 9. Download http://cappuccino.org/download/ Click Here 9 © 2009 Howard Lewis Ship
  10. 10. Install Tools sudo ./install-tools 10 © 2009 Howard Lewis Ship
  11. 11. Tools Install • Pre-Requisites • Mac or Linux Helps! • Cygwin for Windows • Ruby & Rake •cd Tools ; sudo ./install-tools • Tools & Frameworks installed to /usr/local/share • Must add /usr/local/share/bin to $PATH 11 © 2009 Howard Lewis Ship
  12. 12. Create Example capp gen example 12 © 2009 Howard Lewis Ship
  13. 13. Generated Files Info.plist Application startup information main.j main() method for application AppController.j Application controller (builds initial UI) index.html Launches application index-debug.html Launches application (debug mode) Rakefile Rake build file Frameworks Copy of /usr/local/share/objj/lib/Frameworks Resources Resources (images, etc.) available to application 13 © 2009 Howard Lewis Ship
  14. 14. Configuration /* * AppController.j * example * * Created by You on July 14, 2009. * Copyright 2009, Your Company All rights reserved. */ • capp config key value Stored in ~/.cappconfig • user.name • user.email • organization.name • organization.email • organization.url • organization.identifier 14 © 2009 Howard Lewis Ship
  15. 15. View Example App 15 © 2009 Howard Lewis Ship
  16. 16. Objective-J 16 © 2009 Howard Lewis Ship
  17. 17. Lineage 17 © 2009 Howard Lewis Ship
  18. 18. Objective-C + = Preprocessor 18 © 2009 Howard Lewis Ship
  19. 19. Objective-J Syntax Java Syntax Objective-J Syntax window.orderFront(); [window orderFront]; icon.moveToXY(100, 200); [icon moveToX:100 Y:200]; method moveToX:Y: Java Syntax Objective-J Syntax new JFrame(); [[CPWindow alloc] init]; new JFrame("Toolbox"); [[CPWindow alloc] initWithTitle:"Toolbox"]; Class name Class method Java Syntax Objective-J Syntax this.setNeedsDisplay(true); [self setNeedsDisplay:YES]; Cheat Sheet: this ➠ self, true ➠ YES, false ➠ NO, null ➠ nil 19 © 2009 Howard Lewis Ship
  20. 20. Defining Classes Base class PageView.j @import <AppKit/CPView.j> @implementation PageView : CPView { CALayer _rootLayer; } // Methods defined here @end Convention: instance variables start with underscore 20 © 2009 Howard Lewis Ship
  21. 21. Defining Methods - for instance method type of parameter + for class method PageView.j - (id)initWithFrame:(CGRect)aFrame { self = [super initWithFrame:aFrame]; if (self) Return type { _rootLayer = [CALayer layer]; [self setWantsLayer:YES]; [self setLayer:_rootLayer]; [_rootLayer setBackgroundColor:[CPColor whiteColor]]; [_rootLayer setNeedsDisplay]; } return self; } 21 © 2009 Howard Lewis Ship
  22. 22. No Namespaces 22 © 2009 Howard Lewis Ship
  23. 23. Cappuccino User Interfaces M ac O nl y UI Object properties and connections + = Controller Class Interface Builder File Running User Interface [CPBundle loadCibNamed:owner:loadDelegate:] Instantiates & connects 23 © 2009 Howard Lewis Ship
  24. 24. Actions and Outlets triggerClicked: AppController @implementation AppController : CPObject { CPWindow theWindow; CPTextField outputField; } … - (void)triggerClicked:(id)sender { [outputField setObjectValue:"You clicked it!"]; } @end 24 © 2009 Howard Lewis Ship
  25. 25. capp gen BasicControls -t NibApplication 25 © 2009 Howard Lewis Ship
  26. 26. 26 © 2009 Howard Lewis Ship
  27. 27. Be 1 N ta 5 ov http://280atlas.com/ 27 © 2009 Howard Lewis Ship
  28. 28. Running as a Web App Using Maven & Jetty 28 © 2009 Howard Lewis Ship
  29. 29. 29 © 2009 Howard Lewis Ship
  30. 30. Creating a Web App • mvn archetype:generate • #18 (basic web application) • Edit pom.xml: <plugins> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <configuration> <requestLog implementation="org.eclipse.jetty.server.NCSARequestLog"> <append>true</append> </requestLog> </configuration> </plugin> </plugins> • capp gen src/main/webapp/app • mvn jetty:run • Open http://localhost:8080/app 30 © 2009 Howard Lewis Ship
  31. 31. Creating a simple calculator 31 © 2009 Howard Lewis Ship
  32. 32. Cappuccino Classes CPObject CPResponder undoManager : CPUndoManager menu : CPMenu nextResponder : CPResponder CPView CPWindow hidden : BOOL fullBridge : BOOL frame : CGRect - addSubview:CPView : void level : int - display : void visible : BOOL contentView : CPView backgroundColor : CPColor hasShadow : BOOL title : CPString CPControl CPPanel 32 © 2009 Howard Lewis Ship
  33. 33. Cappuccino Classes CPControl action : SEL target: id enabled : BOOL highlighted : BOOL objectValue : id floatValue: float doubleValue : double intValue : int - initWithFrame:CGFrame : CPControl CPButton CPTextField title : CPString editable : BOOL secure: BOOL - sizeToFit : void bezeled : BOOL + buttonWithTitle:CPString : CPButton + labelWithTitle:CPString : CPTextField 33 © 2009 Howard Lewis Ship
  34. 34. Adding Controls AppController.j - (void)applicationDidFinishLaunching:(CPNotification)aNotification { var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], contentView = [theWindow contentView]; _display = [CPTextField labelWithTitle:"(placeholder)"]; [_display setBezeled:YES]; [_display sizeToFit]; [contentView addSubview:_display]; [theWindow orderFront:self]; } 34 © 2009 Howard Lewis Ship
  35. 35. Utility Methods AppController.j - (void)add:(CPView)subview { [_contentView addSubview:subview]; } - (CPButton)makeButton:value at:(CGRect)frame { var button = [[CPButton alloc] initWithFrame:frame]; [button setTitle:value.toString()]; [self add:button]; return button; } 35 © 2009 Howard Lewis Ship
  36. 36. More Controls AppController.j _display = [CPTextField labelWithTitle:"(placeholder)"]; [_display setFrame:CGRectMake(5, 5, 180, 30)] [_display setBezeled:YES]; [self add:_display]; [self makeButton:7 at:CGRectMake(5, 35, 40, 25)]; [self makeButton:8 at:CGRectMake(50, 35, 40, 25)]; [self makeButton:9 at:CGRectMake(95, 35, 40, 25)]; [self makeButton:"*" at:CGRectMake(140, 35, 40, 25)]; [self makeButton:4 at:CGRectMake(5, 65, 40, 25)]; [self makeButton:5 at:CGRectMake(50, 65, 40, 25)]; [self makeButton:6 at:CGRectMake(95, 65, 40, 25)]; [self makeButton:"-" at:CGRectMake(140, 65, 40, 25)]; [self makeButton:1 at:CGRectMake(5, 95, 40, 25)]; [self makeButton:2 at:CGRectMake(50, 95, 40, 25)]; [self makeButton:3 at:CGRectMake(95, 95, 40, 25)]; [self makeButton:"+" at:CGRectMake(140, 95, 40, 25)]; [self makeButton:0 at:CGRectMake(5, 125, 85, 25)]; [self makeButton:"." at:CGRectMake(95, 125, 40, 25)]; [self makeButton:"=" at:CGRectMake(140, 125, 40, 25)]; 36 © 2009 Howard Lewis Ship
  37. 37. Local vars have no type - (CPButton)makeDigit:(int)value at:(CGRect)frame { Should be var CPButton button = [self makeButton:value at:frame action:@selector(digit:)]; [button setTag:value]; return button; } 37 © 2009 Howard Lewis Ship
  38. 38. Local vars have no type - (CPButton)makeDigit:(int)value at:(CGRect)frame { Should be var CPButton button = [self makeButton:value at:frame action:@selector(digit:)]; [button setTag:value]; return button; } Not helpful! 38 © 2009 Howard Lewis Ship
  39. 39. Client Exception — Safari 39 © 2009 Howard Lewis Ship
  40. 40. Client Exception — Safari 40 © 2009 Howard Lewis Ship
  41. 41. Fleshed-Out Calculator AppController.j _display = [CPTextField labelWithTitle:""]; [_display setAlignment:CPRightTextAlignment]; [_display setFrame:CGRectMake(1, 5, 183, 30)] [_display setBezeled:YES]; [self add:_display]; [self makeButton:"C" atX:0 y:0 action:@selector(clear:)]; [self makeButton:"/" atX:3 y:0 action:@selector(div:)]; [self makeButton:"*" atX:3 y:1 action:@selector(mult:)]; [self makeButton:"-" atX:3 y:2 action:@selector(minus:)]; [self makeButton:"+" atX:3 y:3 action:@selector(plus:)]; [self makeDigit:7 atX:0 y:1]; [self makeDigit:8 atX:1 y:1]; [self makeDigit:9 atX:2 y:1]; … [[self makeButton:"=" atX:3 y:4 action:@selector(compute:)] setDefaultButton:YES]; 41 © 2009 Howard Lewis Ship
  42. 42. Utility Methods AppController.j - (CPButton)makeButton:(id)value atX:(int)x y:(int)y action:(SEL)action { var frame = CGRectMake(45 * x + 5, 30 * y + 35, 40, 24); var button = [[CPButton alloc] initWithFrame:frame]; [button setTitle:value.toString()]; [button setTarget:self]; [button setAction:action]; [self add:button]; return button; } - (CPButton)makeDigit:(id)value atX:(int)x y:(int)y { return [self makeButton:value atX:x y:y action:@selector(digit:)]; } 42 © 2009 Howard Lewis Ship
  43. 43. Action Methods @selector(digit:) AppController.j - (void)digit:(CPButton)source { var digit = [source title]; if (_value == "" && digit == "0") return; _value = _sign + _value + digit; _sign = ""; [_display setStringValue:_value]; } - (void)clear:(id)source { [self reset]; } 43 © 2009 Howard Lewis Ship
  44. 44. Nesting Controllers 44 © 2009 Howard Lewis Ship
  45. 45. HUD Panel 45 © 2009 Howard Lewis Ship
  46. 46. Main UI Top level window AppController.j - (void)applicationDidFinishLaunching:(CPNotification)aNotification { var window = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], contentView = [window contentView]; var button = [CPButton buttonWithTitle:@"Calculator"]; [button setFrameOrigin:CGPointMake(60, 40)]; [contentView addSubview:button]; [button setTarget:self]; [button setAction:@selector(raiseCalculatorPanel:)]; [window orderFront:self]; } 46 © 2009 Howard Lewis Ship
  47. 47. Creating CalcController AppController.j … @import "CalcController.j" @implementation AppController : CPObject { CalcController _calcController; } … - (void)raiseCalculatorPanel:(id)sender { if (_calcController == nil) _calcController = [[CalcController alloc] init]; [_calcController show]; } @end 47 © 2009 Howard Lewis Ship
  48. 48. CalcController UI CalcController.j - (id)init { self = [super init]; _panel = [[CPPanel alloc] initWithContentRect:CGRectMake(20, 30, 184, 184) styleMask:CPHUDBackgroundWindowMask | CPClosableWindowMask]; _contentView = [_panel contentView]; [_panel setTitle:"Calculator"]; _display = [CPTextField labelWithTitle:""]; [_display setAlignment:CPRightTextAlignment]; [_display setFrame:CGRectMake(1, 5, 183, 30)] [_display setBezeled:YES]; [self add:_display]; [self makeButton:"C" atX:0 y:0 action:@selector(clear:)]; … return self; } 48 © 2009 Howard Lewis Ship
  49. 49. Window Resizing & Remote Communication 49 © 2009 Howard Lewis Ship
  50. 50. 50 © 2009 Howard Lewis Ship
  51. 51. Twitter Panel UI TwitterController.j _panel = [[CPPanel alloc] initWithContentRect:CGRectMake(20, 30, 245, 184) styleMask:CPHUDBackgroundWindowMask | CPClosableWindowMask | CPResizableWindowMask]; [_panel setTitle:@"Twitter"]; var label = [CPTextField labelWithTitle:"User:"]; [label setFrame:CGRectMake(3, 7, 50, 24)]; [label setTextColor:[CPColor whiteColor]]; _field = [CPTextField textFieldWithStringValue:"" placeholder:"Twitter User" width:200]; [_field setFrame:CGRectMake(40, 0, 200, 28)]; [_field setTarget:self]; [_field setAction:@selector(startSearch:)]; var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0, 32, 245, 160)]; [scrollView setAutohidesScrollers:YES]; var content = [_panel contentView]; [content addSubview:label]; [content addSubview:_field]; [content addSubview:scrollView]; 51 © 2009 Howard Lewis Ship
  52. 52. 52 © 2009 Howard Lewis Ship
  53. 53. Autoresize Flags Containing CPView CPViewMinYMargin CPView HeightSizable CPViewMinXMargin CPViewMaxXMargin CPView CPViewWidthSizable CPViewMaxYMargin 53 © 2009 Howard Lewis Ship
  54. 54. Autoresizing TwitterController.j [_panel setTitle:@"Twitter"]; [_panel setMinSize:CGSizeMake(245, 184)]; var label = [CPTextField labelWithTitle:"User:"]; [label setFrame:CGRectMake(3, 7, 50, 24)]; [label setTextColor:[CPColor whiteColor]]; _field = [CPTextField textFieldWithStringValue:"" placeholder:"Twitter User" width:200]; [_field setFrame:CGRectMake(40, 0, 200, 28)]; [_field setTarget:self]; [_field setAction:@selector(startSearch:)]; [_field setAutoresizingMask:CPViewWidthSizable]; var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0, 32, 245, 160)]; [scrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; [scrollView setAutohidesScrollers:YES]; [scrollView setBackgroundColor:[CPColor whiteColor]]; Temporary 54 © 2009 Howard Lewis Ship
  55. 55. 55 © 2009 Howard Lewis Ship
  56. 56. CPCollectionView TwitterController.j var itemPrototype = [[CPCollectionViewItem alloc] init]; [itemPrototype setView:[[TwitView alloc] init]]; _timelineView = [[CPCollectionView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(scrollViewBounds) - 2, 0)]; [_timelineView setItemPrototype:itemPrototype]; [_timelineView setDelegate:self]; [_timelineView setMaxNumberOfColumns:1]; [_timelineView setAutoresizingMask:CPViewWidthSizable]; [_scrollView setDocumentView:_timelineView]; 56 © 2009 Howard Lewis Ship
  57. 57. JSON ➠ Image & Label { "title" : "Mmm - biscuits and gravy, in my hometown, with the woman I love.", … "user" : { "profile_image_url" : "http://a3.twimg.com/profile_images/71386417/scott_davis_2009_normal.jpg", … } } TwitView.j - (void)setRepresentedObject:(JSONObject)obj { if (!_label) { … } [_imageView setImage:[[CPImage alloc] initByReferencingFile:obj.user.profile_image_url size:CPSizeMake(55, 55)]]; [_label setStringValue:obj.text]; } @end 57 © 2009 Howard Lewis Ship
  58. 58. Sending the Search Request Cached file (to avoid authentication) TwitterController.j - (void)startSearch:(id)sender { var url = "twitter/statuses/friends_timeline/" + [_field stringValue] + ".json"; var request = [CPURLRequest requestWithURL:url]; [CPURLConnection connectionWithRequest:request delegate:self]; } Who to notify when data arrives 58 © 2009 Howard Lewis Ship
  59. 59. Handling the Response TwitterController.j - (void)connection:(CPURLConnection)connection didReceiveData:(CPString)data { var timeline = JSON.parse(data); [_timelineView setContent:timeline]; } - (void)connection:(CPURLConnection)connection didFailWithError:(CPString)error { CPLog.error(error); } TwitView.j - (void)setRepresentedObject:(JSONObject)obj { ... } @end 59 © 2009 Howard Lewis Ship
  60. 60. Cappuccino Pitfalls 60 © 2009 Howard Lewis Ship
  61. 61. Documentation 61 © 2009 Howard Lewis Ship
  62. 62. Mac-Centric 62 © 2009 Howard Lewis Ship
  63. 63. Compilation Exceptions 63 © 2009 Howard Lewis Ship
  64. 64. Client-Side Efficiency 64 © 2009 Howard Lewis Ship
  65. 65. Wrap Up 65 © 2009 Howard Lewis Ship
  66. 66. http://github.com/hlship/nfjs-cappuccino 66 © 2009 Howard Lewis Ship
  67. 67. http://cappuccino.org 67 © 2009 Howard Lewis Ship
  68. 68. Image Credits © 2008 nalungaard http://www.flickr.com/photos/nalundgaard/2587677285/ © 2005 Michael Sarver http://www.flickr.com/photos/michaelsarver/44302391/ © 2007 Till Krech http://www.flickr.com/photos/extranoise/487179535/ © 2009 Phill Davison http://www.flickr.com/photos/phill_dvsn/3771462059/ © 2007 Howard Gees http://www.flickr.com/photos/cyberslayer/952153409/ © 2006 Tyler Hawkins http://www.flickr.com/photos/m4m/279364376/ © 2009 Harald http://www.flickr.com/photos/haarald/3227728698/ © 2006 Brittney Bush Bollay http://www.flickr.com/photos/tzofia/247056173/ 68 © 2009 Howard Lewis Ship

×