source: trunk/macosx/Torrent.m @ 985

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

Don't redraw the progress bar completely each time. The number of pieces for the bar is returned to the previous, larger value.

  • Property svn:keywords set to Date Rev Author Id
File size: 26.9 KB
Line 
1/******************************************************************************
2 * $Id: Torrent.m 985 2006-10-05 21:21:30Z 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            [NSString stringWithCString: (char *) peer.addr encoding: NSUTF8StringEncoding], @"IP",
629            [NSString stringWithCString: (char *) peer.client encoding: NSUTF8StringEncoding], @"Client",
630            [NSNumber numberWithBool: peer.isDownloading], @"UL To",
631            [NSNumber numberWithBool: peer.isUploading], @"DL From", nil]];
632    }
633   
634    tr_torrentPeersFree(peers, totalPeers);
635   
636    return peerDics;
637}
638
639- (NSString *) progressString
640{
641    return fProgressString;
642}
643
644- (NSString *) statusString
645{
646    return fStatusString;
647}
648
649- (NSString *) shortStatusString
650{
651    return fShortStatusString;
652}
653
654- (NSString *) remainingTimeString
655{
656    return fRemainingTimeString;
657}
658
659- (int) seeders
660{
661    return fStat->seeders;
662}
663
664- (int) leechers
665{
666    return fStat->leechers;
667}
668
669- (int) totalPeers
670{
671    return fStat->peersTotal;
672}
673
674//peers uploading to you
675- (int) peersUploading
676{
677    return fStat->peersUploading;
678}
679
680//peers downloading from you
681- (int) peersDownloading
682{
683    return fStat->peersDownloading;
684}
685
686- (float) downloadRate
687{
688    return fStat->rateDownload;
689}
690
691- (float) uploadRate
692{
693    return fStat->rateUpload;
694}
695
696- (float) downloadedValid
697{
698    return [self progress] * [self size];
699}
700
701- (uint64_t) downloadedTotal
702{
703    return fStat->downloaded;
704}
705
706- (uint64_t) uploadedTotal
707{
708    return fStat->uploaded;
709}
710
711- (float) swarmSpeed
712{
713    return fStat->swarmspeed;
714}
715
716- (NSNumber *) orderValue
717{
718    return [NSNumber numberWithInt: fOrderValue];
719}
720
721- (void) setOrderValue: (int) orderValue
722{
723    fOrderValue = orderValue;
724}
725
726- (NSArray *) fileList
727{
728    int count = fInfo->fileCount, i;
729    tr_file_t file;
730    NSMutableArray * files = [NSMutableArray arrayWithCapacity: count];
731   
732    for (i = 0; i < count; i++)
733    {
734        file = fInfo->files[i];
735        [files addObject: [NSDictionary dictionaryWithObjectsAndKeys:
736            [[self downloadFolder] stringByAppendingPathComponent: [NSString stringWithUTF8String: file.name]], @"Name",
737            [NSNumber numberWithUnsignedLongLong: file.length], @"Size", nil]];
738    }
739   
740    return files;
741}
742
743- (NSDate *) date
744{
745    return fDate;
746}
747
748- (NSNumber *) stateSortKey
749{
750    if (![self isActive])
751        return [NSNumber numberWithInt: 0];
752    else if ([self isSeeding])
753        return [NSNumber numberWithInt: 1];
754    else
755        return [NSNumber numberWithInt: 2];
756}
757
758- (NSNumber *) progressSortKey
759{
760    //if finished downloading sort by ratio instead of progress
761    float progress = [self progress];
762    return [NSNumber numberWithFloat: progress < 1.0 ? progress : 2.0 + [self ratio]];
763}
764
765@end
766
767
768@implementation Torrent (Private)
769
770//if a hash is given, attempt to load that; otherwise, attempt to open file at path
771- (id) initWithHash: (NSString *) hashString path: (NSString *) path lib: (tr_handle_t *) lib
772        privateTorrent: (NSNumber *) privateTorrent publicTorrent: (NSNumber *) publicTorrent
773        date: (NSDate *) date stopRatioSetting: (NSNumber *) stopRatioSetting
774        ratioLimit: (NSNumber *) ratioLimit waitToStart: (NSNumber *) waitToStart
775        orderValue: (NSNumber *) orderValue
776{
777    if (!(self = [super init]))
778        return nil;
779
780    fLib = lib;
781    fDefaults = [NSUserDefaults standardUserDefaults];
782
783    fPrivateTorrent = privateTorrent ? [privateTorrent boolValue] : [fDefaults boolForKey: @"SavePrivateTorrent"];
784    fPublicTorrent = !fPrivateTorrent || (publicTorrent ? [publicTorrent boolValue]
785                                            : ![fDefaults boolForKey: @"DeleteOriginalTorrent"]);
786
787    int error;
788    if (fPrivateTorrent && hashString)
789        fHandle = tr_torrentInitSaved(fLib, [hashString UTF8String], TR_FSAVEPRIVATE, & error);
790   
791    if (!fHandle && path)
792        fHandle = tr_torrentInit(fLib, [path UTF8String], fPrivateTorrent ? TR_FSAVEPRIVATE : 0, & error);
793
794    if (!fHandle)
795    {
796        [self release];
797        return nil;
798    }
799   
800    fInfo = tr_torrentInfo( fHandle );
801
802    if (fPublicTorrent)
803        fPublicTorrentLocation = [path retain];
804
805    fDate = date ? [date retain] : [[NSDate alloc] init];
806   
807    fStopRatioSetting = stopRatioSetting ? [stopRatioSetting intValue] : -1;
808    fRatioLimit = ratioLimit ? [ratioLimit floatValue] : [fDefaults floatForKey: @"RatioLimit"];
809    fFinishedSeeding = NO;
810   
811    fWaitToStart = waitToStart ? [waitToStart boolValue] : [fDefaults boolForKey: @"AutoStartDownload"];
812    fOrderValue = orderValue ? [orderValue intValue] : tr_torrentCount(fLib) - 1;
813    fError = NO;
814   
815    NSString * fileType = fInfo->multifile ? NSFileTypeForHFSTypeCode('fldr') : [[self name] pathExtension];
816    fIcon = [[NSWorkspace sharedWorkspace] iconForFileType: fileType];
817    [fIcon retain];
818   
819    fIconFlipped = [fIcon copy];
820    [fIconFlipped setFlipped: YES];
821   
822    fIconSmall = [fIconFlipped copy];
823    [fIconSmall setScalesWhenResized: YES];
824    [fIconSmall setSize: NSMakeSize(16.0, 16.0)];
825
826    fProgressString = [[NSMutableString alloc] initWithCapacity: 50];
827    fStatusString = [[NSMutableString alloc] initWithCapacity: 75];
828    fShortStatusString = [[NSMutableString alloc] initWithCapacity: 30];
829    fRemainingTimeString = [[NSMutableString alloc] initWithCapacity: 30];
830   
831    //set up advanced bar
832    fBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: nil
833        pixelsWide: MAX_PIECES pixelsHigh: BAR_HEIGHT bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES
834        isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: 0 bitsPerPixel: 0];
835   
836    fPieces = malloc(MAX_PIECES);
837    int i;
838    for (i = 0; i < MAX_PIECES; i++)
839        fPieces[i] = BLANK_PIECE;
840
841    [self update];
842    return self;
843}
844
845- (NSImage *) advancedBar
846{
847    int h, w;
848    uint32_t * p;
849    uint8_t * bitmapData = [fBitmap bitmapData];
850    int bytesPerRow = [fBitmap bytesPerRow];
851
852    int8_t * pieces = malloc(MAX_PIECES);
853    [self getAvailability: pieces size: MAX_PIECES];
854    int avail = 0;
855    for (w = 0; w < MAX_PIECES; w++)
856        if (pieces[w] != 0)
857            avail++;
858
859    //first two lines: dark blue to show progression, green to show available
860    int end = [self progress] * MAX_PIECES;
861    p = (uint32_t *) bitmapData;
862
863    for (w = 0; w < end; w++)
864    {
865        p[w] = kBlue4;
866        p[w + bytesPerRow / 4] = kBlue4;
867    }
868    for (; w < avail; w++)
869    {
870        p[w] = kGreen;
871        p[w + bytesPerRow / 4] = kGreen;
872    }
873    for (; w < MAX_PIECES; w++)
874    {
875        p[w] = kWhite;
876        p[w + bytesPerRow / 4] = kWhite;
877    }
878   
879    //lines 2 to 14: blue or grey depending on whether we have the piece or not
880    uint32_t color;
881    BOOL change;
882    for (w = 0; w < MAX_PIECES; w++)
883    {
884        change = NO;
885        if (pieces[w] < 0)
886        {
887            if (fPieces[w] != -1)
888            {
889                color = kGreen;
890                fPieces[w] = -1;
891                change = YES;
892            }
893        }
894        else if (pieces[w] == 0)
895        {
896            if (fPieces[w] != 0)
897            {
898                color = kGray;
899                fPieces[w] = 0;
900                change = YES;
901            }
902        }
903        else if (pieces[w] == 1)
904        {
905            if (fPieces[w] != 1)
906            {
907                color = kBlue1;
908                fPieces[w] = 1;
909                change = YES;
910            }
911        }
912        else if (pieces[w] == 2)
913        {
914            if (fPieces[w] != 2)
915            {
916                color = kBlue2;
917                fPieces[w] = 2;
918                change = YES;
919            }
920        }
921        else
922        {
923            if (fPieces[w] != 3)
924            {
925                color = kBlue3;
926                fPieces[w] = 3;
927                change = YES;
928            }
929        }
930       
931        if (change)
932        {
933            //point to pixel (w, 2) and draw "vertically"
934            p = (uint32_t *)(bitmapData + 2 * bytesPerRow) + w;
935            for (h = 2; h < BAR_HEIGHT; h++)
936            {
937                p[0] = color;
938                p = (uint32_t *)((uint8_t *)p + bytesPerRow);
939            }
940        }
941    }
942
943    free(pieces);
944   
945    //actually draw image
946    NSImage * bar = [[NSImage alloc] initWithSize: [fBitmap size]];
947    [bar addRepresentation: fBitmap];
948    [bar setScalesWhenResized: YES];
949   
950    return [bar autorelease];
951}
952
953- (void) trashFile: (NSString *) path
954{
955    //attempt to move to trash
956    if (![[NSWorkspace sharedWorkspace] performFileOperation: NSWorkspaceRecycleOperation
957            source: [path stringByDeletingLastPathComponent] destination: @""
958            files: [NSArray arrayWithObject: [path lastPathComponent]] tag: nil])
959    {
960        //if cannot trash, just delete it (will work if it is on a remote volume)
961        if (![[NSFileManager defaultManager] removeFileAtPath: path handler: nil])
962            NSLog([@"Could not trash " stringByAppendingString: path]);
963    }
964}
965
966@end
Note: See TracBrowser for help on using the repository browser.