Develop and Download Open Source Software

Browse Subversion Repository

Contents of /XspfManager/XspfMLibraryViewController.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 566 - (show annotations) (download)
Mon Jun 20 14:18:18 2011 UTC (12 years, 10 months ago) by masakih
File size: 18379 byte(s)
[Fix] ライブラリ以外が選択されている時の新規プレイリストの挙動を修正。(#24232)
1 //
2 // XspfMLibraryViewController.m
3 // XspfManager
4 //
5 // Created by Hori,Masaki on 09/11/08.
6 //
7
8 /*
9 This source code is release under the New BSD License.
10 Copyright (c) 2009-2010, masakih
11 All rights reserved.
12
13 ソースコード形式かバイナリ形式か、変更するかしないかを問わず、以下の条件を満たす場合に
14 限り、再頒布および使用が許可されます。
15
16 1, ソースコードを再頒布する場合、上記の著作権表示、本条件一覧、および下記免責条項を含
17 めること。
18 2, バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の資料に、上記の著作権表
19 示、本条件一覧、および下記免責条項を含めること。
20 3, 書面による特別の許可なしに、本ソフトウェアから派生した製品の宣伝または販売促進に、
21 コントリビューターの名前を使用してはならない。
22 本ソフトウェアは、著作権者およびコントリビューターによって「現状のまま」提供されており、
23 明示黙示を問わず、商業的な使用可能性、および特定の目的に対する適合性に関する暗黙の保証
24 も含め、またそれに限定されない、いかなる保証もありません。著作権者もコントリビューター
25 も、事由のいかんを問わず、 損害発生の原因いかんを問わず、かつ責任の根拠が契約であるか
26 厳格責任であるか(過失その他の)不法行為であるかを問わず、仮にそのような損害が発生する
27 可能性を知らされていたとしても、本ソフトウェアの使用によって発生した(代替品または代用
28 サービスの調達、使用の喪失、データの喪失、利益の喪失、業務の中断も含め、またそれに限定
29 されない)直接損害、間接損害、偶発的な損害、特別損害、懲罰的損害、または結果損害につい
30 て、一切責任を負わないものとします。
31 -------------------------------------------------------------------
32 Copyright (c) 2009-2010, masakih
33 All rights reserved.
34
35 Redistribution and use in source and binary forms, with or without
36 modification, are permitted provided that the following conditions
37 are met:
38
39 1, Redistributions of source code must retain the above copyright
40 notice, this list of conditions and the following disclaimer.
41 2, Redistributions in binary form must reproduce the above copyright
42 notice, this list of conditions and the following disclaimer in
43 the documentation and/or other materials provided with the
44 distribution.
45 3, The names of its contributors may be used to endorse or promote
46 products derived from this software without specific prior
47 written permission.
48 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
49 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
50 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
51 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
52 COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
53 INCIDENTAL, SPECIAL,EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
54 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
55 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
56 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
58 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
59 POSSIBILITY OF SUCH DAMAGE.
60 */
61
62 #import "XspfMLibraryViewController.h"
63
64 #import "XspfMXspfListObject.h"
65
66 #import "XspfMRuleEditorDelegate.h"
67
68 #import "XspfMPreferences.h"
69
70
71 @interface XspfMLibraryViewController (HMPrivate)
72 - (NSArray *)sortDescriptors;
73 - (void)setupXspfList;
74 - (void)setupRules;
75
76 - (NSNumber *)orderForNewItem;
77
78 - (void)moveItemOfIndexSet:(NSIndexSet *)indexSet afterIndex:(NSInteger)afterIndex;
79 @end
80
81 enum {
82 kLibraryOrder = 0,
83 kFavoritesOrder,
84 kSmartLibraryOrder,
85 };
86
87 const NSInteger initialOrder = 10000;
88 const NSInteger orderStep = 10000;
89
90 static NSString *const XspfMLibItemPbardType = @"XspfMLibItemPbardType";
91
92 @implementation XspfMLibraryViewController
93
94 - (id)init
95 {
96 [super initWithNibName:@"LibraryView" bundle:nil];
97
98 [self setupXspfList];
99 [self setupRules];
100
101 return self;
102 }
103
104 - (void)dealloc
105 {
106 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
107 [nc removeObserver:self];
108
109 [super dealloc];
110 }
111
112 - (void)awakeFromNib
113 {
114 [[self representedObject] setSortDescriptors:[self sortDescriptors]];
115
116 [tableView registerForDraggedTypes:[NSArray arrayWithObject:XspfMLibItemPbardType]];
117 [tableView setDraggingSourceOperationMask:NSDragOperationMove forLocal:YES];
118
119
120 [self performSelector:@selector(delayExcute:) withObject:self afterDelay:0.02];
121 }
122 - (void)delayExcute:(id)dummy
123 {
124 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
125 [nc addObserver:self
126 selector:@selector(windowWillClose:)
127 name:NSWindowWillCloseNotification
128 object:[self.view window]];
129
130 XspfMPreferences *pref = [XspfMPreferences sharedPreference];
131 [xspfListController setSelectionIndex:pref.libraryLastSelectedIndexSet];
132 }
133
134 - (NSArray *)sortDescriptors
135 {
136 id desc = [[NSSortDescriptor alloc] initWithKey:@"order" ascending:YES];
137 return [NSArray arrayWithObject:[desc autorelease]];
138 }
139
140 - (void)addSmartLibrary:(NSString *)name predicate:(NSPredicate *)predicate order:(NSInteger)order
141 {
142 id obj = [NSEntityDescription insertNewObjectForEntityForName:@"XspfList"
143 inManagedObjectContext:[self managedObjectContext]];
144 [obj setValue:predicate forKey:@"predicate"];
145 [obj setValue:name forKey:@"name"];
146 [obj setValue:[self orderForNewItem] forKey:@"order"];
147 }
148 - (void)setupXspfList
149 {
150 NSManagedObjectContext *moc = [self managedObjectContext];
151 NSError *error = nil;
152 NSFetchRequest *fetch;
153 NSInteger num;
154
155 fetch = [[[NSFetchRequest alloc] init] autorelease];
156 [fetch setEntity:[NSEntityDescription entityForName:@"XspfList"
157 inManagedObjectContext:moc]];
158 num = [moc countForFetchRequest:fetch
159 error:&error];
160 if(num != 0) return;
161
162 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"urlString <> %@", @""];
163 [self addSmartLibrary:@"Library"
164 predicate:predicate
165 order:kLibraryOrder];
166
167 predicate = [NSPredicate predicateWithFormat:@"favorites = %@", [NSNumber numberWithBool:YES]];
168 [self addSmartLibrary:@"Favorites"
169 predicate:predicate
170 order:kFavoritesOrder];
171 }
172
173 - (void)setupRules
174 {
175 [XspfMRuleEditorDelegate registerStringTypeKeyPaths:[NSArray arrayWithObjects:@"title", @"information.voiceActorsList", @"information.productsList", nil]];
176 [XspfMRuleEditorDelegate registerDateTypeKeyPaths:[NSArray arrayWithObjects:@"lastPlayDate", @"modificationDate", @"creationDate", nil]];
177 [XspfMRuleEditorDelegate setUseRating:YES];
178 [XspfMRuleEditorDelegate setUseLablel:YES];
179 }
180
181 - (BOOL)mouseInTableView
182 {
183 NSEvent *event = [[[self view] window] currentEvent];
184 NSPoint mouse = [[tableView superview] convertPoint:[event locationInWindow] fromView:nil];
185
186 return NSPointInRect(mouse, [tableView visibleRect]);
187 }
188 - (XspfMXspfListObject *)targetObject
189 {
190 id array = [[self representedObject] arrangedObjects];
191
192 NSInteger row = [tableView clickedRow];
193 if(row >= 0 && [array count] > row) {
194 return [array objectAtIndex:row];
195 }
196
197 if(![self mouseInTableView]) {
198 NSArray *selection = [[self representedObject] selectedObjects];
199 if([selection count] != 0) {
200 return [selection objectAtIndex:0];
201 }
202 }
203 return nil;
204 }
205
206
207 - (BOOL)canUseNewSmartLibraryName:(NSString *)newName
208 {
209 NSManagedObjectContext *moc = [self managedObjectContext];
210 NSError *error = nil;
211 NSFetchRequest *fetch;
212 NSPredicate *predicate;
213 NSInteger num;
214
215 fetch = [[[NSFetchRequest alloc] init] autorelease];
216 [fetch setEntity:[NSEntityDescription entityForName:@"XspfList"
217 inManagedObjectContext:moc]];
218 predicate = [NSPredicate predicateWithFormat:@"name = %@", newName];
219 [fetch setPredicate:predicate];
220 num = [moc countForFetchRequest:fetch
221 error:&error];
222
223 return num == 0;
224 }
225 - (NSString *)usableSmartLibraryName
226 {
227 NSString *template = NSLocalizedString(@"Untitled Library", @"Untitled Library");
228
229 if([self canUseNewSmartLibraryName:template]) return template;
230
231 NSInteger i = 1;
232 do {
233 NSString *name = [NSString stringWithFormat:@"%@ %d", template, i];
234 if([self canUseNewSmartLibraryName:name]) return name;
235 } while (i++ < INT_MAX);
236
237 return @"hoge";
238 }
239
240 #pragma mark #### Actions ####
241 - (IBAction)createPredicate:(id)sender
242 {
243 if([editor numberOfRows] == 0) {
244 [editor addRow:self];
245 }
246
247 [nameField setStringValue:[self usableSmartLibraryName]];
248 [nameField selectText:self];
249
250 [NSApp beginSheet:predicatePanel
251 modalForWindow:[tableView window]
252 modalDelegate:self
253 didEndSelector:@selector(didEndEditPredicate:returnCode:contextInfo:)
254 contextInfo:@"Createion"];
255 }
256 - (IBAction)editPredicate:(id)sender
257 {
258 XspfMXspfListObject *obj = [sender representedObject];
259 if(!obj) {
260 HMLog(HMLogLevelError, @"-[%@ %@] paramater's representedObject is nil.",
261 NSStringFromClass([self class]), NSStringFromSelector(_cmd));
262 return;
263 }
264 [nameField setStringValue:obj.name];
265 [nameField selectText:self];
266
267 [ruleEditorDelegate setPredicate:obj.predicate];
268
269 [NSApp beginSheet:predicatePanel
270 modalForWindow:[tableView window]
271 modalDelegate:self
272 didEndSelector:@selector(didEndEditPredicate:returnCode:contextInfo:)
273 contextInfo:obj];
274 }
275 - (IBAction)deletePredicate:(id)sender
276 {
277 XspfMXspfListObject *obj = [sender representedObject];
278 if(!obj) {
279 HMLog(HMLogLevelError, @"-[%@ %@] paramater's representedObject is nil.",
280 NSStringFromClass([self class]), NSStringFromSelector(_cmd));
281 return;
282 }
283 NSBeginInformationalAlertSheet(nil, nil, @"Cancel", nil, [[self view] window],
284 self, @selector(didEndAskDelete:::), Nil, obj,
285 NSLocalizedString(@"Do you really delete smart library \"%@\"?", @"Do you really delete smart library \"%@\"?"),
286 obj.name);
287 }
288 - (IBAction)didEndEditPredicate:(id)sender
289 {
290 [predicatePanel orderOut:self];
291 [NSApp endSheet:predicatePanel returnCode:[sender tag]];
292 }
293 - (void)moveUp:(id)sender
294 {
295 NSUInteger row = [tableView selectedRow];
296 if(row == 0) return;
297
298 NSIndexSet *newSelection = [NSIndexSet indexSetWithIndex:row - 1];
299 [tableView selectRowIndexes:newSelection byExtendingSelection:NO];
300 }
301 - (void)moveDown:(id)sender
302 {
303 NSUInteger row = [tableView selectedRow];
304 if(row == [tableView numberOfRows] - 1) return;
305
306 NSIndexSet *newSelection = [NSIndexSet indexSetWithIndex:row + 1];
307 [tableView selectRowIndexes:newSelection byExtendingSelection:NO];
308 }
309
310 - (IBAction)selectLibrayItem:(id)sender
311 {
312 [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
313 }
314
315 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
316 {
317 SEL action = [menuItem action];
318 if(action == @selector(editPredicate:)
319 || action == @selector(deletePredicate:)) {
320 XspfMXspfListObject *obj = [self targetObject];
321 if(!obj) return NO;
322 if(obj.order == kLibraryOrder || obj.order == kFavoritesOrder) return NO;
323 [menuItem setRepresentedObject:obj];
324 }
325
326 return YES;
327 }
328
329 - (void)didEndEditPredicate:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
330 {
331 if(returnCode == NSCancelButton) return;
332
333 [editor reloadPredicate];
334 NSPredicate *predicate = [editor predicate];
335
336 if(!predicate || ![predicate isKindOfClass:[NSPredicate class]]) {
337 HMLog(HMLogLevelError, @"Could not create NSPredicate.");
338 NSBeep();
339 return;
340 }
341 if(![predicate isKindOfClass:[NSCompoundPredicate class]]) {
342 predicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObject:predicate]];
343 }
344
345 NSString *name = [nameField stringValue];
346 if([name length] == 0) {
347 NSBeep();
348 NSBeginAlertSheet(nil, nil, nil, nil, [[self view] window],
349 self, @selector(retryEditPredicate:::), Nil, contextInfo,
350 NSLocalizedString(@"Name must not be empty.", @"Name must not be empty."));
351 return;
352 }
353
354 if([(id)contextInfo isKindOfClass:[NSString class]]) {
355 [self addSmartLibrary:name predicate:predicate order:kSmartLibraryOrder];
356 } else {
357 XspfMXspfListObject *obj = contextInfo;
358 obj.name = name;
359 obj.predicate = predicate;
360 }
361 }
362 - (void)retryEditPredicate:(NSWindow *)sheet :(NSInteger)returnCode :(void *)contextInfo
363 {
364 if([(id)contextInfo isKindOfClass:[NSString class]]) {
365 [self performSelector:@selector(createPredicate:) withObject:nil afterDelay:0.0];
366 } else {
367 [self performSelector:@selector(editPredicate:) withObject:nil afterDelay:0.0];
368 }
369 }
370 - (void)didEndAskDelete:(NSWindow *)sheet :(NSInteger)returnCode :(void *)contextInfo
371 {
372 if(returnCode == NSCancelButton) return;
373
374 [[self managedObjectContext] deleteObject:contextInfo];
375 }
376
377 #pragma mark#### NSTableView Data Source ####
378 - (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard*)pboard
379 {
380 if([rowIndexes containsIndex:0] || [rowIndexes containsIndex:1]) return NO;
381
382 [pboard declareTypes:[NSArray arrayWithObject:XspfMLibItemPbardType] owner:self];
383
384 return [pboard setData:[NSKeyedArchiver archivedDataWithRootObject:rowIndexes] forType:XspfMLibItemPbardType];
385 }
386
387 - (NSDragOperation)tableView:(NSTableView*)aTableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation
388 {
389 if(row == 0 || row == 1) return NSDragOperationNone;
390
391 if(dropOperation == NSTableViewDropOn) {
392 [aTableView setDropRow:row
393 dropOperation:NSTableViewDropAbove];
394 }
395
396 return NSDragOperationMove;
397 }
398
399 - (BOOL)tableView:(NSTableView*)aTableView acceptDrop:(id <NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation
400 {
401 NSPasteboard *pboard = [info draggingPasteboard];
402 NSIndexSet *indexSet = [NSKeyedUnarchiver unarchiveObjectWithData:[pboard dataForType:XspfMLibItemPbardType]];
403
404 [self moveItemOfIndexSet:indexSet afterIndex:row - 1];
405 [xspfListController rearrangeObjects];
406
407 return YES;
408 }
409
410
411 #pragma mark-
412 - (void)packOrder
413 {
414 NSManagedObjectContext *moc = [self managedObjectContext];
415 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"order <> %@ AND order <> %@",
416 [NSNumber numberWithInt:kLibraryOrder], [NSNumber numberWithInt:kFavoritesOrder]];
417 NSEntityDescription *entry = [NSEntityDescription entityForName:@"XspfList"
418 inManagedObjectContext:moc];
419 NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
420 [fetch setEntity:entry];
421 [fetch setPredicate:predicate];
422 [fetch setSortDescriptors:[self sortDescriptors]];
423
424 NSError *error = nil;
425 NSArray *objects = [moc executeFetchRequest:fetch error:&error];
426 if(!objects) {
427 if(error) {
428 HMLog(HMLogLevelError, @"fail fetch reason -> %@", error);
429 }
430 }
431
432 NSInteger newOrder = initialOrder;
433 for(XspfMXspfListObject *obj in objects) {
434 obj.order = newOrder;
435 newOrder += orderStep;
436 }
437 }
438
439 - (NSNumber *)orderForNewItem
440 {
441 NSManagedObjectContext *moc = [self managedObjectContext];
442 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"order <> %@ AND order <> %@",
443 [NSNumber numberWithInt:kLibraryOrder], [NSNumber numberWithInt:kFavoritesOrder]];
444 NSEntityDescription *entry = [NSEntityDescription entityForName:@"XspfList"
445 inManagedObjectContext:moc];
446 NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
447 [fetch setEntity:entry];
448 [fetch setPredicate:predicate];
449 [fetch setSortDescriptors:[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:@"order" ascending:NO] autorelease]]];
450 [fetch setFetchLimit:1];
451
452 NSError *error = nil;
453 NSArray *objects = [moc executeFetchRequest:fetch error:&error];
454 if(!objects) {
455 if(error) {
456 HMLog(HMLogLevelError, @"fail fetch reason -> %@", error);
457 }
458 }
459 HMLog(HMLogLevelDebug, @"objects -> %@", objects);
460
461 if(!objects && [objects count] == 0) return [NSNumber numberWithInteger:initialOrder];
462 XspfMXspfListObject *last = [objects lastObject];
463
464 return [NSNumber numberWithInteger:last.order + orderStep];
465 }
466
467 - (void)moveToLastFromIndexSet:(NSIndexSet *)indexSet
468 {
469 id array = [[self representedObject] arrangedObjects];
470 XspfMXspfListObject *afterItem = [array lastObject];
471 NSInteger insertPoint = afterItem.order + orderStep;
472 NSUInteger targetIndex = [indexSet firstIndex];
473 while(targetIndex != NSNotFound) {
474 XspfMXspfListObject *targetItem = [array objectAtIndex:targetIndex];
475 targetItem.order = insertPoint;
476 insertPoint += orderStep;
477
478 targetIndex = [indexSet indexGreaterThanIndex:targetIndex];
479 }
480 }
481 - (void)moveItemOfIndexSet:(NSIndexSet *)indexSet afterIndex:(NSInteger)afterIndex
482 {
483 id array = [[self representedObject] arrangedObjects];
484
485 if([array count] <= afterIndex + 1) {
486 [self moveToLastFromIndexSet:indexSet];
487 return;
488 }
489
490 XspfMXspfListObject *afterItem = [array objectAtIndex:afterIndex];
491 XspfMXspfListObject *beforeItem = [array objectAtIndex:afterIndex + 1];
492
493 NSInteger diff = beforeItem.order - afterItem.order;
494 if(diff - 1 < [indexSet count]) {
495 [self packOrder];
496 [self moveItemOfIndexSet:indexSet afterIndex:afterIndex];
497 return;
498 }
499
500 NSInteger step = diff / ([indexSet count] + 1);
501 NSInteger insertPoint = afterItem.order + step;
502 NSUInteger targetIndex = [indexSet firstIndex];
503 while(targetIndex != NSNotFound) {
504 XspfMXspfListObject *targetItem = [array objectAtIndex:targetIndex];
505 targetItem.order = insertPoint;
506 insertPoint += step;
507
508 targetIndex = [indexSet indexGreaterThanIndex:targetIndex];
509 }
510
511 [self packOrder];
512 }
513
514 #pragma mark#### NSWindow Delegate ####
515 - (void)windowWillClose:(NSNotification *)notification
516 {
517 if(self.view.window != notification.object) return;
518
519 XspfMPreferences *pref = [XspfMPreferences sharedPreference];
520 pref.libraryLastSelectedIndexSet = xspfListController.selectionIndex;
521 }
522
523 #pragma mark-
524
525 //- (IBAction)test01:(id)sender
526 //{
527 // NSArray *array = [editor rowTemplates];
528
529 // for(id templ in array) {
530 // HMLog(HMLogLevelDebug @"Views -> %@", [templ templateViews]);
531 // for(id v in [templ templateViews]) {
532 // if([v respondsToSelector:@selector(tag)]) {
533 // HMLog(HMLogLevelDebug, @"tag -> %d", [v tag]);
534 // }
535 // }
536 // }
537 // for(id templ in array) {
538 // HMLog(HMLogLevelDebug, @"template -> %@", templ);
539 // }
540 //}
541
542 @end

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26