source: trunk/macosx/Torrent.m @ 987

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

Tooltips display if peer is from incoming or outgoing connection.

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