source: trunk/macosx/Torrent.m @ 953

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

an extra log for extra debugging

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