source: trunk/macosx/Torrent.m @ 940

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

First attempts at warning about not enough disk space (and stopping the offending torrents). Right now this occurs when the torrent is started.

  • Property svn:keywords set to Date Rev Author Id
File size: 25.1 KB
Line 
1/******************************************************************************
2 * $Id: Torrent.m 940 2006-09-28 00:32:26Z 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            tr_torrentStart(fHandle);
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    NSDictionary * fsAttributes = [[NSFileManager defaultManager] fileSystemAttributesAtPath: [self dataLocation]];
423    float remainingSpace = [[fsAttributes objectForKey: NSFileSystemFreeSize] floatValue],
424            torrentRemaining = (float)[self size] * (1.0 - [self progress]);
425   
426    NSLog(@"Remaining disk space: %f", remainingSpace);
427    NSLog(@"Torrent remaining size: %f", torrentRemaining);
428   
429    if (remainingSpace - torrentRemaining <= 10240.0)
430    {
431        NSAlert * alert = [[NSAlert alloc] init];
432        [alert setMessageText: [NSString stringWithFormat: @"Not enough remaining disk space to download \"%@\" completely.",
433                                    [self name]]];
434        [alert setInformativeText: @"The transfer has been paused. Clear up space on your disk to continue."];
435       
436        [alert runModal];
437       
438        return NO;
439    }
440   
441    return YES;
442}
443
444- (NSImage *) icon
445{
446    return fIcon;
447}
448
449- (NSImage *) iconFlipped
450{
451    return fIconFlipped;
452}
453
454- (NSImage *) iconSmall
455{
456    return fIconSmall;
457}
458
459- (NSString *) name
460{
461    return [NSString stringWithUTF8String: fInfo->name];
462}
463
464- (uint64_t) size
465{
466    return fInfo->totalSize;
467}
468
469- (NSString *) tracker
470{
471    return [NSString stringWithFormat: @"%s:%d", fInfo->trackerAddress, fInfo->trackerPort];
472}
473
474- (NSString *) announce
475{
476    return [NSString stringWithUTF8String: fInfo->trackerAnnounce];
477}
478
479- (int) pieceSize
480{
481    return fInfo->pieceSize;
482}
483
484- (int) pieceCount
485{
486    return fInfo->pieceCount;
487}
488
489- (NSString *) hashString
490{
491    return [NSString stringWithUTF8String: fInfo->hashString];
492}
493
494- (NSString *) torrentLocation
495{
496    return [NSString stringWithUTF8String: fInfo->torrent];
497}
498
499- (NSString *) publicTorrentLocation
500{
501    return fPublicTorrentLocation;
502}
503
504- (NSString *) torrentLocationString
505{
506    return fPrivateTorrent ? @"Transmission Support Folder" : [fPublicTorrentLocation stringByAbbreviatingWithTildeInPath];
507}
508
509- (NSString *) dataLocation
510{
511    return [[self downloadFolder] stringByAppendingPathComponent: [self name]];
512}
513
514- (BOOL) publicTorrent
515{
516    return fPublicTorrent;
517}
518
519- (BOOL) privateTorrent
520{
521    return fPrivateTorrent;
522}
523
524- (NSString *) stateString
525{
526    switch( fStat->status )
527    {
528        case TR_STATUS_PAUSE:
529            return @"Paused";
530            break;
531
532        case TR_STATUS_CHECK:
533            return [@"Checking existing files" stringByAppendingEllipsis];
534            break;
535
536        case TR_STATUS_DOWNLOAD:
537            return @"Downloading";
538            break;
539
540        case TR_STATUS_SEED:
541            return @"Seeding";
542            break;
543
544        case TR_STATUS_STOPPING:
545            return [@"Stopping" stringByAppendingEllipsis];
546            break;
547       
548        default:
549            return @"N/A";
550    }
551}
552
553- (float) progress
554{
555    return fStat->progress;
556}
557
558- (int) eta
559{
560    return fStat->eta;
561}
562
563- (BOOL) isActive
564{
565    return fStat->status & TR_STATUS_ACTIVE;
566}
567
568- (BOOL) isSeeding
569{
570    return fStat->status == TR_STATUS_SEED;
571}
572
573- (BOOL) isPaused
574{
575    return fStat->status == TR_STATUS_PAUSE;
576}
577
578- (BOOL) isError
579{
580    return fStat->error & TR_ETRACKER;
581}
582
583- (BOOL) justFinished
584{
585    return tr_getFinished(fHandle);
586}
587
588- (NSArray *) peers
589{
590    int totalPeers, i;
591    tr_peer_stat_t * peers = tr_torrentPeers(fHandle, & totalPeers);
592   
593    NSMutableArray * peerDics = [NSMutableArray arrayWithCapacity: totalPeers];
594    tr_peer_stat_t peer;
595    NSString * client;
596    for (i = 0; i < totalPeers; i++)
597    {
598        peer = peers[i];
599        [peerDics addObject: [NSDictionary dictionaryWithObjectsAndKeys:
600            [NSNumber numberWithBool: peer.isConnected], @"Connected",
601            [NSString stringWithCString: (char *) peer.addr encoding: NSUTF8StringEncoding], @"IP",
602            [NSString stringWithCString: (char *) peer.client encoding: NSUTF8StringEncoding], @"Client",
603            [NSNumber numberWithBool: peer.isDownloading], @"UL To",
604            [NSNumber numberWithBool: peer.isUploading], @"DL From", nil]];
605    }
606   
607    tr_torrentPeersFree(peers, totalPeers);
608   
609    return peerDics;
610}
611
612- (NSString *) progressString
613{
614    return fProgressString;
615}
616
617- (NSString *) statusString
618{
619    return fStatusString;
620}
621
622- (NSString *) shortStatusString
623{
624    return fShortStatusString;
625}
626
627- (NSString *) remainingTimeString
628{
629    return fRemainingTimeString;
630}
631
632- (int) seeders
633{
634    return fStat->seeders;
635}
636
637- (int) leechers
638{
639    return fStat->leechers;
640}
641
642- (int) totalPeers
643{
644    return fStat->peersTotal;
645}
646
647//peers uploading to you
648- (int) peersUploading
649{
650    return fStat->peersUploading;
651}
652
653//peers downloading from you
654- (int) peersDownloading
655{
656    return fStat->peersDownloading;
657}
658
659- (float) downloadRate
660{
661    return fStat->rateDownload;
662}
663
664- (float) uploadRate
665{
666    return fStat->rateUpload;
667}
668
669- (float) downloadedValid
670{
671    return [self progress] * [self size];
672}
673
674- (uint64_t) downloadedTotal
675{
676    return fStat->downloaded;
677}
678
679- (uint64_t) uploadedTotal
680{
681    return fStat->uploaded;
682}
683
684- (float) swarmSpeed
685{
686    return fStat->swarmspeed;
687}
688
689- (NSNumber *) orderValue
690{
691    return [NSNumber numberWithInt: fOrderValue];
692}
693
694- (void) setOrderValue: (int) orderValue
695{
696    fOrderValue = orderValue;
697}
698
699- (NSArray *) fileList
700{
701    int count = fInfo->fileCount, i;
702    tr_file_t file;
703    NSMutableArray * files = [NSMutableArray arrayWithCapacity: count];
704   
705    for (i = 0; i < count; i++)
706    {
707        file = fInfo->files[i];
708        [files addObject: [NSDictionary dictionaryWithObjectsAndKeys:
709            [[self downloadFolder] stringByAppendingPathComponent: [NSString stringWithUTF8String: file.name]], @"Name",
710            [NSNumber numberWithUnsignedLongLong: file.length], @"Size", nil]];
711    }
712   
713    return files;
714}
715
716- (NSDate *) date
717{
718    return fDate;
719}
720
721- (NSNumber *) stateSortKey
722{
723    if (![self isActive])
724        return [NSNumber numberWithInt: 0];
725    else if ([self isSeeding])
726        return [NSNumber numberWithInt: 1];
727    else
728        return [NSNumber numberWithInt: 2];
729}
730
731- (NSNumber *) progressSortKey
732{
733    //if finished downloading sort by ratio instead of progress
734    float progress = [self progress];
735    return [NSNumber numberWithFloat: progress < 1.0 ? progress : 2.0 + [self ratio]];
736}
737
738@end
739
740
741@implementation Torrent (Private)
742
743//if a hash is given, attempt to load that; otherwise, attempt to open file at path
744- (id) initWithHash: (NSString *) hashString path: (NSString *) path lib: (tr_handle_t *) lib
745        privateTorrent: (NSNumber *) privateTorrent publicTorrent: (NSNumber *) publicTorrent
746        date: (NSDate *) date stopRatioSetting: (NSNumber *) stopRatioSetting
747        ratioLimit: (NSNumber *) ratioLimit waitToStart: (NSNumber *) waitToStart
748        orderValue: (NSNumber *) orderValue
749{
750    if (!(self = [super init]))
751        return nil;
752
753    fLib = lib;
754    fDefaults = [NSUserDefaults standardUserDefaults];
755
756    fPrivateTorrent = privateTorrent ? [privateTorrent boolValue] : [fDefaults boolForKey: @"SavePrivateTorrent"];
757    fPublicTorrent = !fPrivateTorrent || (publicTorrent ? [publicTorrent boolValue]
758                                            : ![fDefaults boolForKey: @"DeleteOriginalTorrent"]);
759
760    int error;
761    if (fPrivateTorrent && hashString)
762        fHandle = tr_torrentInitSaved(fLib, [hashString UTF8String], TR_FSAVEPRIVATE, & error);
763   
764    if (!fHandle && path)
765        fHandle = tr_torrentInit(fLib, [path UTF8String], fPrivateTorrent ? TR_FSAVEPRIVATE : 0, & error);
766
767    if (!fHandle)
768    {
769        [self release];
770        return nil;
771    }
772   
773    fInfo = tr_torrentInfo( fHandle );
774
775    if (fPublicTorrent)
776        fPublicTorrentLocation = [path retain];
777
778    fDate = date ? [date retain] : [[NSDate alloc] init];
779   
780    fStopRatioSetting = stopRatioSetting ? [stopRatioSetting intValue] : -1;
781    fRatioLimit = ratioLimit ? [ratioLimit floatValue] : [fDefaults floatForKey: @"RatioLimit"];
782    fFinishedSeeding = NO;
783   
784    fWaitToStart = waitToStart ? [waitToStart boolValue] : [fDefaults boolForKey: @"AutoStartDownload"];
785    fOrderValue = orderValue ? [orderValue intValue] : tr_torrentCount(fLib) - 1;
786   
787    NSString * fileType = fInfo->multifile ? NSFileTypeForHFSTypeCode('fldr') : [[self name] pathExtension];
788    fIcon = [[NSWorkspace sharedWorkspace] iconForFileType: fileType];
789    [fIcon retain];
790   
791    fIconFlipped = [fIcon copy];
792    [fIconFlipped setFlipped: YES];
793   
794    fIconSmall = [fIconFlipped copy];
795    [fIconSmall setScalesWhenResized: YES];
796    [fIconSmall setSize: NSMakeSize(16.0, 16.0)];
797
798    fProgressString = [[NSMutableString alloc] initWithCapacity: 50];
799    fStatusString = [[NSMutableString alloc] initWithCapacity: 75];
800    fShortStatusString = [[NSMutableString alloc] initWithCapacity: 30];
801    fRemainingTimeString = [[NSMutableString alloc] initWithCapacity: 30];
802
803    [self update];
804    return self;
805}
806
807- (NSImage *) advancedBar
808{
809    int width = 324; //integers for bars
810   
811    NSBitmapImageRep * bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: nil
812        pixelsWide: width pixelsHigh: BAR_HEIGHT bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES
813        isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: 0 bitsPerPixel: 0];
814
815    int h, w;
816    uint32_t * p;
817    uint8_t * bitmapData = [bitmap bitmapData];
818    int bytesPerRow = [bitmap bytesPerRow];
819
820    int8_t * pieces = malloc(width);
821    [self getAvailability: pieces size: width];
822    int avail = 0;
823    for (w = 0; w < width; w++)
824        if (pieces[w] != 0)
825            avail++;
826
827    //first two lines: dark blue to show progression, green to show available
828    int end = lrintf(floor([self progress] * width));
829    p = (uint32_t *) bitmapData;
830
831    for (w = 0; w < end; w++)
832    {
833        p[w] = kBlue4;
834        p[w + bytesPerRow / 4] = kBlue4;
835    }
836    for (; w < avail; w++)
837    {
838        p[w] = kGreen;
839        p[w + bytesPerRow / 4] = kGreen;
840    }
841    for (; w < width; w++)
842    {
843        p[w] = kWhite;
844        p[w + bytesPerRow / 4] = kWhite;
845    }
846   
847    //lines 2 to 14: blue or grey depending on whether we have the piece or not
848    uint32_t color;
849    for( w = 0; w < width; w++ )
850    {
851        if (pieces[w] < 0)
852            color = kGreen;
853        else if (pieces[w] == 0)
854            color = kGray;
855        else if (pieces[w] == 1)
856            color = kBlue1;
857        else if (pieces[w] == 2)
858            color = kBlue2;
859        else
860            color = kBlue3;
861       
862        //point to pixel (w, 2) and draw "vertically"
863        p = (uint32_t *) ( bitmapData + 2 * bytesPerRow ) + w;
864        for( h = 2; h < BAR_HEIGHT; h++ )
865        {
866            p[0] = color;
867            p = (uint32_t *) ( (uint8_t *) p + bytesPerRow );
868        }
869    }
870
871    free(pieces);
872   
873    //actually draw image
874    NSImage * bar = [[NSImage alloc] initWithSize: [bitmap size]];
875    [bar addRepresentation: bitmap];
876    [bitmap release];
877   
878    [bar setScalesWhenResized: YES];
879   
880    return [bar autorelease];
881}
882
883- (void) trashFile: (NSString *) path
884{
885    //attempt to move to trash
886    if (![[NSWorkspace sharedWorkspace] performFileOperation: NSWorkspaceRecycleOperation
887            source: [path stringByDeletingLastPathComponent] destination: @""
888            files: [NSArray arrayWithObject: [path lastPathComponent]] tag: nil])
889    {
890        //if cannot trash, just delete it (will work if it is on a remote volume)
891        if (![[NSFileManager defaultManager] removeFileAtPath: path handler: nil])
892            NSLog([@"Could not trash " stringByAppendingString: path]);
893    }
894}
895
896@end
Note: See TracBrowser for help on using the repository browser.