Skip to content

Instantly share code, notes, and snippets.

@Me1000
Created July 3, 2010 06:37
Show Gist options
  • Save Me1000/462368 to your computer and use it in GitHub Desktop.
Save Me1000/462368 to your computer and use it in GitHub Desktop.
/*
* AppController.j
* imdbdemo
*
* Created by Randy Luecke on July 2, 2010.
* Copyright 2010, RCLConcepts, LLC All rights reserved.
*/
@import <Foundation/CPObject.j>
@import <AppKit/CPScrollView.j>
@import <AppKit/CPTableView.j>
@import <AppKit/CPTableColumn.j>
@implementation AppController : CPObject
{
CPDictionary data;
}
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
// convert the data to make it easier to deal with
data = [ ];
// loop through everything and create a dictionary in place of the JSObject adding it to the array
for (var i = 0; i < window.DATA.length; i++)
data[i] = [CPDictionary dictionaryWithJSObject:window.DATA[i] recursively:NO];
var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask],
contentView = [theWindow contentView],
bounds = [contentView bounds];
[contentView setBackgroundColor:[CPColor colorWithHexString:"d7d6d8"]];
var label = [[CPTextField alloc] initWithFrame:CGRectMake(15, 15, 0,0)];
[label setStringValue:"IMDB Ratings"];
[label setFont:[CPFont boldSystemFontOfSize:24]];
[label setTextColor:[CPColor whiteColor]];
[label setTextShadowColor:[CPColor blackColor]];
[label setTextShadowOffset:CGSizeMake(1,1)];
[label sizeToFit];
[contentView addSubview:label];
// give the scrollview a 15px margin on all sides to conform with the HIG
var start = CGRectGetMaxY([label frame]) + 15,
scroll = [[CPScrollView alloc] initWithFrame:CGRectMake(0, start, bounds.size.width, bounds.size.height - start)],
table = [[CPTableView alloc] initWithFrame:CGRectMakeZero()];
// the delegate is notified about behavior stuff
[table setDelegate:self];
// the data source gives the tableview all it's data
[table setDataSource:self];
[table setAllowsMultipleSelection:YES];
[table setUsesAlternatingRowBackgroundColors:YES];
// in order to use Drag and Drop we register for items of the type "myItems"
[table registerForDraggedTypes:["myItems"]];
// We add columns like so
var column = [[CPTableColumn alloc] initWithIdentifier:"title"],
descriptor = [CPSortDescriptor sortDescriptorWithKey:"title" ascending:NO]; // this is used for sorting
[[column headerView] setStringValue:"Title"];
[column setWidth:555.0]; // you can also set a min/max width if you want
// apply the sort descriptor to this column so it knows how to sort.
[column setSortDescriptorPrototype:descriptor];
// finally add it to the table
[table addTableColumn:column];
// we do this two more times
var column2 = [[CPTableColumn alloc] initWithIdentifier:"rating"],
descriptor = [CPSortDescriptor sortDescriptorWithKey:"rating" ascending:NO];
[[column2 headerView] setStringValue:"Rating"];
[column2 setWidth:150.0];
[column2 setSortDescriptorPrototype:descriptor];
[table addTableColumn:column2];
var column3 = [[CPTableColumn alloc] initWithIdentifier:"votes"],
descriptor = [CPSortDescriptor sortDescriptorWithKey:"votes" ascending:NO];
[[column3 headerView] setStringValue:"Votes"];
[column3 setWidth:150.0];
[column3 setSortDescriptorPrototype:descriptor];
[table addTableColumn:column3];
// when then tell the scrollview that it needs to scroll the tableview
[scroll setDocumentView:table];
// and resize so that it fills the screen always
[scroll setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
// and who wants scroll bars when they're not needed?
[scroll setAutohidesScrollers:YES];
// finally add the scrollview to the window's contentview
[contentView addSubview:scroll];
// bring the window to the front.
[theWindow orderFront:self];
}
// since the app controller is the data source we must implement a couple of required data source methods
// first the data source is asked how many rows the tableview contains
- (int)numberOfRowsInTableView:(CPTableView)atableView
{
return [data count];
}
// Then the data source needs to supply the data to the tableview.
- (id)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)aColumn row:(int)aRow
{
// the key is the identifier we assigned to the column
var key = [aColumn identifier];
// the object at our specific row is what we want, but we want a specific value from that dictionary.
return [data[aRow] objectForKey:key];
}
// when the sort descriptor changes we need to sort our data
- (void)tableView:(CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldDescriptors
{
// first we figure out how we're suppose to sort, then sort the data array
var newDescriptors = [aTableView sortDescriptors];
[data sortUsingDescriptors:newDescriptors];
// the reload the table data
[aTableView reloadData];
}
// when you drag a row (or group of rows) the datasource writes the values to the pasteboard and returns wheter or not to allow the drag.
- (BOOL)tableView:(CPTableView)aTableView writeRowsWithIndexes:(CPIndexSet)rowIndexes toPasteboard:(CPPasteboard)pboard
{
// using the keyed archiver we archive the data; in this case the row indexes we're dragging
var encodedData = [CPKeyedArchiver archivedDataWithRootObject:rowIndexes];
// we then declare the pasteboard types
[pboard declareTypes:["myItems"] owner:self];
// and then set the data to the pasteboard
[pboard setData:encodedData forType:"myItems"];
// and return YES to allow the drag.
return YES;
}
// as you drag the tableview needs to validate the drop
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(CPInteger)row proposedDropOperation:(CPTableViewDropOperation)operation
{
// with this method you can set whether you're dropping ABOVE or ON (as in on top of) the row of your choosing.
[aTableView setDropRow:row dropOperation:CPTableViewDropAbove];
// you then return the drag operation (move, copy, none, etc)
return CPDragOperationMove;
}
// when you finally drop on the tableview this method is called
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id)info row:(int)row dropOperation:(CPTableViewDropOperation)operation
{
// get the data you added to your pasteboard
var pboard = [info draggingPasteboard],
rowData = [pboard dataForType:"myItems"];
rowData = [CPKeyedUnarchiver unarchiveObjectWithData:rowData];
// we're using the method we added via a category below to move items around the array
[data moveIndexes:rowData toIndex:row];
// if the number of rows were to change (i.e. you dropped items onto the tablview from someowhere else, rather than reordering them)
// then you would want to call reloadData in order to select the correct indexes in the following methods
//[aTableView reloadData];
// then we want to select the row indexes we just dropped
var destIndexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(row, [rowData count])];
[aTableView selectRowIndexes:destIndexes byExtendingSelection:NO];
// returning YES tells the tableview to reload the data and completes the drop.
return YES;
}
@end
// a simple helper extention to CPArray to make it easier to move indexes around.
@implementation CPArray (MoveIndexes)
- (void)moveIndexes:(CPIndexSet)indexes toIndex:(int)insertIndex
{
var aboveCount = 0,
object,
removeIndex;
var index = [indexes lastIndex];
while (index != CPNotFound)
{
if (index >= insertIndex)
{
removeIndex = index + aboveCount;
aboveCount ++;
}
else
{
removeIndex = index;
insertIndex --;
}
object = [self objectAtIndex:removeIndex];
[self removeObjectAtIndex:removeIndex];
[self insertObject:object atIndex:insertIndex];
index = [indexes indexLessThanIndex:index];
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment