source: branches/CoreData/SapphireFrappliance/MetaDataImporting/SapphireImporterDataMenu.m @ 650

Revision 650, 14.8 KB checked in by gbooker, 6 years ago (diff)

Some changes to the directory scanning. This is a bit faster, but still not fast enough

Line 
1/*
2 * SapphireImporterDataMenu.m
3 * Sapphire
4 *
5 * Created by pnmerrill on Jun. 24, 2007.
6 * Copyright 2007 Sapphire Development Team and/or www.nanopi.net
7 * All rights reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
10 * General Public License as published by the Free Software Foundation; either version 3 of the License,
11 * or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
14 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15 * Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along with this program; if not,
18 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 */
20
21#import "SapphireImporterDataMenu.h"
22#import <BackRow/BackRow.h>
23#import "SapphireDirectoryMetaData.h"
24#import "SapphireFileMetaData.h"
25#import "SapphireCollectionDirectory.h"
26#import <SapphireCompatClasses/SapphireFrontRowCompat.h>
27#import "SapphireImportHelper.h"
28#import "SapphireApplianceController.h"
29#import "NSString-Extensions.h"
30#import "SapphireMetaDataSupport.h"
31
32@interface BRLayerController (compatounth)
33- (NSRect)controllerFrame;  /*technically wrong; it is really a CGRect*/
34@end
35
36@interface SapphireImporterDataMenu (private)
37- (void)layoutFrame;
38- (void)setFileProgress:(NSString *)updateFileProgress;
39- (void)resetUIElements;
40- (void)pause;
41- (void)itemImportBackgrounded;
42@end
43
44@implementation SapphireImporterDataMenu
45- (id) initWithScene: (BRRenderScene *) scene context:(NSManagedObjectContext *)context  importer:(id <SapphireImporter>)import;
46{
47        if ( [super initWithScene: scene] == nil )
48                return ( nil );
49        moc = [context retain];
50        importer = [import retain];
51        [importer setImporterDataMenu:self];
52        importItems = [[NSMutableArray alloc] init];
53        /*Setup the Header Control with default contents*/
54        [self setListTitle:BRLocalizedString(@"Populate Show Data", @"Do a file metadata import")];
55
56        /*Setup the text entry control*/
57        text = [SapphireFrontRowCompat newTextControlWithScene:scene];
58        fileProgress = [SapphireFrontRowCompat newTextControlWithScene:scene];
59        currentFile = [SapphireFrontRowCompat newTextControlWithScene:scene];
60       
61        /*Setup the progress bar*/
62        bar = [SapphireFrontRowCompat newProgressBarWidgetWithScene:scene];
63        [self layoutFrame];
64       
65        [[self list] setDatasource:self];
66       
67        /*add controls*/
68        [self addControl: text];
69        [self addControl: fileProgress] ;
70        [self addControl: currentFile] ;
71        [SapphireFrontRowCompat addSublayer:bar toControl:self];
72
73    return ( self );
74}
75
76- (void) dealloc
77{
78        [text release];
79        [fileProgress release];
80        [currentFile release];
81        [bar release];
82        [moc release];
83        [collectionDirectories release];
84        [skipSet release];
85        [importItems release];
86        [importTimer invalidate];
87        [importer setImporterDataMenu:nil];
88        [importer release];
89        [buttonTitle release];
90        [super dealloc];
91}
92
93- (void)layoutFrame
94{
95        /*title*/
96        NSRect frame = [SapphireFrontRowCompat frameOfController:self];
97        frame.origin.y += frame.size.height * 5.0f / 16.0f;
98        frame.origin.x = frame.size.width / 6.0f;
99        frame.size.height = frame.size.height / 16.0f;
100        frame.size.width = frame.size.width * 2.0f / 3.0f;
101        [bar setFrame: frame] ;
102}
103
104/*!
105 * @brief Sets the informative text
106 *
107 * @param theText The text to set
108 */
109- (void)setText:(NSString *)theText
110{
111        [SapphireFrontRowCompat setText:theText withAtrributes:[[BRThemeInfo sharedTheme] paragraphTextAttributes] forControl:text];
112       
113        NSRect master = [SapphireFrontRowCompat frameOfController:self];
114        NSSize txtSize = [SapphireFrontRowCompat textControl:text renderedSizeWithMaxSize:NSMakeSize(master.size.width * 2.0f/3.0f, master.size.height * 0.4f)];
115       
116        NSRect frame;
117        frame.origin.x = (master.size.width - txtSize.width) * 0.5f;
118        frame.origin.y = (master.size.height * 0.4f - txtSize.height) + master.size.height * 0.3f/0.8f + master.origin.y;
119        frame.size = txtSize;
120        [text setFrame:frame];
121}
122
123/*!
124 * @brief Sets the file progress string
125 *
126 * @param theFileProgress The file progress string to display
127 */
128- (void)setFileProgress:(NSString *)theFileProgress
129{
130        [SapphireFrontRowCompat setText:theFileProgress withAtrributes:[[BRThemeInfo sharedTheme] paragraphTextAttributes] forControl:fileProgress];
131       
132        NSRect master = [SapphireFrontRowCompat frameOfController:self];
133        NSSize progressSize = [SapphireFrontRowCompat textControl:fileProgress renderedSizeWithMaxSize:NSMakeSize(master.size.width * 1.0f/2.0f, master.size.height * 0.3f)];
134       
135        NSRect frame;
136        frame.origin.x =  (master.size.width) * 0.1f;
137        frame.origin.y = (master.size.height * 0.12f) + master.origin.y;
138        frame.size = progressSize;
139        [fileProgress setFrame:frame];
140}
141
142/*!
143 * @brief Sets the display of the current file being processed
144 *
145 * @param theCurrentFile The current file being proccessed
146 */
147- (void)setCurrentFile:(NSString *)theCurrentFile
148{
149        [SapphireFrontRowCompat setText:theCurrentFile withAtrributes:[[BRThemeInfo sharedTheme] paragraphTextAttributes] forControl:currentFile];
150       
151        NSRect master = [SapphireFrontRowCompat frameOfController:self];
152        NSSize currentFileSize = [SapphireFrontRowCompat textControl:currentFile renderedSizeWithMaxSize:NSMakeSize(master.size.width * 9.0f/10.0f, master.size.height * 0.3f)];
153       
154        NSRect frame;
155        frame.origin.x =  (master.size.width) * 0.1f;
156        frame.origin.y = (master.size.height * 0.09f) + master.origin.y;
157        frame.size = currentFileSize;
158        [currentFile setFrame:frame];
159}
160
161/*!
162 * @brief Get the list of all files to process
163 */
164- (void)getItems
165{
166        SapphireCollectionDirectory *collection = [collectionDirectories objectAtIndex:collectionIndex];
167        if([collection isDeleted] || [collection skipValue])
168        {
169                collectionIndex++;
170                [self performSelector:@selector(gotSubFiles:) withObject:[NSArray array] afterDelay:0.0];
171                return;
172        }
173        SapphireDirectoryMetaData *meta = [collection directory];
174        //Prefetch
175/*      NSPredicate *fetchPredicate = [NSPredicate predicateWithFormat:@"path BEGINSWITH %@", [[meta path] stringByAppendingString:@"/"]];
176        NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"path" ascending:YES];
177        doSortedFetchRequest(SapphireDirectoryMetaDataName, moc, fetchPredicate, sort);
178        doSortedFetchRequest(SapphireFileMetaDataName, moc, fetchPredicate, sort);
179        doSortedFetchRequest(SapphireDirectorySymLinkName, moc, fetchPredicate, sort);
180        doSortedFetchRequest(SapphireFileSymLinkName, moc, fetchPredicate, sort);
181        [sort release];*/
182
183        [meta getSubFileMetasWithDelegate:self skipDirectories:skipSet];
184        collectionIndex++;
185}
186
187- (void)setButtonTitle:(NSString *)title
188{
189        if(title != nil)
190        {
191                [buttonTitle release];
192                buttonTitle = [title retain];
193        }
194        BRListControl *list = [self list];
195       
196        [list setHidden:(title == nil)];
197       
198        [list reload];
199}
200
201/*!
202 * @brief Start the import process
203 */
204- (void)import
205{
206        /*Change display*/
207        [self setButtonTitle:BRLocalizedString(@"Cancel Import", @"Cancel the import process")];
208        action = @selector(cancel);
209        [self setFileProgress:BRLocalizedString(@"Initializing...", @"The import is starting")];
210        [SapphireFrontRowCompat renderScene:[self scene]];
211        /*Initialize the import process*/
212        canceled = NO;
213        suspended = NO;
214        collectionIndex = 0;
215        [collectionDirectories release];
216        collectionDirectories = [[SapphireCollectionDirectory availableCollectionDirectoriesInContext:moc] retain];
217        NSArray *skipCol = [SapphireCollectionDirectory skippedCollectionDirectoriesInContext:moc];
218        [skipSet release];
219        skipSet = [NSMutableSet setWithSet:[skipCol valueForKeyPath:@"directory.path"]];
220        [self getItems];
221}
222
223/*!
224 * @brief Metadata delegate method to return final list of files
225 *
226 * @param subs The files which are children of the current directory
227 */
228- (void)gotSubFiles:(NSArray *)subs
229{
230        [importItems addObjectsFromArray:subs];
231        if(collectionIndex != [collectionDirectories count])
232        {
233                [self getItems];
234                return;
235        }
236        updated = 0 ;
237        current = 0;
238        max = [importItems count];
239        if(!canceled)
240                importTimer = [NSTimer scheduledTimerWithTimeInterval:0.0f target:self selector:@selector(importNextItem:) userInfo:nil repeats:NO];
241}
242
243/*!
244 * @brief Metadata delegate method to inform on its scanning progress
245 *
246 * @param dir The current directory it is scanning
247 */
248- (void)scanningDir:(NSString *)dir
249{
250        [self setCurrentFile:[NSString stringWithFormat:BRLocalizedString(@"Scanning Directory: %@", "Current scan import process format, directory"),[NSString stringByCroppingDirectoryPath:dir toLength:3]]];
251        [SapphireFrontRowCompat renderScene:[self scene]];
252}
253
254/*!
255 * @brief Ask if we should cancel the fetching of file listing
256 *
257 * @return YES if the file listing should be canceled, NO otherwise
258 */
259- (BOOL)getSubFilesCanceled
260{
261        return canceled;
262}
263
264/*!
265 * @brief Import a single item
266 *
267 * @return YES if any data was imported, NO otherwise
268 */
269- (BOOL)doImport
270{
271        BOOL ret = NO;
272        SapphireFileMetaData *file = [importItems objectAtIndex:0];
273        if(file.joinedToFile != nil)
274                return NO;
275        @try {
276                ImportState result = [importer importMetaData:file];
277                switch(result)
278                {
279                        case IMPORT_STATE_UPDATED:
280                                ret = YES;
281                                break;
282                        case IMPORT_STATE_NEEDS_SUSPEND:
283                                [self pause];
284                                ret = NO;
285                                break;
286                        case IMPORT_STATE_BACKGROUND:
287                                [self itemImportBackgrounded];
288                                ret = NO;
289                                break;
290                }
291                [SapphireMetaDataSupport save:moc];
292        }
293        @catch (NSException * e) {
294                [SapphireApplianceController logException:e];
295                [e raise];
296        }
297        @finally {
298                return ret;
299        }
300}
301
302/*!
303 * @brief Change the display to show the completion text
304 */
305- (void)setCompletionText
306{
307        [self setText:[importer completionText]];
308}
309
310/*!
311 * @brief Timer function to start the import of the next file
312 *
313 * @param timer The timer that triggered this
314 */
315- (void)importNextItem:(NSTimer *)timer
316{
317        @try
318        {
319                [importTimer invalidate];
320                importTimer = nil;
321                if([importItems count])
322                {
323                        /*Update the display*/
324                        SapphireFileMetaData *fileMeta = [importItems objectAtIndex:0];
325                        NSString * fileName=[[fileMeta path] lastPathComponent] ;
326                        [self setCurrentFile:[NSString stringWithFormat:BRLocalizedString(@"Fetching For: %@", "Current TV Show import process format, filename"),fileName]];
327                       
328                        current++ ;
329                        /*Update the imported count*/
330                        if([self doImport] && !backgrounded)
331                                updated++;             
332                       
333                        /*Check for a suspend and reimport afterwards*/
334                        if(suspended || backgrounded)
335                        {
336                                backgrounded = NO;
337                                current--;
338                                return;
339                        }
340                       
341                        /*Start with the first item*/
342                        [importItems removeObjectAtIndex:0];
343                }
344                else
345                        [self setCurrentFile:BRLocalizedString(@"Waiting for background import to complete", @"The import is complete, just waiting on background processes")];
346                [self setFileProgress:[NSString stringWithFormat:BRLocalizedString(@"Finished Processing: %0.0f / %0.0f", @"Import progress format, current and the max"), current, max,updated]];
347                [bar setPercentage:current/max * 100.0f];
348               
349                /*Check for completion*/
350                if(current == max)
351                {
352                        [SapphireMetaDataSupport save:moc];
353                        /*Update display*/
354                        [self setButtonTitle:nil];
355                        action = NULL;
356                        [self setListTitle:BRLocalizedString(@"Import Complete", @"The import is complete")];
357                        [self setFileProgress:[NSString stringWithFormat:BRLocalizedString(@"Updated %0.0f Entries.", @"Import complete format with number updated"), updated]];
358                        [self setCurrentFile:@""];
359                        [self setCompletionText];
360                        [SapphireFrontRowCompat renderScene:[self scene]];
361                       
362                        NSEnumerator *colEnum = [collectionDirectories objectEnumerator];
363                        SapphireCollectionDirectory *col;
364                        while((col = [colEnum nextObject]) != nil)
365                                [col.directory refreshAllObjects];
366                }
367                else
368                {
369                        importTimer = [NSTimer scheduledTimerWithTimeInterval:0.0f target:self selector:@selector(importNextItem:) userInfo:nil repeats:NO];
370                }
371        }
372        @catch(NSException *e)
373        {
374                [SapphireApplianceController logException:e];
375        }
376}
377
378/*!
379 * @brief Cancel the import process
380 */
381- (void)cancel
382{
383        /*Kill the timer*/
384        canceled = YES;
385        [importTimer invalidate];
386        importTimer = nil;
387        [importItems removeAllObjects];
388        [[SapphireImportHelper sharedHelperForContext:moc] removeObjectsWithInform:self];
389        /*Reset the display and write data*/
390        [self resetUIElements];
391        [SapphireMetaDataSupport save:moc];
392}
393
394- (void)pause
395{
396        /*Kil lthe timer*/
397        suspended = YES;
398}
399
400- (void)resume
401{
402        /*Sanity checks*/
403        [importTimer invalidate];
404        /*Resume*/
405        suspended = NO;
406        importTimer = [NSTimer scheduledTimerWithTimeInterval:0.0f target:self selector:@selector(importNextItem:) userInfo:nil repeats:NO];
407}
408
409- (oneway void)informComplete:(BOOL)fileUpdated
410{
411        if(fileUpdated)
412                updated++;
413        current++;
414        [self importNextItem:nil];
415}
416
417- (void)itemImportBackgrounded
418{
419        if([importItems count] && !suspended)
420                [importItems removeObjectAtIndex:0];
421        backgrounded = YES;
422}
423
424- (void)skipNextItem
425{
426        /*Remove the next item from the queue*/
427        if([importItems count])
428                [importItems removeObjectAtIndex:0];
429        current++;
430}
431
432/*!
433 * @brief Reset the UI after an import completion or cancel
434 */
435- (void)resetUIElements
436{
437        [self setFileProgress:@" "];
438        [self setCurrentFile:@" "] ;
439        [bar setPercentage:0.0f];
440        action = @selector(import);
441        [self setListTitle:[importer initialText]];
442        [self setText:[importer informativeText]];
443        [self setButtonTitle:[importer buttonTitle]];
444}
445
446- (void)wasPushed
447{
448        [self layoutFrame];
449        [self resetUIElements];
450        [super wasPushed];
451}
452
453- (void)wasPopped
454{
455        /*Someone hit menu, so cancel*/
456        [self cancel];
457        [super wasPopped];
458}
459
460- (void) wasExhumedByPoppingController: (BRLayerController *) controller
461{
462        [importer wasExhumedByPoppingController:controller];
463        [super wasExhumedByPoppingController:controller];
464}
465
466- (BOOL)brEventAction:(BREvent *)event{
467        BREventPageUsageHash hashVal = [event pageUsageHash];
468       
469        if([(BRControllerStack *)[self stack] peekController] != self || action == NULL)
470                hashVal = 0;
471       
472        switch(hashVal)
473        {
474                case kBREventTapPlayPause:
475                case kBREventHoldPlayPause:
476                        [self performSelector:action];
477                        return YES;
478                        break;
479                case kBREventTapMenu:
480                        [self cancel];
481                        break;
482        }
483        return [super brEventAction:event];
484}
485
486- (long) itemCount
487{
488        return 1;
489}
490
491- (id<BRMenuItemLayer>) itemForRow: (long) row
492{
493        BRAdornedMenuItemLayer *result = [SapphireFrontRowCompat textMenuItemForScene:[self scene] folder:NO];
494        [SapphireFrontRowCompat setTitle:buttonTitle forMenu:result];
495       
496        return result;
497}
498
499- (NSString *) titleForRow: (long) row
500{
501       
502        if ( row >= 1 ) return ( nil );
503       
504        NSString *result = buttonTitle ;
505       
506        return [NSString stringWithFormat:@"  ????? %@", result];
507}
508
509- (long) rowForTitle: (NSString *) aTitle
510{
511    long result = -1;
512    long i, count = [self itemCount];
513    for ( i = 0; i < count; i++ )
514    {
515        if ( [aTitle isEqualToString: [self titleForRow: i]] )
516        {
517            result = i;
518            break;
519        }
520    }
521   
522    return ( result );
523}
524
525- (NSRect)listRectWithSize:(NSRect)listFrame inMaster:(NSRect)master
526{
527        listFrame.size.height = master.size.height * 3.0f / 16.0f;
528        listFrame.origin.y = master.size.height / 8.0f;
529        listFrame.size.width = master.size.width / 3.0f;
530        listFrame.origin.x = master.size.width / 3.0f;
531        return listFrame;
532}
533
534@end
Note: See TracBrowser for help on using the repository browser.