mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			434 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			434 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| //
 | |
| // AppController.j
 | |
| // FlickrPhoto
 | |
| //
 | |
| // Created by Ross Boucher.
 | |
| // Copyright 2008 - 2010, 280 North, Inc. All rights reserved.
 | |
| 
 | |
| @import <Foundation/Foundation.j>
 | |
| @import <AppKit/AppKit.j>
 | |
| 
 | |
| var SliderToolbarItemIdentifier = "SliderToolbarItemIdentifier",
 | |
|     AddToolbarItemIdentifier = "AddToolbarItemIdentifier",
 | |
|     RemoveToolbarItemIdentifier = "RemoveToolbarItemIdentifier";
 | |
| 
 | |
| /*
 | |
|     Important note about CPJSONPConnection: CPJSONPConnection is ONLY for JSONP APIs.
 | |
|     If aren't sure you NEED JSONP (see http://ajaxian.com/archives/jsonp-json-with-padding ),
 | |
|     you most likely don't want to use CPJSONPConnection, but rather the more standard
 | |
|     CPURLConnection. CPJSONPConnection is designed for cross-domain
 | |
|     connections, and if you are making requests to the same domain (as most web
 | |
|     applications do), you do not need it.
 | |
| */
 | |
| 
 | |
| @implementation AppController : CPObject
 | |
| {
 | |
|     CPString                lastIdentifier;
 | |
|     CPDictionary            photosets;
 | |
| 
 | |
|     CPCollectionView        listCollectionView;
 | |
|     CPCollectionView        photosCollectionView;
 | |
| }
 | |
| 
 | |
| - (void)applicationDidFinishLaunching:(CPNotification)aNotification
 | |
| {
 | |
|     //the first thing we need to do is create a window to take up the full screen
 | |
|     //we'll also create a toolbar to go with it, and grab its size for future reference
 | |
| 
 | |
|     var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask],
 | |
|         contentView = [theWindow contentView],
 | |
|         toolbar = [[CPToolbar alloc] initWithIdentifier:"Photos"],
 | |
|         bounds = [contentView bounds];
 | |
| 
 | |
|     //we tell the toolbar that we want to be its delegate and attach it to theWindow
 | |
|     [toolbar setDelegate:self];
 | |
|     [toolbar setVisible:true];
 | |
|     [theWindow setToolbar:toolbar];
 | |
| 
 | |
|     photosets = [CPDictionary dictionary]; //storage for our sets of photos return from Flickr
 | |
| 
 | |
|     //now we create a scroll view to contain the list of collections of photos (photosets)
 | |
|     //inside the scroll view, we'll place our collection view, which manages a collection of "cells"
 | |
|     //each cell will represent one photo collection, and choosing cells will select that collection
 | |
| 
 | |
|     var listScrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0, 0, 200, CGRectGetHeight(bounds) - 58)];
 | |
|     [listScrollView setAutohidesScrollers:YES];
 | |
|     [listScrollView setAutoresizingMask:CPViewHeightSizable];
 | |
|     [[listScrollView contentView] setBackgroundColor:[CPColor colorWithRed:213.0 / 255.0 green:221.0 / 255.0 blue:230.0 / 255.0 alpha:1.0]];
 | |
| 
 | |
|     //we create the collection view cells by creating a single prototype (CPCollectionViewItem) and setting its view.
 | |
|     //the CPCollectionView class will then duplicate this item as many times as it needs
 | |
| 
 | |
|     var photosListItem = [[CPCollectionViewItem alloc] init];
 | |
|     [photosListItem setView:[[PhotosListCell alloc] initWithFrame:CGRectMakeZero()]];
 | |
| 
 | |
|     listCollectionView = [[CPCollectionView alloc] initWithFrame:CGRectMake(0, 0, 200, 0)];
 | |
| 
 | |
|     [listCollectionView setDelegate:self]; //we want delegate methods
 | |
|     [listCollectionView setItemPrototype:photosListItem]; //set the item prototype
 | |
| 
 | |
|     [listCollectionView setMinItemSize:CGSizeMake(20.0, 45.0)];
 | |
|     [listCollectionView setMaxItemSize:CGSizeMake(1000.0, 45.0)];
 | |
|     [listCollectionView setMaxNumberOfColumns:1]; //setting a single column will make this appear as a vertical list
 | |
| 
 | |
|     [listCollectionView setVerticalMargin:0.0];
 | |
|     [listCollectionView setAutoresizingMask:CPViewWidthSizable];
 | |
