source: trunk/macosx/Torrent.m @ 856

Last change on this file since 856 was 856, checked in by livings124, 15 years ago

Advanced bar should work again.

  • Property svn:keywords set to Date Rev Author Id
File size: 24.8 KB
Line 
1/******************************************************************************
2 * $Id: Torrent.m 856 2006-09-12 00:08:30Z livings124 $
3 *
4 * Copyright (c) 2006 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#import "Torrent.h"
26#import "StringAdditions.h"
27
28#define BAR_HEIGHT 12.0
29
30@interface Torrent (Private)
31
32- (id) initWithHash: (NSString *) hashString path: (NSString *) path lib: (tr_handle_t *) lib
33        privateTorrent: (NSNumber *) privateTorrent publicTorrent: (NSNumber *) publicTorrent
34        date: (NSDate *) date stopRatioSetting: (NSNumber *) stopRatioSetting
35        ratioLimit: (NSNumber *) ratioLimit waitToStart: (NSNumber *) waitToStart
36        orderValue: (NSNumber *) orderValue;
37
38- (NSImage *) advancedBar;
39
40- (void) trashFile: (NSString *) path;
41
42@end
43
44@implementation Torrent
45
46// Used to optimize drawing. They contain packed RGBA pixels for every color needed.
47#define BE OSSwapBigToHostConstInt32
48static uint32_t kBorder[] =
49    { BE(0x00000005), BE(0x00000010), BE(0x00000015), BE(0x00000015),
50      BE(0x00000015), BE(0x00000015), BE(0x00000015), BE(0x00000015),
51      BE(0x00000015), BE(0x00000015), BE(0x00000010), BE(0x00000005) };
52
53static uint32_t kBack[] = { BE(0xB4B4B4FF), BE(0xE3E3E3FF) };
54
55static uint32_t kRed   = BE(0xFF6450FF), //255, 100, 80
56                kBlue1 = BE(0xA0DCFFFF), //160, 220, 255
57                kBlue2 = BE(0x78BEFFFF), //120, 190, 255
58                kBlue3 = BE(0x50A0FFFF), //80, 160, 255
59                kBlue4 = BE(0x1E46B4FF), //30, 70, 180
60                kGray  = BE(0x828282FF), //130, 130, 130
61                kGreen = BE(0x00FF00FF); //0, 255, 0
62
63- (id) initWithPath: (NSString *) path lib: (tr_handle_t *) lib
64{
65    self = [self initWithHash: nil path: path lib: lib privateTorrent: nil publicTorrent: nil
66            date: nil stopRatioSetting: nil ratioLimit: nil waitToStart: nil orderValue: nil];
67   
68    if (self)
69    {
70        if (!fPublicTorrent)
71            [self trashFile: path];
72    }
73    return self;
74}
75
76- (id) initWithHistory: (NSDictionary *) history lib: (tr_handle_t *) lib
77{
78    self = [self initWithHash: [history objectForKey: @"TorrentHash"]
79                path: [history objectForKey: @"TorrentPath"] lib: lib
80                privateTorrent: [history objectForKey: @"PrivateCopy"]
81                publicTorrent: [history objectForKey: @"PublicCopy"]
82                date: [history objectForKey: @"Date"]
83                stopRatioSetting: [history objectForKey: @"StopRatioSetting"]
84                ratioLimit: [history objectForKey: @"RatioLimit"]
85                waitToStart: [history objectForKey: @"WaitToStart"]
86                orderValue: [history objectForKey: @"OrderValue"]];
87   
88    if (self)
89    {
90        NSString * downloadFolder;
91        if (!(downloadFolder = [history objectForKey: @"DownloadFolder"]))
92            downloadFolder = [[fDefaults stringForKey: @"DownloadFolder"] stringByExpandingTildeInPath];
93        [self setDownloadFolder: downloadFolder];
94
95        NSString * paused;
96        if (!(paused = [history objectForKey: @"Paused"]) || [paused isEqualToString: @"NO"])
97            tr_torrentStart(fHandle);
98    }
99    return self;
100}
101
102- (NSDictionary *) history
103{
104    NSMutableDictionary * history = [NSMutableDictionary dictionaryWithObjectsAndKeys:
105                    [NSNumber numberWithBool: fPrivateTorrent], @"PrivateCopy",
106                    [NSNumber numberWithBool: fPublicTorrent], @"PublicCopy",
107                    [self downloadFolder], @"DownloadFolder",
108                    [self isActive] ? @"NO" : @"YES", @"Paused",
109                    [self date], @"Date",
110                    [NSNumber numberWithInt: fStopRatioSetting], @"StopRatioSetting",
111                    [NSNumber numberWithFloat: fRatioLimit], @"RatioLimit",
112                    [NSNumber numberWithBool: fWaitToStart], @"WaitToStart",
113                    [self orderValue], @"OrderValue", nil];
114           
115    if (fPrivateTorrent)
116        [history setObject: [self hashString] forKey: @"TorrentHash"];
117
118    if (fPublicTorrent)
119        [history setObject: [self publicTorrentLocation] forKey: @"TorrentPath"];
120   
121    return history;
122}
123
124- (void) dealloc
125{
126    if (fHandle)
127    {
128        tr_torrentClose(fLib, fHandle);
129       
130        if (fPublicTorrentLocation)
131            [fPublicTorrentLocation release];
132       
133        [fDate release];
134       
135        [fIcon release];
136        [fIconFlipped release];
137        [fIconSmall release];
138       
139        [fProgressString release];
140        [fStatusString release];
141        [fShortStatusString release];
142        [fRemainingTimeString release];
143    }
144    [super dealloc];
145}
146
147- (void) setDownloadFolder: (NSString *) path
148{
149    tr_torrentSetFolder(fHandle, [path UTF8String]);
150}
151
152- (NSString *) downloadFolder
153{
154    return [NSString stringWithUTF8String: tr_torrentGetFolder(fHandle)];
155}
156
157- (void) getAvailability: (int8_t *) tab size: (int) size
158{
159    tr_torrentAvailability(fHandle, tab, size);
160}
161
162- (void) update
163{
164    fStat = tr_torrentStat(fHandle);
165   
166    //notification when downloading finished
167    if ([self justFinished])
168        [[NSNotificationCenter defaultCenter] postNotificationName: @"TorrentFinishedDownloading" object: self];
169   
170    //check to stop for ratio
171    if ([self isSeeding] && ((fStopRatioSetting == RATIO_CHECK && [self ratio] >= fRatioLimit)
172            || (fStopRatioSetting == RATIO_GLOBAL && [fDefaults boolForKey: @"RatioCheck"]
173            && [self ratio] >= [fDefaults floatForKey: @"RatioLimit"])))
174    {
175        [self stopTransfer];
176        [self setStopRatioSetting: RATIO_NO_CHECK];
177        fFinishedSeeding = YES;
178       
179        fStat = tr_torrentStat(fHandle);
180       
181        [[NSNotificationCenter defaultCenter] postNotificationName: @"TorrentStoppedForRatio" object: self];
182    }
183
184    [fProgressString setString: @""];
185    if ([self progress] < 1.0)
186        [fProgressString appendFormat: @"%@ of %@ (%.2f%%)", [NSString stringForFileSize:
187                [self downloadedValid]], [NSString stringForFileSize: [self size]], 100.0 * [self progress]];
188    else
189        [fProgressString appendFormat: @"%@, uploaded %@ (Ratio: %@)", [NSString stringForFileSize:
190                [self size]], [NSString stringForFileSize: [self uploadedTotal]],
191                [NSString stringForRatioWithDownload: [self downloadedTotal] upload: [self uploadedTotal]]];
192
193    switch (fStat->status)
194    {
195        NSString * tempString;
196   
197        case TR_STATUS_PAUSE:
198            if (fFinishedSeeding)
199                tempString = @"Seeding complete";
200            else if (fWaitToStart && [[fDefaults stringForKey: @"StartSetting"] isEqualToString: @"Wait"])
201                tempString = [@"Waiting to start" stringByAppendingEllipsis];
202            else
203                tempString = @"Paused";
204           
205            [fStatusString setString: tempString];
206            [fShortStatusString setString: tempString];
207           
208            break;
209
210        case TR_STATUS_CHECK:
211            tempString = [@"Checking existing files" stringByAppendingEllipsis];
212           
213            [fStatusString setString: tempString];
214            [fShortStatusString setString: tempString];
215            [fRemainingTimeString setString: tempString];
216           
217            break;
218
219        case TR_STATUS_DOWNLOAD:
220            [fStatusString setString: @""];
221            [fStatusString appendFormat:
222                @"Downloading from %d of %d peer%s", [self peersUploading], [self totalPeers],
223                [self totalPeers] == 1 ? "" : "s"];
224           
225            [fRemainingTimeString setString: @""];
226            int eta = [self eta];
227            if (eta < 0)
228            {
229                [fRemainingTimeString setString: @"Unknown"];
230                [fProgressString appendString: @" - remaining time unknown"];
231            }
232            else
233            {
234                if (eta < 60)
235                    [fRemainingTimeString appendFormat: @"%d sec", eta];
236                else if (eta < 3600) //60 * 60
237                    [fRemainingTimeString appendFormat: @"%d min %02d sec", eta / 60, eta % 60];
238                else if (eta < 86400) //24 * 60 * 60
239                    [fRemainingTimeString appendFormat: @"%d hr %02d min", eta / 3600, (eta / 60) % 60];
240                else
241                    [fRemainingTimeString appendFormat: @"%d day%s %d hr",
242                                                eta / 86400, eta / 86400 == 1 ? "" : "s", (eta / 3600) % 24];
243               
244                [fProgressString appendFormat: @" - %@ remaining", fRemainingTimeString];
245            }
246           
247            break;
248
249        case TR_STATUS_SEED:
250            [fStatusString setString: @""];
251            [fStatusString appendFormat:
252                @"Seeding to %d of %d peer%s",
253                [self peersDownloading], [self totalPeers], [self totalPeers] == 1 ? "" : "s"];
254           
255            break;
256
257        case TR_STATUS_STOPPING:
258            tempString = [@"Stopping" stringByAppendingEllipsis];
259       
260            [fStatusString setString: tempString];
261            [fShortStatusString setString: tempString];
262           
263            break;
264    }
265   
266    if( fStat->error & TR_ETRACKER )
267        [fStatusString setString: [@"Error: " stringByAppendingString:
268                        [NSString stringWithUTF8String: fStat->trackerError]]];
269
270    if ([self isActive])
271    {
272        NSString * stringToAppend = @"";
273        if ([self progress] < 1.0)
274        {
275            stringToAppend = [NSString stringWithFormat: @"DL: %@, ", [NSString stringForSpeed: [self downloadRate]]];
276            [fShortStatusString setString: @""];
277        }
278        else
279        {
280            NSString * ratioString = [NSString stringForRatioWithDownload: [self downloadedTotal]
281                                                upload: [self uploadedTotal]];
282       
283            [fShortStatusString setString: [NSString stringWithFormat: @"Ratio: %@, ", ratioString]];
284            [fRemainingTimeString setString: [@"Ratio: " stringByAppendingString: ratioString]];
285        }
286       
287        stringToAppend = [stringToAppend stringByAppendingString: [@"UL: " stringByAppendingString:
288                                                [NSString stringForSpeed: [self uploadRate]]]];
289
290        [fStatusString appendFormat: @" - %@", stringToAppend];
291        [fShortStatusString appendString: stringToAppend];
292    }
293}
294
295- (NSDictionary *) infoForCurrentView
296{
297    NSMutableDictionary * info = [NSMutableDictionary dictionaryWithObjectsAndKeys:
298                                    [self name], @"Name",
299                                    [NSNumber numberWithBool: [self isSeeding]], @"Seeding",
300                                    [NSNumber numberWithFloat: [self progress]], @"Progress",
301                                    [NSNumber numberWithBool: [self isActive]], @"Active",
302                                    [NSNumber numberWithBool: [self isError]], @"Error", nil];
303   
304    if (![fDefaults boolForKey: @"SmallView"])
305    {
306        [info setObject: fIconFlipped forKey: @"Icon"];
307        [info setObject: [self progressString] forKey: @"ProgressString"];
308        [info setObject: [self statusString] forKey: @"StatusString"];
309    }
310    else
311    {
312        [info setObject: fIconSmall forKey: @"Icon"];
313        [info setObject: [self remainingTimeString] forKey: @"RemainingTimeString"];
314        [info setObject: [self shortStatusString] forKey: @"ShortStatusString"];
315    }
316   
317    if ([fDefaults boolForKey: @"UseAdvancedBar"])
318        [info setObject: [self advancedBar] forKey: @"AdvancedBar"];
319   
320    return info;
321}
322
323- (NSImage *) advancedBar
324{
325    int width = 100; //integers for bars
326   
327    NSBitmapImageRep * bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: nil
328        pixelsWide: width pixelsHigh: BAR_HEIGHT bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES
329        isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: 0 bitsPerPixel: 0];
330
331    int h, w;
332    uint32_t * p;
333    uint8_t * bitmapData = [bitmap bitmapData];
334    int bytesPerRow = [bitmap bytesPerRow];
335
336    //left and right borders
337    p = (uint32_t *) bitmapData;
338    for(h = 0; h < BAR_HEIGHT; h++)
339    {
340        p[0] = kBorder[h];
341        p[width - 1] = kBorder[h];
342        p += bytesPerRow / 4;
343    }
344
345    int8_t * pieces = malloc(width);
346    [self getAvailability: pieces size: width];
347    int avail = 0;
348    for (w = 0; w < width; w++)
349        if (pieces[w] != 0)
350            avail++;
351
352    //first two lines: dark blue to show progression, green to show available
353    int end = lrintf(floor([self progress] * (width - 2)));
354    p = (uint32_t *) (bitmapData) + 1;
355
356    for (w = 0; w < end; w++)
357    {
358        p[w] = kBlue4;
359        p[w + bytesPerRow / 4] = kBlue4;
360    }
361    for (; w < avail; w++)
362    {
363        p[w] = kGreen;
364        p[w + bytesPerRow / 4] = kGreen;
365    }
366    for (; w < width - 2; w++)
367    {
368        p[w] = kBack[0];
369        p[w + bytesPerRow / 4] = kBack[1];
370    }
371   
372    //lines 2 to 14: blue or grey depending on whether we have the piece or not
373    uint32_t color;
374    for( w = 0; w < width - 2; w++ )
375    {
376        //point to pixel ( 2 + w, 2 ). We will then draw "vertically"
377        p = (uint32_t *) ( bitmapData + 2 * bytesPerRow ) + 1 + w;
378
379        if (pieces[w] < 0)
380            color = kGray;
381        else if (pieces[w] == 0)
382            color = kRed;
383        else if (pieces[w] == 1)
384            color = kBlue1;
385        else if (pieces[w] == 2)
386            color = kBlue2;
387        else
388            color = kBlue3;
389
390        for( h = 2; h < BAR_HEIGHT; h++ )
391        {
392            p[0] = color;
393            p = (uint32_t *) ( (uint8_t *) p + bytesPerRow );
394        }
395    }
396
397    free(pieces);
398   
399    //actually draw image
400    NSImage * bar = [[NSImage alloc] initWithSize: [bitmap size]];
401    [bar addRepresentation: bitmap];
402    [bitmap release];
403   
404    [bar setScalesWhenResized: YES];
405   
406    return [bar autorelease];
407}
408
409- (void) startTransfer
410{
411    if (![self isActive])
412    {
413        tr_torrentStart(fHandle);
414
415        fFinishedSeeding = NO;
416        fWaitToStart = NO;
417       
418        [[NSNotificationCenter defaultCenter] postNotificationName: @"TorrentSettingChange" object: self];
419    }
420}
421
422- (void) stopTransfer
423{
424    if ([self isActive])
425    {
426        BOOL wasSeeding = [self isSeeding];
427   
428        tr_torrentStop(fHandle);
429
430        if (!wasSeeding)
431            [[NSNotificationCenter defaultCenter] postNotificationName: @"StoppedDownloading" object: self];
432    }
433}
434
435- (void) stopTransferForQuit
436{
437    if ([self isActive])
438        tr_torrentStop(fHandle);
439}
440
441- (void) removeForever
442{
443    if (fPrivateTorrent)
444        tr_torrentRemoveSaved(fHandle);
445}
446
447- (void) sleep
448{
449    if ((fResumeOnWake = [self isActive]))
450        tr_torrentStop(fHandle);
451}
452
453- (void) wakeUp
454{
455    if (fResumeOnWake)
456        tr_torrentStart(fHandle);
457}
458
459- (float) ratio
460{
461    float downloaded = [self downloadedTotal];
462    return downloaded > 0 ? (float)[self uploadedTotal] / downloaded : -1;
463}
464
465- (int) stopRatioSetting
466{
467        return fStopRatioSetting;
468}
469
470- (void) setStopRatioSetting: (int) setting
471{
472    fStopRatioSetting = setting;
473}
474
475- (float) ratioLimit
476{
477    return fRatioLimit;
478}
479
480- (void) setRatioLimit: (float) limit
481{
482    if (limit >= 0)
483        fRatioLimit = limit;
484}
485
486- (void) setWaitToStart: (BOOL) wait
487{
488    fWaitToStart = wait;
489}
490
491- (BOOL) waitingToStart
492{
493    return fWaitToStart;
494}
495
496- (void) revealData
497{
498    [[NSWorkspace sharedWorkspace] selectFile: [self dataLocation] inFileViewerRootedAtPath: nil];
499}
500
501- (void) trashData
502{
503    [self trashFile: [self dataLocation]];
504}
505
506- (void) trashTorrent
507{
508    if (fPublicTorrent)
509        [self trashFile: [self publicTorrentLocation]];
510}
511
512- (NSImage *) icon
513{
514    return fIcon;
515}
516
517- (NSImage *) iconFlipped
518{
519    return fIconFlipped;
520}
521
522- (NSImage *) iconSmall
523{
524    return fIconSmall;
525}
526
527- (NSString *) name
528{
529    return [NSString stringWithUTF8String: fInfo->name];
530}
531
532- (uint64_t) size
533{
534    return fInfo->totalSize;
535}
536
537- (NSString *) tracker
538{
539    return [NSString stringWithFormat: @"%s:%d", fInfo->trackerAddress, fInfo->trackerPort];
540}
541
542- (NSString *) announce
543{
544    return [NSString stringWithUTF8String: fInfo->trackerAnnounce];
545}
546
547- (int) pieceSize
548{
549    return fInfo->pieceSize;
550}
551
552- (int) pieceCount
553{
554    return fInfo->pieceCount;
555}
556
557- (NSString *) hashString
558{
559    return [NSString stringWithUTF8String: fInfo->hashString];
560}
561
562- (NSString *) torrentLocation
563{
564    return [NSString stringWithUTF8String: fInfo->torrent];
565}
566
567- (NSString *) publicTorrentLocation
568{
569    return fPublicTorrentLocation;
570}
571
572- (NSString *) torrentLocationString
573{
574    return fPrivateTorrent ? @"Transmission Support Folder" : [fPublicTorrentLocation stringByAbbreviatingWithTildeInPath];
575}
576
577- (NSString *) dataLocation
578{
579    return [[self downloadFolder] stringByAppendingPathComponent: [self name]];
580}
581
582- (BOOL) publicTorrent
583{
584    return fPublicTorrent;
585}
586
587- (BOOL) privateTorrent
588{
589    return fPrivateTorrent;
590}
591
592- (NSString *) stateString
593{
594    switch( fStat->status )
595    {
596        case TR_STATUS_PAUSE:
597            return @"Paused";
598            break;
599
600        case TR_STATUS_CHECK:
601            return [@"Checking existing files" stringByAppendingEllipsis];
602            break;
603
604        case TR_STATUS_DOWNLOAD:
605            return @"Downloading";
606            break;
607
608        case TR_STATUS_SEED:
609            return @"Seeding";
610            break;
611
612        case TR_STATUS_STOPPING:
613            return [@"Stopping" stringByAppendingEllipsis];
614            break;
615       
616        default:
617            return @"N/A";
618    }
619}
620
621- (float) progress
622{
623    return fStat->progress;
624}
625
626- (int) eta
627{
628    return fStat->eta;
629}
630
631- (BOOL) isActive
632{
633    return fStat->status & TR_STATUS_ACTIVE;
634}
635
636- (BOOL) isSeeding
637{
638    return fStat->status == TR_STATUS_SEED;
639}
640
641- (BOOL) isPaused
642{
643    return fStat->status == TR_STATUS_PAUSE;
644}
645
646- (BOOL) isError
647{
648    return fStat->error & TR_ETRACKER;
649}
650
651- (BOOL) justFinished
652{
653    return tr_getFinished(fHandle);
654}
655
656- (NSArray *) peers
657{
658    int totalPeers, i;
659    tr_peer_stat_t * peers = tr_torrentPeers(fHandle, & totalPeers);
660   
661    NSMutableArray * peerDics = [NSMutableArray arrayWithCapacity: totalPeers];
662    tr_peer_stat_t peer;
663    NSString * client;
664    for (i = 0; i < totalPeers; i++)
665    {
666        peer = peers[i];
667        [peerDics addObject: [NSDictionary dictionaryWithObjectsAndKeys:
668            [NSNumber numberWithBool: peer.isConnected], @"Connected",
669            [NSString stringWithCString: (char *) peer.addr encoding: NSUTF8StringEncoding], @"IP",
670            [NSString stringWithCString: (char *) peer.client encoding: NSUTF8StringEncoding], @"Client",
671            [NSNumber numberWithBool: peer.isDownloading], @"UL To",
672            [NSNumber numberWithBool: peer.isUploading], @"DL From", nil]];
673    }
674   
675    tr_torrentPeersFree(peers, totalPeers);
676   
677    return peerDics;
678}
679
680- (NSString *) progressString
681{
682    return fProgressString;
683}
684
685- (NSString *) statusString
686{
687    return fStatusString;
688}
689
690- (NSString *) shortStatusString
691{
692    return fShortStatusString;
693}
694
695- (NSString *) remainingTimeString
696{
697    return fRemainingTimeString;
698}
699
700- (int) seeders
701{
702    return fStat->seeders;
703}
704
705- (int) leechers
706{
707    return fStat->leechers;
708}
709
710- (int) totalPeers
711{
712    return fStat->peersTotal;
713}
714
715//peers uploading to you
716- (int) peersUploading
717{
718    return fStat->peersUploading;
719}
720
721//peers downloading from you
722- (int) peersDownloading
723{
724    return fStat->peersDownloading;
725}
726
727- (float) downloadRate
728{
729    return fStat->rateDownload;
730}
731
732- (float) uploadRate
733{
734    return fStat->rateUpload;
735}
736
737- (float) downloadedValid
738{
739    return [self progress] * [self size];
740}
741
742- (uint64_t) downloadedTotal
743{
744    return fStat->downloaded;
745}
746
747- (uint64_t) uploadedTotal
748{
749    return fStat->uploaded;
750}
751
752- (float) swarmSpeed
753{
754    return fStat->swarmspeed;
755}
756
757- (NSNumber *) orderValue
758{
759    return [NSNumber numberWithInt: fOrderValue];
760}
761
762- (void) setOrderValue: (int) orderValue
763{
764    fOrderValue = orderValue;
765}
766
767- (NSArray *) fileList
768{
769    int count = fInfo->fileCount, i;
770    tr_file_t file;
771    NSMutableArray * files = [NSMutableArray arrayWithCapacity: count];
772   
773    for (i = 0; i < count; i++)
774    {
775        file = fInfo->files[i];
776        [files addObject: [NSDictionary dictionaryWithObjectsAndKeys:
777            [[self downloadFolder] stringByAppendingPathComponent: [NSString stringWithUTF8String: file.name]], @"Name",
778            [NSNumber numberWithUnsignedLongLong: file.length], @"Size", nil]];
779    }
780   
781    return files;
782}
783
784- (NSDate *) date
785{
786    return fDate;
787}
788
789- (NSNumber *) stateSortKey
790{
791    if (![self isActive])
792        return [NSNumber numberWithInt: 0];
793    else if ([self isSeeding])
794        return [NSNumber numberWithInt: 1];
795    else
796        return [NSNumber numberWithInt: 2];
797}
798
799- (NSNumber *) progressSortKey
800{
801    //if finished downloading sort by ratio instead of progress
802    float progress = [self progress];
803    return [NSNumber numberWithFloat: progress < 1.0 ? progress : 2.0 + [self ratio]];
804}
805
806@end
807
808
809@implementation Torrent (Private)
810
811//if a hash is given, attempt to load that; otherwise, attempt to open file at path
812- (id) initWithHash: (NSString *) hashString path: (NSString *) path lib: (tr_handle_t *) lib
813        privateTorrent: (NSNumber *) privateTorrent publicTorrent: (NSNumber *) publicTorrent
814        date: (NSDate *) date stopRatioSetting: (NSNumber *) stopRatioSetting
815        ratioLimit: (NSNumber *) ratioLimit waitToStart: (NSNumber *) waitToStart
816        orderValue: (NSNumber *) orderValue
817{
818    if (!(self = [super init]))
819        return nil;
820
821    fLib = lib;
822    fDefaults = [NSUserDefaults standardUserDefaults];
823
824    fPrivateTorrent = privateTorrent ? [privateTorrent boolValue] : [fDefaults boolForKey: @"SavePrivateTorrent"];
825    fPublicTorrent = !fPrivateTorrent || (publicTorrent ? [publicTorrent boolValue]
826                                            : ![fDefaults boolForKey: @"DeleteOriginalTorrent"]);
827
828    int error;
829    if (fPrivateTorrent && hashString)
830        fHandle = tr_torrentInitSaved(fLib, [hashString UTF8String], TR_FSAVEPRIVATE, & error);
831   
832    if (!fHandle && path)
833        fHandle = tr_torrentInit(fLib, [path UTF8String], fPrivateTorrent ? TR_FSAVEPRIVATE : 0, & error);
834
835    if (!fHandle)
836    {
837        [self release];
838        return nil;
839    }
840   
841    fInfo = tr_torrentInfo( fHandle );
842
843    if (fPublicTorrent)
844        fPublicTorrentLocation = [path retain];
845
846    fDate = date ? [date retain] : [[NSDate alloc] init];
847   
848    fStopRatioSetting = stopRatioSetting ? [stopRatioSetting intValue] : -1;
849    fRatioLimit = ratioLimit ? [ratioLimit floatValue] : [fDefaults floatForKey: @"RatioLimit"];
850    fFinishedSeeding = NO;
851   
852    fWaitToStart = waitToStart ? [waitToStart boolValue]
853                    : ![[fDefaults stringForKey: @"StartSetting"] isEqualToString: @"Manual"];
854    fOrderValue = orderValue ? [orderValue intValue] : tr_torrentCount(fLib) - 1;
855   
856    NSString * fileType = fInfo->multifile ? NSFileTypeForHFSTypeCode('fldr') : [[self name] pathExtension];
857    fIcon = [[NSWorkspace sharedWorkspace] iconForFileType: fileType];
858    [fIcon retain];
859   
860    fIconFlipped = [fIcon copy];
861    [fIconFlipped setFlipped: YES];
862   
863    fIconSmall = [fIconFlipped copy];
864    [fIconSmall setScalesWhenResized: YES];
865    [fIconSmall setSize: NSMakeSize(16.0, 16.0)];
866
867    fProgressString = [[NSMutableString alloc] initWithCapacity: 50];
868    fStatusString = [[NSMutableString alloc] initWithCapacity: 75];
869    fShortStatusString = [[NSMutableString alloc] initWithCapacity: 30];
870    fRemainingTimeString = [[NSMutableString alloc] initWithCapacity: 30];
871
872    [self update];
873    return self;
874}
875
876- (void) trashFile: (NSString *) path
877{
878    //attempt to move to trash
879    if (![[NSWorkspace sharedWorkspace] performFileOperation: NSWorkspaceRecycleOperation
880            source: [path stringByDeletingLastPathComponent] destination: @""
881            files: [NSArray arrayWithObject: [path lastPathComponent]] tag: nil])
882    {
883        //if cannot trash, just delete it (will work if it is on a remote volume)
884        if (![[NSFileManager defaultManager] removeFileAtPath: path handler: nil])
885            NSLog([@"Could not trash " stringByAppendingString: path]);
886    }
887}
888
889@end
Note: See TracBrowser for help on using the repository browser.