source: trunk/macosx/Torrent.m @ 1027

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

some cleanup from the previous commit

  • Property svn:keywords set to Date Rev Author Id
File size: 30.5 KB
Line 
1/******************************************************************************
2 * $Id: Torrent.m 1027 2006-10-24 20:51:47Z 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#define MAX_PIECES 324
31#define BLANK_PIECE -99
32
33@interface Torrent (Private)
34
35- (id) initWithHash: (NSString *) hashString path: (NSString *) path lib: (tr_handle_t *) lib
36        privateTorrent: (NSNumber *) privateTorrent publicTorrent: (NSNumber *) publicTorrent
37        date: (NSDate *) date stopRatioSetting: (NSNumber *) stopRatioSetting
38        ratioLimit: (NSNumber *) ratioLimit waitToStart: (NSNumber *) waitToStart
39        orderValue: (NSNumber *) orderValue;
40
41- (NSImage *) advancedBar;
42
43- (void) trashFile: (NSString *) path;
44
45@end
46
47@implementation Torrent
48
49// Used to optimize drawing. They contain packed RGBA pixels for every color needed.
50#define BE OSSwapBigToHostConstInt32
51
52static uint32_t kRed   = BE(0xFF6450FF), //255, 100, 80
53                kBlue = BE(0x50A0FFFF), //80, 160, 255
54                kBlue2 = BE(0x1E46B4FF), //30, 70, 180
55                kGray  = BE(0x969696FF), //150, 150, 150
56                kGreen1 = BE(0x99FFCCFF), //153, 255, 204
57                kGreen2 = BE(0x66FF99FF), //102, 255, 153
58                kGreen3 = BE(0x00FF66FF), //0, 255, 102
59                kWhite = BE(0xFFFFFFFF); //255, 255, 255
60
61- (id) initWithPath: (NSString *) path lib: (tr_handle_t *) lib
62{
63    self = [self initWithHash: nil path: path lib: lib privateTorrent: nil publicTorrent: nil
64            date: nil stopRatioSetting: nil ratioLimit: nil waitToStart: nil orderValue: nil];
65   
66    if (self)
67    {
68        if (!fPublicTorrent)
69            [self trashFile: path];
70    }
71    return self;
72}
73
74- (id) initWithHistory: (NSDictionary *) history lib: (tr_handle_t *) lib
75{
76    self = [self initWithHash: [history objectForKey: @"TorrentHash"]
77                path: [history objectForKey: @"TorrentPath"] lib: lib
78                privateTorrent: [history objectForKey: @"PrivateCopy"]
79                publicTorrent: [history objectForKey: @"PublicCopy"]
80                date: [history objectForKey: @"Date"]
81                stopRatioSetting: [history objectForKey: @"StopRatioSetting"]
82                ratioLimit: [history objectForKey: @"RatioLimit"]
83                waitToStart: [history objectForKey: @"WaitToStart"]
84                orderValue: [history objectForKey: @"OrderValue"]];
85   
86    if (self)
87    {
88        NSString * downloadFolder;
89        if (!(downloadFolder = [history objectForKey: @"DownloadFolder"]))
90            downloadFolder = [[fDefaults stringForKey: @"DownloadFolder"] stringByExpandingTildeInPath];
91        [self setDownloadFolder: downloadFolder];
92
93        NSString * paused;
94        if (!(paused = [history objectForKey: @"Paused"]) || [paused isEqualToString: @"NO"])
95        {
96            fStat = tr_torrentStat(fHandle);
97            [self startTransfer];
98        }
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       
146        [fBitmap release];
147        free(fPieces);
148    }
149    [super dealloc];
150}
151
152- (void) setDownloadFolder: (NSString *) path
153{
154    tr_torrentSetFolder(fHandle, [path UTF8String]);
155}
156
157- (NSString *) downloadFolder
158{
159    return [NSString stringWithUTF8String: tr_torrentGetFolder(fHandle)];
160}
161
162- (void) getAvailability: (int8_t *) tab size: (int) size
163{
164    tr_torrentAvailability(fHandle, tab, size);
165}
166
167- (void) getAmountFinished: (float *) tab size: (int) size
168{
169    tr_torrentAmountFinished(fHandle, tab, size);
170}
171
172- (void) update
173{
174    fStat = tr_torrentStat(fHandle);
175   
176    //notification when downloading finished
177    if ([self justFinished])
178        [[NSNotificationCenter defaultCenter] postNotificationName: @"TorrentFinishedDownloading" object: self];
179   
180    //check to stop for ratio
181    if ([self isSeeding] && ((fStopRatioSetting == RATIO_CHECK && [self ratio] >= fRatioLimit)
182            || (fStopRatioSetting == RATIO_GLOBAL && [fDefaults boolForKey: @"RatioCheck"]
183            && [self ratio] >= [fDefaults floatForKey: @"RatioLimit"])))
184    {
185        [self stopTransfer];
186        [self setStopRatioSetting: RATIO_NO_CHECK];
187        fFinishedSeeding = YES;
188       
189        fStat = tr_torrentStat(fHandle);
190       
191        [[NSNotificationCenter defaultCenter] postNotificationName: @"TorrentStoppedForRatio" object: self];
192    }
193
194    [fProgressString setString: @""];
195    if ([self progress] < 1.0)
196        [fProgressString appendFormat: NSLocalizedString(@"%@ of %@ (%.2f%%)", "Torrent -> progress string"),
197                            [NSString stringForFileSize: [self downloadedValid]],
198                            [NSString stringForFileSize: [self size]], 100.0 * [self progress]];
199    else
200        [fProgressString appendFormat: NSLocalizedString(@"%@, uploaded %@ (Ratio: %@)", "Torrent -> progress string"),
201                [NSString stringForFileSize: [self size]], [NSString stringForFileSize: [self uploadedTotal]],
202                [NSString stringForRatioWithDownload: [self downloadedTotal] upload: [self uploadedTotal]]];
203
204    switch (fStat->status)
205    {
206        NSString * tempString;
207   
208        case TR_STATUS_PAUSE:
209            if (fFinishedSeeding)
210                tempString = NSLocalizedString(@"Seeding complete", "Torrent -> status string");
211            else if (fWaitToStart)
212                tempString = [NSLocalizedString(@"Waiting to start", "Torrent -> status string") stringByAppendingEllipsis];
213            else
214                tempString = NSLocalizedString(@"Paused", "Torrent -> status string");
215           
216            [fStatusString setString: tempString];
217            [fShortStatusString setString: tempString];
218           
219            break;
220
221        case TR_STATUS_CHECK:
222            tempString = [NSLocalizedString(@"Checking existing files", "Torrent -> status string") stringByAppendingEllipsis];
223           
224            [fStatusString setString: tempString];
225            [fShortStatusString setString: tempString];
226            [fRemainingTimeString setString: tempString];
227           
228            break;
229
230        case TR_STATUS_DOWNLOAD:
231            [fStatusString setString: @""];
232            if ([self totalPeers] > 1)
233                [fStatusString appendFormat: NSLocalizedString(@"Downloading from %d of %d peers",
234                                                "Torrent -> status string"), [self peersUploading], [self totalPeers]];
235            else
236                [fStatusString appendFormat: NSLocalizedString(@"Downloading from %d of %d peer",
237                                                "Torrent -> status string"), [self peersUploading], [self totalPeers]];
238           
239            [fRemainingTimeString setString: @""];
240            int eta = [self eta];
241            if (eta < 0)
242            {
243                [fRemainingTimeString setString: NSLocalizedString(@"Unknown", "Torrent -> remaining time")];
244                [fProgressString appendString: NSLocalizedString(@" - remaining time unknown", "Torrent -> progress string")];
245            }
246            else
247            {
248                if (eta < 60)
249                    [fRemainingTimeString appendFormat: NSLocalizedString(@"%d sec", "Torrent -> remaining time"), eta];
250                else if (eta < 3600) //60 * 60
251                    [fRemainingTimeString appendFormat: NSLocalizedString(@"%d min %02d sec", "Torrent -> remaining time"),
252                                                            eta / 60, eta % 60];
253                else if (eta < 86400) //24 * 60 * 60
254                    [fRemainingTimeString appendFormat: NSLocalizedString(@"%d hr %02d min", "Torrent -> remaining time"),
255                                                            eta / 3600, (eta / 60) % 60];
256                else
257                {
258                    if (eta / 86400 > 1)
259                        [fRemainingTimeString appendFormat: NSLocalizedString(@"%d days %d hr", "Torrent -> remaining time"),
260                                                                eta / 86400, (eta / 3600) % 24];
261                    else
262                        [fRemainingTimeString appendFormat: NSLocalizedString(@"%d day %d hr", "Torrent -> remaining time"),
263                                                                eta / 86400, (eta / 3600) % 24];
264                }
265               
266                [fProgressString appendFormat: NSLocalizedString(@" - %@ remaining", "Torrent -> progress string"),
267                                                                    fRemainingTimeString];
268            }
269           
270            break;
271
272        case TR_STATUS_SEED:
273            [fStatusString setString: @""];
274            if ([self totalPeers] > 1)
275                [fStatusString appendFormat: NSLocalizedString(@"Seeding to %d of %d peers", "Torrent -> status string"),
276                                                [self peersDownloading], [self totalPeers]];
277            else
278                [fStatusString appendFormat: NSLocalizedString(@"Seeding to %d of %d peer", "Torrent -> status string"),
279                                                [self peersDownloading], [self totalPeers]];
280           
281            break;
282
283        case TR_STATUS_STOPPING:
284            tempString = [NSLocalizedString(@"Stopping", "Torrent -> status string") stringByAppendingEllipsis];
285       
286            [fStatusString setString: tempString];
287            [fShortStatusString setString: tempString];
288           
289            break;
290    }
291   
292    if (fStat->error & TR_ETRACKER)
293    {
294        [fStatusString setString: [NSLocalizedString(@"Error: ", "Torrent -> status string") stringByAppendingString:
295                                    [NSString stringWithUTF8String: fStat->trackerError]]];
296        if (!fError && [self isActive])
297        {
298            fError = YES;
299            if (![self isSeeding])
300                [[NSNotificationCenter defaultCenter] postNotificationName: @"StoppedDownloading" object: self];
301        }
302    }
303    else
304    {
305        if (fError)
306            fError = NO;
307    }
308
309    if ([self isActive])
310    {
311        NSString * stringToAppend = @"";
312        if ([self progress] < 1.0)
313        {
314            stringToAppend = [NSString stringWithFormat: NSLocalizedString(@"DL: %@, ", "Torrent -> status string"),
315                                [NSString stringForSpeed: [self downloadRate]]];
316            [fShortStatusString setString: @""];
317        }
318        else
319        {
320            NSString * ratioString = [NSString stringForRatioWithDownload: [self downloadedTotal]
321                                                upload: [self uploadedTotal]];
322       
323            [fShortStatusString setString: [NSString stringWithFormat: NSLocalizedString(@"Ratio: %@, ",
324                                            "Torrent -> status string"), ratioString]];
325            [fRemainingTimeString setString: [NSLocalizedString(@"Ratio: ", "Torrent -> status string")
326                                                stringByAppendingString: ratioString]];
327        }
328       
329        stringToAppend = [stringToAppend stringByAppendingString: [NSLocalizedString(@"UL: ", "Torrent -> status string")
330                                            stringByAppendingString: [NSString stringForSpeed: [self uploadRate]]]];
331
332        [fStatusString appendFormat: @" - %@", stringToAppend];
333        [fShortStatusString appendString: stringToAppend];
334    }
335}
336
337- (NSDictionary *) infoForCurrentView
338{
339    NSMutableDictionary * info = [NSMutableDictionary dictionaryWithObjectsAndKeys:
340                                    [self name], @"Name",
341                                    [NSNumber numberWithBool: [self isSeeding]], @"Seeding",
342                                    [NSNumber numberWithFloat: [self progress]], @"Progress",
343                                    [NSNumber numberWithBool: [self isActive]], @"Active",
344                                    [NSNumber numberWithBool: [self isError]], @"Error", nil];
345   
346    if (![fDefaults boolForKey: @"SmallView"])
347    {
348        [info setObject: fIconFlipped forKey: @"Icon"];
349        [info setObject: [self progressString] forKey: @"ProgressString"];
350        [info setObject: [self statusString] forKey: @"StatusString"];
351    }
352    else
353    {
354        [info setObject: fIconSmall forKey: @"Icon"];
355        [info setObject: [self remainingTimeString] forKey: @"RemainingTimeString"];
356        [info setObject: [self shortStatusString] forKey: @"ShortStatusString"];
357    }
358   
359    if ([fDefaults boolForKey: @"UseAdvancedBar"])
360        [info setObject: [self advancedBar] forKey: @"AdvancedBar"];
361   
362    return info;
363}
364
365- (void) startTransfer
366{
367    fWaitToStart = NO;
368    fFinishedSeeding = NO;
369   
370    if (![self isActive] && [self remainingDiskSpaceForTorrent])
371        tr_torrentStart(fHandle);
372}
373
374- (void) stopTransfer
375{
376    fError = NO;
377   
378    if ([self isActive])
379    {
380        BOOL wasSeeding = [self isSeeding];
381   
382        tr_torrentStop(fHandle);
383
384        if (!wasSeeding)
385            [[NSNotificationCenter defaultCenter] postNotificationName: @"StoppedDownloading" object: self];
386    }
387}
388
389- (void) stopTransferForQuit
390{
391    if ([self isActive])
392        tr_torrentStop(fHandle);
393}
394
395- (void) removeForever
396{
397    if (fPrivateTorrent)
398        tr_torrentRemoveSaved(fHandle);
399}
400
401- (void) sleep
402{
403    if ((fResumeOnWake = [self isActive]))
404        tr_torrentStop(fHandle);
405}
406
407- (void) wakeUp
408{
409    if (fResumeOnWake)
410        tr_torrentStart(fHandle);
411}
412
413- (float) ratio
414{
415    float downloaded = [self downloadedTotal];
416    return downloaded > 0 ? (float)[self uploadedTotal] / downloaded : -1;
417}
418
419- (int) stopRatioSetting
420{
421        return fStopRatioSetting;
422}
423
424- (void) setStopRatioSetting: (int) setting
425{
426    fStopRatioSetting = setting;
427}
428
429- (float) ratioLimit
430{
431    return fRatioLimit;
432}
433
434- (void) setRatioLimit: (float) limit
435{
436    if (limit >= 0)
437        fRatioLimit = limit;
438}
439
440- (void) setWaitToStart: (BOOL) wait
441{
442    fWaitToStart = wait;
443}
444
445- (BOOL) waitingToStart
446{
447    return fWaitToStart;
448}
449
450- (void) revealData
451{
452    [[NSWorkspace sharedWorkspace] selectFile: [self dataLocation] inFileViewerRootedAtPath: nil];
453}
454
455- (void) revealPublicTorrent
456{
457    if (fPublicTorrent)
458        [[NSWorkspace sharedWorkspace] selectFile: fPublicTorrentLocation inFileViewerRootedAtPath: nil];
459}
460
461- (void) trashData
462{
463    [self trashFile: [self dataLocation]];
464}
465
466- (void) trashTorrent
467{
468    if (fPublicTorrent)
469        [self trashFile: [self publicTorrentLocation]];
470}
471
472- (BOOL) remainingDiskSpaceForTorrent
473{
474    if ([self progress] >= 1.0)
475        return YES;
476   
477    NSString * location = [self dataLocation],
478                * volume = [[[NSFileManager defaultManager] componentsToDisplayForPath: location] objectAtIndex: 0];
479    NSDictionary * fsAttributes = [[NSFileManager defaultManager] fileSystemAttributesAtPath: location];
480    uint64_t remainingSpace = [[fsAttributes objectForKey: NSFileSystemFreeSize] unsignedLongLongValue],
481            torrentRemaining = [self size] - (uint64_t)[self downloadedValid];
482   
483    NSLog(@"Volume: %@", volume);
484    NSLog(@"Remaining disk space: %qu (%@)", remainingSpace, [NSString stringForFileSize: remainingSpace]);
485    NSLog(@"Torrent remaining size: %qu (%@)", torrentRemaining, [NSString stringForFileSize: torrentRemaining]);
486   
487    if (volume && remainingSpace <= torrentRemaining)
488    {
489        NSAlert * alert = [[NSAlert alloc] init];
490        [alert setMessageText: [NSString stringWithFormat:
491                                NSLocalizedString(@"Not enough remaining disk space to download \"%@\" completely.",
492                                    "Torrent file disk space alert -> title"), [self name]]];
493        [alert setInformativeText: [NSString stringWithFormat:
494                        NSLocalizedString(@"The transfer will be paused. Clear up space on %@ to continue.",
495                                            "Torrent file disk space alert -> message"), volume]];
496        [alert addButtonWithTitle: NSLocalizedString(@"OK", "Torrent file disk space alert -> button")];
497        [alert addButtonWithTitle: NSLocalizedString(@"Download Anyway", "Torrent file disk space alert -> button")];
498       
499        if ([alert runModal] == NSAlertFirstButtonReturn)
500        {
501            [[NSNotificationCenter defaultCenter] postNotificationName: @"StoppedDownloading" object: self];
502            return NO;
503        }
504        else
505            return YES;
506    }
507    return YES;
508}
509
510- (NSImage *) icon
511{
512    return fIcon;
513}
514
515- (NSImage *) iconFlipped
516{
517    return fIconFlipped;
518}
519
520- (NSImage *) iconSmall
521{
522    return fIconSmall;
523}
524
525- (NSString *) name
526{
527    return [NSString stringWithUTF8String: fInfo->name];
528}
529
530- (uint64_t) size
531{
532    return fInfo->totalSize;
533}
534
535- (NSString *) tracker
536{
537    return [NSString stringWithFormat: @"%s:%d", fInfo->trackerAddress, fInfo->trackerPort];
538}
539
540- (NSString *) announce
541{
542    return [NSString stringWithUTF8String: fInfo->trackerAnnounce];
543}
544
545- (int) pieceSize
546{
547    return fInfo->pieceSize;
548}
549
550- (int) pieceCount
551{
552    return fInfo->pieceCount;
553}
554
555- (NSString *) hashString
556{
557    return [NSString stringWithUTF8String: fInfo->hashString];
558}
559
560- (NSString *) torrentLocation
561{
562    return [NSString stringWithUTF8String: fInfo->torrent];
563}
564
565- (NSString *) publicTorrentLocation
566{
567    return fPublicTorrentLocation;
568}
569
570- (NSString *) torrentLocationString
571{
572    return fPrivateTorrent ? NSLocalizedString(@"Transmission Support Folder", "Torrent -> location")
573                            : [fPublicTorrentLocation stringByAbbreviatingWithTildeInPath];
574}
575
576- (NSString *) dataLocation
577{
578    return [[self downloadFolder] stringByAppendingPathComponent: [self name]];
579}
580
581- (BOOL) publicTorrent
582{
583    return fPublicTorrent;
584}
585
586- (BOOL) privateTorrent
587{
588    return fPrivateTorrent;
589}
590
591- (NSString *) stateString
592{
593    switch( fStat->status )
594    {
595        case TR_STATUS_PAUSE:
596            return NSLocalizedString(@"Paused", "Torrent -> status string");
597            break;
598
599        case TR_STATUS_CHECK:
600            return [NSLocalizedString(@"Checking existing files", "Torrent -> status string") stringByAppendingEllipsis];
601            break;
602
603        case TR_STATUS_DOWNLOAD:
604            return NSLocalizedString(@"Downloading", "Torrent -> status string");
605            break;
606
607        case TR_STATUS_SEED:
608            return NSLocalizedString(@"Seeding", "Torrent -> status string");
609            break;
610
611        case TR_STATUS_STOPPING:
612            return [NSLocalizedString(@"Stopping", "Torrent -> status string") stringByAppendingEllipsis];
613            break;
614       
615        default:
616            return NSLocalizedString(@"N/A", "Torrent -> status string");
617    }
618}
619
620- (float) progress
621{
622    return fStat->progress;
623}
624
625- (int) eta
626{
627    return fStat->eta;
628}
629
630- (BOOL) isActive
631{
632    return fStat->status & TR_STATUS_ACTIVE;
633}
634
635- (BOOL) isSeeding
636{
637    return fStat->status == TR_STATUS_SEED;
638}
639
640- (BOOL) isPaused
641{
642    return fStat->status == TR_STATUS_PAUSE;
643}
644
645- (BOOL) isError
646{
647    return fStat->error & TR_ETRACKER;
648}
649
650- (BOOL) justFinished
651{
652    return tr_getFinished(fHandle);
653}
654
655- (NSArray *) peers
656{
657    int totalPeers, i;
658    tr_peer_stat_t * peers = tr_torrentPeers(fHandle, & totalPeers);
659   
660    NSMutableArray * peerDics = [NSMutableArray arrayWithCapacity: totalPeers];
661    tr_peer_stat_t peer;
662    NSString * client;
663    for (i = 0; i < totalPeers; i++)
664    {
665        peer = peers[i];
666        [peerDics addObject: [NSDictionary dictionaryWithObjectsAndKeys:
667            [NSNumber numberWithBool: peer.isConnected], @"Connected",
668            [NSNumber numberWithBool: peer.isIncoming], @"Incoming",
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- (int) totalPeersIncoming
716{
717    return fStat->peersIncoming;
718}
719
720- (int) totalPeersOutgoing
721{
722    return [self totalPeers] - [self totalPeersIncoming];
723}
724
725//peers uploading to you
726- (int) peersUploading
727{
728    return fStat->peersUploading;
729}
730
731//peers downloading from you
732- (int) peersDownloading
733{
734    return fStat->peersDownloading;
735}
736
737- (float) downloadRate
738{
739    return fStat->rateDownload;
740}
741
742- (float) uploadRate
743{
744    return fStat->rateUpload;
745}
746
747- (float) downloadedValid
748{
749    return [self progress] * [self size];
750}
751
752- (uint64_t) downloadedTotal
753{
754    return fStat->downloaded;
755}
756
757- (uint64_t) uploadedTotal
758{
759    return fStat->uploaded;
760}
761
762- (float) swarmSpeed
763{
764    return fStat->swarmspeed;
765}
766
767- (NSNumber *) orderValue
768{
769    return [NSNumber numberWithInt: fOrderValue];
770}
771
772- (void) setOrderValue: (int) orderValue
773{
774    fOrderValue = orderValue;
775}
776
777- (NSArray *) fileList
778{
779    int count = fInfo->fileCount, i;
780    tr_file_t file;
781    NSMutableArray * files = [NSMutableArray arrayWithCapacity: count];
782   
783    for (i = 0; i < count; i++)
784    {
785        file = fInfo->files[i];
786        [files addObject: [NSDictionary dictionaryWithObjectsAndKeys:
787            [[self downloadFolder] stringByAppendingPathComponent: [NSString stringWithUTF8String: file.name]], @"Name",
788            [NSNumber numberWithUnsignedLongLong: file.length], @"Size", nil]];
789    }
790   
791    return files;
792}
793
794- (NSDate *) date
795{
796    return fDate;
797}
798
799- (NSNumber *) stateSortKey
800{
801    if (![self isActive])
802        return [NSNumber numberWithInt: 0];
803    else if ([self isSeeding])
804        return [NSNumber numberWithInt: 1];
805    else
806        return [NSNumber numberWithInt: 2];
807}
808
809- (NSNumber *) progressSortKey
810{
811    //if finished downloading sort by ratio instead of progress
812    float progress = [self progress];
813    return [NSNumber numberWithFloat: progress < 1.0 ? progress : 2.0 + [self ratio]];
814}
815
816@end
817
818
819@implementation Torrent (Private)
820
821//if a hash is given, attempt to load that; otherwise, attempt to open file at path
822- (id) initWithHash: (NSString *) hashString path: (NSString *) path lib: (tr_handle_t *) lib
823        privateTorrent: (NSNumber *) privateTorrent publicTorrent: (NSNumber *) publicTorrent
824        date: (NSDate *) date stopRatioSetting: (NSNumber *) stopRatioSetting
825        ratioLimit: (NSNumber *) ratioLimit waitToStart: (NSNumber *) waitToStart
826        orderValue: (NSNumber *) orderValue
827{
828    if (!(self = [super init]))
829        return nil;
830
831    fLib = lib;
832    fDefaults = [NSUserDefaults standardUserDefaults];
833
834    fPrivateTorrent = privateTorrent ? [privateTorrent boolValue] : [fDefaults boolForKey: @"SavePrivateTorrent"];
835    fPublicTorrent = !fPrivateTorrent || (publicTorrent ? [publicTorrent boolValue]
836                                            : ![fDefaults boolForKey: @"DeleteOriginalTorrent"]);
837
838    int error;
839    if (fPrivateTorrent && hashString)
840        fHandle = tr_torrentInitSaved(fLib, [hashString UTF8String], TR_FSAVEPRIVATE, & error);
841   
842    if (!fHandle && path)
843        fHandle = tr_torrentInit(fLib, [path UTF8String], fPrivateTorrent ? TR_FSAVEPRIVATE : 0, & error);
844
845    if (!fHandle)
846    {
847        [self release];
848        return nil;
849    }
850   
851    fInfo = tr_torrentInfo( fHandle );
852
853    if (fPublicTorrent)
854        fPublicTorrentLocation = [path retain];
855
856    fDate = date ? [date retain] : [[NSDate alloc] init];
857   
858    fStopRatioSetting = stopRatioSetting ? [stopRatioSetting intValue] : -1;
859    fRatioLimit = ratioLimit ? [ratioLimit floatValue] : [fDefaults floatForKey: @"RatioLimit"];
860    fFinishedSeeding = NO;
861   
862    fWaitToStart = waitToStart ? [waitToStart boolValue] : [fDefaults boolForKey: @"AutoStartDownload"];
863    fOrderValue = orderValue ? [orderValue intValue] : tr_torrentCount(fLib) - 1;
864    fError = NO;
865   
866    NSString * fileType = fInfo->multifile ? NSFileTypeForHFSTypeCode('fldr') : [[self name] pathExtension];
867    fIcon = [[NSWorkspace sharedWorkspace] iconForFileType: fileType];
868    [fIcon retain];
869   
870    fIconFlipped = [fIcon copy];
871    [fIconFlipped setFlipped: YES];
872   
873    fIconSmall = [fIconFlipped copy];
874    [fIconSmall setScalesWhenResized: YES];
875    [fIconSmall setSize: NSMakeSize(16.0, 16.0)];
876
877    fProgressString = [[NSMutableString alloc] initWithCapacity: 50];
878    fStatusString = [[NSMutableString alloc] initWithCapacity: 75];
879    fShortStatusString = [[NSMutableString alloc] initWithCapacity: 30];
880    fRemainingTimeString = [[NSMutableString alloc] initWithCapacity: 30];
881   
882    //set up advanced bar
883    fBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: nil
884        pixelsWide: MAX_PIECES pixelsHigh: BAR_HEIGHT bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES
885        isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: 0 bitsPerPixel: 0];
886   
887    fPieces = malloc(MAX_PIECES);
888    int i;
889    for (i = 0; i < MAX_PIECES; i++)
890        fPieces[i] = BLANK_PIECE;
891
892    [self update];
893    return self;
894}
895
896- (NSImage *) advancedBar
897{
898    int h, w;
899    uint32_t * p;
900    uint8_t * bitmapData = [fBitmap bitmapData];
901    int bytesPerRow = [fBitmap bytesPerRow];
902
903    int8_t * pieces = malloc(MAX_PIECES);
904    [self getAvailability: pieces size: MAX_PIECES];
905   
906    //lines 2 to 14: blue, green, or gray depending on whether we have the piece or not
907    int have = 0, avail = 0;
908    uint32_t color;
909    BOOL change;
910    for (w = 0; w < MAX_PIECES; w++)
911    {
912        change = NO;
913        if (pieces[w] < 0)
914        {
915            if (fPieces[w] != -1)
916            {
917                color = kBlue;
918                fPieces[w] = -1;
919                change = YES;
920            }
921            have++;
922        }
923        else if (pieces[w] == 0)
924        {
925            if (fPieces[w] != 0)
926            {
927                color = kGray;
928                fPieces[w] = 0;
929                change = YES;
930            }
931        }
932        else
933        {
934            if (pieces[w] == 1)
935            {
936                if (fPieces[w] != 1)
937                {
938                    color = kGreen1;
939                    fPieces[w] = 1;
940                    change = YES;
941                }
942            }
943            else if (pieces[w] == 2)
944            {
945                if (fPieces[w] != 2)
946                {
947                    color = kGreen2;
948                    fPieces[w] = 2;
949                    change = YES;
950                }
951            }
952            else
953            {
954                if (fPieces[w] != 3)
955                {
956                    color = kGreen3;
957                    fPieces[w] = 3;
958                    change = YES;
959                }
960            }
961            avail++;
962        }
963       
964        if (change)
965        {
966            //point to pixel (w, 2) and draw "vertically"
967            p = (uint32_t *)(bitmapData + 2 * bytesPerRow) + w;
968            for (h = 2; h < BAR_HEIGHT; h++)
969            {
970                p[0] = color;
971                p = (uint32_t *)((uint8_t *)p + bytesPerRow);
972            }
973        }
974    }
975   
976    //first two lines: dark blue to show progression, green to show available
977    p = (uint32_t *) bitmapData;
978    for (w = 0; w < have; w++)
979    {
980        p[w] = kBlue2;
981        p[w + bytesPerRow / 4] = kBlue2;
982    }
983    for (; w < avail + have; w++)
984    {
985        p[w] = kGreen3;
986        p[w + bytesPerRow / 4] = kGreen3;
987    }
988    for (; w < MAX_PIECES; w++)
989    {
990        p[w] = kWhite;
991        p[w + bytesPerRow / 4] = kWhite;
992    }
993   
994    free(pieces);
995   
996    //actually draw image
997    NSImage * bar = [[NSImage alloc] initWithSize: [fBitmap size]];
998    [bar addRepresentation: fBitmap];
999    [bar setScalesWhenResized: YES];
1000   
1001    return [bar autorelease];
1002}
1003
1004- (void) trashFile: (NSString *) path
1005{
1006    //attempt to move to trash
1007    if (![[NSWorkspace sharedWorkspace] performFileOperation: NSWorkspaceRecycleOperation
1008            source: [path stringByDeletingLastPathComponent] destination: @""
1009            files: [NSArray arrayWithObject: [path lastPathComponent]] tag: nil])
1010    {
1011        //if cannot trash, just delete it (will work if it is on a remote volume)
1012        if (![[NSFileManager defaultManager] removeFileAtPath: path handler: nil])
1013            NSLog([@"Could not trash " stringByAppendingString: path]);
1014    }
1015}
1016
1017@end
Note: See TracBrowser for help on using the repository browser.