| 
 | |
|     //finally, we put our collection view inside the scroll view as it's document view, so it can be scrolled
 | |
|     [listScrollView setDocumentView:listCollectionView];
 | |
| 
 | |
|     //and we add it to the window's content view, so it will show up on the screen
 | |
|     [contentView addSubview:listScrollView];
 | |
| 
 | |
|     //repeat the process with another collection view for the actual photos
 | |
|     //this time we'll use a different view for the prototype (PhotoCell)
 | |
| 
 | |
|     var photoItem = [[CPCollectionViewItem alloc] init];
 | |
|     [photoItem setView:[[PhotoCell alloc] initWithFrame:CGRectMake(0, 0, 150, 150)]];
 | |
| 
 | |
|     var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(200, 0, CGRectGetWidth(bounds) - 200, CGRectGetHeight(bounds) - 58)];
 | |
| 
 | |
|     photosCollectionView = [[CPCollectionView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(bounds) - 200, 0)];
 | |
| 
 | |
|     [photosCollectionView setDelegate:self];
 | |
|     [photosCollectionView setItemPrototype:photoItem];
 | |
| 
 | |
|     [photosCollectionView setMinItemSize:CGSizeMake(150, 150)];
 | |
|     [photosCollectionView setMaxItemSize:CGSizeMake(150, 150)];
 | |
|     [photosCollectionView setAutoresizingMask:CPViewWidthSizable];
 | |
| 
 | |
|     [scrollView setAutoresizingMask:CPViewHeightSizable | CPViewWidthSizable];
 | |
|     [scrollView setDocumentView:photosCollectionView];
 | |
|     [scrollView setAutohidesScrollers:YES];
 | |
| 
 | |
|     [[scrollView contentView] setBackgroundColor:[CPColor colorWithCalibratedWhite:0.25 alpha:1.0]];
 | |
| 
 | |
|     [contentView addSubview:scrollView];
 | |
| 
 | |
|     //bring forward the window to display it
 | |
|     [theWindow orderFront:self];
 | |
| 
 | |
|     //get the most interesting photos on flickr
 | |
|     var request = [CPURLRequest requestWithURL:"http://www.flickr.com/services/rest/?method=flickr.interestingness.getList&per_page=20&format=json&api_key=ca4dd89d3dfaeaf075144c3fdec76756"];
 | |
| 
 | |
|     // see important note about CPJSONPConnection above
 | |
|     var connection = [CPJSONPConnection sendRequest:request callback:"jsoncallback" delegate:self];
 | |
| 
 | |
|     lastIdentifier = "Interesting Photos";
 | |
| }
 | |
| 
 | |
| - (void)add:(id)sender
 | |
| {
 | |
|     var string = prompt("Enter a tag to search Flickr for photos.");
 | |
| 
 | |
|     if (string)
 | |
|     {
 | |
|         //create a new request for the photos with the tag returned from the javascript prompt
 | |
|         var request = [CPURLRequest requestWithURL:"http://www.flickr.com/services/rest/?"+
 | |
|                                                     "method=flickr.photos.search&tags="+encodeURIComponent(string)+
 | |
|                                                     "&media=photos&machine_tag_mode=any&per_page=20&format=json&api_key=ca4dd89d3dfaeaf075144c3fdec76756"];
 | |
| 
 | |
|         // see important note about CPJSONPConnection above
 | |
|         [CPJSONPConnection sendRequest:request callback:"jsoncallback" delegate:self];
 | |
| 
 | |
|         lastIdentifier = string;
 | |
|     }
 | |
| }
 | |
| 
 | |
| - (void)remove:(id)sender
 | |
| {
 | |
|     //remove this photo
 | |
|     [self removeImageListWithIdentifier:[[photosets allKeys] objectAtIndex:[[listCollectionView selectionIndexes] firstIndex]]];
 | |
| }
 | |
| 
 | |
| - (void)addImageList:(CPArray)images withIdentifier:(CPString)aString
 | |
| {
 | |
|     [photosets setObject:images forKey:aString];
 | |
| 
 | |
|     [listCollectionView setContent:[[photosets allKeys] copy]];
 | |
|     [listCollectionView setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[photosets allKeys] indexOfObject:aString]]];
 | |
| }
 | |
| 
 | |
| - (void)removeImageListWithIdentifier:(CPString)aString
 | |
