-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathRSRTVArrayController.m
executable file
·219 lines (179 loc) · 6.07 KB
/
RSRTVArrayController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// RSRTVArrayController.m
//
// RSRTV stands for Red Sweater Reordering Table View Controller.
//
// Based on code from Apple's DragNDropOutlineView example, which granted
// unlimited modification and redistribution rights, provided Apple not be held legally liable.
//
// Differences between this file and the original are © 2006 Red Sweater Software.
//
// You are granted a non-exclusive, unlimited license to use, reproduce, modify and
// redistribute this source code in any form provided that you agree to NOT hold liable
// Red Sweater Software or Daniel Jalkut for any damages caused by such use.
//
#import "RSRTVArrayController.h"
NSString *kRSRTVMovedRowsType = @"com.red-sweater.RSRTVArrayController";
@implementation RSRTVArrayController
- (void) awakeFromNib
{
[oTableView registerForDraggedTypes:[NSArray arrayWithObjects:kRSRTVMovedRowsType, nil]];
[self setDraggingEnabled:YES];
}
// draggingEnabled
- (BOOL) draggingEnabled
{
return mDraggingEnabled;
}
- (void) setDraggingEnabled: (BOOL) flag
{
mDraggingEnabled = flag;
}
- (BOOL)tableView:(NSTableView *)tv writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard
{
if ([self draggingEnabled] == YES)
{
// Declare our "moved rows" drag type
[pboard declareTypes:[NSArray arrayWithObjects:kRSRTVMovedRowsType, nil] owner:self];
// Just add the rows themselves to the pasteboard
[pboard setPropertyList:rows forType:kRSRTVMovedRowsType];
}
return [self draggingEnabled];
}
- (BOOL) tableObjectsSupportCopying
{
return [[[self arrangedObjects] objectAtIndex:0] conformsToProtocol:@protocol(NSCopying)];
}
- (NSDragOperation)tableView:(NSTableView*)tv validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)op
{
NSDragOperation dragOp = NSDragOperationNone;
// if drag source is our own table view, it's a move or a copy
if ([info draggingSource] == tv)
{
// At a minimum, allow move
dragOp = NSDragOperationMove;
// Only expose the copy method if objects in this table appear to support copying...
if (([info draggingSourceOperationMask] == NSDragOperationCopy) && ([self tableObjectsSupportCopying] == YES))
{
dragOp = NSDragOperationCopy;
}
}
// we want to put the object at, not over,
// the current row (contrast NSTableViewDropOn)
[tv setDropRow:row dropOperation:NSTableViewDropAbove];
return dragOp;
}
- (BOOL)tableView:(NSTableView*)tv acceptDrop:(id <NSDraggingInfo>)info row:(int)row dropOperation:(NSTableViewDropOperation)op
{
if (row < 0)
{
row = 0;
}
// if drag source is self, it's a move or copy
if ([info draggingSource] == tv)
{
NSArray *rows = [[info draggingPasteboard] propertyListForType:kRSRTVMovedRowsType];
NSIndexSet *indexSet = [self indexSetFromRows:rows];
int rowsAbove = 0;
if (([info draggingSourceOperationMask] == NSDragOperationCopy) && [self tableObjectsSupportCopying])
{
[self copyObjectsInArrangedObjectsFromIndexes:indexSet toIndex:row];
}
else
{
[self moveObjectsInArrangedObjectsFromIndexes:indexSet toIndex:row];
// set selected rows to those that were just moved
// Need to work out what moved where to determine proper selection...
rowsAbove = [self rowsAboveRow:row inIndexSet:indexSet];
}
NSRange range = NSMakeRange(row - rowsAbove, [indexSet count]);
indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
[self setSelectionIndexes:indexSet];
return YES;
}
return NO;
}
-(void) copyObjectsInArrangedObjectsFromIndexes:(NSIndexSet*)indexSet toIndex:(unsigned int)insertIndex
{
NSArray *objects = [self arrangedObjects];
int copyFromIndex = [indexSet lastIndex];
int aboveInsertIndexCount = 0;
id object;
int copyIndex;
while (NSNotFound != copyFromIndex)
{
if (copyFromIndex >= insertIndex)
{
copyIndex = copyFromIndex + aboveInsertIndexCount;
aboveInsertIndexCount += 1;
}
else
{
copyIndex = copyFromIndex;
// insertIndex -= 1;
}
object = [objects objectAtIndex:copyIndex];
[self insertObject:[object copy] atArrangedObjectIndex:insertIndex];
copyFromIndex = [indexSet indexLessThanIndex:copyFromIndex];
}
}
-(void) moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet*)indexSet toIndex:(unsigned int)insertIndex
{
NSArray *objects = [self arrangedObjects];
int index = [indexSet lastIndex];
int aboveInsertIndexCount = 0;
id object;
int removeIndex;
while (NSNotFound != index)
{
if (index >= insertIndex)
{
removeIndex = index + aboveInsertIndexCount;
aboveInsertIndexCount += 1;
}
else
{
removeIndex = index;
insertIndex -= 1;
}
// Get the object we're moving
object = [objects objectAtIndex:removeIndex];
// In case nobody else is retaining the object, we need to keep it alive while we move it
[object retain];
[self removeObjectAtArrangedObjectIndex:removeIndex];
[self insertObject:object atArrangedObjectIndex:insertIndex];
[object release];
index = [indexSet indexLessThanIndex:index];
}
}
- (NSIndexSet *)indexSetFromRows:(NSArray *)rows
{
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
NSEnumerator *rowEnumerator = [rows objectEnumerator];
NSNumber *idx;
while (idx = [rowEnumerator nextObject])
{
[indexSet addIndex:[idx intValue]];
}
return indexSet;
}
- (int)rowsAboveRow:(int)row inIndexSet:(NSIndexSet *)indexSet
{
unsigned currentIndex = [indexSet firstIndex];
int i = 0;
while (currentIndex != NSNotFound)
{
if (currentIndex < row) { i++; }
currentIndex = [indexSet indexGreaterThanIndex:currentIndex];
}
return i;
}
// WORK AROUND an NSTableView or something bug where the collapsed column leaves its contents drawn
// in the cornerView area when resized... by aggressively redrawing the cornerview whenever the
// columns resize, we can assure a clean slate.
- (void)tableViewColumnDidResize:(NSNotification *)notification
{
// Pay attention to column resizes and aggressively force the tableview's
// cornerview to redraw.
[[oTableView cornerView] setNeedsDisplay:YES];
}
@end