//
// VersionsViewController.m
// Perforce
//
// Created by Adam Czubernat on 18/12/2013.
// Copyright (c) 2013 Perforce Software, Inc. All rights reserved.
//
#import "VersionsViewController.h"
#import "VersionsViewCell.h"
#import "PSTableRowView.h"
#import "PSCoverFlow.h"
#import "P4Workspace.h"
#import "P4Item.h"
@interface VersionsViewController () <NSTableViewDataSource, NSTableViewDelegate, PSCoverFlowDelegate> {
P4Item *item;
__unsafe_unretained id <P4ItemActionDelegate> actionDelegate;
NSMutableArray *versions;
NSMutableDictionary *shelved;
CGFloat *rowHeights;
NSMutableArray *tableItems;
// Outlets
__weak IBOutlet NSTableView *tableView;
__weak IBOutlet PSCoverFlow *coverFlow;
}
- (void)updateRows;
- (void)loadVersions;
- (void)loadDetails:(NSArray *)paths;
- (void)loadShelved;
- (void)versionAction:(NSButton *)sender;
- (void)shelveAction:(NSButton *)sender;
@end
@implementation VersionsViewController
- (id)initWithItem:(P4Item *)anItem actionDelegate:(id<P4ItemActionDelegate>)delegate {
if (self = [self initWithNibName:NSStringFromClass([self class]) bundle:nil]) {
item = anItem;
actionDelegate = delegate;
}
return self;
}
- (void)dealloc {
free(rowHeights);
rowHeights = NULL;
}
- (void)loadView {
[super loadView];
[tableView setBackgroundColor:[NSUserDefaults colorForKey:kColorBackgroundColumnContainer]];
[self reload];
}
#pragma mark - Public
- (void)reload {
versions = [NSMutableArray array];
tableItems = [NSMutableArray arrayWithObject:[NSNull null]];
free(rowHeights);
rowHeights = NULL;
[tableView reloadData];
[self loadVersions];
}
#pragma mark - Private
- (void)updateRows {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(updateRows) object:nil];
[tableView updateRowsHeightFromIndex:0 toIndex:tableItems.count];
}
- (void)loadVersions {
NSString *path = item.path;
NSString *action = item.status;
BOOL skipFirstSection = YES;
if (action) {
if ([action isEqualToString:@"delete"] ||
[action isEqualToString:@"move/delete"]) {
path = item.remotePath;
skipFirstSection = NO;
} else if ([action isEqualToString:@"move/add"]) {
path = [item.metadata objectForKey:@"movedFile"];
skipFirstSection = NO;
}
}
[[P4Workspace sharedInstance]
listVersions:path
response:^(P4Operation *operation, NSArray *response) {
// Add shelved row
if (item.isShelved)
[tableItems addObject:shelved = [NSMutableDictionary dictionary]];
NSMutableArray *paths = [NSMutableArray array];
for (NSDictionary *version in response) {
// Append versions
NSArray *items = [version objectForKey:@"versions"];
[versions addObjectsFromArray:items];
// Get version path
NSString *path = [version objectForKey:@"depotFile"];
if (paths.count || !skipFirstSection) // Don't show section for first path
[tableItems addObject:path]; // Use as section in table
// Store path with revision number (there could be new file at that path)
NSNumber *rev = [[items objectAtIndex:0] objectForKey:@"rev"];
path = [path stringByAppendingFormat:@"#%@", rev];
[paths addObject:path];
// Append table Items
[tableItems addObjectsFromArray:items];
}
free(rowHeights);
rowHeights = calloc(tableItems.count, sizeof(CGFloat));
// Add new rows
if (tableItems.count > 1)
[tableView insertRowsFromIndex:1 toIndex:tableItems.count-1
withAnimation:NSTableViewAnimationEffectFade];
// Load details
[self loadDetails:paths];
// Load shelved details
[self loadShelved];
}];
}
- (void)loadDetails:(NSArray *)paths {
if (!paths.count) {
// Remove loading
[tableItems removeObjectAtIndex:0];
[tableView removeRowsFromIndex:0 toIndex:0 withAnimation:NSTableViewAnimationSlideUp];
return;
}
[coverFlow reload];
[self.view.window makeFirstResponder:coverFlow];
[[P4Workspace sharedInstance]
listVersionsDetails:paths
response:^(P4Operation *operation, NSArray *response) {
[response enumerateObjectsUsingBlock:^(NSDictionary *record, NSUInteger idx, BOOL *stop) {
NSMutableDictionary *versionItem = [versions objectAtIndex:idx];
NSNumber *versionChange = [versionItem objectForKey:@"change"];
NSNumber *recordChange = [record objectForKey:@"headChange"];
if (![versionChange isEqual:recordChange])
return;
// Append new details
[versionItem addEntriesFromDictionary:record];
}];
// Remove loading
[tableItems removeObjectAtIndex:0];
[tableView removeRowsFromIndex:0 toIndex:0 withAnimation:NSTableViewAnimationSlideUp];
[tableView reloadDataForRowsFromIndex:0 toIndex:tableItems.count-1];
[tableView updateRowsHeightFromIndex:0 toIndex:tableItems.count-1];
[coverFlow reloadImagesInRange:(NSRange) { 0, tableItems.count }];
}];
};
- (void)loadShelved {
if (!shelved)
return;
[[P4Workspace sharedInstance]
listShelvedFiles:@[ item.path ]
response:^(P4Operation *operation, NSArray *response) {
if (operation.errors || !response.count)
return;
[shelved addEntriesFromDictionary:[response objectAtIndex:0]];
NSInteger idx = [tableItems indexOfObjectIdenticalTo:shelved];
[tableView reloadDataForRowsFromIndex:idx toIndex:idx];
}];
}
#pragma mark Actions
- (void)versionAction:(NSButton *)sender {
NSInteger row = [tableView selectedRow];
NSDictionary *tableItem = [tableItems objectAtIndex:row];
NSString *path = [tableItem objectForKey:@"depotFile"];
NSNumber *rev = [tableItem objectForKey:@"headRev"];
NSString *versionPath = versionPath = [NSString stringWithFormat:@"%@#%@", path, rev];
if (!versionPath)
return;
if (sender.tag)
[item
performAction:@selector(revertToVersion:)
object:versionPath
delegate:actionDelegate];
else
[item
performAction:@selector(openVersion:)
object:versionPath
delegate:actionDelegate];
}
- (void)shelveAction:(NSButton *)sender {
if (sender.tag == 2)
[item
performAction:@selector(discardShelve)
object:nil
delegate:actionDelegate];
else if (sender.tag == 1)
[item
performAction:@selector(unshelve)
object:nil
delegate:actionDelegate];
else
[item
performAction:@selector(openShelve)
object:nil
delegate:actionDelegate];
}
#pragma mark - NSTableView data source
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return tableItems.count;
}
- (CGFloat)tableView:(NSTableView *)table heightOfRow:(NSInteger)row {
id tableItem = [tableItems objectAtIndex:row];
if (![tableItem isKindOfClass:[NSDictionary class]])
return 32.0f;
if (tableItem == shelved)
return 74.0f;
return rowHeights[row] ?: 114.0f;
}
- (NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row {
PSTableRowView *rowView = [[PSTableRowView alloc] init];
rowView.selectionColor = nil;
return rowView;
}
- (NSView *)tableView:(NSTableView *)aTableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
id tableItem = [tableItems objectAtIndex:row];
if (tableItem == shelved) {
VersionsViewCell *cell;
cell = [tableView makeViewWithIdentifier:@"ShelveCell" owner:self];
[cell setShelveDictionary:tableItem];
[cell setShowsButtons:YES];
[cell setButtonsTarget:self];
[cell setButtonsAction:@selector(shelveAction:)];
rowHeights[row] = [cell rowHeight];
return cell;
} else if ([tableItem isKindOfClass:[NSDictionary class]]) {
VersionsViewCell *cell;
cell = [tableView makeViewWithIdentifier:@"VersionCell" owner:self];
[cell setVersionDictionary:tableItem];
NSString *tags = [tableItem objectForKey:@"attr-tags"];
[cell setTags:[tags componentsSeparatedByString:@","]];
NSString *statusColorKey = kColorStatusAvailable;
if ([versions indexOfObjectIdenticalTo:tableItem] == 0) {
// Set status color for latest version
if (item.status)
statusColorKey = kColorStatusCheckedOut;
else if (item.statusOwner)
statusColorKey = kColorStatusCheckedOutSomeone;
}
[cell setStatusColor:[NSUserDefaults colorForKey:statusColorKey]];
NSString *action = [tableItem objectForKey:@"headAction"];
BOOL showButtons = action && ![@[ @"delete", @"move/delete" ] containsObject:action];
[cell setShowsButtons:showButtons];
[cell setButtonsTarget:self];
[cell setButtonsAction:@selector(versionAction:)];
if (!rowHeights[row]) {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(updateRows) object:nil];
[self performSelector:@selector(updateRows) withObject:nil afterDelay:0.01f];
}
rowHeights[row] = [cell rowHeight];
return cell;
} else if ([tableItem isKindOfClass:[NSNull class]]) {
NSView *indicatorCell = [tableView makeViewWithIdentifier:@"LoadingCell" owner:self];
[[indicatorCell.subviews lastObject] startAnimation:nil];
return indicatorCell;
} else {
NSTableCellView *cell = [tableView makeViewWithIdentifier:@"HeaderCell" owner:self];
cell.textField.stringValue = tableItem;
cell.toolTip = tableItem;
return cell;
}
}
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row {
id tableItem = [tableItems objectAtIndex:row];
return [tableItem isKindOfClass:[NSDictionary class]];
}
//- (NSIndexSet *)tableView:(NSTableView *)tableView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes {
// NSInteger row = proposedSelectionIndexes.firstIndex;
// id tableItem = row < 0 ? nil : [tableItems objectAtIndex:row];
// if ([versionItems containsObject:tableItem])
// return proposedSelectionIndexes;
// return [NSIndexSet indexSetWithIndex:proposedSelectionIndexes.firstIndex+1];
//}
- (void)tableViewSelectionDidChange:(NSNotification *)notification {
if (tableView.selectedRow == -1)
return;
id tableItem = [tableItems objectAtIndex:tableView.selectedRow];
NSInteger index = [versions indexOfObjectIdenticalTo:tableItem];
[coverFlow setSelectedIndex:index];
}
#pragma mark - PSCoverFlow delegate
- (NSInteger)numberOfImagesInCoverFlow:(id)coverFlow {
return versions.count;
}
- (NSImage *)coverFlow:(id)coverFlow imageForIndex:(NSInteger)index {
NSDictionary *versionItem = [versions objectAtIndex:index];
NSData *data = [versionItem objectForKey:@"attr-thumb"];
return [[NSImage alloc] initWithData:data];
}
- (void)coverFlow:(id)coverFlow didSelectIndex:(NSInteger)index {
// Translate index
id versionItem = [versions objectAtIndex:index];
NSInteger row = [tableItems indexOfObjectIdenticalTo:versionItem];
[tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
NSRect rowRect = [tableView rectOfRow:row];
NSPoint scrollOrigin = rowRect.origin;
[[[tableView.enclosingScrollView contentView] animator] setBoundsOrigin:scrollOrigin];
}
@end
# |
Change |
User |
Description |
Committed |
|
#1
|
10691 |
DWishR |
Populate //guest/DWishR/piper/.... |
|
|
//guest/perforce_software/piper/Perforce/Classes/ViewControllers/Versions/VersionsViewController.m |
#1
|
8919 |
Matt Attaway |
Initial add of Piper, a lightweight Perforce client for artists and designers. |
|
|