| {
 | |
|     var nextIndex = MAX([[listCollectionView content] indexOfObject:aString] - 1, 0);
 | |
| 
 | |
|     [photosets removeObjectForKey:aString];
 | |
| 
 | |
|     [listCollectionView setContent:[[photosets allKeys] copy]];
 | |
|     [listCollectionView setSelectionIndexes:[CPIndexSet indexSetWithIndex:nextIndex]];
 | |
| }
 | |
| 
 | |
| - (void)adjustImageSize:(id)sender
 | |
| {
 | |
|     var newSize = [sender value];
 | |
| 
 | |
|     [photosCollectionView setMinItemSize:CGSizeMake(newSize, newSize)];
 | |
|     [photosCollectionView setMaxItemSize:CGSizeMake(newSize, newSize)];
 | |
| }
 | |
| 
 | |
| - (void)collectionViewDidChangeSelection:(CPCollectionView)aCollectionView
 | |
| {
 | |
|     if (aCollectionView == listCollectionView)
 | |
|     {
 | |
|         var listIndex = [[listCollectionView selectionIndexes] firstIndex];
 | |
| 
 | |
|         if (listIndex === CPNotFound)
 | |
|             return;
 | |
| 
 | |
|         var key = [listCollectionView content][listIndex];
 | |
| 
 | |
|         [photosCollectionView setContent:[photosets objectForKey:key]];
 | |
|         [photosCollectionView setSelectionIndexes:[CPIndexSet indexSet]];
 | |
|     }
 | |
| }
 | |
| 
 | |
| - (void)connection:(CPJSONPConnection)aConnection didReceiveData:(CPString)data
 | |
| {
 | |
|     //this method is called when the network request returns. the data is the returned
 | |
|     //information from flickr. we set the array of photo urls as the data to our collection view
 | |
| 
 | |
|     [self addImageList:data.photos.photo withIdentifier:lastIdentifier];
 | |
| }
 | |
| 
 | |
| - (void)connection:(CPJSONPConnection)aConnection didFailWithError:(CPString)error
 | |
| {
 | |
|     alert(error); //a network error occurred
 | |
| }
 | |
| 
 | |
| //these two methods are the toolbar delegate methods, and tell the toolbar what it should display to the user
 | |
| 
 | |
| - (CPArray)toolbarAllowedItemIdentifiers:(CPToolbar)aToolbar
 | |
| {
 | |
|    return [self toolbarDefaultItemIdentifiers:aToolbar];
 | |
| }
 | |
| 
 | |
| - (CPArray)toolbarDefaultItemIdentifiers:(CPToolbar)aToolbar
 | |
| {
 | |
|    return [AddToolbarItemIdentifier, RemoveToolbarItemIdentifier, CPToolbarFlexibleSpaceItemIdentifier, SliderToolbarItemIdentifier];
 | |
| }
 | |
| 
 | |
| //this delegate method returns the actual toolbar item for the given identifier
 | |
| 
 | |
| - (CPToolbarItem)toolbar:(CPToolbar)aToolbar itemForItemIdentifier:(CPString)anItemIdentifier willBeInsertedIntoToolbar:(BOOL)aFlag
 | |
| {
 | |
|     var toolbarItem = [[CPToolbarItem alloc] initWithItemIdentifier:anItemIdentifier];
 | |
| 
 | |
|     if (anItemIdentifier == SliderToolbarItemIdentifier)
 | |
|     {
 | |
|         [toolbarItem setView:[[PhotoResizeView alloc] initWithFrame:CGRectMake(0, 0, 180, 32)]];
 | |
|         [toolbarItem setMinSize:CGSizeMake(180, 32)];
 | |
|         [toolbarItem setMaxSize:CGSizeMake(180, 32)];
 | |
|         [toolbarItem setLabel:"Scale"];
 | |
|     }
 | |
|     else if (anItemIdentifier == AddToolbarItemIdentifier)
 | |
|     {
 | |
|         var image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle mainBundle] pathForResource:"add.png"] size:CPSizeMake(30, 25)],
 | |
|             highlighted = [[CPImage alloc] initWithContentsOfFile:[[CPBundle mainBundle] pathForResource:"addHighlighted.png"] size:CPSizeMake(30, 25)];
 | |
| 
 | |
|         [toolbarItem setImage:image];
 | |
|         [toolbarItem setAlternateImage:highlighted];
 | |
| 
 | |
|         [toolbarItem setTarget:self];
 | |
|         [toolbarItem setAction:@selector(add:)];
 | |
