source: trunk/macosx/Torrent.m @ 980

Last change on this file since 980 was 980, checked in by livings124, 16 years ago

Faster scrolling at the cost of a bit less detailed advanced bar (if you want more details, use the info window ;))

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