source: trunk/macosx/Torrent.m @ 859

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

white instead of "back" color

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