|         [toolbarItem setLabel:"Add Photo List"];
 | |
| 
 | |
|         [toolbarItem setMinSize:CGSizeMake(32, 32)];
 | |
|         [toolbarItem setMaxSize:CGSizeMake(32, 32)];
 | |
|     }
 | |
|     else if (anItemIdentifier == RemoveToolbarItemIdentifier)
 | |
|     {
 | |
|         var image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle mainBundle] pathForResource:"remove.png"] size:CPSizeMake(30, 25)],
 | |
|             highlighted = [[CPImage alloc] initWithContentsOfFile:[[CPBundle mainBundle] pathForResource:"removeHighlighted.png"] size:CPSizeMake(30, 25)];
 | |
| 
 | |
|         [toolbarItem setImage:image];
 | |
|         [toolbarItem setAlternateImage:highlighted];
 | |
| 
 | |
|         [toolbarItem setTarget:self];
 | |
|         [toolbarItem setAction:@selector(remove:)];
 | |
|         [toolbarItem setLabel:"Remove Photo List"];
 | |
| 
 | |
|         [toolbarItem setMinSize:CGSizeMake(32, 32)];
 | |
|         [toolbarItem setMaxSize:CGSizeMake(32, 32)];
 | |
|     }
 | |
| 
 | |
|     return toolbarItem;
 | |
| }
 | |
| 
 | |
| @end
 | |
| 
 | |
| /*
 | |
|     This code demonstrates how to add a category to an existing class.
 | |
|     In this case, we are adding the class method +flickr_labelWithText: to
 | |
|     the CPTextField class. Later on, we can call [CPTextField flickr_labelWithText:"foo"]
 | |
|     to return a new text field with the string foo.
 | |
|     Best practices suggest prefixing category methods with your unique prefix, to prevent collisions.
 | |
| */
 | |
| 
 | |
| @implementation CPTextField (CreateLabel)
 | |
| 
 | |
| + (CPTextField)flickr_labelWithText:(CPString)aString
 | |
| {
 | |
|     var label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
 | |
| 
 | |
|     [label setStringValue:aString];
 | |
|     [label sizeToFit];
 | |
|     [label setTextShadowColor:[CPColor whiteColor]];
 | |
|     [label setTextShadowOffset:CGSizeMake(0, 1)];
 | |
| 
 | |
|     return label;
 | |
| }
 | |
| 
 | |
| @end
 | |
| 
 | |
| // This class wraps our slider + labels combo
 | |
| 
 | |
| @implementation PhotoResizeView : CPView
 | |
| {
 | |
| }
 | |
| 
 | |
| - (id)initWithFrame:(CGRect)aFrame
 | |
| {
 | |
|     self = [super initWithFrame:aFrame];
 | |
| 
 | |
|     var slider = [[CPSlider alloc] initWithFrame:CGRectMake(30, CGRectGetHeight(aFrame) / 2.0 - 8, CGRectGetWidth(aFrame) - 65, 24)];
 | |
| 
 | |
|     [slider setMinValue:50.0];
 | |
|     [slider setMaxValue:250.0];
 | |
|     [slider setIntValue:150.0];
 | |
|     [slider setAction:@selector(adjustImageSize:)];
 | |
| 
 | |
|     [self addSubview:slider];
 | |
| 
 | |
|     var label = [CPTextField flickr_labelWithText:"50"];
 | |
|     [label setFrameOrigin:CGPointMake(0, CGRectGetHeight(aFrame) / 2.0 - 4.0)];
 | |
|     [self addSubview:label];
 | |
| 
 | |
|     label = [CPTextField flickr_labelWithText:"250"];
 | |
|     [label setFrameOrigin:CGPointMake(CGRectGetWidth(aFrame) - CGRectGetWidth([label frame]), CGRectGetHeight(aFrame) / 2.0 - 4.0)];
 | |
|     [self addSubview:label];
 | |
| 
 | |
|     return self;
 | |
| }
 | |
| 
 | |
| @end
 | |
| 
 | |
| // This class displays a single photo collection inside our list of photo collecitions
 | |
| 
 | |
| @implementation PhotosListCell : CPView
 | |
| {
 | |
|     CPTextField     label;
 | |
|     CPView          highlightView;
 | |
| }
 | |
| 
 | |
| - (void)setRepresentedObject:(JSObject)anObject
 | |
| {
 | |
|     if (!label)
 | |
|     {
 | |
|         label = [[CPTextField alloc] initWithFrame:CGRectInset([self bounds], 4, 4)];
 | |
| 
 | |
|         [label setFont:[CPFont systemFontOfSize:16.0]];
 | |
|         [label setTextShadowColor:[CPColor whiteColor]];
 | |
|         [label setTextShadowOffset:CGSizeMake(0, 1)];
 | |
| 
 | |
|         [self addSubview:label];
 | |
|     }
 | |
| 
 | |
|     [label setStringValue:anObject];
 | |
|     [label sizeToFit];
 | |
| 
 | |
|     [label setFrameOrigin:CGPointMake(10,CGRectGetHeight([label bounds]) / 2.0)];
 | |
| }
 | |
| 
 | |
| - (void)setSelected:(BOOL)flag
 | |
| {
 | |
|     if (!highlightView)
 | |
|     {
 | |
|         highlightView = [[CPView alloc] initWithFrame:CGRectCreateCopy([self bounds])];
 | |
|         [highlightView setBackgroundColor:[CPColor blueColor]];
 | |
|     }
 | |
| 
 | |
|     if (flag)
 | |
|     {
 | |
|         [self addSubview:highlightView positioned:CPWindowBelow relativeTo:label];
 | |
|         [label setTextColor:[CPColor whiteColor]];
 | |
|         [label setTextShadowColor:[CPColor blackColor]];
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         [highlightView removeFromSuperview];
 | |
|         [label setTextColor:[CPColor blackColor]];
 | |
|         [label setTextShadowColor:[CPColor whiteColor]];
 | |
|     }
 | |
| }
 | |
| 
 | |
| @end
 | |
| 
 | |
| // This class displays a single photo from our collection
 | |
| 
 | |
| @implementation PhotoCell : CPView
 | |
| {
 | |
|     CPImage         image;
 | |
|     CPImageView     imageView;
 | |
|     CPView          highlightView;
 | |
| }
 | |
| 
 | |
| - (void)setRepresentedObject:(JSObject)anObject
 | |
| {
 | |
|     if (!imageView)
 | |
|     {
 | |
|         imageView = [[CPImageView alloc] initWithFrame:CGRectMakeCopy([self bounds])];
 | |
|         [imageView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
 | |
|         [imageView setImageScaling:CPScaleProportionally];
 | |
|         [imageView setHasShadow:YES];
 | |
|         [self addSubview:imageView];
 | |
|     }
 | |
| 
 | |
|     [image setDelegate:nil];
 | |
| 
 | |
|     image = [[CPImage alloc] initWithContentsOfFile:thumbForFlickrPhoto(anObject)];
 | |
| 
 | |
|     [image setDelegate:self];
 | |
| 
 | |
|     if ([image loadStatus] == CPImageLoadStatusCompleted)
 | |
|         [imageView setImage:image];
 | |
|     else
 | |
|         [imageView setImage:nil];
 | |
| }
 | |
| 
 | |
| - (void)imageDidLoad:(CPImage)anImage
 | |
| {
 | |
|     [imageView setImage:anImage];
 | |
| }
 | |
| 
 | |
| - (void)setSelected:(BOOL)flag
 | |
| {
 | |
|     if (!highlightView)
 | |
|     {
 | |
|         highlightView = [[CPView alloc] initWithFrame:[self bounds]];
 | |
|         [highlightView setBackgroundColor:[CPColor colorWithCalibratedWhite:0.8 alpha:0.6]];
 | |
|         [highlightView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
 | |
|     }
 | |
| 
 | |
|     if (flag)
 | |
|     {
 | |
|         [highlightView setFrame:[self bounds]];
 | |
|         [self addSubview:highlightView positioned:CPWindowBelow relativeTo:imageView];
 | |
|     }
 | |
|     else
 | |
|         [highlightView removeFromSuperview];
 | |
| }
 | |
| 
 | |
| @end
 | |
| 
 | |
| // helper javascript functions for turning a Flickr photo object into a URL for getting the image
 | |
| 
 | |
| function urlForFlickrPhoto(photo)
 | |
| {
 | |
|     return "http://farm" + photo.farm + ".static.flickr.com/" + photo.server + "/" + photo.id+"_" + photo.secret + ".jpg";
 | |
| }
 | |
| 
 | |
| function thumbForFlickrPhoto(photo)
 | |
| {
 | |
|     return "http://farm" + photo.farm + ".static.flickr.com/" + photo.server + "/" + photo.id + "_" + photo.secret + "_m.jpg";
 | |
| } |